dido.c 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434
  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. #ifdef GW_AREA_MAIN_2021
  24. /*------------------------------- 宏定义 --------------------------------------
  25. */
  26. /*------------------------------ 类型结构 -------------------------------------
  27. */
  28. /*------------------------------ 全局变量 -------------------------------------
  29. */
  30. struct di g_di[EQU_SLOT_NUM_MAX];
  31. struct _do g_do[EQU_SLOT_NUM_MAX];
  32. struct di_struct g_di_st[EQU_SLOT_NUM_MAX][DIDO_MAX_DI_PER_SLOT*2];
  33. int g_do_flag;
  34. struct rt_stat g_stat_di_delay;
  35. struct rt_stat g_stat_do_delay;
  36. static u32 di_error_count = 0;
  37. static u32 di_change_num = 0;
  38. static u32 error_count = 0;
  39. struct do_time g_do_time[EQU_SLOT_NUM_MAX];
  40. /*------------------------------ 函数声明 -------------------------------------
  41. */
  42. int dido_do_time(void);
  43. /*------------------------------ 外部函数 -------------------------------------
  44. 外部函数供其它实体文件引用,必须仔细检查传入参数的合法性.
  45. */
  46. int dido_init(void)
  47. {
  48. int i;
  49. memset(g_di,0,sizeof(g_di));
  50. memset(g_do,0,sizeof(g_do));
  51. memset(g_do_time,0,sizeof(g_do_time));
  52. // 检查装置配置
  53. if(equ_config_null())
  54. {
  55. return -1;
  56. }
  57. // 初始化取反标志
  58. for(i=0; i< g_equ_config->di_num; i++)
  59. {
  60. if(g_equ_config_di[i].is_Inverse == 0)
  61. {
  62. continue;
  63. }
  64. if(g_equ_config_di[i].slot < EQU_SLOT_NUM_MAX && g_equ_config_di[i].index < DIDO_MAX_DI_PER_SLOT)
  65. {
  66. if(g_equ_config_di[i].index < 32)
  67. {
  68. g_di[g_equ_config_di[i].slot].inv[0] |= 1<<g_equ_config_di[i].index;
  69. }
  70. else
  71. {
  72. g_di[g_equ_config_di[i].slot].inv[1] |= 1<<(g_equ_config_di[i].index - 32);
  73. }
  74. }
  75. }
  76. dido_stat_reset();
  77. return 0;
  78. }
  79. int dido_di_is_on(u8 slot,u8 index)
  80. {
  81. if(slot >= EQU_SLOT_NUM_MAX || index >= 64)
  82. {
  83. return 0;
  84. }
  85. if(index < 32)
  86. {
  87. if(g_di[slot].value[0]&(1<<index))
  88. {
  89. return 1;
  90. }
  91. }
  92. else
  93. {
  94. index -= 32;
  95. if(g_di[slot].value[1]&(1<<index))
  96. {
  97. return 1;
  98. }
  99. }
  100. return 0;
  101. }
  102. // 查看某个时间点下的开入值
  103. int dido_di_is_on_ts(u8 slot,u8 index,u32 ts)
  104. {
  105. int i,r;
  106. struct ts_index ts_i;
  107. if(slot >= EQU_SLOT_NUM_MAX || index >= 32)
  108. {
  109. return 0;
  110. }
  111. #if 0
  112. {
  113. static int cnt = 0;
  114. if(cnt++ < 16)
  115. rt_printf("slot=%d,index=%d,ts=%d.\r\n",slot,index,ts);
  116. }
  117. #endif
  118. ts_i.n = g_di[slot].ts_i[index].n - 1; //ts_i下是无值的,所以应该减1
  119. for(i=0;i<DIDO_TS_NUM;i++)
  120. {
  121. r = (int)(ts - g_di[slot].ts_t[index][ts_i.n]);
  122. if(r >= 0)
  123. {
  124. return g_di[slot].ts_v[index][ts_i.n];
  125. }
  126. ts_i.n--;
  127. }
  128. if(g_di[slot].value[0]&(1<<index))
  129. {
  130. return 1;
  131. }
  132. return 0;
  133. }
  134. int dido_di_update(u8 * buf)
  135. {
  136. struct can_frame_head *cfh;
  137. struct timespec ts,ts_rec;
  138. u32 di,value_new,value_old;
  139. int i,j,is_on;
  140. unsigned long flags;
  141. u32 dt;
  142. // static bool bDI_Init[EQU_SLOT_NUM_MAX] = {false};
  143. // 检查帧内容
  144. cfh = (struct can_frame_head *)buf;
  145. if(cfh->src >= EQU_SLOT_NUM_MAX)
  146. {
  147. return -1;
  148. }
  149. if(cfh->len != 8)
  150. {
  151. return -2;
  152. }
  153. // 检查帧类型
  154. switch(buf[0])
  155. {
  156. case CAN_FRAME_TYPE_DI_INIT:
  157. case CAN_FRAME_TYPE_DI_ON:
  158. case CAN_FRAME_TYPE_DI_OFF:
  159. j = 0;
  160. break;
  161. case CAN_FRAME_TYPE_DI_INIT1:
  162. case CAN_FRAME_TYPE_DI_ON1:
  163. case CAN_FRAME_TYPE_DI_OFF1:
  164. j = 1;
  165. break;
  166. default:
  167. return -3;
  168. }
  169. // 获取数据
  170. memcpy(&di,buf+4,4);
  171. switch(buf[0])
  172. {
  173. case CAN_FRAME_TYPE_DI_INIT:
  174. case CAN_FRAME_TYPE_DI_INIT1:
  175. {
  176. //g_di[cfh->src].value[j] = di^g_di[cfh->src].inv[j];
  177. value_old = g_di[cfh->src].value[j];
  178. value_new = di^g_di[cfh->src].inv[j];
  179. di = value_old ^ value_new; // 得到有变化的位
  180. g_di[cfh->src].value[j] = value_new;
  181. // rt_printf("DI_INIT:src=%d,j=%d,di=%08x,oldv=%08x,newv=%08x.\r\n",cfh->src,j,di,value_old,value_new);
  182. if(g_di[cfh->src].bInited == 0)
  183. {
  184. // 更新逻辑模型中的值
  185. for(i=0;i<DIDO_MAX_DI_PER_SLOT;i++)
  186. {
  187. is_on = (g_di[cfh->src].value[j]&(1<<i)) ? 1 : 0;
  188. sw_di_set( g_di_st[cfh->src][(j<<5)+i].owner,
  189. g_di_st[cfh->src][(j<<5)+i].type,
  190. is_on ? SW_DI_TYPE_ON : SW_DI_TYPE_OFF);
  191. // 双点的值也需要重新初始化
  192. plc_db_init_value(cfh->src,(j<<5)+i,is_on);
  193. // 遥信时标
  194. g_di[cfh->src].ts_t[i][g_di[cfh->src].ts_i[i].n] = 0;
  195. g_di[cfh->src].ts_v[i][g_di[cfh->src].ts_i[i].n] = is_on;
  196. g_di[cfh->src].ts_i[i].n++;
  197. }
  198. g_di[cfh->src].bInited = true;
  199. // bDI_Init[cfh->src] = true;
  200. return 0;
  201. }
  202. }
  203. break;
  204. case CAN_FRAME_TYPE_DI_ON:
  205. case CAN_FRAME_TYPE_DI_ON1:
  206. value_old = g_di[cfh->src].value[j] & (~di);
  207. value_new = (di^g_di[cfh->src].inv[j]) & di;
  208. g_di[cfh->src].value[j] = value_old | value_new;
  209. break;
  210. case CAN_FRAME_TYPE_DI_OFF:
  211. case CAN_FRAME_TYPE_DI_OFF1:
  212. value_old = g_di[cfh->src].value[j] & (~di);
  213. value_new = ((~di)^g_di[cfh->src].inv[j]) & di;
  214. g_di[cfh->src].value[j] = value_old | value_new;
  215. break;
  216. default:
  217. return -3;
  218. }
  219. // 得到当前时刻,通过关中断保证时间的一致性
  220. rt_irq_save(flags);
  221. // gps_get_time(&ts); //modify by EWen can app 对时用的是clk_time_get,此处记录di时间取同一时间源
  222. clk_time_get(&ts);
  223. dt=g_adc_dots_count;
  224. rt_irq_restore(flags);
  225. // 计算变位的真正时刻
  226. // 记录秒的低8位和纳秒的高24位合成32位时间戳放在buf[8]~buf[11]的位置。
  227. // 因为开入滤波时间最长为65.536S,所以用秒的低8位(256S)
  228. // 作为时间戳有足够的余量保证时间戳的正确性,但需要考虑秒的进位。
  229. ts_rec.tv_sec = (ts.tv_sec & ~0xff) | buf[8];
  230. ts_rec.tv_nsec=(buf[9]<<24) | (buf[10]<<16) | (buf[11]<<8);
  231. if((u8)(ts.tv_sec & 0xff) < buf[8])
  232. {
  233. // 如果当前时刻秒的低8位小于记录时刻的低8位,说明当前秒的低8位
  234. // 已进位,记录秒需去掉此进位。
  235. ts_rec.tv_sec -= 0x100;
  236. }
  237. {
  238. u32 diff;
  239. diff = ts.tv_nsec + (ts.tv_sec - ts_rec.tv_sec)*NSEC_PER_SEC;
  240. diff -= ts_rec.tv_nsec;
  241. // 修正对应采样时间点
  242. dt -= (u32)rt_round(g_freq*CFG_ADC_DOTS_PER_PERIOD*diff/NSEC_PER_SEC);
  243. rt_stat_in(&g_stat_di_delay,diff);
  244. /*
  245. di_change_num ++;
  246. rt_printf("开入变位:src=%d,buf[0]=%02x,DI==0x%08x,new=0x%08x,T=%d,di_change_num=%d.\r\n",
  247. cfh->src,
  248. buf[0],
  249. g_di[cfh->src].value,
  250. di,
  251. diff,
  252. di_change_num);
  253. */
  254. #if 0
  255. if(diff > 1000000)
  256. {
  257. struct rtc_time_t tm;
  258. di_error_count ++;
  259. rt_printf("开入变位时间超出次数:%d\r\n\r\n",di_error_count);
  260. timespec_to_rtc(ts,&tm,0);
  261. rt_printf("当前时间: %04d-%02d-%02d %02d:%02d:%02d:%09d!\r\n",
  262. tm.year + 2000,
  263. tm.month,
  264. tm.day,
  265. tm.hour,
  266. tm.min,
  267. tm.ms/1000,
  268. ts.tv_nsec
  269. );
  270. timespec_to_rtc(ts_rec,&tm,0);
  271. rt_printf("变位时间: %04d-%02d-%02d %02d:%02d:%02d:%09d!\r\n",
  272. tm.year + 2000,
  273. tm.month,
  274. tm.day,
  275. tm.hour,
  276. tm.min,
  277. tm.ms/1000,
  278. ts_rec.tv_nsec
  279. );
  280. }
  281. #endif
  282. }
  283. // if (bDI_Init[cfh->src])
  284. // {
  285. // bDI_Init[cfh->src] = false;
  286. // }
  287. // else
  288. {
  289. // 记录遥信变位
  290. for(i=0; i<32; i++)
  291. {
  292. if(di&(0x01<<i))
  293. {
  294. // 记录SOE
  295. is_on = (g_di[cfh->src].value[j] & (1<<i)) ? 1:0;
  296. soe_record_yx((WORD)((j<<5) + i +(cfh->src<<8)),is_on,&ts_rec);
  297. // 更新逻辑模型中的值
  298. sw_di_set( g_di_st[cfh->src][(j<<5)+i].owner,
  299. g_di_st[cfh->src][(j<<5)+i].type,
  300. (is_on)? SW_DI_TYPE_ON : SW_DI_TYPE_OFF);
  301. // 更新记录
  302. g_di[cfh->src].ts_t[i][g_di[cfh->src].ts_i[i].n] = dt;
  303. g_di[cfh->src].ts_v[i][g_di[cfh->src].ts_i[i].n] = is_on;
  304. g_di[cfh->src].ts_i[i].n++;
  305. }
  306. }
  307. }
  308. return 0;
  309. }
  310. void dido_qd_set_keeptime(u32 us)
  311. {
  312. }
  313. int dido_do_have_select(u32 slot,u32 index)
  314. {
  315. // 只有开出板有选择继电器,其它板如辅助板没有
  316. if(g_board_info[slot].type == BOARD_TYPE_DO || g_board_info[slot].type == BOARD_TYPE_DO_2)
  317. {
  318. return 1;
  319. }
  320. return 0;
  321. }
  322. int dido_do(u32 slot,u32 v,int is_on)
  323. {
  324. unsigned long flags;
  325. //检查子板是否正常
  326. if(equ_slot_check(slot) != 0)
  327. {
  328. return -1;
  329. }
  330. // 检查DO资源
  331. if(equ_get_do_num(slot) == 0)
  332. {
  333. return -2;
  334. }
  335. // 保存输出值,在5ms中断中输出
  336. rt_irq_save(flags);
  337. g_do_flag = 1;
  338. if(is_on)
  339. {
  340. g_do[slot].on |= v;
  341. }
  342. else
  343. {
  344. g_do[slot].off |= v;
  345. }
  346. rt_irq_restore(flags);
  347. return 0;
  348. }
  349. int _dido_do(u32 slot,u32 v,int is_on)
  350. {
  351. int i,ret,err;
  352. u8 *buf;
  353. u32 do_time;
  354. struct timespec ts;
  355. // 帧头
  356. buf = can_request_tx_buf(CAN_FRAME_TYPE_DO_ON);
  357. if(is_on)
  358. {
  359. buf[0] = CAN_FRAME_TYPE_DO_ON;
  360. }
  361. else
  362. {
  363. buf[0] = CAN_FRAME_TYPE_DO_OFF;
  364. }
  365. buf[1] = slot;
  366. buf[2] = 0;
  367. buf[3] = 8;
  368. // 开出值
  369. buf[4] = (v>>24) & 0xff;
  370. buf[5] = (v>>16) & 0xff;
  371. buf[6] = (v>> 8) & 0xff;
  372. buf[7] = (v>> 0) & 0xff;
  373. // 开出时间
  374. clk_time_get(&ts);
  375. do_time = (u32)(((ts.tv_sec&0xff)<<24) | (ts.tv_nsec>>8));
  376. buf[8] = (unsigned char)(do_time>>24);
  377. buf[9] = (unsigned char)(do_time>>16);
  378. buf[10] = (unsigned char)(do_time>>8);
  379. buf[11] = (unsigned char)(do_time);
  380. // 开出帧发送,为了提高可靠性,连发2帧
  381. err = 0;
  382. for(i=0; i<2; i++)
  383. {
  384. ret = can_send(equ_slot_can_bus(slot),buf);
  385. if(ret < 0)
  386. {
  387. rt_printf("dido_do err:i=%d,ret=%d\r\n",i,ret);
  388. err++;
  389. }
  390. }
  391. return -err;
  392. }
  393. void dido_do_poll(void)
  394. {
  395. int i;
  396. // 检查开出标志
  397. if(g_do_flag == 0)
  398. {
  399. return;
  400. }
  401. g_do_flag = 0;
  402. // 真正开出
  403. for(i=0; i<EQU_SLOT_NUM_MAX; i++)
  404. {
  405. if(g_do[i].on)
  406. {
  407. _dido_do(i,g_do[i].on,1);
  408. g_do[i].on = 0;
  409. }
  410. if(g_do[i].off)
  411. {
  412. _dido_do(i,g_do[i].off,0);
  413. g_do[i].off = 0;
  414. }
  415. }
  416. return;
  417. }
  418. /*------------------------------ 内部函数 -------------------------------------
  419. 内部函数以下划线‘_’开头,不需要检查参数的合法性.
  420. */
  421. /*------------------------------ 测试函数 -------------------------------------
  422. 一个实体文件必须带一个本模块的测试函数来进行单元测试,如果的确不方便在本模块中
  423. 进行单元测试,必须在此注明实际的测试位置(例如在哪个实体文件中使用哪个测试函数).
  424. */
  425. int dido_printf(void)
  426. {
  427. int i,slot,index;
  428. struct ts_index ts_i;
  429. rt_printf("槽号\t值\r\n");
  430. for(i=0; i<EQU_SLOT_NUM_MAX; i++)
  431. {
  432. rt_printf("%02d:\tvalue=0x%08x_%08x,inv=0x%08x_%08x\r\n",i,g_di[i].value[1],g_di[i].value[0],g_di[i].inv[1],g_di[i].inv[0]);
  433. }
  434. rt_printf("\r\n");
  435. slot = 3;
  436. index = 2;
  437. ts_i.n = g_di[slot].ts_i[index].n;
  438. rt_printf("开入时间戳记录:slot=%d,index=%d,ts_i=%d.\r\n",slot,index,ts_i.n);
  439. rt_printf("序号\t值\t时间戳\r\n");
  440. ts_i.n = 0;
  441. for(i=0;i<DIDO_TS_NUM;i++)
  442. {
  443. rt_printf("%02d\t%d\t%08d\r\n",ts_i.n,g_di[slot].ts_v[index][ts_i.n],g_di[slot].ts_t[index][ts_i.n]);
  444. ts_i.n++;
  445. }
  446. rt_stat_printf(&g_stat_di_delay);
  447. rt_stat_printf(&g_stat_do_delay);
  448. #if 0
  449. {
  450. char tmpbuf[7];
  451. tmpbuf[0] = 1;
  452. tmpbuf[1] = 4;
  453. dido_auto_test(tmpbuf,1);
  454. }
  455. #endif
  456. return 0;
  457. }
  458. int dido_stat_reset(void)
  459. {
  460. rt_stat_init(&g_stat_di_delay,"di_delay");
  461. rt_stat_init(&g_stat_do_delay,"do_delay");
  462. return 0 ;
  463. }
  464. int dido_led_test(void)
  465. {
  466. #if 0
  467. int i;
  468. // 测试告警灯
  469. for(i=0; i<SWITCH_NUM_MAX; i++)
  470. {
  471. dido_led(1<<i);
  472. ustimer_delay(200*USTIMER_MS);
  473. dido_led(~(1<<i));
  474. }
  475. // 所有LED ON
  476. dido_led(0xffff);
  477. ustimer_delay(1*USTIMER_SEC);
  478. // 所有LED OFF
  479. dido_led(0xffff);
  480. #endif
  481. return 0;
  482. }
  483. int dido_single_test(u8 slot, u8 point)
  484. {
  485. int do_num;
  486. do_num = equ_get_do_num(slot);
  487. if(do_num == 0)
  488. {
  489. return 0;
  490. }
  491. switch (point/4)
  492. {
  493. case 0:
  494. dido_do(slot,(1<<do_num),1);
  495. break;
  496. case 1:
  497. dido_do(slot,(1<<(do_num+1)),1);
  498. break;
  499. case 2:
  500. dido_do(slot,(1<<(do_num+2)),1);
  501. break;
  502. case 3:
  503. dido_do(slot,(1<<(do_num+3)),1);
  504. break;
  505. case 4:
  506. dido_do(slot,(1<<(do_num+4)),1);
  507. break;
  508. case 5:
  509. dido_do(slot,(1<<(do_num+5)),1);
  510. break;
  511. default:
  512. break;
  513. }
  514. dido_do(slot,(1<<point),1);
  515. // ustimer_delay(100*USTIMER_MS);
  516. // dido_do(slot,(1<<point),0);
  517. return 0;
  518. }
  519. int dido_test(void)
  520. {
  521. static unsigned long us0 = 0;
  522. static char dido_test_pair[3][2] =
  523. {
  524. {1,3},
  525. {2,4},
  526. {5,5},
  527. };
  528. static char dido_test_di[32] =
  529. {
  530. 0,1,2,3,
  531. 0,1,2,3,
  532. 4,5,6,7,
  533. 4,5,6,7,
  534. 8,9,10,11,
  535. 8,9,10,11,
  536. 12,13,10,11,
  537. 12,13,12,13
  538. };
  539. int i,j,k,err_once,di_num;
  540. u32 slot_di,slot_do;
  541. if(g_test_on == 0)
  542. {
  543. return 0;
  544. }
  545. // 5秒处理一次
  546. if(ustimer_delay_origin2(&us0,10*USTIMER_SEC) != 1)
  547. {
  548. return 0;
  549. }
  550. rt_printf("dido_test begin...\r\n");
  551. #if 0
  552. // 所有开出ON
  553. rt_printf("dido_test all on.\r\n");
  554. dido_do(1,0xffff,1);
  555. dido_do(2,0xffff,1);
  556. dido_do(5,0xffff,1);
  557. dido_led(0xffff);
  558. // 检查所有开入
  559. ustimer_delay(1*USTIMER_SEC);
  560. // 所有开出OFF
  561. rt_printf("dido_test all off.\r\n");
  562. dido_do(1,0xffff,0);
  563. dido_do(2,0xffff,0);
  564. dido_do(5,0xffff,0);
  565. dido_led(0);
  566. #endif
  567. ustimer_delay(1*USTIMER_SEC);
  568. #if 1
  569. // 测试开出板、开入板
  570. // 开出板逐一开出
  571. rt_printf("dido_test single.\r\n");
  572. err_once = 0;
  573. for(i=0; i<3; i++)
  574. {
  575. slot_do = dido_test_pair[i][0];
  576. slot_di = dido_test_pair[i][1];
  577. if(equ_slot_check(slot_do)!= 0 || equ_slot_check(slot_di) != 0)
  578. {
  579. rt_printf("dido_test:board error:slot_do=%d,slot_in=%d\r\n",slot_do,slot_di);
  580. continue;
  581. }
  582. if(g_board_info[slot_do].status != BOARD_STATUS_NORMAL ||g_board_info[slot_di].status != BOARD_STATUS_NORMAL)
  583. {
  584. rt_printf("dido_test:board status error:slot_do=%d,slot_in=%d\r\n",slot_do,slot_di);
  585. continue;
  586. }
  587. for(j=0;j<equ_get_do_num(slot_do); j++)
  588. {
  589. dido_do(slot_do,(1<<j),1);
  590. // rt_printf("dido_test:开出:j=%d\r\n",j);
  591. ustimer_delay(250*USTIMER_MS);
  592. di_num = equ_get_di_num(slot_di);
  593. if(slot_di == equ_get_slot_by_type(BOARD_TYPE_AUX))
  594. {
  595. di_num -= 1;
  596. }
  597. for(k=0;k<di_num; k++)
  598. {
  599. // 是否对应的开出点
  600. if(dido_test_di[k] == j)
  601. {
  602. if((g_di[slot_di].value[0] & (1<<k)) == 0)
  603. {
  604. err_once++;
  605. error_count++;
  606. rt_printf("dido_test on err(err=%d):i=%d,j=%d,k=%d,di=0x%08x.\r\n",err_once,i,j,k,g_di[slot_di].value[0]);
  607. }
  608. }
  609. else
  610. {
  611. if((g_di[slot_di].value[0] & (1<<k)) != 0)
  612. {
  613. err_once++;
  614. error_count++;
  615. rt_printf("dido_test off err(err=%d):i=%d,j=%d,k=%d,di=0x%08x.\r\n",err_once,i,j,k,g_di[slot_di].value[0]);
  616. }
  617. }
  618. }
  619. dido_do(slot_do,(1<<j),0);
  620. ustimer_delay(20*USTIMER_MS);
  621. watchdog_feed_mainloop();
  622. }
  623. }
  624. #endif
  625. #if 0
  626. // 测试告警灯
  627. for(i=0; i<SWITCH_NUM_MAX; i++)
  628. {
  629. dido_led(1<<i);
  630. ustimer_delay(200*USTIMER_MS);
  631. }
  632. // 所有开出ON
  633. dido_do(1,0xffff,1);
  634. dido_do(2,0xffff,1);
  635. dido_do(5,0xffff,1);
  636. dido_led(0xffff);
  637. ustimer_delay(1*USTIMER_SEC);
  638. // 所有开出OFF
  639. dido_do(1,0xffff,0);
  640. dido_do(2,0xffff,0);
  641. dido_do(5,0xffff,0);
  642. dido_led(0);
  643. #endif
  644. rt_printf("\r\n开入变位时间超出次数:%d\r\n",di_error_count);
  645. rt_printf("name\t\t\tmin\tmax\tavg\tsum\t\tcnt\n");
  646. rt_stat_printf(&g_stat_di_delay);
  647. can_app_sb_monitor();
  648. rt_printf("\r\n");
  649. for(i=0;i<5;i++)
  650. {
  651. if(g_do_time[i].slot != 0)
  652. {
  653. rt_printf("do_time[%d]:diff_max=%d,diff_out_count=%d\r\n",g_do_time[i].slot,g_do_time[i].diff_max,g_do_time[i].diff_out_count);
  654. }
  655. }
  656. rt_printf("\r\n");
  657. rt_printf("dido_test end:err_once=%d,error_count=%d!\r\n\r\n\r\n",err_once,error_count);
  658. return 0;
  659. }
  660. int dido_auto_test(char *buf,int num)
  661. {
  662. static char test_do[16][4] =
  663. {
  664. {1,5,0,0,},
  665. {2,6,0,0,},
  666. {3,7,0,0,},
  667. {4,8,0,0,},
  668. {9,13,0,0,},
  669. {10,14,0,0,},
  670. {11,15,0,0,},
  671. {12,16,0,0,},
  672. {17,21,0,0,},
  673. {18,22,0,0,},
  674. {19,23,0,0,},
  675. {20,24,0,0,},
  676. {25,29,0,0,},
  677. {26,30,0,0,},
  678. {27,0,0,0,},
  679. {28,0,0,0,},
  680. };
  681. int i,j,k,err_once,flag,flag1,di_num, do_num;
  682. u32 slot_di,slot_do;
  683. u8 tmp[5],tmp_data[5];
  684. u8 bd_di60=0;
  685. u8 di_ok[4] = {0};
  686. u8 do_errflag = 0;
  687. char dido_test_pair[num][2];
  688. unsigned long us_begin = 0;
  689. dido_stat_reset();
  690. for(i=0;i<(num*2);)
  691. {
  692. for(j=0;j<2;j++)
  693. {
  694. dido_test_pair[i/2][j] = buf[i];
  695. i++;
  696. }
  697. }
  698. flag = 0;
  699. flag1 = 0;
  700. memset(tmp,0,sizeof(tmp));
  701. memset(tmp_data,0,sizeof(tmp_data));
  702. memset(dido_buf,0,sizeof(dido_buf));
  703. rt_printf("dido_test begin...\r\n");
  704. err_once = 0;
  705. for(i=0; i<num; i++)
  706. {
  707. slot_do = dido_test_pair[i][0];
  708. slot_di = dido_test_pair[i][1];
  709. if(equ_slot_check(slot_do)!= 0 || equ_slot_check(slot_di) != 0 || slot_di == equ_get_slot_by_type(BOARD_TYPE_AUX))
  710. {
  711. rt_printf("dido_test:board error:slot_do=%d,slot_in=%d\r\n",slot_do,slot_di);
  712. dido_buf[i+i*13] = 0;
  713. dido_buf[i+i*13+5] = 0;
  714. continue;
  715. }
  716. if(g_board_info[slot_do].status != BOARD_STATUS_NORMAL ||g_board_info[slot_di].status != BOARD_STATUS_NORMAL)
  717. {
  718. rt_printf("dido_test:board status error:slot_do=%d,slot_in=%d\r\n",slot_do,slot_di);
  719. dido_buf[i+i*13] = 0;
  720. dido_buf[i+i*13+5] = 0;
  721. continue;
  722. }
  723. dido_buf[i+i*13] = slot_do;
  724. dido_buf[i+i*13+5] = slot_di;
  725. if(slot_di == equ_get_slot_by_type(BOARD_TYPE_DI60))
  726. {
  727. bd_di60 = 1;
  728. }
  729. di_num = equ_get_di_num(slot_di);
  730. do_num = equ_get_do_num(slot_do);
  731. us_begin = ustimer_get_origin();
  732. //以循环保证不论开出所配置的脉宽是多少,都能保持2s输出
  733. while(1)
  734. {
  735. // 点亮所有遥信灯
  736. for(j=0; j<do_num; j++)
  737. {
  738. dido_do(slot_do,(1<<j),1);
  739. }
  740. // 延时2秒,让测试人员观察所有遥信灯是否正常点亮
  741. if(ustimer_get_duration(us_begin) > (2000*USTIMER_MS))
  742. // if(ustimer_get_duration(us_begin) > (10000*USTIMER_MS))
  743. {
  744. break;
  745. }
  746. }
  747. // 关闭所有遥信灯
  748. for(j=0; j<do_num; j++)
  749. {
  750. dido_do(slot_do,(1<<j),0);
  751. }
  752. // 等待子板的开出硬件接点真正释放,一般至少6ms
  753. ustimer_delay(20*USTIMER_MS);
  754. // 开始逐一测试开入开出对
  755. for(j=0; j<do_num; j++)
  756. {
  757. dido_do(slot_do,(1<<j),1);
  758. ustimer_delay(150*USTIMER_MS);
  759. memset(di_ok,0,sizeof(di_ok));
  760. do_errflag = 4;
  761. for (k=0; k<4; k++)
  762. {
  763. if (!test_do[j+bd_di60*i*do_num][k])
  764. {
  765. do_errflag--;
  766. }
  767. else if (test_do[j+bd_di60*i*do_num][k] < 33) //开入小于32个
  768. {
  769. if (!(g_di[slot_di].value[0] & (1<<(test_do[j+bd_di60*i*do_num][k]-1)))) //对应开入无值
  770. {
  771. do_errflag--;
  772. di_ok[k] = test_do[j+bd_di60*i*do_num][k];
  773. }
  774. }
  775. else if (test_do[j+bd_di60*i*do_num][k] >= 33) //开入小于32个 //开入大于32个
  776. {
  777. if (!(g_di[slot_di].value[1] & (1<<(test_do[j+bd_di60*i*do_num][k]-33)))) //对应开入无值
  778. {
  779. do_errflag--;
  780. di_ok[k] = test_do[j+bd_di60*i*do_num][k];
  781. }
  782. }
  783. }
  784. if (!do_errflag) //开出对应的所有开入都没有值,即代表该开出有问题
  785. {
  786. if (j<8)
  787. {
  788. dido_buf[i+i*13+1] |= (1<<j); //开出错误标志
  789. }
  790. else if (j<16)
  791. {
  792. dido_buf[i+i*13+2] |= (1<<(j-8)); //开出错误标志
  793. }
  794. rt_printf("dido_test do err:i=%d,j=%d,di=%d,di_l=0x%04x,di_h=0x%04x.\r\n",i,j,di_ok[0], g_di[slot_di].value[0],g_di[slot_di].value[1]);
  795. }
  796. else
  797. {
  798. for (k=0; k<4; k++)
  799. {
  800. if (!di_ok[k])
  801. continue;
  802. if ((di_ok[k]-1) < 8)
  803. {
  804. dido_buf[i+i*13+6] |= (1<<(di_ok[k]-1));
  805. }
  806. else if ((di_ok[k]-1) < 16)
  807. {
  808. dido_buf[i+i*13+7] |= (1<<(di_ok[k]-1-8));
  809. }
  810. else if ((di_ok[k]-1) < 24)
  811. {
  812. dido_buf[i+i*13+8] |= (1<<(di_ok[k]-1-16));
  813. }
  814. else if ((di_ok[k]-1) < 32)
  815. {
  816. dido_buf[i+i*13+9] |= (1<<(di_ok[k]-1-24));
  817. }
  818. else if ((di_ok[k]-1) < 40)
  819. {
  820. dido_buf[i+i*13+10] |= (1<<(di_ok[k]-1-32));
  821. }
  822. else if ((di_ok[k]-1) < 48)
  823. {
  824. dido_buf[i+i*13+11] |= (1<<(di_ok[k]-1-40));
  825. }
  826. else if ((di_ok[k]-1) < 56)
  827. {
  828. dido_buf[i+i*13+12] |= (1<<(di_ok[k]-1-48));
  829. }
  830. else if ((di_ok[k]-1) < 64)
  831. {
  832. dido_buf[i+i*13+13] |= (1<<(di_ok[k]-1-56));
  833. }
  834. rt_printf("dido_test di err:i=%d,j=%d,di=%d,di_l=0x%04x,di_h=0x%04x.\r\n",i,j,di_ok[k], g_di[slot_di].value[0],g_di[slot_di].value[1]);
  835. }
  836. }
  837. dido_do(slot_do,(1<<j),0);
  838. ustimer_delay(20*USTIMER_MS);
  839. watchdog_feed_mainloop();
  840. }
  841. }
  842. for(i=0;i<5;i++)
  843. {
  844. if(g_do_time[i].slot != 0)
  845. {
  846. rt_printf("do_time[%d]:diff_max=%d,diff_out_count=%d\r\n",g_do_time[i].slot,g_do_time[i].diff_max,g_do_time[i].diff_out_count);
  847. }
  848. }
  849. //rt_printf("\r\n");
  850. rt_printf("dido_test end:err_once=%d,error_count=%d!\r\n\r\n\r\n",err_once,error_count);
  851. return 0;
  852. }
  853. #else
  854. #include "gpio.h"
  855. #include "ad7616.h"
  856. /*------------------------------- 宏定义 --------------------------------------
  857. */
  858. #define DO_PWM_SW_HZ 0
  859. #define DO_PWM_SW_QD 1
  860. #define DO_PWM_SW_NULL 2
  861. #define DO_PWM_SW_FZ 3
  862. #ifdef __MINI_DTU__
  863. #define DO_QD_KC DO_OUT1
  864. #else
  865. #define DO_QD_KC DO_OUT4
  866. #endif
  867. /*------------------------------ 类型结构 -------------------------------------
  868. */
  869. /*------------------------------ 全局变量 -------------------------------------
  870. */
  871. struct di g_di[EQU_SLOT_NUM_MAX];
  872. struct _do g_do[EQU_SLOT_NUM_MAX];
  873. struct di_struct g_di_st[EQU_SLOT_NUM_MAX][DIDO_MAX_DI_PER_SLOT];
  874. struct do_struct g_do_st[DO_NUM];
  875. u16 g_do_status; // 开出状态,因为仅主板有开出
  876. u32 g_do_start_time;
  877. int g_do_flag;
  878. extern u32 g_brd_type_kz;
  879. struct rt_stat g_stat_di_delay;
  880. struct rt_stat g_stat_do_delay;
  881. static u32 di_error_count = 0;
  882. static u32 error_count = 0;
  883. struct do_time g_do_time[EQU_SLOT_NUM_MAX];
  884. /*------------------------------ 函数声明 -------------------------------------
  885. */
  886. static int _dido_do(u32 slot,u16 v,int is_on);
  887. static int _get_di(int slot,u16 di_num, u32 di, struct timespec ts);
  888. static inline void _io_do_status_update(int on, unsigned int i);
  889. unsigned int change_di_ch(unsigned int di);
  890. /*------------------------------ 外部函数 -------------------------------------
  891. 外部函数供其它实体文件引用,必须仔细检查传入参数的合法性.
  892. */
  893. /******************************************************************************
  894. 函数名称: dido_init
  895. 函数版本: 01.01
  896. 创建作者:
  897. 创建日期: 2013-03-13
  898. 函数说明: 开入开出初始化
  899. 参数说明: 无
  900. 返回值: 无
  901. 修改记录:
  902. */
  903. void dido_init_di(void)
  904. {
  905. //return ret;
  906. u32 i,slot;
  907. u32 di0,di,di_num;
  908. di0 = gpio_get_di();
  909. // 主板
  910. slot = EQU_SLOT_KZ;
  911. di = (di0 & 0x7FFFF);
  912. g_di[slot].value[0] = di^g_di[slot].inv[0];
  913. di_num = equ_get_di_num(slot);
  914. for(i=0; i<di_num; i++)
  915. {
  916. if(di&(1<<i))
  917. {
  918. g_di_st[slot][i].b_on = 1;
  919. }
  920. else
  921. {
  922. g_di_st[slot][i].b_on = 0;
  923. }
  924. if(g_di[slot].value[0]&(1<<i))
  925. {
  926. sw_di_set(g_di_st[slot][i].owner,g_di_st[slot][i].type,SW_DI_TYPE_ON);
  927. g_di[slot].ts_v[i][g_di[slot].ts_i[i].n] = 1;
  928. }
  929. g_di[slot].ts_t[i][g_di[slot].ts_i[i].n] = 0;
  930. g_di[slot].ts_i[i].n++;
  931. }
  932. }
  933. int dido_init(void)
  934. {
  935. u32 i;
  936. // 检查装置配置
  937. if(equ_config_null())
  938. {
  939. return -1;
  940. }
  941. // 初始化取反标志
  942. for(i=0; i< g_equ_config->di_num; i++)
  943. {
  944. if(g_equ_config_di[i].is_Inverse == 0)
  945. {
  946. continue;
  947. }
  948. if(g_equ_config_di[i].slot < EQU_SLOT_NUM_MAX && g_equ_config_di[i].index < DIDO_MAX_DI_PER_SLOT)
  949. {
  950. if(g_equ_config_di[i].index < 32)
  951. {
  952. g_di[g_equ_config_di[i].slot].inv[0] |= 1<<g_equ_config_di[i].index;
  953. }
  954. else
  955. {
  956. g_di[g_equ_config_di[i].slot].inv[1] |= 1<<(g_equ_config_di[i].index - 32);
  957. }
  958. }
  959. }
  960. dido_init_di();
  961. dido_stat_reset();
  962. return 0;
  963. }
  964. // 只有分合闸有选择启动继电器
  965. int dido_do_have_select(u32 slot,u32 index)
  966. {
  967. int i = 0;
  968. i = equ_get_do_channel(index);
  969. if(i==DO_OUT0||i==DO_OUT1||i==DO_OUT5||i==DO_OUT6)
  970. {
  971. return 1;
  972. }
  973. return 0;
  974. }
  975. /******************************************************************************
  976. 函数名称: dido_do
  977. 函数版本: 01.01
  978. 创建作者:
  979. 创建日期: 2013-03-13
  980. 函数说明: 板卡开出动作
  981. 参数说明: 无
  982. 返回值:
  983. 修改记录:
  984. */
  985. int dido_do(u32 slot,u16 v,int is_on)
  986. {
  987. //unsigned long flags;
  988. // 检查DO资源
  989. if(equ_get_do_num(slot) == 0)
  990. {
  991. return -2;
  992. }
  993. // 保存输出值,在5ms中断中输出
  994. rt_irq_save(flags);
  995. g_do_flag = 1;
  996. if(is_on)
  997. {
  998. g_do[slot].on |= v;
  999. }
  1000. else
  1001. {
  1002. g_do[slot].off |= v;
  1003. }
  1004. rt_irq_restore(flags);
  1005. return 0;
  1006. }
  1007. /******************************************************************************
  1008. 函数名称: do_kout_check
  1009. 函数版本:
  1010. 创建作者:
  1011. 创建日期: 2013-03-13
  1012. 函数说明: 开出反校。
  1013. 参数说明: 无
  1014. 返回值: 结果
  1015. 修改记录:
  1016. */
  1017. void io_do_check(void)
  1018. {
  1019. u16 now,fj;
  1020. u32 us;
  1021. #ifdef DO_KOUT_CHECK
  1022. u8 index;
  1023. // 取返校值,必须在下面时间点检查之
  1024. index=g_equ_config_di[g_sw[0].di_cfg_index[SW_DI_KOCHK]].index;
  1025. fj = gpio_di_fj(index)&0x01;//0x02;
  1026. // 返回值只判断启动、分闸、合闸
  1027. now = 0;
  1028. if(g_do_status &(1<<DO_QD_KC))//预置反校DO_PWM_SW_QD
  1029. {
  1030. now |= 0x01;
  1031. }
  1032. //if(g_do_status &((1<<DO_PWM_SW_FZ)|(1<<DO_PWM_SW_HZ)))//动作反校
  1033. //{
  1034. //now |= 0x01;//0x02;
  1035. //}
  1036. #else
  1037. // 取返校值,必须在下面时间点检查之
  1038. fj = gpio_di_fj()&0x02;
  1039. // 返回值只判断启动、分闸、合闸
  1040. now = 0;
  1041. if(g_do_status &(1<<DO_PWM_SW_QD))
  1042. {
  1043. //now |= 0x01;
  1044. }
  1045. if(g_do_status &((1<<DO_PWM_SW_FZ)|(1<<DO_PWM_SW_HZ)))
  1046. {
  1047. now |= 0x02;
  1048. }
  1049. #endif
  1050. //开出动作20ms内不进行开出自检,
  1051. //经实测启动继电器因为是继电器触点返校,其返回时间最长,但也小于10ms。
  1052. //分合闸继电器是光耦返校,本身需要的时间可以忽略不计,但受启动继电器的影响
  1053. us = ustimer_get_duration(g_do_start_time);
  1054. if(us < 20*1000)
  1055. {
  1056. return ;
  1057. }
  1058. if (fj != now)
  1059. {
  1060. // rt_printf("返校失败:fj=%04x,now=%04x, g_do_status=%04x(us=%d)\r\n",fj,now, g_do_status,us);
  1061. rt_err_set(ERR_CODE_DO_CHECK,0);
  1062. return ;
  1063. }
  1064. }
  1065. /******************************************************************************
  1066. 函数名称: io_do_return
  1067. 函数版本: 01.01
  1068. 创建作者:
  1069. 创建日期: 2013-03-13
  1070. 函数说明: 开出保持时间
  1071. 参数说明: 无
  1072. 返回值: 无
  1073. 修改记录:
  1074. */
  1075. void io_do_return(void)
  1076. {
  1077. int i;
  1078. u32 dly;
  1079. for(i=0; i<DO_NUM; i++) //开出保持
  1080. {
  1081. if(g_do_status & (1<<i)) //正在开出
  1082. {
  1083. dly = ustimer_get_duration(g_do_st[i].us_on);
  1084. // +2500是为了提高脉宽精度,因为此函数是在5ms(5000)中断中调用的.
  1085. // 如果us_keep为0,表示此开出没有自动返回的需求,应忽略。
  1086. if (((dly + 2500) > g_do_st[i].us_keep) && (g_do_st[i].us_keep>0))
  1087. {
  1088. dido_do_kz(0,i);
  1089. }
  1090. }
  1091. }
  1092. }
  1093. /******************************************************************************
  1094. 函数名称: dido_do_poll
  1095. 函数版本: 01.01
  1096. 创建作者:
  1097. 创建日期: 2013-03-13
  1098. 函数说明: 是否开出巡检
  1099. 参数说明: 无
  1100. 返回值: 无
  1101. 修改记录:
  1102. */
  1103. void dido_do_poll(void)
  1104. {
  1105. #if 1
  1106. int i;
  1107. // 真正开出
  1108. if(g_do_flag)
  1109. {
  1110. g_do_flag = 0;
  1111. for(i=0; i<EQU_SLOT_NUM_MAX; i++)
  1112. {
  1113. if(g_do[i].on)
  1114. {
  1115. _dido_do(i,g_do[i].on,1);
  1116. g_do[i].on = 0;
  1117. }
  1118. if(g_do[i].off)
  1119. {
  1120. _dido_do(i,g_do[i].off,0);
  1121. g_do[i].off = 0;
  1122. }
  1123. }
  1124. }
  1125. // 开出返回
  1126. io_do_return();
  1127. // 开出返校
  1128. if(g_board_info[EQU_SLOT_KZ].do_num != 0)
  1129. {
  1130. #ifdef DO_KOUT_CHECK
  1131. if((short)g_sw[0].di_cfg_index[SW_DI_KOCHK] != INDEX_INVALLID)
  1132. {
  1133. io_do_check();
  1134. }
  1135. #else
  1136. //io_do_check();
  1137. #endif
  1138. }
  1139. return;
  1140. #endif
  1141. }
  1142. /******************************************************************************
  1143. 函数名称: dido_qd_set_keeptime
  1144. 函数版本: 01.01
  1145. 创建作者: sunxi
  1146. 创建日期: 2013-06-10
  1147. 函数说明: 设置启动继电器的保持时间
  1148. 参数说明: 无
  1149. 返回值: 无
  1150. 修改记录:
  1151. */
  1152. void dido_qd_set_keeptime(u32 us)
  1153. {
  1154. g_do_st[DO_QD_KC].us_keep = us;
  1155. }
  1156. /******************************************************************************
  1157. 函数名称: get_di
  1158. 函数版本: 01.01
  1159. 创建作者:
  1160. 创建日期: 2013-03-13
  1161. 函数说明: 开入防抖处理
  1162. 参数说明: 无
  1163. 返回值: 无
  1164. 修改记录:
  1165. */
  1166. //unsigned int di_val;
  1167. void dido_di_poll(SHM_SAMPLE_T *sample_data)
  1168. {
  1169. u32 di,di_num,slot;
  1170. u64 us0;
  1171. // 如果交流延时失电信号有,闭锁遥信
  1172. if(pRunSet->dSDYX_T && g_run_stu.dcjlsd_t)
  1173. {
  1174. return;
  1175. }
  1176. us0 = ustimer_get_origin();
  1177. // 主板,19个遥信
  1178. slot = EQU_SLOT_KZ;
  1179. di_num = equ_get_di_num(slot);
  1180. // di = gpio_get_di();
  1181. di = change_di_ch(~sample_data->yx_buf[0]);
  1182. rt_printf("gpio_get_di:yx_buf[0]=%x di=%x\r\n",sample_data->yx_buf[0],di);
  1183. _get_di(slot, di_num, di, sample_data->ts);
  1184. rt_stat_other_in(6,ustimer_get_duration(us0));
  1185. }
  1186. /******************************************************************************
  1187. 函数名称: dido_di_is_on
  1188. 函数版本: 01.01
  1189. 创建作者:
  1190. 创建日期: 2013-03-13
  1191. 函数说明: 开入状态
  1192. 参数说明: 无
  1193. 返回值: 1:有开入,0:无开入
  1194. 修改记录:
  1195. */
  1196. int dido_di_is_on(u8 slot,u8 index)
  1197. {
  1198. if(slot >= EQU_SLOT_NUM_MAX || index >= 64)
  1199. {
  1200. return 0;
  1201. }
  1202. if(index < 32)
  1203. {
  1204. if(g_di[slot].value[0]&(1<<index))
  1205. {
  1206. return 1;
  1207. }
  1208. }
  1209. else
  1210. {
  1211. index -= 32;
  1212. if(g_di[slot].value[1]&(1<<index))
  1213. {
  1214. return 1;
  1215. }
  1216. }
  1217. return 0;
  1218. }
  1219. // 查看某个时间点下的开入值
  1220. int dido_di_is_on_ts(u8 slot,u8 index,u32 ts)
  1221. {
  1222. int i,r;
  1223. struct ts_index ts_i;
  1224. if(slot >= EQU_SLOT_NUM_MAX || index >= 32)
  1225. {
  1226. return 0;
  1227. }
  1228. #if 0
  1229. {
  1230. static int cnt = 0;
  1231. if(cnt++ < 16)
  1232. rt_printf("slot=%d,index=%d,ts=%d.\r\n",slot,index,ts);
  1233. }
  1234. #endif
  1235. ts_i.n = g_di[slot].ts_i[index].n - 1; //ts_i下是无值的,所以应该减1
  1236. for(i=0;i<DIDO_TS_NUM;i++)
  1237. {
  1238. r = (int)(ts - g_di[slot].ts_t[index][ts_i.n]);
  1239. if(r >= 0)
  1240. {
  1241. return g_di[slot].ts_v[index][ts_i.n];
  1242. }
  1243. ts_i.n--;
  1244. }
  1245. if(g_di[slot].value[0]&(1<<index))
  1246. {
  1247. return 1;
  1248. }
  1249. return 0;
  1250. }
  1251. int dido_do_kz(int on, unsigned int i)
  1252. {
  1253. if(on) // 开出,需启动启动继电器打开电源
  1254. {
  1255. if(i==DO_OUT0||i==DO_OUT1||i==DO_OUT5||i==DO_OUT6)
  1256. {
  1257. gpio_kout_do(on, DO_QD_KC-DO_OUT0); // 对应X4端子的DO0~DO7
  1258. _io_do_status_update(1,DO_QD_KC);
  1259. }
  1260. }
  1261. // if(i<=DO_PWM3)
  1262. // {
  1263. // gpio_pwm_do(on, i); // 对应X3端子的OUT3,分闸
  1264. // _io_do_status_update(on,i);
  1265. // }
  1266. // else
  1267. if(i==DO_QD_KC) //启动继电器出口
  1268. {
  1269. if(!on)
  1270. {
  1271. if(g_tRelay[0].zqd) // 如果保护启动,禁止关闭启动继电器
  1272. {
  1273. return -2;
  1274. }
  1275. if(g_do_status&(~(1<<DO_QD_KC))) //有其他开出,不收启动继电器
  1276. {
  1277. return -3;
  1278. }
  1279. }
  1280. gpio_kout_do(on, i-DO_OUT0); // 对应X4端子的DO0~DO7
  1281. _io_do_status_update(on,i);
  1282. }
  1283. else if ((i >= DO_OUT0) && (i <= DO_OUT7))
  1284. {
  1285. gpio_kout_do(on, i-DO_OUT0); // 对应X4端子的DO0~DO7
  1286. _io_do_status_update(on,i);
  1287. }
  1288. else
  1289. {
  1290. rt_printf("dido_do_kz err(on=%d,i=%d).\r\n",on,i);
  1291. }
  1292. return 0;
  1293. }
  1294. /*------------------------------ 内部函数 -------------------------------------
  1295. 内部函数以下划线‘_’开头,不需要检查参数的合法性.
  1296. */
  1297. static inline void _io_do_status_update(int on, unsigned int i)
  1298. {
  1299. if(on)
  1300. {
  1301. g_do_status |= (1<<i);
  1302. g_do_st[i].us_on= ustimer_get_origin();
  1303. }
  1304. else
  1305. {
  1306. g_do_status &= ~(1<<i);
  1307. }
  1308. // 更新返校检查时间
  1309. g_do_start_time = ustimer_get_origin();
  1310. }
  1311. static int _dido_do(u32 slot,u16 v,int is_on)
  1312. {
  1313. int i;
  1314. // 循环检查开出位
  1315. for(i=0; i<g_board_info[slot].do_num; i++)
  1316. {
  1317. // 如果对应开出位有效,开出。
  1318. if(((v>>i) & 0x1))
  1319. {
  1320. dido_do_kz(is_on,equ_get_do_channel(i));
  1321. }
  1322. }
  1323. if(((v>>g_board_info[slot].do_num) & 0x1)) // 启动继电器
  1324. {
  1325. dido_do_kz(is_on,DO_QD_KC);
  1326. }
  1327. return 0;
  1328. }
  1329. /******************************************************************************
  1330. 函数名称: _get_di
  1331. 函数版本: 01.01
  1332. 创建作者:
  1333. 创建日期: 2013-03-13
  1334. 函数说明: 开入防抖处理
  1335. 参数说明: 无
  1336. 返回值:
  1337. 修改记录:
  1338. */
  1339. #ifdef CN_AREA_GUANGXI//遥信全部为0
  1340. u32 kktime_0=0;
  1341. #endif
  1342. static int _get_di(int slot,u16 di_num, u32 di, struct timespec ts)
  1343. {
  1344. int i,b_on;
  1345. struct rtc_time_t ct;
  1346. uint32 diff_nsec;
  1347. // struct timespec ts;
  1348. #if 0//#ifdef CN_AREA_GUANGXI//遥信全部为0,则关闭屏幕或者关机
  1349. if(di==0)
  1350. {
  1351. kktime_0++;
  1352. if(kktime_0 > 10)
  1353. {
  1354. #if 1
  1355. g_run_stu.yxError=true; //遥信错误,关闭屏幕
  1356. #else
  1357. char *argv[] = {"poweroff", NULL};
  1358. char *envp[] = { NULL };
  1359. call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);//关机
  1360. #endif
  1361. return 0;
  1362. }
  1363. }
  1364. else
  1365. {
  1366. g_run_stu.yxError=0;
  1367. kktime_0=0;
  1368. }
  1369. #endif
  1370. // 获取遥信值,并记录时间戳。
  1371. // 用秒的低8位和纳秒的高24位合成32位时间戳
  1372. // clk_time_get(&ts);
  1373. // 循环处理每一个遥信
  1374. for(i=0; i<di_num; i++)
  1375. {
  1376. struct di_struct *pt=&g_di_st[slot][i];
  1377. // 处理当前变位遥信。
  1378. b_on = (di&(1<<i))? 1:0;
  1379. if(b_on^pt->b_on)
  1380. {
  1381. if(!pt->b_first_change)
  1382. {
  1383. pt->b_first_change=true;
  1384. pt->tm_back=0;
  1385. pt->tm_keep=0;
  1386. // 记录变位的起始时刻点
  1387. pt->ts_di = ts;
  1388. pt->dt=g_adc_dots_data_count;
  1389. #ifdef DIDO_TS_MODE
  1390. pt->ts_tmp = ts;
  1391. #endif
  1392. }
  1393. else
  1394. {
  1395. // 累计保持时间
  1396. #ifdef DIDO_TS_MODE
  1397. if(ts.tv_nsec >= pt->ts_tmp.tv_nsec)
  1398. {
  1399. diff_nsec = ts.tv_nsec - pt->ts_tmp.tv_nsec;
  1400. }
  1401. else
  1402. {
  1403. diff_nsec = 1000000000ul - pt->ts_tmp.tv_nsec + ts.tv_nsec;
  1404. }
  1405. if(diff_nsec > 312500ul)
  1406. {
  1407. diff_nsec = 156250ul;
  1408. }
  1409. pt->acc_nsec += diff_nsec;
  1410. while(pt->acc_nsec >= 156250ul)
  1411. {
  1412. pt->tm_keep++;
  1413. pt->acc_nsec -= 156250ul;
  1414. }
  1415. pt->ts_tmp = ts;
  1416. // rt_printf("diff_nsec:%d, pt->tm_keep:%d\r\n", diff_nsec, pt->tm_keep);
  1417. #else
  1418. pt->tm_keep++;
  1419. #endif
  1420. pt->tm_back=0; // 现在返回门限是0.5us,所有必须在此清零。
  1421. // 保持时间到,处理变位
  1422. if(pt->tm_keep > pt->tm_filter)
  1423. {
  1424. // 记录遥信状态
  1425. #if defined CN_AREA_GUANGXI || defined YX_DI_ERROR //广西遥信异常后,遥信屏蔽不保存,不上报
  1426. if( g_run_stu.yxEnable==0 && b_on==0)
  1427. {
  1428. pt->type = SOE_TYPE_TST;
  1429. pt->b_first_change=false;
  1430. pt->tm_back=0;
  1431. pt->tm_keep=0;
  1432. return 0;
  1433. }
  1434. #endif
  1435. pt->b_on = b_on;
  1436. if(g_di[slot].inv[0] & (1<<i))
  1437. {
  1438. b_on = !b_on;
  1439. }
  1440. if(b_on)
  1441. {
  1442. g_di[slot].value[0] |= (1<<i);
  1443. }
  1444. else
  1445. {
  1446. g_di[slot].value[0] &= ~(1<<i);
  1447. }
  1448. // 记录SOE
  1449. soe_record_yx((WORD)(i+(slot<<8)),b_on,&pt->ts_di);
  1450. timespec_to_rtc(ts, &ct, 1);
  1451. rt_printf("di=%x value[0]=%x\r\n",di,g_di[slot].value[0]);
  1452. // 更新逻辑模型中的值
  1453. 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);
  1454. // 更新记录
  1455. g_di[slot].ts_t[i][g_di[slot].ts_i[i].n] = pt->dt;
  1456. g_di[slot].ts_v[i][g_di[slot].ts_i[i].n] = b_on;
  1457. g_di[slot].ts_i[i].n++;
  1458. //滤波处理数据复位
  1459. pt->b_first_change=false;
  1460. pt->tm_back=0;
  1461. pt->tm_keep=0;
  1462. }
  1463. }
  1464. }
  1465. else if(pt->b_first_change)
  1466. {
  1467. // 变位返回处理
  1468. pt->tm_back++;
  1469. // 屏蔽下一行,
  1470. // 最新逻辑,有效电平不连续可计数累加;
  1471. // 无效电平连续超0.5ms复归,且不连续累加。
  1472. //pt->tm_keep=0;
  1473. // if(pt->tm_back > pt->tm_filter)
  1474. if(pt->tm_back>4) // 针对高频振荡波测试优化,返回门限设置为500us附件(4*156=624us)。
  1475. {
  1476. pt->tm_back = 0;
  1477. pt->tm_keep=0;
  1478. pt->b_first_change = false;
  1479. }
  1480. }
  1481. }
  1482. return 0;
  1483. }
  1484. /*------------------------------ 测试函数 -------------------------------------
  1485. 一个实体文件必须带一个本模块的测试函数来进行单元测试,如果的确不方便在本模块中
  1486. 进行单元测试,必须在此注明实际的测试位置(例如在哪个实体文件中使用哪个测试函数).
  1487. */
  1488. // SOE信号发生器控制全局变量
  1489. extern int g_soe_gen_state; // 状态,0停止,1初始化,2运行
  1490. extern int g_soe_gen_on_us; // 导通时间
  1491. extern int g_soe_gen_off_us; // 断开时间
  1492. extern int g_soe_gen_seq_us; // 通道序列间隔时间
  1493. #define SOE_GEN_NUM 8
  1494. u32 g_soe_gen_count;
  1495. u32 g_soe_gen_us0[SOE_GEN_NUM];
  1496. u8 g_soe_gen_on[SOE_GEN_NUM];
  1497. void dido_soe_gen(void)
  1498. {
  1499. int i;
  1500. if(g_soe_gen_state == 0)
  1501. {
  1502. return;
  1503. }
  1504. else if(g_soe_gen_state == 1)
  1505. {
  1506. pit_156us_period_set(78.125);
  1507. g_soe_gen_count = 0;
  1508. for(i=0; i<SOE_GEN_NUM; i++)
  1509. {
  1510. g_soe_gen_us0[i] = g_soe_gen_seq_us*(i);
  1511. g_soe_gen_on[i] = 0;
  1512. g_soe_gen_state = 2;
  1513. }
  1514. }
  1515. else if(dido_di_is_on(1,0))
  1516. {
  1517. for(i=0; i<SOE_GEN_NUM; i++)
  1518. {
  1519. if(g_soe_gen_on[i] == 0)
  1520. {
  1521. if((int)(g_soe_gen_count - g_soe_gen_us0[i]) >= g_soe_gen_off_us)
  1522. {
  1523. g_soe_gen_on[i] = 1;
  1524. gpio_kout_do(1,i);
  1525. g_soe_gen_us0[i] = g_soe_gen_count;
  1526. }
  1527. }
  1528. else
  1529. {
  1530. if((int)(g_soe_gen_count - g_soe_gen_us0[i]) >= g_soe_gen_on_us)
  1531. {
  1532. g_soe_gen_on[i] = 0;
  1533. gpio_kout_do(0,i);
  1534. g_soe_gen_us0[i] = g_soe_gen_count;
  1535. }
  1536. }
  1537. }
  1538. }
  1539. else
  1540. {
  1541. g_soe_gen_count = 0;
  1542. for(i=0; i<SOE_GEN_NUM; i++)
  1543. {
  1544. g_soe_gen_us0[i] = g_soe_gen_seq_us*(i);
  1545. g_soe_gen_on[i] = 0;
  1546. g_soe_gen_state = 2;
  1547. }
  1548. }
  1549. g_soe_gen_count++;
  1550. }
  1551. int dido_printf(void)
  1552. {
  1553. int i,slot,index;
  1554. struct ts_index ts_i;
  1555. rt_printf("槽号\t值\r\n");
  1556. for(i=0; i<EQU_SLOT_NUM_MAX; i++) // xj 2015-5-4
  1557. {
  1558. 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]);
  1559. }
  1560. rt_printf("\r\n");
  1561. slot = EQU_SLOT_MAIN;
  1562. index = 1;
  1563. ts_i.n = g_di[slot].ts_i[index].n;
  1564. rt_printf("开入时间戳记录:slot=%d,index=%d,ts_i=%d.\r\n",slot,index,ts_i.n);
  1565. rt_printf("序号\t值\t时间戳\r\n");
  1566. ts_i.n = 0;
  1567. for(i=0;i<DIDO_TS_NUM;i++)
  1568. {
  1569. 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]);
  1570. ts_i.n++;
  1571. }
  1572. rt_printf("开出状态:0x%04x\r\n\r\n",g_do_status);
  1573. rt_stat_printf(&g_stat_di_delay);
  1574. rt_stat_printf(&g_stat_do_delay);
  1575. return 0;
  1576. }
  1577. int dido_stat_reset(void)
  1578. {
  1579. rt_stat_init(&g_stat_di_delay,"di_delay");
  1580. rt_stat_init(&g_stat_do_delay,"do_delay");
  1581. return 0 ;
  1582. }
  1583. int dido_single_test(u8 slot, u8 point)
  1584. {
  1585. dido_do(slot,(1<<point),1);
  1586. ustimer_delay(250*USTIMER_MS);
  1587. dido_do(slot,(1<<point),0);
  1588. return 0;
  1589. }
  1590. int dido_test(void)
  1591. {
  1592. static unsigned long us0 = 0;
  1593. static char dido_test_pair[3][2] =
  1594. {
  1595. {1,3},
  1596. {2,4},
  1597. {5,5},
  1598. };
  1599. static char dido_test_di[32] =
  1600. {
  1601. 0,1,2,3,
  1602. 0,1,2,3,
  1603. 4,5,6,7,
  1604. 4,5,6,7,
  1605. 8,9,10,11,
  1606. 8,9,10,11,
  1607. 12,13,10,11,
  1608. 12,13,12,13
  1609. };
  1610. int i,j,k,err_once,di_num;
  1611. u32 slot_di,slot_do;
  1612. if(g_test_on == 0)
  1613. {
  1614. return 0;
  1615. }
  1616. // 5秒处理一次
  1617. if(ustimer_delay_origin2(&us0,10*USTIMER_SEC) != 1)
  1618. {
  1619. return 0;
  1620. }
  1621. rt_printf("dido_test begin...\r\n");
  1622. ustimer_delay(1*USTIMER_SEC);
  1623. #if 1
  1624. // 测试开出板、开入板
  1625. // 开出板逐一开出
  1626. rt_printf("dido_test single.\r\n");
  1627. err_once = 0;
  1628. for(i=0; i<3; i++)
  1629. {
  1630. slot_do = dido_test_pair[i][0];
  1631. slot_di = dido_test_pair[i][1];
  1632. for(j=0;j<equ_get_do_num(slot_do); j++)
  1633. {
  1634. dido_do(slot_do,(1<<j),1);
  1635. ustimer_delay(250*USTIMER_MS);
  1636. di_num = equ_get_di_num(slot_di);
  1637. if(slot_di == equ_get_slot_by_type(BOARD_TYPE_AUX))
  1638. {
  1639. di_num -= 1;
  1640. }
  1641. for(k=0;k<di_num; k++)
  1642. {
  1643. // 是否对应的开出点
  1644. if(dido_test_di[k] == j)
  1645. {
  1646. if((g_di[slot_di].value[0] & (1<<k)) == 0)
  1647. {
  1648. err_once++;
  1649. error_count++;
  1650. 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]);
  1651. }
  1652. }
  1653. else
  1654. {
  1655. if((g_di[slot_di].value[0] & (1<<k)) != 0)
  1656. {
  1657. err_once++;
  1658. error_count++;
  1659. 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]);
  1660. }
  1661. }
  1662. }
  1663. dido_do(slot_do,(1<<j),0);
  1664. ustimer_delay(20*USTIMER_MS);
  1665. watchdog_feed_mainloop();
  1666. }
  1667. }
  1668. #endif
  1669. rt_printf("\r\n开入变位时间超出次数:%lu\r\n",di_error_count);
  1670. rt_printf("name\t\t\tmin\tmax\tavg\tsum\t\tcnt\n");
  1671. rt_stat_printf(&g_stat_di_delay);
  1672. rt_printf("\r\n");
  1673. for(i=0;i<EQU_SLOT_NUM_MAX;i++)
  1674. {
  1675. if(g_do_time[i].slot != 0)
  1676. {
  1677. rt_printf("do_time[%d]:diff_max=%lu,diff_out_count=%lu\r\n",
  1678. g_do_time[i].slot,g_do_time[i].diff_max,g_do_time[i].diff_out_count);
  1679. }
  1680. }
  1681. rt_printf("\r\n");
  1682. rt_printf("dido_test end:err_once=%d,error_count=%lu!\r\n\r\n\r\n",err_once,error_count);
  1683. return 0;
  1684. }
  1685. bool check_board_di_valid(u8 slot,u8 index)
  1686. {
  1687. u32 i;
  1688. // 初始化取反标志
  1689. index-=1;
  1690. for(i=0; i< g_equ_config->di_num; i++)
  1691. {
  1692. if((g_equ_config_di[i].slot==1)&&(g_equ_config_di[i].index==index))
  1693. {
  1694. if(g_equ_config_di[i].type==0)return true;
  1695. }
  1696. }
  1697. return false;
  1698. }
  1699. bool check_board_kc6_close(u8 slot,u8 index)
  1700. {
  1701. u32 i;
  1702. // 初始化取反标志
  1703. index-=1;
  1704. for(i=0; i< g_equ_config->do_num; i++)
  1705. {
  1706. if((g_equ_config_do[i].slot==slot)&&(g_equ_config_do[i].index==index))
  1707. {
  1708. if(g_equ_config_do[i].type!=0)return true;
  1709. }
  1710. }
  1711. return false;
  1712. }
  1713. #define DIGROUP 4
  1714. #define V3_OUT_NUM 5
  1715. int dido_auto_test_for_v3(char *buf,int num)
  1716. {
  1717. // 12个开入,用5个开出进行测试
  1718. static char test_di[6][DIGROUP] =
  1719. {
  1720. {1, 6, 11,0},
  1721. {2, 7, 12,0},
  1722. {3, 8, 13,0},
  1723. {4, 9, 14,0},
  1724. {16, 0, 0,0},
  1725. {5, 10, 15,0},
  1726. };
  1727. int i,j,k,err_once,flag,flag1,di_num, do_num;
  1728. u32 slot_di,slot_do, di_result;
  1729. u8 tmp[5],tmp_data[5];
  1730. u8 di_ok[4] = {0};
  1731. u8 do_errflag = 0;
  1732. char dido_test_pair[num][2];
  1733. unsigned long us_begin = 0;
  1734. bool bkc6close=false;
  1735. slot_do=0;
  1736. bkc6close=check_board_kc6_close(1,6);
  1737. dido_stat_reset();
  1738. if(bkc6close)
  1739. {
  1740. dido_do(slot_do,(1<<5),1); // 开出6若焊接为常闭输出,先开出,打开节点
  1741. ustimer_delay(100*USTIMER_MS);
  1742. }
  1743. // 取出板卡槽位
  1744. for(i=0;i<(num*2);)
  1745. {
  1746. for(j=0;j<2;j++)
  1747. {
  1748. dido_test_pair[i/2][j] = buf[i];
  1749. i++;
  1750. }
  1751. }
  1752. flag = 0;
  1753. flag1 = 0;
  1754. memset(tmp,0,sizeof(tmp));
  1755. memset(tmp_data,0,sizeof(tmp_data));
  1756. memset(dido_buf,0,sizeof(dido_buf));
  1757. rt_printf("dido_test begin...\r\n");
  1758. err_once = 0;
  1759. // 以组为循环
  1760. for(i=0; i<num; i++)
  1761. {
  1762. slot_do = dido_test_pair[i][0];
  1763. slot_di = dido_test_pair[i][1];
  1764. // 槽位暂存
  1765. dido_buf[i+i*13] = slot_do;
  1766. dido_buf[i+i*13+5] = slot_di;
  1767. // 取出对应槽位的板卡中DI和DO的数量
  1768. di_num = equ_get_di_num(slot_di);
  1769. do_num = equ_get_do_num(slot_do);
  1770. //dido_do(slot_do,(1<<5),1); //磁保持继电器
  1771. // 启动记时
  1772. us_begin = ustimer_get_origin();
  1773. // 逐一输出开出点
  1774. for(j=0; j<V3_OUT_NUM; j++)
  1775. {
  1776. dido_do(slot_do,(1<<j),1);
  1777. if(j==5&&bkc6close)
  1778. {
  1779. dido_do(slot_do,(1<<5),0); // 开出6若焊接为常闭输出,反操作为闭合
  1780. }
  1781. ustimer_delay(150*USTIMER_MS);
  1782. memset(di_ok,0,sizeof(di_ok));
  1783. do_errflag = DIGROUP;
  1784. for (k=0; k<4; k++)
  1785. {
  1786. bool bIgnore=false;
  1787. di_result = (g_di[slot_di].value[0] ^ g_di[slot_di].inv[0]);
  1788. k+=i*2;
  1789. if(test_di[j][k]==17)
  1790. {
  1791. bIgnore=check_board_di_valid(slot_di,17);
  1792. }
  1793. if(test_di[j][k]==18)
  1794. {
  1795. bIgnore=check_board_di_valid(slot_di,18);
  1796. }
  1797. if (!test_di[j][k]||bIgnore)
  1798. {
  1799. do_errflag--;
  1800. }
  1801. else
  1802. {
  1803. if (!(di_result & (1<<(test_di[j][k]-1)))) //对应开入无值
  1804. {
  1805. do_errflag--;
  1806. di_ok[k] = test_di[j][k];
  1807. }
  1808. }
  1809. }
  1810. if (!do_errflag) //开出对应的所有开入都没有值,即代表该开出有问题
  1811. {
  1812. if (j<8)
  1813. {
  1814. dido_buf[i+i*13+1] |= (1<<j); //开出错误标志
  1815. }
  1816. else if (j<16)
  1817. {
  1818. dido_buf[i+i*13+2] |= (1<<(j-8)); //开出错误标志
  1819. }
  1820. rt_printf("dido_test do err:i=%d,j=%d,di=%d,di_l=0x%04lx,di_h=0x%04lx.\r\n",
  1821. i,j,di_ok[0], g_di[slot_di].value[0],g_di[slot_di].value[1]);
  1822. }
  1823. else
  1824. {
  1825. for (k=0; k<4; k++)
  1826. {
  1827. if (!di_ok[k])
  1828. continue;
  1829. if ((di_ok[k]-1) < 8)
  1830. {
  1831. dido_buf[i+i*13+6] |= (1<<(di_ok[k]-1));
  1832. }
  1833. else if ((di_ok[k]-1) < 16)
  1834. {
  1835. dido_buf[i+i*13+7] |= (1<<(di_ok[k]-1-8));
  1836. }
  1837. else if ((di_ok[k]-1) < 24)
  1838. {
  1839. dido_buf[i+i*13+8] |= (1<<(di_ok[k]-1-16));
  1840. }
  1841. else if ((di_ok[k]-1) < 32)
  1842. {
  1843. dido_buf[i+i*13+9] |= (1<<(di_ok[k]-1-24));
  1844. }
  1845. else if ((di_ok[k]-1) < 40)
  1846. {
  1847. dido_buf[i+i*13+10] |= (1<<(di_ok[k]-1-32));
  1848. }
  1849. else if ((di_ok[k]-1) < 48)
  1850. {
  1851. dido_buf[i+i*13+11] |= (1<<(di_ok[k]-1-40));
  1852. }
  1853. else if ((di_ok[k]-1) < 56)
  1854. {
  1855. dido_buf[i+i*13+12] |= (1<<(di_ok[k]-1-48));
  1856. }
  1857. else if ((di_ok[k]-1) < 64)
  1858. {
  1859. dido_buf[i+i*13+13] |= (1<<(di_ok[k]-1-56));
  1860. }
  1861. rt_printf("dido_test di err:i=%d,j=%d,di=%d,di_l=0x%04lx,di_h=0x%04lx.\r\n",
  1862. i,j,di_ok[k], g_di[slot_di].value[0],g_di[slot_di].value[1]);
  1863. }
  1864. }
  1865. dido_do(slot_do,(1<<j),0);
  1866. if(j==5&&bkc6close)
  1867. {
  1868. dido_do(slot_do,(1<<5),1); // 开出6若焊接为常闭输出,反操作为闭合
  1869. }
  1870. //if(j==4)
  1871. //{
  1872. //dido_do(slot_do,(1<<5),1); //磁保持继电器
  1873. //}
  1874. ustimer_delay(20*USTIMER_MS);
  1875. watchdog_feed_mainloop();
  1876. }
  1877. }
  1878. for(i=0;i<EQU_SLOT_NUM_MAX;i++)
  1879. {
  1880. if(g_do_time[i].slot != 0)
  1881. {
  1882. rt_printf("do_time[%d]:diff_max=%lu,diff_out_count=%lu\r\n",
  1883. g_do_time[i].slot,g_do_time[i].diff_max,g_do_time[i].diff_out_count);
  1884. }
  1885. }
  1886. rt_printf("dido_test end:err_once=%d,error_count=%lu!\r\n\r\n\r\n",err_once,error_count);
  1887. return 0;
  1888. }
  1889. extern u32 g_brd_type_kz;
  1890. int dido_auto_test(char *buf,int num)
  1891. {
  1892. #define KC_COUNT 11
  1893. // 12个开入,用5个开出进行测试
  1894. #if 0
  1895. static char test_di[6][DIGROUP] =
  1896. {
  1897. {1, 6, 11,0},
  1898. {2, 7, 12,0},
  1899. {3, 8, 13,0},
  1900. {4, 9, 14,0},
  1901. {16, 0, 0,0},
  1902. {5, 10, 15,0},
  1903. };
  1904. #endif
  1905. static char test_di[KC_COUNT][DIGROUP] =
  1906. {
  1907. {1, 12, 23,0},
  1908. {2, 13, 24,0},
  1909. {3, 14, 0,0},
  1910. {4, 15, 0,0},
  1911. {5, 16, 0,0},
  1912. {6, 17, 0,0},
  1913. {7, 18, 0,0},
  1914. {8, 19, 0,0},
  1915. {9, 20, 0,0},
  1916. {10,21, 0,0},
  1917. {11,22, 0,0},
  1918. // { 0, 0, 0,0}
  1919. };
  1920. u8 brd_v3[] = {22, 23};
  1921. int i,j,k,err_once,flag,flag1,di_num, do_num;
  1922. u32 slot_di,slot_do, di_result;
  1923. u8 tmp[5],tmp_data[5];
  1924. u8 di_ok[4] = {0};
  1925. u8 do_errflag = 0;
  1926. char dido_test_pair[num][2];
  1927. unsigned long us_begin = 0;
  1928. bool bkc6close=false;
  1929. rt_printf("g_brd_type_kz = %lu\r\n ", g_brd_type_kz);
  1930. rt_printf("g_equ_config->do_num = %lu\r\n ", g_equ_config->do_num);
  1931. for(i=0; i<(int)sizeof(brd_v3); i++)
  1932. {
  1933. if(g_brd_type_kz+BOARD_TYPE_DFTU_KC00==brd_v3[i])//
  1934. {
  1935. rt_printf("auto_test_for_v3\r\n ");
  1936. return (dido_auto_test_for_v3(buf, num));
  1937. }
  1938. }
  1939. rt_printf("auto_test_for_v4\r\n ");
  1940. //bkc6close=check_board_kc6_close(1,6);
  1941. dido_stat_reset();
  1942. if(bkc6close)
  1943. {
  1944. dido_do(1,(1<<5),1); // 开出6若焊接为常闭输出,先开出,打开节点
  1945. ustimer_delay(100*USTIMER_MS);
  1946. }
  1947. // 取出板卡槽位
  1948. for(i=0;i<(num*2);)
  1949. {
  1950. for(j=0;j<2;j++)
  1951. {
  1952. dido_test_pair[i/2][j] = buf[i];
  1953. i++;
  1954. }
  1955. }
  1956. flag = 0;
  1957. flag1 = 0;
  1958. memset(tmp,0,sizeof(tmp));
  1959. memset(tmp_data,0,sizeof(tmp_data));
  1960. memset(dido_buf,0,sizeof(dido_buf));
  1961. rt_printf("dido_test begin...\r\n");
  1962. err_once = 0;
  1963. // 以组为循环
  1964. for(i=0; i<num; i++)
  1965. {
  1966. slot_do = dido_test_pair[i][0];
  1967. slot_di = dido_test_pair[i][1];
  1968. // 槽位暂存
  1969. dido_buf[i+i*13] = slot_do;
  1970. dido_buf[i+i*13+5] = slot_di;
  1971. // 取出对应槽位的板卡中DI和DO的数量
  1972. di_num = equ_get_di_num(slot_di);
  1973. do_num = equ_get_do_num(slot_do);
  1974. //dido_do(slot_do,(1<<5),1); //磁保持继电器
  1975. // 启动记时
  1976. us_begin = ustimer_get_origin();
  1977. // 逐一输出开出点
  1978. for(j=0; j<KC_COUNT; j++)
  1979. {
  1980. dido_do(slot_do,(1<<j),1);
  1981. if(j==5&&bkc6close)
  1982. {
  1983. dido_do(slot_do,(1<<5),0); // 开出6若焊接为常闭输出,反操作为闭合
  1984. }
  1985. ustimer_delay(150*USTIMER_MS);
  1986. memset(di_ok,0,sizeof(di_ok));
  1987. do_errflag = DIGROUP;
  1988. for (k=0; k<4; k++)
  1989. {
  1990. bool bIgnore=false;
  1991. di_result = (g_di[slot_di].value[0] ^ g_di[slot_di].inv[0]);
  1992. k+=i*2;
  1993. if(test_di[j][k]==17)
  1994. {
  1995. bIgnore=check_board_di_valid(slot_di,17);
  1996. }
  1997. if(test_di[j][k]==18)
  1998. {
  1999. bIgnore=check_board_di_valid(slot_di,18);
  2000. }
  2001. if (!test_di[j][k]||bIgnore)
  2002. {
  2003. do_errflag--;
  2004. }
  2005. else
  2006. {
  2007. if (!(di_result & (1<<(test_di[j][k]-1)))) //对应开入无值
  2008. {
  2009. do_errflag--;
  2010. di_ok[k] = test_di[j][k];
  2011. }
  2012. }
  2013. }
  2014. if (!do_errflag) //开出对应的所有开入都没有值,即代表该开出有问题
  2015. {
  2016. if (j<8)
  2017. {
  2018. dido_buf[i+i*13+1] |= (1<<j); //开出错误标志
  2019. }
  2020. else if (j<16)
  2021. {
  2022. dido_buf[i+i*13+2] |= (1<<(j-8)); //开出错误标志
  2023. }
  2024. rt_printf("dido_test do err:i=%d,j=%d,di=%d,di_l=0x%04lx,di_h=0x%04lx.\r\n",
  2025. i,j,di_ok[0], g_di[slot_di].value[0],g_di[slot_di].value[1]);
  2026. }
  2027. else
  2028. {
  2029. for (k=0; k<4; k++)
  2030. {
  2031. if (!di_ok[k])
  2032. continue;
  2033. if ((di_ok[k]-1) < 8)
  2034. {
  2035. dido_buf[i+i*13+6] |= (1<<(di_ok[k]-1));
  2036. }
  2037. else if ((di_ok[k]-1) < 16)
  2038. {
  2039. dido_buf[i+i*13+7] |= (1<<(di_ok[k]-1-8));
  2040. }
  2041. else if ((di_ok[k]-1) < 24)
  2042. {
  2043. dido_buf[i+i*13+8] |= (1<<(di_ok[k]-1-16));
  2044. }
  2045. else if ((di_ok[k]-1) < 32)
  2046. {
  2047. dido_buf[i+i*13+9] |= (1<<(di_ok[k]-1-24));
  2048. }
  2049. else if ((di_ok[k]-1) < 40)
  2050. {
  2051. dido_buf[i+i*13+10] |= (1<<(di_ok[k]-1-32));
  2052. }
  2053. else if ((di_ok[k]-1) < 48)
  2054. {
  2055. dido_buf[i+i*13+11] |= (1<<(di_ok[k]-1-40));
  2056. }
  2057. else if ((di_ok[k]-1) < 56)
  2058. {
  2059. dido_buf[i+i*13+12] |= (1<<(di_ok[k]-1-48));
  2060. }
  2061. else if ((di_ok[k]-1) < 64)
  2062. {
  2063. dido_buf[i+i*13+13] |= (1<<(di_ok[k]-1-56));
  2064. }
  2065. rt_printf("dido_test di err:i=%d,j=%d,di=%d,di_l=0x%04lx,di_h=0x%04lx.\r\n",
  2066. i,j,di_ok[k], g_di[slot_di].value[0],g_di[slot_di].value[1]);
  2067. }
  2068. }
  2069. dido_do(slot_do,(1<<j),0);
  2070. if(j==5&&bkc6close)
  2071. {
  2072. dido_do(slot_do,(1<<5),1); // 开出6若焊接为常闭输出,反操作为闭合
  2073. }
  2074. //if(j==4)
  2075. //{
  2076. //dido_do(slot_do,(1<<5),1); //磁保持继电器
  2077. //}
  2078. ustimer_delay(20*USTIMER_MS);
  2079. watchdog_feed_mainloop();
  2080. }
  2081. }
  2082. for(i=0;i<EQU_SLOT_NUM_MAX;i++)
  2083. {
  2084. if(g_do_time[i].slot != 0)
  2085. {
  2086. rt_printf("do_time[%d]:diff_max=%lu,diff_out_count=%lu\r\n",
  2087. g_do_time[i].slot,g_do_time[i].diff_max,g_do_time[i].diff_out_count);
  2088. }
  2089. }
  2090. rt_printf("dido_test end:err_once=%d,error_count=%lu!\r\n\r\n\r\n",err_once,error_count);
  2091. return 0;
  2092. }
  2093. #endif // GW_AREA_MAIN_2021
  2094. /*------------------------------ 文件结束 -------------------------------------
  2095. */