dido.c 38 KB

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