dido.c 48 KB

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