dido.c 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511
  1. /******************************************************************************
  2. 版权所有:
  3. 文件名称: dido.c
  4. 文件版本: 01.01
  5. 创建作者: sunxi
  6. 创建日期: 2013-02-28
  7. 功能说明: 开入开出
  8. 其它说明:
  9. // 启动继电器
  10. 1、启动继电器可以重复多次启动,每次启动都将重新计算超时时间。
  11. 2、启动继电器有2种关闭方式:
  12. 1) 超时自动关闭,超时时间为装置参数的遥控超时时间。
  13. 2) 通过函数调用关闭。
  14. 3、有保护启动标志时,选择继电器不允许关闭。
  15. 4、需提供启动继电器的超时设置函数.
  16. 5、只所以采用超时自动关闭,是因为以前的程序关闭方式存在问题,可能由于资源竞争的关系,
  17. 导致不该关闭时却关闭了,虽然概率很小,但理论上存在。
  18. 修改记录:
  19. */
  20. /*------------------------------- 头文件 --------------------------------------
  21. */
  22. #include "head.h"
  23. #include "gpio.h"
  24. #include "ad7616.h"
  25. /*------------------------------- 宏定义 --------------------------------------
  26. */
  27. #define DO_PWM_SW_HZ 0
  28. #define DO_PWM_SW_QD 1
  29. #define DO_PWM_SW_NULL 2
  30. #define DO_PWM_SW_FZ 3
  31. #define DO_QD_KC DO_OUT4
  32. /*------------------------------ 类型结构 -------------------------------------
  33. */
  34. /*------------------------------ 全局变量 -------------------------------------
  35. */
  36. struct di g_di[EQU_SLOT_NUM_MAX];
  37. struct _do g_do[EQU_SLOT_NUM_MAX];
  38. struct di_struct g_di_st[EQU_SLOT_NUM_MAX][DIDO_MAX_DI_PER_SLOT];
  39. struct do_struct g_do_st[DO_NUM];
  40. u16 g_do_status; // 开出状态,因为仅主板有开出
  41. u32 g_do_start_time;
  42. int g_do_flag;
  43. extern u32 g_brd_type_kz;
  44. struct rt_stat g_stat_di_delay;
  45. struct rt_stat g_stat_do_delay;
  46. static u32 di_error_count = 0;
  47. static u32 error_count = 0;
  48. struct do_time g_do_time[EQU_SLOT_NUM_MAX];
  49. /*------------------------------ 函数声明 -------------------------------------
  50. */
  51. static int _dido_do(u32 slot, u16 v, int is_on);
  52. static int _get_di(int slot, u16 di_num, u32 di, struct timespec ts);
  53. static inline void _io_do_status_update(int on, unsigned int i);
  54. unsigned int change_di_ch(unsigned int di);
  55. /*------------------------------ 外部函数 -------------------------------------
  56. 外部函数供其它实体文件引用,必须仔细检查传入参数的合法性.
  57. */
  58. /******************************************************************************
  59. 函数名称: dido_init
  60. 函数版本: 01.01
  61. 创建作者:
  62. 创建日期: 2013-03-13
  63. 函数说明: 开入开出初始化
  64. 参数说明: 无
  65. 返回值: 无
  66. 修改记录:
  67. */
  68. void dido_init_di(void)
  69. {
  70. u32 i, slot;
  71. u32 di0, di, di_num;
  72. di0 = gpio_get_di();
  73. // 主板
  74. slot = EQU_SLOT_KZ;
  75. di = (di0 & 0x7FFFF);
  76. g_di[slot].value[0] = di ^ g_di[slot].inv[0];
  77. di_num = equ_get_di_num(slot);
  78. for (i = 0; i < di_num; i++)
  79. {
  80. if (di & (1 << i))
  81. {
  82. g_di_st[slot][i].b_on = 1;
  83. }
  84. else
  85. {
  86. g_di_st[slot][i].b_on = 0;
  87. }
  88. if (g_di[slot].value[0] & (1 << i))
  89. {
  90. sw_di_set(g_di_st[slot][i].owner, g_di_st[slot][i].type, SW_DI_TYPE_ON);
  91. g_di[slot].ts_v[i][g_di[slot].ts_i[i].n] = 1;
  92. }
  93. g_di[slot].ts_t[i][g_di[slot].ts_i[i].n] = 0;
  94. g_di[slot].ts_i[i].n++;
  95. }
  96. }
  97. int dido_init(void)
  98. {
  99. u32 i;
  100. // 检查装置配置
  101. if (equ_config_null())
  102. {
  103. return -1;
  104. }
  105. // 初始化取反标志
  106. for (i = 0; i < g_equ_config->di_num; i++)
  107. {
  108. if (g_equ_config_di[i].is_Inverse == 0)
  109. {
  110. continue;
  111. }
  112. if (g_equ_config_di[i].slot < EQU_SLOT_NUM_MAX && g_equ_config_di[i].index < DIDO_MAX_DI_PER_SLOT)
  113. {
  114. if (g_equ_config_di[i].index < 32)
  115. {
  116. g_di[g_equ_config_di[i].slot].inv[0] |= 1 << g_equ_config_di[i].index;
  117. }
  118. else
  119. {
  120. g_di[g_equ_config_di[i].slot].inv[1] |= 1 << (g_equ_config_di[i].index - 32);
  121. }
  122. }
  123. }
  124. dido_init_di();
  125. dido_stat_reset();
  126. return 0;
  127. }
  128. // 只有分合闸有选择启动继电器
  129. int dido_do_have_select(u32 slot, u32 index)
  130. {
  131. int i = 0;
  132. i = equ_get_do_channel(index);
  133. if (i == DO_OUT0 || i == DO_OUT1 || i == DO_OUT5 || i == DO_OUT6)
  134. {
  135. return 1;
  136. }
  137. return 0;
  138. }
  139. /******************************************************************************
  140. 函数名称: dido_do
  141. 函数版本: 01.01
  142. 创建作者:
  143. 创建日期: 2013-03-13
  144. 函数说明: 板卡开出动作
  145. 参数说明: 无
  146. 返回值:
  147. 修改记录:
  148. */
  149. int dido_do(u32 slot, u16 v, int is_on)
  150. {
  151. // unsigned long flags;
  152. // 检查DO资源
  153. if (equ_get_do_num(slot) == 0)
  154. {
  155. return -2;
  156. }
  157. // 保存输出值,在5ms中断中输出
  158. rt_irq_save(flags);
  159. g_do_flag = 1;
  160. if (is_on)
  161. {
  162. g_do[slot].on |= v;
  163. }
  164. else
  165. {
  166. g_do[slot].off |= v;
  167. }
  168. rt_irq_restore(flags);
  169. return 0;
  170. }
  171. /******************************************************************************
  172. 函数名称: do_kout_check
  173. 函数版本:
  174. 创建作者:
  175. 创建日期: 2013-03-13
  176. 函数说明: 开出反校。
  177. 参数说明: 无
  178. 返回值: 结果
  179. 修改记录:
  180. */
  181. void io_do_check(void)
  182. {
  183. u16 now, fj;
  184. u32 us;
  185. #ifdef DO_KOUT_CHECK
  186. u8 index;
  187. // 取返校值,必须在下面时间点检查之
  188. index = g_equ_config_di[g_sw[0].di_cfg_index[SW_DI_KOCHK]].index;
  189. fj = gpio_di_fj(index) & 0x01; // 0x02;
  190. // 返回值只判断启动、分闸、合闸
  191. now = 0;
  192. if (g_do_status & (1 << DO_QD_KC)) // 预置反校DO_PWM_SW_QD
  193. {
  194. now |= 0x01;
  195. }
  196. // if(g_do_status &((1<<DO_PWM_SW_FZ)|(1<<DO_PWM_SW_HZ)))//动作反校
  197. //{
  198. // now |= 0x01;//0x02;
  199. //}
  200. #else
  201. // 取返校值,必须在下面时间点检查之
  202. fj = gpio_di_fj() & 0x02;
  203. // 返回值只判断启动、分闸、合闸
  204. now = 0;
  205. if (g_do_status & (1 << DO_PWM_SW_QD))
  206. {
  207. // now |= 0x01;
  208. }
  209. if (g_do_status & ((1 << DO_PWM_SW_FZ) | (1 << DO_PWM_SW_HZ)))
  210. {
  211. now |= 0x02;
  212. }
  213. #endif
  214. // 开出动作20ms内不进行开出自检,
  215. // 经实测启动继电器因为是继电器触点返校,其返回时间最长,但也小于10ms。
  216. // 分合闸继电器是光耦返校,本身需要的时间可以忽略不计,但受启动继电器的影响
  217. us = ustimer_get_duration(g_do_start_time);
  218. if (us < 20 * 1000)
  219. {
  220. return;
  221. }
  222. if (fj != now)
  223. {
  224. // rt_printf("返校失败:fj=%04x,now=%04x, g_do_status=%04x(us=%d)\r\n",fj,now, g_do_status,us);
  225. rt_err_set(ERR_CODE_DO_CHECK, 0);
  226. return;
  227. }
  228. }
  229. /******************************************************************************
  230. 函数名称: io_do_return
  231. 函数版本: 01.01
  232. 创建作者:
  233. 创建日期: 2013-03-13
  234. 函数说明: 开出保持时间
  235. 参数说明: 无
  236. 返回值: 无
  237. 修改记录:
  238. */
  239. void io_do_return(void)
  240. {
  241. int i;
  242. u32 dly;
  243. for (i = 0; i < DO_NUM; i++) // 开出保持
  244. {
  245. if (g_do_status & (1 << i)) // 正在开出
  246. {
  247. dly = ustimer_get_duration(g_do_st[i].us_on);
  248. // +2500是为了提高脉宽精度,因为此函数是在5ms(5000)中断中调用的.
  249. // 如果us_keep为0,表示此开出没有自动返回的需求,应忽略。
  250. if (((dly + 2500) > g_do_st[i].us_keep) && (g_do_st[i].us_keep > 0))
  251. {
  252. dido_do_kz(0, i);
  253. }
  254. }
  255. }
  256. }
  257. /******************************************************************************
  258. 函数名称: dido_do_poll
  259. 函数版本: 01.01
  260. 创建作者:
  261. 创建日期: 2013-03-13
  262. 函数说明: 是否开出巡检
  263. 参数说明: 无
  264. 返回值: 无
  265. 修改记录:
  266. */
  267. void dido_do_poll(void)
  268. {
  269. #if 1
  270. int i;
  271. // 真正开出
  272. if (g_do_flag)
  273. {
  274. g_do_flag = 0;
  275. for (i = 0; i < EQU_SLOT_NUM_MAX; i++)
  276. {
  277. if (g_do[i].on)
  278. {
  279. _dido_do(i, g_do[i].on, 1);
  280. g_do[i].on = 0;
  281. }
  282. if (g_do[i].off)
  283. {
  284. _dido_do(i, g_do[i].off, 0);
  285. g_do[i].off = 0;
  286. }
  287. }
  288. }
  289. // 开出返回
  290. io_do_return();
  291. // 开出返校
  292. if (g_board_info[EQU_SLOT_KZ].do_num != 0)
  293. {
  294. #ifdef DO_KOUT_CHECK
  295. if ((short)g_sw[0].di_cfg_index[SW_DI_KOCHK] != INDEX_INVALLID)
  296. {
  297. io_do_check();
  298. }
  299. #else
  300. // io_do_check();
  301. #endif
  302. }
  303. return;
  304. #endif
  305. }
  306. /******************************************************************************
  307. 函数名称: dido_qd_set_keeptime
  308. 函数版本: 01.01
  309. 创建作者: sunxi
  310. 创建日期: 2013-06-10
  311. 函数说明: 设置启动继电器的保持时间
  312. 参数说明: 无
  313. 返回值: 无
  314. 修改记录:
  315. */
  316. void dido_qd_set_keeptime(u32 us)
  317. {
  318. g_do_st[DO_QD_KC].us_keep = us;
  319. }
  320. /******************************************************************************
  321. 函数名称: get_di
  322. 函数版本: 01.01
  323. 创建作者:
  324. 创建日期: 2013-03-13
  325. 函数说明: 开入防抖处理
  326. 参数说明: 无
  327. 返回值: 无
  328. 修改记录:
  329. */
  330. // unsigned int di_val;
  331. void dido_di_poll(SHM_SAMPLE_T *sample_data)
  332. {
  333. u32 di, di_num, slot;
  334. u64 us0;
  335. // 如果交流延时失电信号有,闭锁遥信
  336. if (pRunSet->dSDYX_T && g_run_stu.dcjlsd_t)
  337. {
  338. return;
  339. }
  340. us0 = ustimer_get_origin();
  341. // 主板,19个遥信
  342. slot = EQU_SLOT_KZ;
  343. di_num = equ_get_di_num(slot);
  344. // di = gpio_get_di();
  345. di = change_di_ch(~sample_data->yx_buf[0]);
  346. rt_printf("gpio_get_di:yx_buf[0]=%x di=%x\r\n", sample_data->yx_buf[0], di);
  347. _get_di(slot, di_num, di, sample_data->ts);
  348. rt_stat_other_in(6, ustimer_get_duration(us0));
  349. }
  350. /******************************************************************************
  351. 函数名称: dido_di_is_on
  352. 函数版本: 01.01
  353. 创建作者:
  354. 创建日期: 2013-03-13
  355. 函数说明: 开入状态
  356. 参数说明: 无
  357. 返回值: 1:有开入,0:无开入
  358. 修改记录:
  359. */
  360. int dido_di_is_on(u8 slot, u8 index)
  361. {
  362. if (slot >= EQU_SLOT_NUM_MAX || index >= 64)
  363. {
  364. return 0;
  365. }
  366. if (index < 32)
  367. {
  368. if (g_di[slot].value[0] & (1 << index))
  369. {
  370. return 1;
  371. }
  372. }
  373. else
  374. {
  375. index -= 32;
  376. if (g_di[slot].value[1] & (1 << index))
  377. {
  378. return 1;
  379. }
  380. }
  381. return 0;
  382. }
  383. // 查看某个时间点下的开入值
  384. int dido_di_is_on_ts(u8 slot, u8 index, u32 ts)
  385. {
  386. int i, r;
  387. struct ts_index ts_i;
  388. if (slot >= EQU_SLOT_NUM_MAX || index >= 32)
  389. {
  390. return 0;
  391. }
  392. #if 0
  393. {
  394. static int cnt = 0;
  395. if(cnt++ < 16)
  396. rt_printf("slot=%d,index=%d,ts=%d.\r\n",slot,index,ts);
  397. }
  398. #endif
  399. ts_i.n = g_di[slot].ts_i[index].n - 1; // ts_i下是无值的,所以应该减1
  400. for (i = 0; i < DIDO_TS_NUM; i++)
  401. {
  402. r = (int)(ts - g_di[slot].ts_t[index][ts_i.n]);
  403. if (r >= 0)
  404. {
  405. return g_di[slot].ts_v[index][ts_i.n];
  406. }
  407. ts_i.n--;
  408. }
  409. if (g_di[slot].value[0] & (1 << index))
  410. {
  411. return 1;
  412. }
  413. return 0;
  414. }
  415. int dido_do_kz(int on, unsigned int i)
  416. {
  417. if (on) // 开出,需启动启动继电器打开电源
  418. {
  419. if (i == DO_OUT0 || i == DO_OUT1 || i == DO_OUT5 || i == DO_OUT6)
  420. {
  421. gpio_kout_do(on, DO_QD_KC - DO_OUT0); // 对应X4端子的DO0~DO7
  422. _io_do_status_update(1, DO_QD_KC);
  423. }
  424. }
  425. // if(i<=DO_PWM3)
  426. // {
  427. // gpio_pwm_do(on, i); // 对应X3端子的OUT3,分闸
  428. // _io_do_status_update(on,i);
  429. // }
  430. // else
  431. if (i == DO_QD_KC) // 启动继电器出口
  432. {
  433. if (!on)
  434. {
  435. if (g_tRelay[0].zqd) // 如果保护启动,禁止关闭启动继电器
  436. {
  437. return -2;
  438. }
  439. if (g_do_status & (~(1 << DO_QD_KC))) // 有其他开出,不收启动继电器
  440. {
  441. return -3;
  442. }
  443. }
  444. gpio_kout_do(on, i - DO_OUT0); // 对应X4端子的DO0~DO7
  445. _io_do_status_update(on, i);
  446. }
  447. else if ((i >= DO_OUT0) && (i <= DO_OUT7))
  448. {
  449. gpio_kout_do(on, i - DO_OUT0); // 对应X4端子的DO0~DO7
  450. _io_do_status_update(on, i);
  451. }
  452. else
  453. {
  454. rt_printf("dido_do_kz err(on=%d,i=%d).\r\n", on, i);
  455. }
  456. return 0;
  457. }
  458. /*------------------------------ 内部函数 -------------------------------------
  459. 内部函数以下划线‘_’开头,不需要检查参数的合法性.
  460. */
  461. static inline void _io_do_status_update(int on, unsigned int i)
  462. {
  463. if (on)
  464. {
  465. g_do_status |= (1 << i);
  466. g_do_st[i].us_on = ustimer_get_origin();
  467. }
  468. else
  469. {
  470. g_do_status &= ~(1 << i);
  471. }
  472. // 更新返校检查时间
  473. g_do_start_time = ustimer_get_origin();
  474. }
  475. static int _dido_do(u32 slot, u16 v, int is_on)
  476. {
  477. int i;
  478. // 循环检查开出位
  479. for (i = 0; i < g_board_info[slot].do_num; i++)
  480. {
  481. // 如果对应开出位有效,开出。
  482. if (((v >> i) & 0x1))
  483. {
  484. dido_do_kz(is_on, equ_get_do_channel(i));
  485. }
  486. }
  487. if (((v >> g_board_info[slot].do_num) & 0x1)) // 启动继电器
  488. {
  489. dido_do_kz(is_on, DO_QD_KC);
  490. }
  491. return 0;
  492. }
  493. /******************************************************************************
  494. 函数名称: _get_di
  495. 函数版本: 01.01
  496. 创建作者:
  497. 创建日期: 2013-03-13
  498. 函数说明: 开入防抖处理
  499. 参数说明: 无
  500. 返回值:
  501. 修改记录:
  502. */
  503. #ifdef CN_AREA_GUANGXI // 遥信全部为0
  504. u32 kktime_0 = 0;
  505. #endif
  506. static int _get_di(int slot, u16 di_num, u32 di, struct timespec ts)
  507. {
  508. int i, b_on;
  509. struct rtc_time_t ct;
  510. uint32 diff_nsec;
  511. // struct timespec ts;
  512. #if 0 // #ifdef CN_AREA_GUANGXI//遥信全部为0,则关闭屏幕或者关机
  513. if(di==0)
  514. {
  515. kktime_0++;
  516. if(kktime_0 > 10)
  517. {
  518. #if 1
  519. g_run_stu.yxError=true; //遥信错误,关闭屏幕
  520. #else
  521. char *argv[] = {"poweroff", NULL};
  522. char *envp[] = { NULL };
  523. call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);//关机
  524. #endif
  525. return 0;
  526. }
  527. }
  528. else
  529. {
  530. g_run_stu.yxError=0;
  531. kktime_0=0;
  532. }
  533. #endif
  534. // 获取遥信值,并记录时间戳。
  535. // 用秒的低8位和纳秒的高24位合成32位时间戳
  536. // clk_time_get(&ts);
  537. // 循环处理每一个遥信
  538. for (i = 0; i < di_num; i++)
  539. {
  540. struct di_struct *pt = &g_di_st[slot][i];
  541. // 处理当前变位遥信。
  542. b_on = (di & (1 << i)) ? 1 : 0;
  543. if (b_on ^ pt->b_on)
  544. {
  545. if (!pt->b_first_change)
  546. {
  547. pt->b_first_change = true;
  548. pt->tm_back = 0;
  549. pt->tm_keep = 0;
  550. // 记录变位的起始时刻点
  551. pt->ts_di = ts;
  552. pt->dt = g_adc_dots_data_count;
  553. #ifdef DIDO_TS_MODE
  554. pt->ts_tmp = ts;
  555. #endif
  556. }
  557. else
  558. {
  559. // 累计保持时间
  560. #ifdef DIDO_TS_MODE
  561. if (ts.tv_nsec >= pt->ts_tmp.tv_nsec)
  562. {
  563. diff_nsec = ts.tv_nsec - pt->ts_tmp.tv_nsec;
  564. }
  565. else
  566. {
  567. diff_nsec = 1000000000ul - pt->ts_tmp.tv_nsec + ts.tv_nsec;
  568. }
  569. if (diff_nsec > 312500ul)
  570. {
  571. diff_nsec = 156250ul;
  572. }
  573. pt->acc_nsec += diff_nsec;
  574. while (pt->acc_nsec >= 156250ul)
  575. {
  576. pt->tm_keep++;
  577. pt->acc_nsec -= 156250ul;
  578. }
  579. pt->ts_tmp = ts;
  580. // rt_printf("diff_nsec:%d, pt->tm_keep:%d\r\n", diff_nsec, pt->tm_keep);
  581. #else
  582. pt->tm_keep++;
  583. #endif
  584. pt->tm_back = 0; // 现在返回门限是0.5us,所有必须在此清零。
  585. // 保持时间到,处理变位
  586. if (pt->tm_keep > pt->tm_filter)
  587. {
  588. // 记录遥信状态
  589. #if defined CN_AREA_GUANGXI || defined YX_DI_ERROR // 广西遥信异常后,遥信屏蔽不保存,不上报
  590. if (g_run_stu.yxEnable == 0 && b_on == 0)
  591. {
  592. pt->type = SOE_TYPE_TST;
  593. pt->b_first_change = false;
  594. pt->tm_back = 0;
  595. pt->tm_keep = 0;
  596. return 0;
  597. }
  598. #endif
  599. pt->b_on = b_on;
  600. if (g_di[slot].inv[0] & (1 << i))
  601. {
  602. b_on = !b_on;
  603. }
  604. if (b_on)
  605. {
  606. g_di[slot].value[0] |= (1 << i);
  607. }
  608. else
  609. {
  610. g_di[slot].value[0] &= ~(1 << i);
  611. }
  612. // 记录SOE
  613. soe_record_yx((WORD)(i + (slot << 8)), b_on, &pt->ts_di);
  614. timespec_to_rtc(ts, &ct, 1);
  615. rt_printf("di=%x value[0]=%x\r\n", di, g_di[slot].value[0]);
  616. // 更新逻辑模型中的值
  617. sw_di_set(g_di_st[slot][i].owner, g_di_st[slot][i].type, b_on ? SW_DI_TYPE_ON : SW_DI_TYPE_OFF);
  618. // 更新记录
  619. g_di[slot].ts_t[i][g_di[slot].ts_i[i].n] = pt->dt;
  620. g_di[slot].ts_v[i][g_di[slot].ts_i[i].n] = b_on;
  621. g_di[slot].ts_i[i].n++;
  622. // 滤波处理数据复位
  623. pt->b_first_change = false;
  624. pt->tm_back = 0;
  625. pt->tm_keep = 0;
  626. }
  627. }
  628. }
  629. else if (pt->b_first_change)
  630. {
  631. // 变位返回处理
  632. pt->tm_back++;
  633. // 屏蔽下一行,
  634. // 最新逻辑,有效电平不连续可计数累加;
  635. // 无效电平连续超0.5ms复归,且不连续累加。
  636. // pt->tm_keep=0;
  637. // if(pt->tm_back > pt->tm_filter)
  638. if (pt->tm_back > 4) // 针对高频振荡波测试优化,返回门限设置为500us附件(4*156=624us)。
  639. {
  640. pt->tm_back = 0;
  641. pt->tm_keep = 0;
  642. pt->b_first_change = false;
  643. }
  644. }
  645. }
  646. return 0;
  647. }
  648. #if (0) /* TODO 获取开入量 */
  649. int dido_di_update(uint32_t _value_new, uint8_t _index, struct timespec *ts)
  650. {
  651. static uint8_t init_flag = 0;
  652. uint32_t dt;
  653. int i, j, is_on;
  654. if (init_flag == 0)
  655. {
  656. init_flag = 1;
  657. // DI数量未超32个,只用第一个元素就够了
  658. g_di[g_di_slot].value[0] = _value_new;
  659. // 更新逻辑模型中的值
  660. for (i = 0; i < DIDO_MAX_DI_PER_SLOT; i++)
  661. {
  662. is_on = (g_di[g_di_slot].value[0] & (1 << i)) ? 1 : 0;
  663. sw_di_set(g_di_st[g_di_slot][i].owner,
  664. g_di_st[g_di_slot][i].type,
  665. is_on ? SW_DI_TYPE_ON : SW_DI_TYPE_OFF);
  666. // 双点的值也需要重新初始化
  667. plc_db_init_value(g_di_slot, i, is_on);
  668. // 遥信时标
  669. g_di[g_di_slot].ts_t[i][g_di[g_di_slot].ts_i[i].n] = 0;
  670. g_di[g_di_slot].ts_v[i][g_di[g_di_slot].ts_i[i].n] = is_on;
  671. g_di[g_di_slot].ts_i[i].n++;
  672. }
  673. g_di[g_di_slot].bInited = RT_TRUE;
  674. return 0;
  675. }
  676. if (_value_new == 1)
  677. g_di[g_di_slot].value[0] |= _value_new << _index;
  678. else
  679. g_di[g_di_slot].value[0] &= ~((_value_new ^ 1) << _index);
  680. // clock_gettime(CLOCK_REALTIME, &ts);
  681. // 记录遥信变位
  682. is_on = (g_di[g_di_slot].value[0] & (1 << _index)) ? 1 : 0;
  683. soe_record_yx(_index + (g_di_slot << 8), is_on, ts);
  684. // 更新逻辑模型中的值
  685. sw_di_set(g_di_st[g_di_slot][_index].owner,
  686. g_di_st[g_di_slot][_index].type,
  687. (is_on) ? SW_DI_TYPE_ON : SW_DI_TYPE_OFF);
  688. // 更新记录
  689. // TODO:原DTU此处更新采样点会关中断更新,但考虑到频繁关中断会影响采样,此处不关中断先观察
  690. dt = g_adc_dots_count;
  691. g_di[g_di_slot].ts_t[_index][g_di[g_di_slot].ts_i[_index].n] = dt;
  692. g_di[g_di_slot].ts_v[_index][g_di[g_di_slot].ts_i[_index].n] = is_on;
  693. g_di[g_di_slot].ts_i[_index].n++;
  694. // rt_kprintf("板卡:%d,di[%d]:%d\r\n",g_di_slot,_index,is_on); //test_use
  695. }
  696. /**
  697. * @brief Get the shm didata object
  698. * @author lch (lch_work@foxmail.com)
  699. * @version 1.0
  700. * @date 20251219
  701. * @return * int
  702. * @retval none
  703. *
  704. * @warning none
  705. * @note none
  706. */
  707. int get_shm_didata(void)
  708. {
  709. int l_read_ret = 0, l_cnt = 0;
  710. struct t_shmdata_di shm_data_di = {0};
  711. l_read_ret = shm_packet_read_v2(SHM_ADDR_W_DI, sizeof(shm_data_di), (uint8_t *)&shm_data_di, sizeof(shm_data_di));
  712. while (l_read_ret > 0)
  713. {
  714. if (++l_cnt > 5)
  715. break;
  716. usleep(300);
  717. }
  718. }
  719. #endif
  720. /*------------------------------ 测试函数 -------------------------------------
  721. 一个实体文件必须带一个本模块的测试函数来进行单元测试,如果的确不方便在本模块中
  722. 进行单元测试,必须在此注明实际的测试位置(例如在哪个实体文件中使用哪个测试函数).
  723. */
  724. // SOE信号发生器控制全局变量
  725. extern int g_soe_gen_state; // 状态,0停止,1初始化,2运行
  726. extern int g_soe_gen_on_us; // 导通时间
  727. extern int g_soe_gen_off_us; // 断开时间
  728. extern int g_soe_gen_seq_us; // 通道序列间隔时间
  729. #define SOE_GEN_NUM 8
  730. u32 g_soe_gen_count;
  731. u32 g_soe_gen_us0[SOE_GEN_NUM];
  732. u8 g_soe_gen_on[SOE_GEN_NUM];
  733. void dido_soe_gen(void)
  734. {
  735. int i;
  736. if (g_soe_gen_state == 0)
  737. {
  738. return;
  739. }
  740. else if (g_soe_gen_state == 1)
  741. {
  742. pit_156us_period_set(78.125);
  743. g_soe_gen_count = 0;
  744. for (i = 0; i < SOE_GEN_NUM; i++)
  745. {
  746. g_soe_gen_us0[i] = g_soe_gen_seq_us * (i);
  747. g_soe_gen_on[i] = 0;
  748. g_soe_gen_state = 2;
  749. }
  750. }
  751. else if (dido_di_is_on(1, 0))
  752. {
  753. for (i = 0; i < SOE_GEN_NUM; i++)
  754. {
  755. if (g_soe_gen_on[i] == 0)
  756. {
  757. if ((int)(g_soe_gen_count - g_soe_gen_us0[i]) >= g_soe_gen_off_us)
  758. {
  759. g_soe_gen_on[i] = 1;
  760. gpio_kout_do(1, i);
  761. g_soe_gen_us0[i] = g_soe_gen_count;
  762. }
  763. }
  764. else
  765. {
  766. if ((int)(g_soe_gen_count - g_soe_gen_us0[i]) >= g_soe_gen_on_us)
  767. {
  768. g_soe_gen_on[i] = 0;
  769. gpio_kout_do(0, i);
  770. g_soe_gen_us0[i] = g_soe_gen_count;
  771. }
  772. }
  773. }
  774. }
  775. else
  776. {
  777. g_soe_gen_count = 0;
  778. for (i = 0; i < SOE_GEN_NUM; i++)
  779. {
  780. g_soe_gen_us0[i] = g_soe_gen_seq_us * (i);
  781. g_soe_gen_on[i] = 0;
  782. g_soe_gen_state = 2;
  783. }
  784. }
  785. g_soe_gen_count++;
  786. }
  787. int dido_printf(void)
  788. {
  789. int i, slot, index;
  790. struct ts_index ts_i;
  791. rt_printf("槽号\t值\r\n");
  792. for (i = 0; i < EQU_SLOT_NUM_MAX; i++) // xj 2015-5-4
  793. {
  794. rt_printf("%02d:\tvalue=0x%08lx_%08lx,inv=0x%08lx_%08lx\r\n", i, g_di[i].value[1], g_di[i].value[0], g_di[i].inv[1], g_di[i].inv[0]);
  795. }
  796. rt_printf("\r\n");
  797. slot = EQU_SLOT_MAIN;
  798. index = 1;
  799. ts_i.n = g_di[slot].ts_i[index].n;
  800. rt_printf("开入时间戳记录:slot=%d,index=%d,ts_i=%d.\r\n", slot, index, ts_i.n);
  801. rt_printf("序号\t值\t时间戳\r\n");
  802. ts_i.n = 0;
  803. for (i = 0; i < DIDO_TS_NUM; i++)
  804. {
  805. rt_printf("%02d\t%d\t%08lu\r\n", ts_i.n, g_di[slot].ts_v[index][ts_i.n], g_di[slot].ts_t[index][ts_i.n]);
  806. ts_i.n++;
  807. }
  808. rt_printf("开出状态:0x%04x\r\n\r\n", g_do_status);
  809. rt_stat_printf(&g_stat_di_delay);
  810. rt_stat_printf(&g_stat_do_delay);
  811. return 0;
  812. }
  813. int dido_stat_reset(void)
  814. {
  815. rt_stat_init(&g_stat_di_delay, "di_delay");
  816. rt_stat_init(&g_stat_do_delay, "do_delay");
  817. return 0;
  818. }
  819. int dido_single_test(u8 slot, u8 point)
  820. {
  821. dido_do(slot, (1 << point), 1);
  822. ustimer_delay(250 * USTIMER_MS);
  823. dido_do(slot, (1 << point), 0);
  824. return 0;
  825. }
  826. int dido_test(void)
  827. {
  828. static unsigned long us0 = 0;
  829. static char dido_test_pair[3][2] =
  830. {
  831. {1, 3},
  832. {2, 4},
  833. {5, 5},
  834. };
  835. static char dido_test_di[32] =
  836. {
  837. 0, 1, 2, 3,
  838. 0, 1, 2, 3,
  839. 4, 5, 6, 7,
  840. 4, 5, 6, 7,
  841. 8, 9, 10, 11,
  842. 8, 9, 10, 11,
  843. 12, 13, 10, 11,
  844. 12, 13, 12, 13};
  845. int i, j, k, err_once, di_num;
  846. u32 slot_di, slot_do;
  847. if (g_test_on == 0)
  848. {
  849. return 0;
  850. }
  851. // 5秒处理一次
  852. if (ustimer_delay_origin2(&us0, 10 * USTIMER_SEC) != 1)
  853. {
  854. return 0;
  855. }
  856. rt_printf("dido_test begin...\r\n");
  857. ustimer_delay(1 * USTIMER_SEC);
  858. #if 1
  859. // 测试开出板、开入板
  860. // 开出板逐一开出
  861. rt_printf("dido_test single.\r\n");
  862. err_once = 0;
  863. for (i = 0; i < 3; i++)
  864. {
  865. slot_do = dido_test_pair[i][0];
  866. slot_di = dido_test_pair[i][1];
  867. for (j = 0; j < equ_get_do_num(slot_do); j++)
  868. {
  869. dido_do(slot_do, (1 << j), 1);
  870. ustimer_delay(250 * USTIMER_MS);
  871. di_num = equ_get_di_num(slot_di);
  872. if (slot_di == equ_get_slot_by_type(BOARD_TYPE_AUX))
  873. {
  874. di_num -= 1;
  875. }
  876. for (k = 0; k < di_num; k++)
  877. {
  878. // 是否对应的开出点
  879. if (dido_test_di[k] == j)
  880. {
  881. if ((g_di[slot_di].value[0] & (1 << k)) == 0)
  882. {
  883. err_once++;
  884. error_count++;
  885. rt_printf("dido_test on err(err=%d):i=%d,j=%d,k=%d,di=0x%08lx.\r\n", err_once, i, j, k, g_di[slot_di].value[0]);
  886. }
  887. }
  888. else
  889. {
  890. if ((g_di[slot_di].value[0] & (1 << k)) != 0)
  891. {
  892. err_once++;
  893. error_count++;
  894. rt_printf("dido_test off err(err=%d):i=%d,j=%d,k=%d,di=0x%08lx.\r\n", err_once, i, j, k, g_di[slot_di].value[0]);
  895. }
  896. }
  897. }
  898. dido_do(slot_do, (1 << j), 0);
  899. ustimer_delay(20 * USTIMER_MS);
  900. watchdog_feed_mainloop();
  901. }
  902. }
  903. #endif
  904. rt_printf("\r\n开入变位时间超出次数:%lu\r\n", di_error_count);
  905. rt_printf("name\t\t\tmin\tmax\tavg\tsum\t\tcnt\n");
  906. rt_stat_printf(&g_stat_di_delay);
  907. rt_printf("\r\n");
  908. for (i = 0; i < EQU_SLOT_NUM_MAX; i++)
  909. {
  910. if (g_do_time[i].slot != 0)
  911. {
  912. rt_printf("do_time[%d]:diff_max=%lu,diff_out_count=%lu\r\n",
  913. g_do_time[i].slot, g_do_time[i].diff_max, g_do_time[i].diff_out_count);
  914. }
  915. }
  916. rt_printf("\r\n");
  917. rt_printf("dido_test end:err_once=%d,error_count=%lu!\r\n\r\n\r\n", err_once, error_count);
  918. return 0;
  919. }
  920. bool check_board_di_valid(u8 slot, u8 index)
  921. {
  922. u32 i;
  923. // 初始化取反标志
  924. index -= 1;
  925. for (i = 0; i < g_equ_config->di_num; i++)
  926. {
  927. if ((g_equ_config_di[i].slot == 1) && (g_equ_config_di[i].index == index))
  928. {
  929. if (g_equ_config_di[i].type == 0)
  930. return true;
  931. }
  932. }
  933. return false;
  934. }
  935. bool check_board_kc6_close(u8 slot, u8 index)
  936. {
  937. u32 i;
  938. // 初始化取反标志
  939. index -= 1;
  940. for (i = 0; i < g_equ_config->do_num; i++)
  941. {
  942. if ((g_equ_config_do[i].slot == slot) && (g_equ_config_do[i].index == index))
  943. {
  944. if (g_equ_config_do[i].type != 0)
  945. return true;
  946. }
  947. }
  948. return false;
  949. }
  950. #define DIGROUP 4
  951. #define V3_OUT_NUM 5
  952. int dido_auto_test_for_v3(char *buf, int num)
  953. {
  954. // 12个开入,用5个开出进行测试
  955. static char test_di[6][DIGROUP] =
  956. {
  957. {1, 6, 11, 0},
  958. {2, 7, 12, 0},
  959. {3, 8, 13, 0},
  960. {4, 9, 14, 0},
  961. {16, 0, 0, 0},
  962. {5, 10, 15, 0},
  963. };
  964. int i, j, k, err_once, flag, flag1, di_num, do_num;
  965. u32 slot_di, slot_do, di_result;
  966. u8 tmp[5], tmp_data[5];
  967. u8 di_ok[4] = {0};
  968. u8 do_errflag = 0;
  969. char dido_test_pair[num][2];
  970. unsigned long us_begin = 0;
  971. bool bkc6close = false;
  972. slot_do = 0;
  973. bkc6close = check_board_kc6_close(1, 6);
  974. dido_stat_reset();
  975. if (bkc6close)
  976. {
  977. dido_do(slot_do, (1 << 5), 1); // 开出6若焊接为常闭输出,先开出,打开节点
  978. ustimer_delay(100 * USTIMER_MS);
  979. }
  980. // 取出板卡槽位
  981. for (i = 0; i < (num * 2);)
  982. {
  983. for (j = 0; j < 2; j++)
  984. {
  985. dido_test_pair[i / 2][j] = buf[i];
  986. i++;
  987. }
  988. }
  989. flag = 0;
  990. flag1 = 0;
  991. memset(tmp, 0, sizeof(tmp));
  992. memset(tmp_data, 0, sizeof(tmp_data));
  993. memset(dido_buf, 0, sizeof(dido_buf));
  994. rt_printf("dido_test begin...\r\n");
  995. err_once = 0;
  996. // 以组为循环
  997. for (i = 0; i < num; i++)
  998. {
  999. slot_do = dido_test_pair[i][0];
  1000. slot_di = dido_test_pair[i][1];
  1001. // 槽位暂存
  1002. dido_buf[i + i * 13] = slot_do;
  1003. dido_buf[i + i * 13 + 5] = slot_di;
  1004. // 取出对应槽位的板卡中DI和DO的数量
  1005. di_num = equ_get_di_num(slot_di);
  1006. do_num = equ_get_do_num(slot_do);
  1007. // dido_do(slot_do,(1<<5),1); //磁保持继电器
  1008. // 启动记时
  1009. us_begin = ustimer_get_origin();
  1010. // 逐一输出开出点
  1011. for (j = 0; j < V3_OUT_NUM; j++)
  1012. {
  1013. dido_do(slot_do, (1 << j), 1);
  1014. if (j == 5 && bkc6close)
  1015. {
  1016. dido_do(slot_do, (1 << 5), 0); // 开出6若焊接为常闭输出,反操作为闭合
  1017. }
  1018. ustimer_delay(150 * USTIMER_MS);
  1019. memset(di_ok, 0, sizeof(di_ok));
  1020. do_errflag = DIGROUP;
  1021. for (k = 0; k < 4; k++)
  1022. {
  1023. bool bIgnore = false;
  1024. di_result = (g_di[slot_di].value[0] ^ g_di[slot_di].inv[0]);
  1025. k += i * 2;
  1026. if (test_di[j][k] == 17)
  1027. {
  1028. bIgnore = check_board_di_valid(slot_di, 17);
  1029. }
  1030. if (test_di[j][k] == 18)
  1031. {
  1032. bIgnore = check_board_di_valid(slot_di, 18);
  1033. }
  1034. if (!test_di[j][k] || bIgnore)
  1035. {
  1036. do_errflag--;
  1037. }
  1038. else
  1039. {
  1040. if (!(di_result & (1 << (test_di[j][k] - 1)))) // 对应开入无值
  1041. {
  1042. do_errflag--;
  1043. di_ok[k] = test_di[j][k];
  1044. }
  1045. }
  1046. }
  1047. if (!do_errflag) // 开出对应的所有开入都没有值,即代表该开出有问题
  1048. {
  1049. if (j < 8)
  1050. {
  1051. dido_buf[i + i * 13 + 1] |= (1 << j); // 开出错误标志
  1052. }
  1053. else if (j < 16)
  1054. {
  1055. dido_buf[i + i * 13 + 2] |= (1 << (j - 8)); // 开出错误标志
  1056. }
  1057. rt_printf("dido_test do err:i=%d,j=%d,di=%d,di_l=0x%04lx,di_h=0x%04lx.\r\n",
  1058. i, j, di_ok[0], g_di[slot_di].value[0], g_di[slot_di].value[1]);
  1059. }
  1060. else
  1061. {
  1062. for (k = 0; k < 4; k++)
  1063. {
  1064. if (!di_ok[k])
  1065. continue;
  1066. if ((di_ok[k] - 1) < 8)
  1067. {
  1068. dido_buf[i + i * 13 + 6] |= (1 << (di_ok[k] - 1));
  1069. }
  1070. else if ((di_ok[k] - 1) < 16)
  1071. {
  1072. dido_buf[i + i * 13 + 7] |= (1 << (di_ok[k] - 1 - 8));
  1073. }
  1074. else if ((di_ok[k] - 1) < 24)
  1075. {
  1076. dido_buf[i + i * 13 + 8] |= (1 << (di_ok[k] - 1 - 16));
  1077. }
  1078. else if ((di_ok[k] - 1) < 32)
  1079. {
  1080. dido_buf[i + i * 13 + 9] |= (1 << (di_ok[k] - 1 - 24));
  1081. }
  1082. else if ((di_ok[k] - 1) < 40)
  1083. {
  1084. dido_buf[i + i * 13 + 10] |= (1 << (di_ok[k] - 1 - 32));
  1085. }
  1086. else if ((di_ok[k] - 1) < 48)
  1087. {
  1088. dido_buf[i + i * 13 + 11] |= (1 << (di_ok[k] - 1 - 40));
  1089. }
  1090. else if ((di_ok[k] - 1) < 56)
  1091. {
  1092. dido_buf[i + i * 13 + 12] |= (1 << (di_ok[k] - 1 - 48));
  1093. }
  1094. else if ((di_ok[k] - 1) < 64)
  1095. {
  1096. dido_buf[i + i * 13 + 13] |= (1 << (di_ok[k] - 1 - 56));
  1097. }
  1098. rt_printf("dido_test di err:i=%d,j=%d,di=%d,di_l=0x%04lx,di_h=0x%04lx.\r\n",
  1099. i, j, di_ok[k], g_di[slot_di].value[0], g_di[slot_di].value[1]);
  1100. }
  1101. }
  1102. dido_do(slot_do, (1 << j), 0);
  1103. if (j == 5 && bkc6close)
  1104. {
  1105. dido_do(slot_do, (1 << 5), 1); // 开出6若焊接为常闭输出,反操作为闭合
  1106. }
  1107. // if(j==4)
  1108. //{
  1109. // dido_do(slot_do,(1<<5),1); //磁保持继电器
  1110. //}
  1111. ustimer_delay(20 * USTIMER_MS);
  1112. watchdog_feed_mainloop();
  1113. }
  1114. }
  1115. for (i = 0; i < EQU_SLOT_NUM_MAX; i++)
  1116. {
  1117. if (g_do_time[i].slot != 0)
  1118. {
  1119. rt_printf("do_time[%d]:diff_max=%lu,diff_out_count=%lu\r\n",
  1120. g_do_time[i].slot, g_do_time[i].diff_max, g_do_time[i].diff_out_count);
  1121. }
  1122. }
  1123. rt_printf("dido_test end:err_once=%d,error_count=%lu!\r\n\r\n\r\n", err_once, error_count);
  1124. return 0;
  1125. }
  1126. int dido_auto_test(char *buf, int num)
  1127. {
  1128. #define KC_COUNT 11
  1129. // 12个开入,用5个开出进行测试
  1130. #if 0
  1131. static char test_di[6][DIGROUP] =
  1132. {
  1133. {1, 6, 11,0},
  1134. {2, 7, 12,0},
  1135. {3, 8, 13,0},
  1136. {4, 9, 14,0},
  1137. {16, 0, 0,0},
  1138. {5, 10, 15,0},
  1139. };
  1140. #endif
  1141. static char test_di[KC_COUNT][DIGROUP] =
  1142. {
  1143. {1, 12, 23, 0},
  1144. {2, 13, 24, 0},
  1145. {3, 14, 0, 0},
  1146. {4, 15, 0, 0},
  1147. {5, 16, 0, 0},
  1148. {6, 17, 0, 0},
  1149. {7, 18, 0, 0},
  1150. {8, 19, 0, 0},
  1151. {9, 20, 0, 0},
  1152. {10, 21, 0, 0},
  1153. {11, 22, 0, 0},
  1154. // { 0, 0, 0,0}
  1155. };
  1156. u8 brd_v3[] = {22, 23};
  1157. int i, j, k, err_once, flag, flag1, di_num, do_num;
  1158. u32 slot_di, slot_do, di_result;
  1159. u8 tmp[5], tmp_data[5];
  1160. u8 di_ok[4] = {0};
  1161. u8 do_errflag = 0;
  1162. char dido_test_pair[num][2];
  1163. unsigned long us_begin = 0;
  1164. bool bkc6close = false;
  1165. rt_printf("g_brd_type_kz = %lu\r\n ", g_brd_type_kz);
  1166. rt_printf("g_equ_config->do_num = %lu\r\n ", g_equ_config->do_num);
  1167. for (i = 0; i < (int)sizeof(brd_v3); i++)
  1168. {
  1169. if (g_brd_type_kz + BOARD_TYPE_DFTU_KC00 == brd_v3[i]) //
  1170. {
  1171. rt_printf("auto_test_for_v3\r\n ");
  1172. return (dido_auto_test_for_v3(buf, num));
  1173. }
  1174. }
  1175. rt_printf("auto_test_for_v4\r\n ");
  1176. // bkc6close=check_board_kc6_close(1,6);
  1177. dido_stat_reset();
  1178. if (bkc6close)
  1179. {
  1180. dido_do(1, (1 << 5), 1); // 开出6若焊接为常闭输出,先开出,打开节点
  1181. ustimer_delay(100 * USTIMER_MS);
  1182. }
  1183. // 取出板卡槽位
  1184. for (i = 0; i < (num * 2);)
  1185. {
  1186. for (j = 0; j < 2; j++)
  1187. {
  1188. dido_test_pair[i / 2][j] = buf[i];
  1189. i++;
  1190. }
  1191. }
  1192. flag = 0;
  1193. flag1 = 0;
  1194. memset(tmp, 0, sizeof(tmp));
  1195. memset(tmp_data, 0, sizeof(tmp_data));
  1196. memset(dido_buf, 0, sizeof(dido_buf));
  1197. rt_printf("dido_test begin...\r\n");
  1198. err_once = 0;
  1199. // 以组为循环
  1200. for (i = 0; i < num; i++)
  1201. {
  1202. slot_do = dido_test_pair[i][0];
  1203. slot_di = dido_test_pair[i][1];
  1204. // 槽位暂存
  1205. dido_buf[i + i * 13] = slot_do;
  1206. dido_buf[i + i * 13 + 5] = slot_di;
  1207. // 取出对应槽位的板卡中DI和DO的数量
  1208. di_num = equ_get_di_num(slot_di);
  1209. do_num = equ_get_do_num(slot_do);
  1210. // dido_do(slot_do,(1<<5),1); //磁保持继电器
  1211. // 启动记时
  1212. us_begin = ustimer_get_origin();
  1213. // 逐一输出开出点
  1214. for (j = 0; j < KC_COUNT; j++)
  1215. {
  1216. dido_do(slot_do, (1 << j), 1);
  1217. if (j == 5 && bkc6close)
  1218. {
  1219. dido_do(slot_do, (1 << 5), 0); // 开出6若焊接为常闭输出,反操作为闭合
  1220. }
  1221. ustimer_delay(150 * USTIMER_MS);
  1222. memset(di_ok, 0, sizeof(di_ok));
  1223. do_errflag = DIGROUP;
  1224. for (k = 0; k < 4; k++)
  1225. {
  1226. bool bIgnore = false;
  1227. di_result = (g_di[slot_di].value[0] ^ g_di[slot_di].inv[0]);
  1228. k += i * 2;
  1229. if (test_di[j][k] == 17)
  1230. {
  1231. bIgnore = check_board_di_valid(slot_di, 17);
  1232. }
  1233. if (test_di[j][k] == 18)
  1234. {
  1235. bIgnore = check_board_di_valid(slot_di, 18);
  1236. }
  1237. if (!test_di[j][k] || bIgnore)
  1238. {
  1239. do_errflag--;
  1240. }
  1241. else
  1242. {
  1243. if (!(di_result & (1 << (test_di[j][k] - 1)))) // 对应开入无值
  1244. {
  1245. do_errflag--;
  1246. di_ok[k] = test_di[j][k];
  1247. }
  1248. }
  1249. }
  1250. if (!do_errflag) // 开出对应的所有开入都没有值,即代表该开出有问题
  1251. {
  1252. if (j < 8)
  1253. {
  1254. dido_buf[i + i * 13 + 1] |= (1 << j); // 开出错误标志
  1255. }
  1256. else if (j < 16)
  1257. {
  1258. dido_buf[i + i * 13 + 2] |= (1 << (j - 8)); // 开出错误标志
  1259. }
  1260. rt_printf("dido_test do err:i=%d,j=%d,di=%d,di_l=0x%04lx,di_h=0x%04lx.\r\n",
  1261. i, j, di_ok[0], g_di[slot_di].value[0], g_di[slot_di].value[1]);
  1262. }
  1263. else
  1264. {
  1265. for (k = 0; k < 4; k++)
  1266. {
  1267. if (!di_ok[k])
  1268. continue;
  1269. if ((di_ok[k] - 1) < 8)
  1270. {
  1271. dido_buf[i + i * 13 + 6] |= (1 << (di_ok[k] - 1));
  1272. }
  1273. else if ((di_ok[k] - 1) < 16)
  1274. {
  1275. dido_buf[i + i * 13 + 7] |= (1 << (di_ok[k] - 1 - 8));
  1276. }
  1277. else if ((di_ok[k] - 1) < 24)
  1278. {
  1279. dido_buf[i + i * 13 + 8] |= (1 << (di_ok[k] - 1 - 16));
  1280. }
  1281. else if ((di_ok[k] - 1) < 32)
  1282. {
  1283. dido_buf[i + i * 13 + 9] |= (1 << (di_ok[k] - 1 - 24));
  1284. }
  1285. else if ((di_ok[k] - 1) < 40)
  1286. {
  1287. dido_buf[i + i * 13 + 10] |= (1 << (di_ok[k] - 1 - 32));
  1288. }
  1289. else if ((di_ok[k] - 1) < 48)
  1290. {
  1291. dido_buf[i + i * 13 + 11] |= (1 << (di_ok[k] - 1 - 40));
  1292. }
  1293. else if ((di_ok[k] - 1) < 56)
  1294. {
  1295. dido_buf[i + i * 13 + 12] |= (1 << (di_ok[k] - 1 - 48));
  1296. }
  1297. else if ((di_ok[k] - 1) < 64)
  1298. {
  1299. dido_buf[i + i * 13 + 13] |= (1 << (di_ok[k] - 1 - 56));
  1300. }
  1301. rt_printf("dido_test di err:i=%d,j=%d,di=%d,di_l=0x%04lx,di_h=0x%04lx.\r\n",
  1302. i, j, di_ok[k], g_di[slot_di].value[0], g_di[slot_di].value[1]);
  1303. }
  1304. }
  1305. dido_do(slot_do, (1 << j), 0);
  1306. if (j == 5 && bkc6close)
  1307. {
  1308. dido_do(slot_do, (1 << 5), 1); // 开出6若焊接为常闭输出,反操作为闭合
  1309. }
  1310. // if(j==4)
  1311. //{
  1312. // dido_do(slot_do,(1<<5),1); //磁保持继电器
  1313. //}
  1314. ustimer_delay(20 * USTIMER_MS);
  1315. watchdog_feed_mainloop();
  1316. }
  1317. }
  1318. for (i = 0; i < EQU_SLOT_NUM_MAX; i++)
  1319. {
  1320. if (g_do_time[i].slot != 0)
  1321. {
  1322. rt_printf("do_time[%d]:diff_max=%lu,diff_out_count=%lu\r\n",
  1323. g_do_time[i].slot, g_do_time[i].diff_max, g_do_time[i].diff_out_count);
  1324. }
  1325. }
  1326. rt_printf("dido_test end:err_once=%d,error_count=%lu!\r\n\r\n\r\n", err_once, error_count);
  1327. return 0;
  1328. }
  1329. /*------------------------------ 文件结束 -------------------------------------
  1330. */