dido.c 38 KB

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