IEC101.c 123 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428
  1. /********************************************************************
  2. 版权所有:
  3. 文件版本: V1.00
  4. 文件名称: IEC101.c
  5. 生成日期: 2010年04月26日
  6. 作 者:hhw
  7. 使用范围:
  8. 功 能: IEC101规约处理
  9. 更新信息:
  10. 更新日志1
  11. 修改者:
  12. 修改日期:
  13. 修改内容:
  14. 修改原因:
  15. *********************************************************************/
  16. #include "head.h"
  17. u32 IEC101_SendEvent(IEC101_DEF *pt,int is_send_cos);
  18. void IEC101_Info_Printf_One(IEC101_DEF *p);
  19. extern int gprs_vs_write(const unsigned char * buf, int count);
  20. GPRS_INF_DEF tGprsInf;
  21. static void IEC101_State(IEC101_DEF *pt101,int state)
  22. {
  23. if(pt101->st101 != state)
  24. {
  25. char buf[64];
  26. char log_info[128];
  27. rt_printf_time("IEC101(%d) state: %d => %d!\r\n", pt101->chnl,pt101->st101,state);
  28. pt101->st101 = state;
  29. if(state == IEC101_ST_DATA)
  30. {
  31. sprintf(buf,"101主站连接(%s)!\r\n",get_comm_name(pt101->chnl + 1));
  32. log_str_time(LOG_OPERATE,buf,0,1);
  33. sprintf(log_info,"IEC101(%d):101 main station connection",pt101->chnl+1);
  34. load_hs_log_rcd(TYPE_CHNL_LINK,true,NULL,log_info,1);
  35. if(log_flag.com_err[pt101->chnl] == true)
  36. {
  37. memset(log_info,0,sizeof(log_info));
  38. sprintf(log_info,"IEC101(%d):Communication process anomaly return",pt101->chnl+1);
  39. load_hs_log_rcd(TYPE_COMM_ERR,true,NULL,log_info,0);
  40. log_flag.com_err[pt101->chnl] = false;
  41. }
  42. // SOE发送缓冲区复位,发送指针回到ACK的位置
  43. if(pRunSet->bTT_SoeResumeComm)
  44. {
  45. #ifdef SOE_RELINK_DISCOS
  46. if(!g_soe_queue.bSoeRelink[pt101->chnl])
  47. {
  48. //g_soe_queue.relink_tail_bak[pt101->chnl].n = g_soe_queue.tail_send[pt101->chnl].n;
  49. g_soe_queue.relink_tail_bak[pt101->chnl].n = g_soe_queue.tail_eep.n;
  50. }
  51. g_soe_queue.bSoeRelink[pt101->chnl] = true;
  52. #endif
  53. //pt101->bSoeRelink = true;
  54. g_soe_queue.tail_send[pt101->chnl].n=g_soe_queue.tail_ack[pt101->chnl].n;
  55. }
  56. }
  57. else if(state == IEC101_ST_NONE)
  58. {
  59. sprintf(buf,"101主站断开(%s)!\r\n",get_comm_name(pt101->chnl + 1));
  60. log_str_time(LOG_OPERATE,buf,0,0);
  61. sprintf(log_info,"IEC101(%d):101 main station disconnection",pt101->chnl + 1);
  62. load_hs_log_rcd(TYPE_CHNL_LINK,true,NULL,log_info,0);
  63. }
  64. }
  65. return;
  66. }
  67. static void IEC101_ResetTxBuf(IEC101_DEF *pt101)
  68. {
  69. pt101->btx_buf_m = false;
  70. pt101->btx_buf_s = false;
  71. memset(&pt101->tx_buf,0,sizeof(pt101->tx_buf));
  72. }
  73. static void IEC101_Reset(IEC101_DEF *pt101)
  74. {
  75. // 通道属性、连接计数不允许复位
  76. // 规约状态复位
  77. g_comm_link_status &= ~(1<<pt101->chnl);
  78. IEC101_State(pt101,IEC101_ST_NONE);
  79. pt101->bSendChange=false;
  80. // 计时
  81. pt101->us0_sec = ustimer_get_origin();
  82. pt101->secs = 0;
  83. pt101->us0_sendpiece=ustimer_get_origin();
  84. // 对时
  85. pt101->us0_frame = 0;
  86. pt101->ms_delay = 0;
  87. // 1级、2级数据发送
  88. pt101->bFirstFCV = 1;
  89. pt101->tb_index = -1;
  90. pt101->FCBSave=0;
  91. // 遥测发送处理
  92. pt101->bycsend = FALSE;
  93. pt101->ycno=0;
  94. pt101->us0_yc = ustimer_get_origin();
  95. memset(pt101->yc_save,0,sizeof(pt101->yc_save));
  96. // 其它状态复位
  97. pt101->bRmtSM2=false;
  98. pt101->dValidTime=0;
  99. pt101->bMSend=false;
  100. pt101->bDIR=true;
  101. pt101->bResetProcess = false;
  102. pt101->tm.us0_callall=dTCounter; // 不能用微妙定时器,最多支持13分钟
  103. pt101->tm.bAppEcho=false;
  104. //pt101->bSoeRelink = false;
  105. pt101->bTimeSyn = false;
  106. #if 0
  107. // SOE发送缓冲区复位,发送指针回到ACK的位置
  108. if(pRunSet->bTT_SoeResumeComm)
  109. {
  110. #ifdef SOE_RELINK_DISCOS
  111. if(!g_soe_queue.bSoeRelink[pt101->chnl])
  112. {
  113. //g_soe_queue.relink_tail_bak[pt101->chnl].n = g_soe_queue.tail_send[pt101->chnl].n;
  114. g_soe_queue.relink_tail_bak[pt101->chnl].n = g_soe_queue.tail_eep.n;
  115. }
  116. g_soe_queue.bSoeRelink[pt101->chnl] = true;
  117. #endif
  118. //pt101->bSoeRelink = true;
  119. g_soe_queue.tail_send[pt101->chnl].n=g_soe_queue.tail_ack[pt101->chnl].n;
  120. }
  121. #endif
  122. // 遥控信息复位
  123. ResetRctrl(MASTER_101+pt101->chnl);
  124. // 发送缓冲区复位
  125. IEC101_ResetTxBuf(pt101);
  126. RS_Recv_Enable(pt101->chnl);
  127. #ifdef RCD_STRAN_S
  128. rt_printf_time("-> Link Reset, Clear File Cache\r\n");
  129. iec_freefile(&pt101->tf);
  130. pt101->tf.bTransing=false;
  131. pt101->tf.bdatTraned=false;
  132. #endif
  133. }
  134. void IEC101_Init(IEC101_DEF *pt,u8 chnl)
  135. {
  136. // 接收帧间隔为重发间隔时间的一半
  137. g_tRsComm[chnl].us_recv_timeout = pRunSet->dT101Resend*USTIMER_SEC/2;
  138. memset(pt,0,sizeof(IEC101_DEF));
  139. pt->type=IEC101_CHN;
  140. pt->chnl=chnl;
  141. pt->bMaintainComm=false;
  142. if(tRunPara.tUartPara[chnl].wProtocol==PROTOCOL_MAINTAIN)
  143. {
  144. pt->bMaintainComm=true;
  145. }
  146. // 初始化接收buf结构
  147. pt->rx_buf.chn = pt->chnl;
  148. pt->rx_buf.buf = pt->recvbuf;
  149. rt_fifo_init(&pt->recv_fifo,pt->recv_fifo_buf,IEC101_FIFO_SIZE);
  150. #ifdef RCD_STRAN_S
  151. queue_init(&pt->rcd_qt.queue,NEWRCD_COUNT,&pt->rcd_qt.data,NEWRCD_SIZE);
  152. #endif
  153. IEC101_Reset(pt);
  154. }
  155. /**************************************************************************
  156. 函数名称:IEC101_Send
  157. 函数版本:1.00
  158. 作者:
  159. 创建日期:2008.9.1
  160. 函数功能说明:启动485口的数据发送
  161. 输入参数:
  162. 输出参数:
  163. 返回值:
  164. 更新信息:
  165. 更新日志1:
  166. 日期:
  167. 修改者:
  168. 修改内容:
  169. 修改原因:
  170. ***************************************************************************/
  171. void IEC101_SSend(IEC101_DEF *pt)
  172. {
  173. u8 *sb = g_tRsComm[pt->chnl].sendbuf;
  174. // 如果链路层没有数据,直接返回
  175. if(pt->btx_buf_s == false)
  176. {
  177. return;
  178. }
  179. // 有数据,复制到真正的发送BUF并清标志
  180. memcpy(sb,pt->tx_buf_s,pt->tx_buf_s[0]+1);
  181. pt->btx_buf_s = false;
  182. // 置发送标志
  183. RS_Send_Enable(pt->chnl);
  184. g_tRsComm[pt->chnl].nSendCnt=1; // 发送缓冲区的第一个字节为发送长度
  185. pt->bSend=true;
  186. if(!g_bCommLed)g_bCommLed=true;
  187. if(UART_CHANNEL[pt->chnl]==CFG_UART_GPRS_IN )
  188. {
  189. //gprs_vs_write(&sb[1], sb[0]);
  190. pt->bSend=false;
  191. s_stat_tx((int)pt->chnl, sb[0]);
  192. }
  193. #ifdef FUN_FUXI_ESAM
  194. if(UART_CHANNEL[pt->chnl]==CFG_UART_CHIP_S1 )
  195. {
  196. write_chip_s1(&sb[1], sb[0]);
  197. pt->bSend=false;
  198. }
  199. #endif
  200. if(g_print_101 && (g_print_port & (1<<pt->chnl)))
  201. {
  202. rt_printf("TX_S101_%d:",pt->chnl);
  203. print_msg("",&sb[1],sb[0]);
  204. }
  205. //统计发送帧数
  206. s_stat_tx_frame((int)pt->chnl);
  207. }
  208. /**************************************************************************
  209. 函数名称:IEC101_MSend
  210. 函数版本:1.00
  211. 作者:
  212. 创建日期:2008.9.1
  213. 函数功能说明:平衡101,作为主站发送
  214. 输入参数:
  215. 输出参数:
  216. 返回值:
  217. 更新信息:
  218. 更新日志1:
  219. 日期:
  220. 修改者:
  221. 修改内容:
  222. 修改原因:
  223. ***************************************************************************/
  224. static void IEC101_MSend(IEC101_DEF *pt)
  225. {
  226. u8 *sb = g_tRsComm[pt->chnl].sendbuf;
  227. // 如果链路层没有数据,直接返回
  228. if(pt->btx_buf_m == false)
  229. {
  230. return;
  231. }
  232. // 有数据,复制到真正的发送BUF并清标志
  233. memcpy(sb,pt->tx_buf_m,pt->tx_buf_m[0]+1);
  234. pt->btx_buf_m = false;
  235. // 置发送标志
  236. RS_Send_Enable(pt->chnl);
  237. g_tRsComm[pt->chnl].nSendCnt=1;
  238. pt->bSend=true;
  239. if(!g_bCommLed)g_bCommLed=true;
  240. if(UART_CHANNEL[pt->chnl]==CFG_UART_GPRS_IN )
  241. {
  242. //gprs_vs_write(&sb[1], sb[0]);
  243. pt->bSend=false;
  244. s_stat_tx((int)pt->chnl, sb[0]);
  245. }
  246. #ifdef FUN_FUXI_ESAM
  247. if(UART_CHANNEL[pt->chnl]==CFG_UART_CHIP_S1 )
  248. {
  249. write_chip_s1(&sb[1], sb[0]);
  250. pt->bSend=false;
  251. }
  252. #endif
  253. if(g_print_101 && (g_print_port & (1<<pt->chnl)))
  254. {
  255. rt_printf("TX_M101_%d:",pt->chnl);
  256. print_msg("",&sb[1],sb[0]);
  257. }
  258. //统计发送帧数
  259. s_stat_tx_frame((int)pt->chnl);
  260. }
  261. static void IEC101_ext_send(IEC101_DEF *pt, u8 *buf,u16 len)
  262. {
  263. #ifdef FUNC_ENCRY_IN_ONE_SERIAL
  264. if((tRunPara.tUartPara[0].wProtocol == PROTOCOL_WED_ENC) && pt->chnl==1)
  265. {//投入纬德规约时,串口通道1/3/4的待发数据统一由串口通道0发送处理
  266. u8 *sb = g_tRsComm[0].extsendbuf_1;
  267. memcpy(sb,buf,len);
  268. g_tRsComm[0].extsendcnt_1=0;
  269. g_tRsComm[0].extsendlen_1=len;
  270. g_tRsComm[0].bextsend_1=true;
  271. }
  272. else if((tRunPara.tUartPara[0].wProtocol == PROTOCOL_WED_ENC) && pt->chnl==3)
  273. {//投入纬德规约时,串口通道1/3/4的待发数据统一由串口通道0发送处理
  274. u8 *sb = g_tRsComm[0].extsendbuf_2;
  275. memcpy(sb,buf,len);
  276. g_tRsComm[0].extsendcnt_2=0;
  277. g_tRsComm[0].extsendlen_2=len;
  278. g_tRsComm[0].bextsend_2=true;
  279. }
  280. else if((tRunPara.tUartPara[0].wProtocol == PROTOCOL_WED_ENC) && pt->chnl==4)
  281. {//投入纬德规约时,串口通道1/3/4的待发数据统一由串口通道0发送处理
  282. u8 *sb = g_tRsComm[0].extsendbuf_3;
  283. memcpy(sb,buf,len);
  284. g_tRsComm[0].extsendcnt_3=0;
  285. g_tRsComm[0].extsendlen_3=len;
  286. g_tRsComm[0].bextsend_3=true;
  287. }
  288. else
  289. #endif
  290. {
  291. u8 *sb = g_tRsComm[pt->chnl].extsendbuf;
  292. memcpy(sb,buf,len);
  293. g_tRsComm[pt->chnl].extsendcnt=0;
  294. g_tRsComm[pt->chnl].extsendlen=len;
  295. g_tRsComm[pt->chnl].bextsend=true;
  296. }
  297. }
  298. static void IEC101_Send_Polling(IEC101_DEF *pt)
  299. {
  300. #ifdef FUNC_ENCRY_IN_ONE_SERIAL
  301. int i=0,j=0,crc_sum=0;
  302. #endif
  303. u8 *buf;
  304. #ifdef FUNC_ENCRY_IN_ONE_SERIAL
  305. memset(&g_tRsComm[pt->chnl].enc_sendbuf,0,sizeof(&g_tRsComm[pt->chnl].enc_sendbuf));
  306. #endif
  307. // 如果串口忙,不能发送数据
  308. if(g_tRsComm[pt->chnl].bextsend
  309. #ifdef FUNC_ENCRY_IN_ONE_SERIAL
  310. || g_tRsComm[0].bextsend_1 || g_tRsComm[0].bextsend_2 || g_tRsComm[0].bextsend_3
  311. #endif
  312. )
  313. {
  314. pt->us0_sendpiece=ustimer_get_origin();
  315. return;
  316. }
  317. if(pt->bSend)// 有数据要发送了
  318. {
  319. int len=g_tRsComm[pt->chnl].sendbuf[0];
  320. #ifdef FUNC_ENCRY_IN_ONE_SERIAL
  321. if(tRunPara.tUartPara[0].wProtocol == PROTOCOL_WED_ENC)
  322. {//纬德规约内容组包
  323. g_tRsComm[pt->chnl].enc_sendbuf[i++] = 0xAA;
  324. g_tRsComm[pt->chnl].enc_sendbuf[i++] = (u8)(len); //数据报文长度
  325. g_tRsComm[pt->chnl].enc_sendbuf[i++] = (u8)((len)>>8);
  326. g_tRsComm[pt->chnl].enc_sendbuf[i++] = pt->enc_tunnel;
  327. memcpy(&g_tRsComm[pt->chnl].enc_sendbuf[i],&g_tRsComm[pt->chnl].sendbuf[1],len);
  328. i = i+len;
  329. for(j=1;j<i;j++)
  330. {
  331. crc_sum = crc_sum + g_tRsComm[pt->chnl].enc_sendbuf[j];
  332. }
  333. g_tRsComm[pt->chnl].enc_sendbuf[i++] = (u8)crc_sum;
  334. g_tRsComm[pt->chnl].enc_sendbuf[i++] = 0x55;
  335. buf = &g_tRsComm[pt->chnl].enc_sendbuf[0];
  336. len = i;
  337. }
  338. else
  339. #endif
  340. {
  341. buf = &g_tRsComm[pt->chnl].sendbuf[1];
  342. }
  343. if(pRunSet->bTT_ESAM&&(!pt->bMaintainComm))
  344. {
  345. u8 ti,cot,se;
  346. u8 *out;
  347. iec_GetMsgInfo(buf,len,&ti,&cot,&se,true);
  348. len = sec_encrpt_iec(ti,cot,se,buf,len,&out);
  349. if(len > 0)
  350. {
  351. IEC101_ext_send(pt,out,len);
  352. }
  353. }
  354. else
  355. {
  356. IEC101_ext_send(pt,buf,len);
  357. }
  358. pt->bSend=false;
  359. return;
  360. }
  361. if(ustimer_get_duration(pt->us0_sendpiece) < USTIMER_MS*5) // 发送帧之间间隔5ms
  362. {
  363. return;
  364. }
  365. // 如果有从动站数据,发送
  366. if(pt->btx_buf_s)
  367. {
  368. IEC101_SSend(pt);
  369. pt->us0_sendpiece=ustimer_get_origin();
  370. }
  371. // 如果有启动站数据,发送
  372. else if(pt->btx_buf_m)
  373. {
  374. IEC101_MSend(pt);
  375. pt->us0_sendpiece=ustimer_get_origin();
  376. }
  377. else if(pt->bEchosecmd5)
  378. {
  379. u8 md5buf[24];
  380. u16 len;
  381. len=sec_md5_echo(md5buf);
  382. IEC101_ext_send(pt,md5buf,len);
  383. pt->bEchosecmd5=false;
  384. }
  385. }
  386. /**************************************************************************
  387. 函数名称:IEC101_GetOneBuf
  388. 函数版本:1.00
  389. 作者:
  390. 创建日期:2008.9.1
  391. 函数功能说明:将数据添加到一级数据缓冲区
  392. 输入参数:pt 各通道101结构定义首地址,ps源数据地址
  393. 输出参数:
  394. 返回值:
  395. 更新信息:
  396. 更新日志1:
  397. 日期:
  398. 修改者:
  399. 修改内容:
  400. 修改原因:
  401. ***************************************************************************/
  402. static int IEC101_BufFreeNum(iec_tbuf_t *pt)
  403. {
  404. return (pt->tb_tail_ack - pt->tb_head - 1)&(IEC_TBUF_NUM-1);
  405. }
  406. static u16 IEC101_GetOneBuf(iec_tbuf_t *pt)
  407. {
  408. u16 head;
  409. head = pt->tb_head;
  410. pt->tb_head++;
  411. // 系统设计时,保证缓冲不会满,以下情况不应出现
  412. if(pt->tb_head==pt->tb_tail_ack || pt->tb_head==pt->tb_tail_send)
  413. {
  414. rt_printf_time("IEC101: IEC101_GetOneBuf error:head=%d,send=%d,ack=%d.\r\n",pt->tb_head,pt->tb_tail_send,pt->tb_tail_ack);
  415. }
  416. return head;
  417. }
  418. /**************************************************************************
  419. 函数名称:IEC101_FrameEcho
  420. 函数版本:1.00
  421. 作者:
  422. 创建日期:2008.9.1
  423. 函数功能说明:应答短帧报文
  424. 输入参数:pt 各通道101结构定义首地址,ZoneByte短政控制域
  425. 输出参数:
  426. 返回值:
  427. 更新信息:
  428. 更新日志1:
  429. 日期:
  430. 修改者:
  431. 修改内容:
  432. 修改原因:
  433. ***************************************************************************/
  434. static void IEC101_FrameEcho(IEC101_DEF *pt,unsigned char ZoneByte)
  435. {
  436. u8 *pd=pt->tx_buf_s;
  437. // 如果此时正在发送数据,说明逻辑不对
  438. if(pt->btx_buf_s)
  439. {
  440. rt_printf("IEC101_FrameEcho(%d) err:链路层BUF已有数据\r\n",pt->chnl);
  441. }
  442. // 更新ACD或DIR位
  443. if(tRunPara.tUartPara[pt->chnl].b101PH)
  444. {
  445. // 平衡101,DIR置1
  446. if(!pt->bDIR)
  447. {
  448. IEC101_SETDIR(ZoneByte);
  449. }
  450. }
  451. else
  452. {
  453. // 目前所有数据都当成一级数据,等新标准正式颁布后再分一、二级数据。
  454. // 非平衡101, 如果还有一级数据,设置ACD位
  455. if((pt->tx_buf[0].tb_head != pt->tx_buf[0].tb_tail_send)
  456. || (pt->tx_buf[1].tb_head != pt->tx_buf[1].tb_tail_send)
  457. || (pt->tx_buf[2].tb_head != pt->tx_buf[2].tb_tail_send))
  458. {
  459. IEC101_SETACD(ZoneByte);
  460. }
  461. }
  462. // 形成报文
  463. if(!tRunPara.b101Addr2Byte)
  464. {
  465. pd[0]=5;
  466. pd[1]=0x10;
  467. pd[2]=ZoneByte;
  468. pd[3]=(u8)tRunPara.byAddr;
  469. pd[4]=pd[2]+pd[3];
  470. pd[5]=0x16;
  471. }
  472. else
  473. {
  474. pd[0]=6;
  475. pd[1]=0x10;
  476. pd[2]=ZoneByte;
  477. pd[3]=(u8)tRunPara.byAddr;
  478. pd[4]=(u8)(tRunPara.byAddr>>8);
  479. pd[5]=pd[2]+pd[3]+pd[4];
  480. pd[6]=0x16;
  481. }
  482. }
  483. /**************************************************************************
  484. 函数名称:IEC101_GetClassOne
  485. 函数版本:1.00
  486. 作者:
  487. 创建日期:2008.9.1
  488. 函数功能说明:从一级数据缓冲区里读取数据
  489. 输入参数:
  490. 输出参数:
  491. 返回值:
  492. 更新信息:
  493. 更新日志1:
  494. 日期:
  495. 修改者:
  496. 修改内容:
  497. 修改原因:
  498. ***************************************************************************/
  499. static void IEC101_UpdateCOS(u8 *pd)
  500. {
  501. u8 sq,num,i,ti;
  502. u16 cp;
  503. u8 addr=0; //传送原因双字节
  504. u8 SIQ;
  505. if(tRunPara.b101Cot2Byte) addr++;
  506. if(tRunPara.b101App2Byte) addr++;
  507. ti=pd[0];
  508. sq = pd[1]&0x80;
  509. num = pd[1]&0x7f;
  510. cp = pd[4+addr] | (pd[5+addr]<<8);
  511. pd +=(6+addr);
  512. for(i=0;i<num;i++)
  513. {
  514. SIQ = tbl_get_yx(tbl_cp2index(cp),(ti==3?1:0));
  515. #if !defined FUNC_JX_YX_BEFORE
  516. if(g_run_stu.bjx)
  517. SIQ|=0x80;
  518. #endif
  519. *pd++ = SIQ;
  520. if(sq == 0)
  521. {
  522. cp = pd[0] | (pd[1]<<8);
  523. pd += 2;
  524. }
  525. else
  526. {
  527. cp++;
  528. }
  529. }
  530. }
  531. //101可变帧长中信息体相对于帧头的地址。
  532. u32 IEC101_InfoAddr(void)
  533. {
  534. u32 addr;
  535. // 10 = 68 L L 68 CTRL LADDR TYPE VSQ COT PADDR
  536. addr = 10;
  537. if(tRunPara.b101Addr2Byte) addr++;
  538. if(tRunPara.b101App2Byte) addr++;
  539. if(tRunPara.b101Cot2Byte) addr++;
  540. return addr;
  541. }
  542. static bool IEC101_SendOneBuf(IEC101_DEF *pt101)
  543. {
  544. u16 i,len,frm_attr,cnt;
  545. u8 *pd,cs,tb_send;
  546. iec_tbuf_t *pt;
  547. // 还有上帧数据没有发送完,直接返回。逻辑上不应该有这种现象出现
  548. if(tRunPara.tUartPara[pt101->chnl].b101PH ? pt101->btx_buf_m : pt101->btx_buf_s)
  549. {
  550. RT_PRINTF_POSITION();
  551. return false;
  552. }
  553. // 运行到这,如果有数据就无条件发送
  554. for(i=0;i<3;i++)
  555. {
  556. pt = &pt101->tx_buf[i];
  557. if(pt->tb_head == pt->tb_tail_send)
  558. {
  559. continue;
  560. }
  561. // 更新发送尾指针,保留老指针备用。
  562. // 由于系统设计时保证发送BUF队列不会溢出,所以指针先加也是没有问题的。
  563. tb_send = pt->tb_tail_send;
  564. pt->tb_tail_send++;
  565. //拷贝数据并设置控制域
  566. len = pt->tb_data[tb_send][0];
  567. if(tRunPara.tUartPara[pt101->chnl].b101PH)
  568. {
  569. u8 zone;
  570. // 获取数据
  571. pd = pt101->tx_buf_m;
  572. memcpy(pd,pt->tb_data[tb_send],len + 1);
  573. // 平衡101,将控制域修改,原来一级数据缓冲区中为8,现在需要变为3
  574. zone=IEC101_CALL_DATA;
  575. // 合纵FTU现场,测试长帧,功能码需回2,不能是3 (原来为3,不合理)
  576. if(pd[7+tRunPara.b101Addr2Byte]==104) //长帧测试帧
  577. {
  578. zone=IEC101_CALL_TESTLINK;
  579. pt101->bTestFrameL = true;
  580. }
  581. //梅州FTU,101主站总召前,通讯续传不回确认帧
  582. if((pd[7+tRunPara.b101Addr2Byte]==0x1e)&&(pt101->bSendChange == 0)) //SOE
  583. {
  584. pt101->bSoeResume = true;
  585. }
  586. IEC101_SETFCV(zone); //FCV位有效
  587. IEC101_SETPRM(zone);
  588. if(!pt101->bDIR)IEC101_SETDIR(zone);
  589. if(pt101->bMFCB)
  590. {
  591. IEC101_SETFCB(zone);
  592. }
  593. else
  594. {
  595. IEC101_CLRFCB(zone);
  596. }
  597. pd[5]=zone;
  598. }
  599. else
  600. {
  601. // 获取数据
  602. pd = pt101->tx_buf_s;
  603. memcpy(pd,pt->tb_data[tb_send],len + 1);
  604. // 目前所有数据都当成一级数据,等新标准正式颁布后再分一、二级数据。
  605. // 非平衡101,如果还有一级数据,设置ACD位
  606. if((pt101->tx_buf[0].tb_head != pt101->tx_buf[0].tb_tail_send)
  607. || (pt101->tx_buf[1].tb_head != pt101->tx_buf[1].tb_tail_send)
  608. || (pt101->tx_buf[2].tb_head != pt101->tx_buf[2].tb_tail_send))
  609. {
  610. IEC101_SETACD(pd[5]);
  611. }
  612. }
  613. // 更新低优先级的COS
  614. frm_attr = pt->tb_info[tb_send].frm_attr;
  615. if((frm_attr&(FRAME_I_PRIOR_LOW|FRAME_I_COS)) == (FRAME_I_PRIOR_LOW|FRAME_I_COS))
  616. {
  617. IEC101_UpdateCOS(pd + 7 + tRunPara.b101Addr2Byte);
  618. }
  619. // 如果是延时获取帧,校验和计算前计算延时
  620. if(frm_attr & FRAME_I_106)
  621. {
  622. u16 ms;
  623. u8 * info_addr;
  624. info_addr = pd + 1 + IEC101_InfoAddr();
  625. ms = info_addr[2] + (info_addr[3] << 8);
  626. ms += ustimer_get_duration(pt101->us0_frame)/USTIMER_MS;
  627. info_addr[0] = 0;
  628. info_addr[1] = 0;
  629. info_addr[2] = ms;
  630. info_addr[3] = ms>>8;
  631. }
  632. // 计算校验和
  633. cs=0;
  634. len = pd[2];
  635. pd=&pd[5];
  636. for(cnt=0;cnt<len;cnt++) //标示拷贝
  637. {
  638. cs+=*pd++;
  639. }
  640. *pd++=cs;
  641. // 保留发送的索引,供确认的时候用
  642. pt101->tb_index=i;
  643. // 设置安全报文发送标志
  644. if(frm_attr & FRAME_I_ENCRYPT)
  645. {
  646. pt101->bMSend_encrypt = true;
  647. }
  648. return true;
  649. }
  650. return false;
  651. }
  652. static void IEC101_AckOneBuf(IEC101_DEF *pt101) //调整一级数据缓冲区,已发送数据清除
  653. {
  654. iec_tbuf_t *pt;
  655. char log_info[128]={0};
  656. // 如果最后发送的遥测帧,确认遥测帧
  657. if (pt101->bycsend)
  658. {
  659. pt101->bycsend = FALSE;
  660. return;
  661. }
  662. // 如果没有发送报文,不需要确认
  663. if(pt101->tb_index < 0)
  664. {
  665. return;
  666. }
  667. // 如果没有需要确认的帧,返回,但这不是正常流程
  668. pt = &pt101->tx_buf[pt101->tb_index];
  669. pt101->tb_index = -1;
  670. if(pt->tb_tail_ack == pt->tb_tail_send)
  671. {
  672. rt_printf_time("IEC101_AckOneBuf error!\r\n");
  673. IEC101_Info_Printf_One(pt101);
  674. sprintf(log_info,"IEC101(%d):IEC101_AckOneBuf error!",pt101->chnl+1);
  675. load_hs_log_rcd(TYPE_COMM_ERR,true,NULL,log_info,1);
  676. log_flag.com_err[pt101->chnl] = true;
  677. return;
  678. }
  679. // 如果是SOE报文,需确认SOE缓冲池中SOE.
  680. if(pt->tb_info[pt->tb_tail_ack].frm_attr&FRAME_I_SOE)
  681. {
  682. soe_ack(pt101->chnl,pt->tb_info[pt->tb_tail_ack].soe_tail_send);
  683. }
  684. pt->tb_tail_ack++;
  685. }
  686. /**************************************************************************
  687. 函数名称: IEC101_Asdu_Yc
  688. 函数版本:1.00
  689. 作者:
  690. 创建日期:2008.9.1
  691. 函数功能说明:通用分类数据的链路直接响应
  692. 输入参数:pt 缓冲区地址,pdat报文数据,len报文长度
  693. vsq,inf,cot ,rii,IEC101规约要求的内容
  694. 输出参数:
  695. 返回值:
  696. 更新信息:
  697. 更新日志1:
  698. 日期:
  699. 修改者:
  700. 修改内容:
  701. 修改原因:
  702. ***************************************************************************/
  703. static void IEC101_Asdu_Yc(IEC101_DEF *pt,u8 *pdat,u8 len,u8 vsq, u8 cot)
  704. {
  705. u8 *pd,*pdata;
  706. u8 cnt,checksum,sum;
  707. u8 AddByte=0;
  708. sum=0;
  709. if(tRunPara.tUartPara[pt->chnl].b101PH)
  710. {
  711. pdata=pt->tx_buf_m;
  712. }
  713. else
  714. {
  715. pdata=pt->tx_buf_s;
  716. }
  717. if(tRunPara.b101Addr2Byte) AddByte=1;
  718. pd=&pdata[7+AddByte];
  719. if(tRunPara.bYcBDH) //标度化值
  720. {
  721. pd[sum++]=11; //类型标示
  722. }
  723. else if(tRunPara.bYcFloat) //浮点值
  724. {
  725. pd[sum++]=13; //类型标示浮点数
  726. }
  727. else
  728. {
  729. pd[sum++]=9; //类型标示
  730. }
  731. pd[sum++]=vsq; //VSQ
  732. pd[sum++]=cot; //传送原因
  733. if(tRunPara.b101Cot2Byte) pd[sum++]=0; //传送原因
  734. pd[sum++]=(u8)tRunPara.byAddr; //应用服务单元地址
  735. if(tRunPara.b101App2Byte) pd[sum++]=(u8)(tRunPara.byAddr>>8); //应用服务单元地址
  736. for(cnt=0;cnt<len;cnt++) //标示拷贝
  737. {
  738. pd[sum++]=*pdat++;
  739. }
  740. pdata[0]=(sum+2+6+AddByte); //报文长度 +2=控制域、地址 +6=报文头(4字节)校验和、结束符
  741. pdata[1]=0x68; //报文头
  742. pdata[2]=sum+2+AddByte; //数据长度
  743. pdata[3]=sum+2+AddByte;
  744. pdata[4]=0x68;
  745. if(tRunPara.tUartPara[pt->chnl].b101PH)
  746. {
  747. pdata[5]=IEC101_CALL_DATA;
  748. IEC101_SETFCV(pdata[5]); //FCV位有效
  749. IEC101_SETPRM(pdata[5]);
  750. if(!pt->bDIR)IEC101_SETDIR(pdata[5]);
  751. if(pt->bMFCB)
  752. {
  753. IEC101_SETFCB(pdata[5]);
  754. }
  755. else
  756. {
  757. IEC101_CLRFCB(pdata[5]);
  758. }
  759. }
  760. else
  761. {
  762. pdata[5]=IEC101_ECHO_DATA; //类型标示
  763. }
  764. pdata[6]=(u8)tRunPara.byAddr; //链路地址
  765. if(tRunPara.b101Addr2Byte) pdata[7]=(u8)(tRunPara.byAddr>>8); //链路地址
  766. checksum=0;
  767. pd=&pdata[5];
  768. for(cnt=0;cnt<pdata[2];cnt++) //标示拷贝
  769. {
  770. checksum+=*pd++;
  771. }
  772. *pd++=checksum;
  773. *pd++=0x16;
  774. }
  775. /**************************************************************************
  776. 函数名称:IEC101_GetYc
  777. 函数版本:1.00
  778. 作者:
  779. 创建日期:2008.9.1
  780. 函数功能说明:响应遥测帧
  781. 输入参数:
  782. 输出参数:
  783. 返回值:
  784. 更新信息:
  785. 更新日志1:
  786. 日期:
  787. 修改者:
  788. 修改内容:
  789. 修改原因:
  790. ***************************************************************************/
  791. static bool IEC101_GetYc(IEC101_DEF *pt)
  792. {
  793. bool bContinue=false; //是否保存当前判断的遥测位置
  794. u8 *pd;
  795. u8 vsq;
  796. int i,num;
  797. WORD cp=0;
  798. int ycvalue;
  799. union{
  800. float ff;
  801. u8 tt[4];
  802. }ff;
  803. // 主动上送遥测条件:
  804. // 1、总查询结束后可送
  805. // 2、没有在处理加密遥控报文
  806. // 3、不是复位进程状态
  807. // 4、主动上送遥测投入
  808. if((!pt->bSendChange) || pt->bRmtSM2 || pt->bResetProcess || (!tRunPara.bAutoSendYc))
  809. {
  810. return false;
  811. }
  812. //平衡101,主动发送不能小于发送间隔时间
  813. if(tRunPara.tUartPara[pt->chnl].b101PH)
  814. {
  815. if((ustimer_get_duration(pt->us0_yc) < (DWORD)rt_round(tRunPara.fYcTime*USTIMER_SEC))|| byc_filter)//
  816. {
  817. return false;
  818. }
  819. }
  820. #if defined IEC_JXYB_DEAL || defined NO_SEND_YC
  821. if(g_run_stu.bjx)
  822. return false;
  823. #endif
  824. // 得到一遥测帧
  825. pd=g_arrIECBuf;
  826. vsq=0;
  827. num=0;
  828. for(i=pt->ycno;i<g_table_head->ac_num;i++)
  829. {
  830. u8 QDS=0; //品质描述, 默认为零
  831. u8 no=g_ac_table[i].indexno;
  832. long lmeaval;
  833. bool bsend=false;
  834. if(g_ac_table[i].dead_value==0||g_ac_table[i].normal==0) continue; //死区或额定为零,不主动上送
  835. if(no>0)
  836. {
  837. DWORD dwMax=0;
  838. DWORD dwDeadVal=0;
  839. float rate;
  840. float f_65536=65536.0;
  841. u8 link_qds=0;
  842. no-=1;
  843. rate=(float)g_ac_table[i].rate/65536.0;
  844. //dwMax=(DWORD)g_ac_table[i].normal;
  845. dwMax = (tRunPara.bDeadType==true) ? (DWORD)g_ac_table[i].normal:_AbsL(pt->yc_save[i]);
  846. if(dwMax==0) //防止额定或者前一次保存值为0
  847. dwMax=1;
  848. dwDeadVal=_Mul_Div_U(g_ac_table[i].dead_value,dwMax,6553600);
  849. if(dwDeadVal==0)dwDeadVal=1;
  850. if(dwMax==0)f_65536=1.0;
  851. lmeaval=GetRmtMeaVal(g_ac_table[i].owner,no,&link_qds);
  852. ff.ff=(float)lmeaval/f_65536*rate; //转为浮点数
  853. #ifdef VOLT_ADAPTIVE_FACTOR
  854. if(pRunSet->bTT_AdaptiveFactor)
  855. {
  856. if(0 == g_ac_table[i].owner)
  857. {
  858. if((no <= PUB_AC_UCA1) && (no >= PUB_AC_UA1))
  859. {
  860. ff.ff=((float)lmeaval)/f_65536*10/pRunSet->pt1_two;
  861. }
  862. else if((no <= PUB_AC_UCA2) && (no >= PUB_AC_UA2))
  863. {
  864. ff.ff=((float)lmeaval)/f_65536*10/pRunSet->pt2_two;
  865. }
  866. }
  867. }
  868. #endif
  869. ycvalue=(int)rt_round(ff.ff);
  870. // 溢出处理
  871. if(tRunPara.bYcFloat)
  872. {
  873. if(_AbsL(lmeaval) > (dwMax*10)) // 大于额定值的10倍*65536
  874. {
  875. if(dwMax>0)QDS|=0x01; //遥测溢出
  876. }
  877. }
  878. else
  879. {
  880. if (ycvalue >= 0)
  881. {
  882. if (ycvalue > 32767)
  883. {
  884. ycvalue = 32767;
  885. QDS|=0x01; //遥测溢出
  886. }
  887. }
  888. else
  889. {
  890. if (ycvalue < (-32768))
  891. {
  892. ycvalue = -32768;
  893. QDS|=0x01; //遥测溢出
  894. }
  895. }
  896. }
  897. if(((no==PUB_AC_YC9) || (no==PUB_AC_YC10) || (no==PUB_AC_YC11) || (no==PUB_AC_YC12)))
  898. {
  899. bsend = true;
  900. }
  901. // 如果大于死区值,上送
  902. #ifndef IEC_JXYB_DEAL
  903. if(bsend || ((i<MAX_YC_NUMBER)&&(_AbsL(lmeaval-pt->yc_save[i])>=dwDeadVal)))
  904. #else
  905. if(bsend || ((i<MAX_YC_NUMBER)&&(_AbsL(lmeaval-pt->yc_save[i])>=dwDeadVal)&& (link_qds!=0x80)))
  906. #endif
  907. {
  908. if(g_run_stu.bToolRmtTest||g_run_stu.bHmiRmtTest) //在测试模式下,置无效状态
  909. {
  910. if(pRunSet->bTT_RmtTest)QDS|=0x80;
  911. }
  912. cp=g_ac_table[i].cp;
  913. if(i<MAX_YC_NUMBER) pt->yc_save[i]=lmeaval;
  914. pd[num++]=(u8)cp; //信息体地址L
  915. pd[num++]=(u8)(cp>>8); //信息体地址H
  916. if(tRunPara.bYcFloat) //浮点值上送
  917. {
  918. num += CopySwap(&pd[num],ff.tt,sizeof(ff.tt),true);
  919. }
  920. else
  921. {
  922. pd[num++]=(u8)(ycvalue); //无符号整数
  923. pd[num++]=(u8)(ycvalue>>8); //无符号整数
  924. }
  925. if(g_run_stu.bjx)
  926. {
  927. QDS|=0x80;//带品质描述,有效 <1>:=无效
  928. }
  929. #ifdef IEC_QDS_HAVE
  930. QDS|=link_qds;
  931. #endif
  932. pd[num++]=QDS;
  933. vsq++;
  934. }
  935. if(num>MAX_101_FRAME_LENTH)
  936. {
  937. bContinue=true;
  938. break;
  939. }
  940. }
  941. }
  942. // 更新下一帧的遥测序号
  943. pt->ycno = bContinue ? (i+1) : 0;
  944. // 发送遥测帧
  945. if(num>0)
  946. {
  947. IEC101_Asdu_Yc(pt,g_arrIECBuf,num,vsq,3);
  948. pt->us0_yc = ustimer_get_origin();
  949. return true;
  950. }
  951. return false;
  952. }
  953. static void IEC101_LinkInf(IEC101_DEF *pt)
  954. {
  955. //68 bc bc 68 28 01 f0 08 14 01 01 40 00 00 00 00 00 00 00 00 00 00 00 00 00 遥测帧
  956. // vsq cot appaddr
  957. u8 *pd,*pdata;
  958. u8 checksum,sum;
  959. int i;
  960. WORD cp;
  961. u8 num;
  962. WORD count=0;
  963. pdata=pt->tx_buf_s;
  964. sum=0;
  965. pd=&pdata[5];
  966. pd[sum++]=IEC101_ECHO_DATA; //类型标示
  967. pd[sum++]=(u8)tRunPara.byAddr; //链路地址
  968. pd[sum++]=250; //类型标示
  969. pd[sum++]=8; //长度
  970. pd[sum++]=14; //传送原因
  971. pd[sum++]=1; //KOD
  972. pd[sum++]=0; //统计遥测遥信个数
  973. cp=g_di_table[0].cp;
  974. num=0;
  975. for(i=0;i<g_table_head->di_num;i++) // 遥信个数统计
  976. {
  977. if(g_di_table[i].cp==(cp+num))
  978. {
  979. num++;
  980. }
  981. else
  982. {
  983. pd[sum++]=1; //遥信类型
  984. pd[sum++]=num;
  985. pd[sum++]=(u8)cp; //遥信个数
  986. pd[sum++]=(u8)(cp>>8); //遥信个数
  987. count++;
  988. cp=g_di_table[i].cp;
  989. num=1;
  990. }
  991. }
  992. if(num)
  993. {
  994. pd[sum++]=1; //遥信类型
  995. pd[sum++]=num;
  996. pd[sum++]=(u8)cp; //遥信点号
  997. pd[sum++]=(u8)(cp>>8); //遥信点号
  998. count++;
  999. }
  1000. cp=g_ac_table[0].cp;
  1001. num=0;
  1002. for(i=0;i<g_table_head->ac_num;i++) // 遥测个数统计
  1003. {
  1004. if(g_ac_table[i].cp==(cp+num))
  1005. {
  1006. num++;
  1007. }
  1008. else
  1009. {
  1010. pd[sum++]=2; //遥测类型
  1011. pd[sum++]=num;
  1012. pd[sum++]=(u8)cp; //遥测个数
  1013. pd[sum++]=(u8)(cp>>8); //遥测个数
  1014. count++;
  1015. cp=g_ac_table[i].cp;
  1016. num=1;
  1017. }
  1018. }
  1019. if(num)
  1020. {
  1021. pd[sum++]=2; //遥测类型
  1022. pd[sum++]=num;
  1023. pd[sum++]=(u8)cp; //遥测个数
  1024. pd[sum++]=(u8)(cp>>8); //遥测个数
  1025. count++;
  1026. }
  1027. pdata[0]=sum+6; //报文长度 +2=控制域、地址 +6=报文头(4字节)校验和、结束符
  1028. pdata[1]=0x68; //报文头
  1029. pdata[2]=sum; //数据长度
  1030. pdata[3]=sum;
  1031. pdata[4]=0x68;
  1032. pdata[11]=count;
  1033. checksum=0;
  1034. pd=&pdata[5];
  1035. for(i=0;i<sum;i++) //标示拷贝
  1036. {
  1037. checksum+=*pd++;
  1038. }
  1039. *pd++=checksum;
  1040. *pd++=0x16;
  1041. }
  1042. /**************************************************************************
  1043. 函数名称:IEC101_Asdu_Add
  1044. 函数版本:1.00
  1045. 作者:
  1046. 创建日期:2008.9.1
  1047. 函数功能说明:将通用分类数据添加到一级数据缓冲区中
  1048. 输入参数:pt 缓冲区地址,pdat报文数据,len报文长度
  1049. vsq,inf,cot ,rii,IEC101规约要求的内容
  1050. 输出参数:
  1051. 返回值:
  1052. 更新信息:
  1053. 更新日志1:
  1054. 日期:
  1055. 修改者:
  1056. 修改内容:
  1057. 修改原因:
  1058. ***************************************************************************/
  1059. static void IEC101_Asdu_Add_sts(IEC101_DEF *pt,u8 *pdat,u8 len,u8 vsq, u8 cot,u8 type,u16 attr,u16 soe_tail_send)
  1060. {
  1061. u8 *pd;
  1062. u8 cnt,L;
  1063. u16 head;
  1064. iec_tbuf_t *ptb;
  1065. // 获取BUF
  1066. ptb=&pt->tx_buf[1];
  1067. if(attr&FRAME_I_PRIOR_HIGH)ptb=&pt->tx_buf[0];
  1068. else if(attr&FRAME_I_PRIOR_LOW)ptb=&pt->tx_buf[2];
  1069. head = IEC101_GetOneBuf(ptb);
  1070. // 保存数据
  1071. ptb->tb_info[head].frm_attr = attr;
  1072. ptb->tb_info[head].soe_tail_send = g_soe_queue.tail_send[pt->chnl].n;
  1073. L = IEC101_InfoAddr() + len - 4;
  1074. // 报文生成
  1075. pd=ptb->tb_data[head];
  1076. *pd++=L+6; //报文长度 +2=控制域、地址 +6=报文头(4字节)校验和、结束符
  1077. *pd++=0x68; //报文头
  1078. *pd++=L; //数据长度
  1079. *pd++=L;
  1080. *pd++=0x68;
  1081. *pd++=IEC101_ECHO_DATA; //非平衡功能码,平衡通道发送时再修改
  1082. *pd++=(u8)tRunPara.byAddr; //链路地址1
  1083. if(tRunPara.b101Addr2Byte)
  1084. {
  1085. *pd++=(u8)(tRunPara.byAddr>>8); //链路地址2
  1086. }
  1087. *pd++=type; //类型标示
  1088. *pd++=vsq; //VSQ
  1089. *pd++=cot; //传送原因1
  1090. if(tRunPara.b101Cot2Byte)
  1091. {
  1092. *pd++=0; //传送原因2
  1093. }
  1094. *pd++=(u8)tRunPara.byAddr; //应用服务单元地址1
  1095. if(tRunPara.b101App2Byte)
  1096. {
  1097. *pd++=(u8)(tRunPara.byAddr>>8); //应用服务单元地址2
  1098. }
  1099. for(cnt=0;cnt<len;cnt++)
  1100. {
  1101. *pd++=*pdat++; //信息体
  1102. }
  1103. *pd++=0; // 校验和,推迟计算
  1104. *pd++=0x16; // 结束字符
  1105. return;
  1106. }
  1107. void IEC101_Asdu_Add(IEC101_DEF *pt,u8 *pdat,u8 len,u8 vsq, u8 cot,u8 type,u16 attr)
  1108. {
  1109. IEC101_Asdu_Add_sts(pt,pdat,len,vsq,cot,type,attr,0);
  1110. }
  1111. /**************************************************************************
  1112. 函数名称:IEC101_TimeSet
  1113. 函数版本:1.00
  1114. 作者:
  1115. 创建日期:2008.9.1
  1116. 函数功能说明:时间同步,并应答
  1117. 输入参数:
  1118. 输出参数:
  1119. 返回值:
  1120. 更新信息:
  1121. 更新日志1:
  1122. 日期:
  1123. 修改者:
  1124. 修改内容:
  1125. 修改原因:
  1126. ***************************************************************************/
  1127. static void IEC101_TimeSetEcho(IEC101_DEF *pt101,u8 *ps,u8 scot) //确认帧
  1128. {
  1129. u8 *pd;
  1130. int num;
  1131. int check_time=false;
  1132. u8 cot;
  1133. TIME ct;
  1134. struct timespec ts;
  1135. u8 week;
  1136. //对时
  1137. if(scot == IEC_COT_ACT)
  1138. {
  1139. ct.ms=ps[0]+((WORD)ps[1]<<8);
  1140. ct.min=(ps[2]&0x3F);
  1141. ct.hour=(ps[3]&0x1F);
  1142. ct.day=(ps[4]&0x1F);
  1143. ct.month=(ps[5]&0x0F);
  1144. ct.year=(ps[6]&0x7F);
  1145. // 检查时间,如果合法,重新设置系统时间
  1146. check_time = check_rtc(&ct);
  1147. if(check_time)
  1148. {
  1149. u32 ms;
  1150. // 计算延时,传输延时T2和发送该报文的传输耗时T3
  1151. ms = ustimer_get_duration(pt101->us0_frame)/USTIMER_MS;
  1152. // rt_printf("时间设置:T2=%dms,T3=%dms.\r\n",pt101->ms_delay,ms);
  1153. ms += pt101->ms_delay;
  1154. // 修正时间
  1155. ct.ms += ms;
  1156. if(ct.ms>=60000)
  1157. {
  1158. ct.ms-=60000;
  1159. sys_time_change(&ct);
  1160. }
  1161. // 设置时间
  1162. sys_time_set_rmt(&ct);
  1163. }
  1164. }
  1165. clk_time_get(&ts);
  1166. timespec_to_rtc(ts,&ct,1);
  1167. // 得到星期
  1168. rtc_to_timespec(&ct, &ts);
  1169. week = WEEK_DAY(ts.tv_sec);
  1170. //组织报文,以最新时间返回
  1171. pd=g_arrIECBuf;
  1172. num=0;
  1173. #if defined GD_AREA_ZHONGSHAN || defined GD_AREA_ZHONGSHAN_2020
  1174. pd[num++]=0; //信息序号=0时钟同步
  1175. pd[num++]=0; //信息序号=0时钟同步
  1176. if(scot==IEC_COT_ACT)
  1177. {
  1178. pd[num++]=ps[0]; //MsL
  1179. pd[num++]=ps[1]; //MsH
  1180. pd[num++]=ps[2]; //Min
  1181. pd[num++]=ps[3]; //hour
  1182. pd[num++]=ps[4]; //Day
  1183. pd[num++]=ps[5]; //month
  1184. pd[num++]=ps[6]; //year
  1185. }
  1186. else
  1187. {
  1188. pd[num++]=(u8)ct.ms; //MsL
  1189. pd[num++]=(u8)(ct.ms>>8); //MsH
  1190. pd[num++]=ct.min; //Min
  1191. pd[num++]=ct.hour; //hour
  1192. pd[num++]=ct.day; //Day
  1193. pd[num++]=ct.month; //month
  1194. pd[num++]=ct.year; //year
  1195. }
  1196. #else
  1197. pd[num++]=0; //信息序号=0时钟同步
  1198. pd[num++]=0; //信息序号=0时钟同步
  1199. pd[num++]=(u8)ct.ms; //MsL
  1200. pd[num++]=(u8)(ct.ms>>8); //MsH
  1201. pd[num++]=ct.min; //Min
  1202. pd[num++]=ct.hour; //hour
  1203. pd[num++]=((week<<5) | ct.day); //Day
  1204. pd[num++]=ct.month; //month
  1205. pd[num++]=ct.year; //year
  1206. #endif
  1207. if(scot == IEC_COT_REQ)
  1208. {
  1209. cot=0x05;
  1210. }
  1211. else
  1212. {
  1213. cot = check_time ? 0x07:0x47; //对时内容非法,即将传送原因的P/N位置为1
  1214. }
  1215. IEC101_Asdu_Add(pt101,g_arrIECBuf,num,1,cot,103,FRAME_I);//
  1216. }
  1217. static void IEC101_TestFrame(IEC101_DEF *pt101,u8 *ps) //测试确认帧
  1218. {
  1219. u8 *pd;
  1220. int num;
  1221. //组织报文
  1222. pd=g_arrIECBuf;
  1223. num=0;
  1224. pd[num++]=0; //信息体地址
  1225. pd[num++]=0; //
  1226. pd[num++]=ps[0];//pd[num++]=0xAA; //测试码
  1227. pd[num++]=ps[1];//pd[num++]=0x55; //测试码
  1228. IEC101_Asdu_Add(pt101,g_arrIECBuf,num,1,7,104,FRAME_I|FRAME_I_PRIOR_LOW);//
  1229. }
  1230. /**************************************************************************
  1231. 函数名称:IEC101_InitOK
  1232. 函数版本:1.00
  1233. 作者:
  1234. 创建日期:2007.9.1
  1235. 函数功能说明:子站初始化完毕
  1236. 输入参数:
  1237. 输出参数:
  1238. 返回值:
  1239. 更新信息:
  1240. 更新日志1:
  1241. 日期:
  1242. 修改者:
  1243. 修改内容:
  1244. 修改原因:
  1245. ***************************************************************************/
  1246. static void IEC101_InitOK(IEC101_DEF *pt101)
  1247. {
  1248. u8 *pd;
  1249. int num;
  1250. u8 cot;
  1251. //组织报文
  1252. pd=g_arrIECBuf;
  1253. num=0;
  1254. pd[num++] = 0;
  1255. pd[num++] = 0;
  1256. if(pt101->bInitCot)
  1257. {
  1258. pd[num++]=2; //远方复位
  1259. }
  1260. else
  1261. {
  1262. pd[num++]=0; //当地电源合上
  1263. }
  1264. pt101->bInitCot=true;
  1265. cot = pRunSet->bTT_101Cot03 ? 3 : 4;
  1266. IEC101_Asdu_Add(pt101,g_arrIECBuf,num,1,cot,70,FRAME_I);//70 初始化结束帧
  1267. }
  1268. // 复位进程
  1269. static void IEC101_ResetProcess(IEC101_DEF *pt101,u8 qrp)
  1270. {
  1271. u8 *pd;
  1272. int num;
  1273. //组织报文
  1274. pd=g_arrIECBuf;
  1275. num=0;
  1276. pd[num++] = 0;
  1277. pd[num++] = 0;
  1278. pd[num++] = qrp;
  1279. IEC101_Asdu_Add(pt101,g_arrIECBuf,num,1,7,105,FRAME_I);
  1280. }
  1281. /**************************************************************************
  1282. 函数名称:IEC101_CallAll
  1283. 函数版本:1.00
  1284. 作者:
  1285. 创建日期:2008.9.1
  1286. 函数功能说明:通用范围总查询响应
  1287. 输入参数:
  1288. 输出参数:
  1289. 返回值:
  1290. 更新信息:
  1291. 更新日志1:
  1292. 日期:
  1293. 修改者:
  1294. 修改内容:
  1295. 修改原因:
  1296. ***************************************************************************/
  1297. static void IEC101_CallAll(IEC101_DEF *pt,u8 QOI) //确认帧
  1298. {
  1299. u8 *pd,*pdata;
  1300. u8 vsq;//通用分类数据集数目
  1301. u16 cp=0,attr;
  1302. int i,num,begin,end;
  1303. pdata=g_arrIECBuf;
  1304. pt->ycno=0;
  1305. attr = pt->bSendChange ? FRAME_I_PRIOR_LOW : FRAME_I;//| FRAME_I_PRIOR_HIGH
  1306. //总召唤确认帧
  1307. num=0;
  1308. pd=pdata;
  1309. pd[num++] = 0;
  1310. pd[num++] = 0;
  1311. pd[num++] = QOI;
  1312. IEC101_Asdu_Add(pt,pdata,num,1,7,100, FRAME_I);
  1313. // 遥测帧
  1314. if((QOI==IEC_QOI_CALL_ALL_GROUP)|((QOI >= IEC_QOI_CALL_YC_BEGIN && QOI <= IEC_QOI_CALL_YC_END)))
  1315. {
  1316. int ycvalue;
  1317. u8 ti;
  1318. union{
  1319. float ff;
  1320. u8 tt[4];
  1321. }ff;
  1322. long lmeaval;
  1323. // 类型标识
  1324. if(tRunPara.bYcBDH)
  1325. {
  1326. ti=11; // 标度化值
  1327. }
  1328. else if(tRunPara.bYcFloat)
  1329. {
  1330. ti=13; // 浮点值
  1331. }
  1332. else
  1333. {
  1334. ti=9; // 归一化值
  1335. }
  1336. // 确认起止点号
  1337. if(QOI == IEC_QOI_CALL_ALL_GROUP || pRunSet->dGroupYcSize == 0)
  1338. {
  1339. begin = 0;
  1340. end = g_table_head->ac_num;
  1341. }
  1342. else if(pRunSet->dGroupYcSize)
  1343. {
  1344. begin = (QOI - IEC_QOI_CALL_YC_BEGIN) * pRunSet->dGroupYcSize;
  1345. end = begin + pRunSet->dGroupYcSize;
  1346. if(end > g_table_head->ac_num)
  1347. {
  1348. end = g_table_head->ac_num;
  1349. }
  1350. }
  1351. // 得到第一点的通讯点号,必须检查g_ac_table,否则有可能系统崩溃
  1352. if(g_ac_table)
  1353. {
  1354. cp=g_ac_table[begin].cp;
  1355. }
  1356. // 初始数据
  1357. pd=pdata;
  1358. vsq=0;
  1359. num=0;
  1360. // 如果点号连续,保存第一点点号
  1361. if(pRunSet->bDIContinue)
  1362. {
  1363. pd[num++]=(u8)cp;
  1364. pd[num++]=(u8)(cp>>8);
  1365. }
  1366. // 发送begin到end之间的所有遥测值
  1367. for(i=begin;i<end;i++)
  1368. {
  1369. u8 QDS=0; //品质描述, 默认为零
  1370. u8 link_qds=0;
  1371. u8 no=g_ac_table[i].indexno;
  1372. // 得到遥测值
  1373. if(no>0)
  1374. {
  1375. DWORD dwMax=0;
  1376. float rate;
  1377. float f_65536=65536.0;
  1378. no-=1;
  1379. rate=(float)g_ac_table[i].rate/65536.0;
  1380. //dwMax=(DWORD)g_ac_table[i].normal;
  1381. dwMax = (tRunPara.bDeadType==true) ? (DWORD)g_ac_table[i].normal:_AbsL(pt->yc_save[i]);
  1382. if(dwMax==0) //防止额定或者前一次保存值为0
  1383. dwMax=1;
  1384. lmeaval=GetRmtMeaVal(g_ac_table[i].owner,no,&link_qds);
  1385. if(dwMax==0)f_65536=1.0;
  1386. ff.ff=((float)lmeaval)/f_65536*rate; //转为浮点数
  1387. #ifdef VOLT_ADAPTIVE_FACTOR
  1388. if(pRunSet->bTT_AdaptiveFactor)
  1389. {
  1390. if(0 == g_ac_table[i].owner)
  1391. {
  1392. if((no <= PUB_AC_UCA1) && (no >= PUB_AC_UA1))
  1393. {
  1394. ff.ff=((float)lmeaval)/f_65536*10/pRunSet->pt1_two;
  1395. }
  1396. else if((no <= PUB_AC_UCA2) && (no >= PUB_AC_UA2))
  1397. {
  1398. ff.ff=((float)lmeaval)/f_65536*10/pRunSet->pt2_two;
  1399. }
  1400. }
  1401. }
  1402. #endif
  1403. ycvalue=(int)rt_round(ff.ff);
  1404. if(tRunPara.bYcFloat)
  1405. {
  1406. if(_AbsL(lmeaval) > (dwMax*10)) // 大于额定值的10倍*65536
  1407. {
  1408. if(dwMax>0)QDS|=0x01; //遥测溢出
  1409. }
  1410. }
  1411. else
  1412. {
  1413. if (ycvalue >= 0)
  1414. {
  1415. if (ycvalue > 32767)
  1416. {
  1417. ycvalue = 32767;
  1418. QDS|=0x01; //遥测溢出
  1419. }
  1420. }
  1421. else
  1422. {
  1423. if (ycvalue < (-32768))
  1424. {
  1425. ycvalue = -32768;
  1426. QDS|=0x01; //遥测溢出
  1427. }
  1428. }
  1429. }
  1430. }
  1431. else //备用点号,数值上送0
  1432. {
  1433. lmeaval=0;
  1434. ycvalue=0;
  1435. ff.ff=0;
  1436. if(!pRunSet->bDIContinue) continue; // 点号不连续上送,可不送备用点
  1437. }
  1438. //如果在测试模式下,置无效状态
  1439. if(g_run_stu.bToolRmtTest||g_run_stu.bHmiRmtTest)
  1440. {
  1441. if(pRunSet->bTT_RmtTest)QDS|=0x80;//带品质描述,有效 <1>:=无效
  1442. }
  1443. #if !defined FUNC_JX_YC_SIQ00
  1444. if(g_run_stu.bjx)
  1445. {
  1446. QDS|=0x80;//带品质描述,有效 <1>:=无效
  1447. }
  1448. #endif
  1449. #ifdef IEC_QDS_HAVE
  1450. QDS|=link_qds;
  1451. #endif
  1452. //保存遥测值,供主动遥测上送比较用
  1453. if(i<MAX_YC_NUMBER)pt->yc_save[i]=lmeaval;
  1454. // 如果点号不连续,上送每个点的点号
  1455. if(!pRunSet->bDIContinue)
  1456. {
  1457. cp=g_ac_table[i].cp;
  1458. pd[num++]=(u8)cp;
  1459. pd[num++]=(u8)(cp>>8);
  1460. }
  1461. // 上送值
  1462. if(tRunPara.bYcFloat)
  1463. {
  1464. //浮点值上送
  1465. num += CopySwap(&pd[num],ff.tt,sizeof(ff.tt),true);
  1466. }
  1467. else
  1468. { // 整型
  1469. pd[num++]=(u8)(ycvalue);
  1470. pd[num++]=(u8)(ycvalue>>8);
  1471. }
  1472. pd[num++]=QDS;
  1473. vsq++;
  1474. // 发送一帧
  1475. if(num>MAX_101_FRAME_LENTH&&(i<g_table_head->ac_num-1))
  1476. {
  1477. u8 vsq1=vsq;
  1478. if(pRunSet->bDIContinue)
  1479. {
  1480. vsq1|=0x80;
  1481. }
  1482. IEC101_Asdu_Add(pt,pdata,num,(vsq1),QOI,ti,attr);
  1483. num=0;
  1484. pd=pdata;
  1485. if(pRunSet->bDIContinue)
  1486. {
  1487. pd[num++]=(u8)(cp+vsq);
  1488. pd[num++]=(u8)((cp+vsq)>>8);
  1489. cp+=vsq;
  1490. }
  1491. vsq=0;
  1492. }
  1493. }
  1494. if(num>2)
  1495. {
  1496. u8 vsq1=vsq;
  1497. if(pRunSet->bDIContinue)
  1498. {
  1499. vsq1|=0x80;
  1500. }
  1501. IEC101_Asdu_Add(pt,pdata,num,(vsq1),QOI,ti,attr);
  1502. }
  1503. pt->us0_yc = ustimer_get_origin();
  1504. }
  1505. // 事件帧
  1506. if((QOI == IEC_QOI_CALL_ALL_GROUP) || (QOI >= IEC_QOI_CALL_YX_BEGIN && QOI <= IEC_QOI_CALL_YX_END))
  1507. {
  1508. u8 ti;
  1509. u8 yxtype=0;
  1510. // 确定类型标识,单点(1)或双点(3)
  1511. ti = tRunPara.bDPI ? 3:1;
  1512. // 确定起止点号
  1513. if(QOI == IEC_QOI_CALL_ALL_GROUP || pRunSet->dGroupYxSize == 0)
  1514. {
  1515. begin = 0;
  1516. end = g_table_head->di_num;
  1517. }
  1518. else
  1519. {
  1520. begin = (QOI - IEC_QOI_CALL_YX_BEGIN) * pRunSet->dGroupYxSize;
  1521. end = begin + pRunSet->dGroupYxSize;
  1522. if(end > g_table_head->di_num)
  1523. {
  1524. end = g_table_head->di_num;
  1525. }
  1526. }
  1527. // 初始数据
  1528. pd=pdata;
  1529. vsq=0;
  1530. num=0;
  1531. // 得到第一点的通讯点号,必须检查g_di_table,否则有可能系统崩溃
  1532. if(g_di_table)
  1533. {
  1534. cp=g_di_table[begin].cp;
  1535. yxtype=tbl_get_dpi(begin);
  1536. }
  1537. // 如果点号连续,保存第一点点号
  1538. if(pRunSet->bDIContinue)
  1539. {
  1540. pd[num++]=(u8)cp;
  1541. pd[num++]=(u8)(cp>>8);
  1542. }
  1543. // 发送begin到end之间的所有遥信值
  1544. for(i=begin;i<end;i++)
  1545. {
  1546. u8 SIQ;
  1547. // 得到遥信值
  1548. if(tRunPara.bSDPI) // 单双点分别上送
  1549. {
  1550. u8 type=tbl_get_dpi(i);
  1551. if(yxtype!=type&&num>2)
  1552. {
  1553. u8 vsq2=vsq;
  1554. u8 ti2=yxtype ? 3:1;
  1555. yxtype=type;
  1556. if(pRunSet->bDIContinue)
  1557. {
  1558. vsq2|=0x80;
  1559. }
  1560. IEC101_Asdu_Add(pt,pdata,num,(vsq2),QOI,ti2, attr| FRAME_I_COS);//cot=9总查询
  1561. num=0;
  1562. pd=pdata;
  1563. if(pRunSet->bDIContinue)
  1564. {
  1565. pd[num++]=(u8)(cp+vsq);
  1566. pd[num++]=(u8)((cp+vsq)>>8);
  1567. cp+=vsq;
  1568. }
  1569. vsq=0;
  1570. yxtype=type;
  1571. }
  1572. SIQ = tbl_get_yx(i,type);
  1573. ti=type ? 3:1;
  1574. }
  1575. else
  1576. {
  1577. SIQ = tbl_get_yx(i,tRunPara.bDPI);
  1578. }
  1579. #if !defined FUNC_JX_YX_BEFORE
  1580. if(g_run_stu.bjx)
  1581. {
  1582. SIQ|=0x80;//带品质描述,有效 <1>:=无效
  1583. }
  1584. #endif
  1585. if(g_run_stu.bToolRmtTest||g_run_stu.bHmiRmtTest) //测试模式,遥信置为无效
  1586. {
  1587. if(pRunSet->bTT_RmtTest)SIQ|=0x80;
  1588. }
  1589. // 点号
  1590. if(!pRunSet->bDIContinue)
  1591. {
  1592. cp=g_di_table[i].cp;
  1593. pd[num++]=(u8)cp;
  1594. pd[num++]=(u8)(cp>>8);
  1595. }
  1596. pd[num++]=SIQ;
  1597. vsq++;
  1598. if(((vsq>120)||(num>MAX_101_FRAME_LENTH))&&(i<g_table_head->di_num-1)) // ngd不能超过128,因个数最高位为连续标示位
  1599. {
  1600. u8 vsq1=vsq;
  1601. if(pRunSet->bDIContinue)
  1602. {
  1603. vsq1|=0x80;
  1604. }
  1605. IEC101_Asdu_Add(pt,pdata,num,(vsq1),QOI,ti, attr| FRAME_I_COS);//cot=9总查询
  1606. num=0;
  1607. pd=pdata;
  1608. if(pRunSet->bDIContinue)
  1609. {
  1610. pd[num++]=(u8)(cp+vsq);
  1611. pd[num++]=(u8)((cp+vsq)>>8);
  1612. cp+=vsq;
  1613. }
  1614. vsq=0;
  1615. }
  1616. }
  1617. if(num>2)
  1618. {
  1619. u8 vsq1=vsq;
  1620. if(pRunSet->bDIContinue)
  1621. {
  1622. vsq1|=0x80;
  1623. }
  1624. IEC101_Asdu_Add(pt,pdata,num,(vsq1),QOI,ti, attr| FRAME_I_COS);//cot=9总查询
  1625. }
  1626. }
  1627. // 总召唤结束帧
  1628. num=0;
  1629. pd=pdata;
  1630. pd[num++] = 0;
  1631. pd[num++] = 0;
  1632. pd[num++] = QOI;
  1633. IEC101_Asdu_Add(pt,pdata,num,1,10,100, attr);
  1634. // 不允许通讯续传的情况下,第一次总召先清SOE队列,保证上传事件是总召后产生的,后续总召不清SOE队列
  1635. if((pRunSet->bTT_SoeResumeComm == 0) &&(!pt->bSendChange))
  1636. {
  1637. g_soe_queue.tail_send[pt->chnl].n=g_soe_queue.head.n;
  1638. g_soe_queue.tail_ack[pt->chnl].n = g_soe_queue.tail_send[pt->chnl].n;
  1639. }
  1640. #ifdef FUN_SOE_DELAY_TIME
  1641. if(pt->bSendChange == false)
  1642. {
  1643. pt->DTSendChange = dTCounter;
  1644. pt->bfirst_call = true;
  1645. }
  1646. #endif
  1647. // 置总召标志
  1648. pt->bSendChange=true;
  1649. }
  1650. static void IEC101_DDAll(IEC101_DEF *pt,u8 QCC) //确认帧
  1651. {
  1652. u8 *pd,*pdata;
  1653. u8 vsq,cot;//通用分类数据集数目
  1654. u16 cp;
  1655. int i,num;
  1656. pdata=g_arrIECBuf;
  1657. num=0;
  1658. //总召唤确认帧
  1659. pd=pdata;
  1660. pd[num++] = 0;
  1661. pd[num++] = 0;
  1662. pd[num++] = QCC;
  1663. IEC101_Asdu_Add(pt,pdata,num,1,7,101, FRAME_I);
  1664. // 电度值
  1665. if((QCC==1)||(QCC==5))
  1666. {
  1667. // 初始数据
  1668. pd=pdata;
  1669. vsq=0;
  1670. num=0;
  1671. cp=g_dd_table[0].cp;
  1672. if(QCC==5)cot=37; // 总召
  1673. else cot=QCC+37; // 召某一组
  1674. pd[num++]=(u8)cp;
  1675. pd[num++]=(u8)(cp>>8);
  1676. for(i=0;i<g_table_head->dd_num;i++)
  1677. {
  1678. int sw,no;
  1679. float rate;
  1680. union{
  1681. float ff;
  1682. u8 tt[4];
  1683. }ff;
  1684. sw=g_dd_table[i].owner;
  1685. no=g_dd_table[i].indexno;
  1686. if(no>0)
  1687. {
  1688. rate=(float)g_dd_table[i].rate/65536.0;
  1689. ff.ff=GetRmtDdVal(sw,no-1)*rate;
  1690. }
  1691. else
  1692. {
  1693. ff.ff=0;
  1694. }
  1695. num += CopySwap(&pd[num],ff.tt,sizeof(ff.tt),true);
  1696. pd[num++]=0;
  1697. vsq++;
  1698. // 发送一帧
  1699. if((num>MAX_101_FRAME_LENTH)||(i==g_table_head->dd_num-1))
  1700. {
  1701. IEC101_Asdu_Add(pt,pdata,num,(vsq|0x80),cot,206,FRAME_I_PRIOR_LOW);
  1702. cp+=vsq;
  1703. pd=pdata;
  1704. num=0;
  1705. vsq=0;
  1706. pd[num++]=(u8)cp;
  1707. pd[num++]=(u8)(cp>>8);
  1708. }
  1709. }
  1710. }
  1711. if(QCC==0x45)//主站扩展瞬时冻结电度命令
  1712. {
  1713. //rand_file_info.b_frz=true;
  1714. }
  1715. // 总召唤结束帧
  1716. num=0;
  1717. pd=pdata;
  1718. pd[num++] = 0;
  1719. pd[num++] = 0;
  1720. pd[num++] = QCC;
  1721. IEC101_Asdu_Add(pt,pdata,num,1,10,101, FRAME_I_PRIOR_LOW);
  1722. }
  1723. /**************************************************************************
  1724. 函数名称:IEC101_RmtCtrl
  1725. 函数版本:1.00
  1726. 作者:
  1727. 创建日期:2007.9.1
  1728. 函数功能说明:遥控处理
  1729. 输入参数: 点号开始21 0b 00 82 (10-13)
  1730. 输出参数:
  1731. 返回值:
  1732. 更新信息:
  1733. 更新日志1:
  1734. 日期:
  1735. 修改者:
  1736. 修改内容:
  1737. 修改原因:
  1738. ***************************************************************************/
  1739. void IEC101_Echo_YK(IEC101_DEF *pt,u16 cp,u8 ti,u8 cot,u8 v)
  1740. {
  1741. u8 *pd,*pdata;
  1742. int num;
  1743. pdata=g_arrIECBuf;
  1744. pd = pdata;
  1745. num=0;
  1746. pd[num++]=(u8)cp;
  1747. pd[num++]=(u8)(cp>>8);
  1748. pd[num++]=v;
  1749. IEC101_Asdu_Add(pt,pdata,num,1,cot,ti,FRAME_I|FRAME_I_PRIOR_HIGH);//cot=9总查询
  1750. pt->bRmtSM2 = false; //遥控执行完成,清除SM2标志,开放事件上传
  1751. }
  1752. void IEC101_Echo_PAR(IEC101_DEF *pt,u16 cp,u8 ti,u8 cot,BYTE *buf,u8 len,u8 vsq)
  1753. {
  1754. u8 *pd,*pdata;
  1755. int num;
  1756. pdata=g_arrIECBuf;
  1757. pd = pdata;
  1758. num=0;
  1759. //pd[num++]=(u8)cp;
  1760. //pd[num++]=(u8)(cp>>8);
  1761. memcpy(&pd[num],buf,len);
  1762. num+=len;
  1763. //pd[num++]=v;
  1764. IEC101_Asdu_Add(pt,pdata,num,vsq,cot,ti,FRAME_I);//cot=9总查询
  1765. }
  1766. int get_yk_info_cp(u8 cp)
  1767. {
  1768. int i;
  1769. for(i=0;i<g_table_head->do_num;i++)
  1770. {
  1771. //rt_printf("cp=%X link_ch=%x cp=%x \r\n",cp,(g_do_table[i].link_ch&0x0f),g_do_table[i].link_cp);
  1772. if((g_do_table[i].link_ch&0x01f) == cp)
  1773. {
  1774. return (u8)i;
  1775. }
  1776. }
  1777. return -1;
  1778. }
  1779. u8 get_par_link_101_to_104(BYTE *out,BYTE *in,BYTE parNum,u8 ti)
  1780. {
  1781. int size=0,i=0,j=0;
  1782. int no=0;
  1783. if((ti==FOS_PAR_SET_MUL) || (ti==FOS_PAR_SET_ONE))
  1784. size = (parNum*(sizeof(float)+2+1)); //写定值时需多一位QOS位
  1785. else if(ti==FOS_PAR_READ_MUL || ti==FOS_PAR_READ_ONE)
  1786. size = (parNum*(sizeof(float)+2));
  1787. rt_printf("size=%d,parNum=%d\n\r",size,parNum);
  1788. for(no=0;no<parNum;no++)
  1789. {
  1790. if((ti==FOS_PAR_READ_MUL) || (ti==FOS_PAR_READ_ONE))
  1791. {
  1792. out[j++] = in[i++]; //地址
  1793. out[j++] = in[i++]; //地址
  1794. out[j++] = 0;
  1795. out[j++] = in[i++]; //值
  1796. out[j++] = in[i++]; //值
  1797. out[j++] = in[i++]; //值
  1798. out[j++] = in[i++]; //值
  1799. }
  1800. else if((ti==FOS_PAR_SET_MUL) || (ti==FOS_PAR_SET_ONE))
  1801. {
  1802. out[j++] = in[i++]; //地址
  1803. out[j++] = in[i++]; //地址
  1804. out[j++] = 0;
  1805. out[j++] = in[i++]; //值
  1806. out[j++] = in[i++]; //值
  1807. out[j++] = in[i++]; //值
  1808. out[j++] = in[i++]; //值
  1809. out[j++] = in[i++]; //QOS
  1810. }
  1811. }
  1812. return (size+parNum);
  1813. }
  1814. u8 get_par_link_data(BYTE *out,BYTE *in,BYTE parNum,u8 ti)
  1815. {
  1816. int size;
  1817. if(ti == FOS_PAR_SET_MUL)//写带品质描述,长度+1
  1818. size = (parNum*(sizeof(float)+2+1));//4
  1819. else
  1820. size = (parNum*(sizeof(float)+2));
  1821. memcpy(out,in,size);//拷贝遥参点表地址=2 && 参数值=size
  1822. return (size);
  1823. }
  1824. u8 get_par_link_104_to_104(BYTE *out,BYTE *in,BYTE parNum,u8 ti)
  1825. {
  1826. int size;
  1827. if(ti == FOS_PAR_SET_MUL)//写带品质描述,长度+1
  1828. size = (parNum*(sizeof(float)+3+1));//4
  1829. else
  1830. size = (parNum*(sizeof(float)+3));
  1831. memcpy(out,in,size);//拷贝遥参点表地址=2 && 参数值=size
  1832. return (size);
  1833. }
  1834. u8 get_par_link_data_dz(BYTE *out,BYTE *in,BYTE parNum,u8 ti)
  1835. {
  1836. int size=0,i,j=0;
  1837. if((ti==FOS_PAR_SET_MUL) || (ti==FOS_PAR_SET_ONE))
  1838. size = (parNum*(sizeof(float)+3+1)); //写定值时需多一位QOS位
  1839. else if(ti==FOS_PAR_READ_MUL || ti==FOS_PAR_READ_ONE)
  1840. size = (parNum*(sizeof(float)+3));
  1841. rt_printf("size=%d,parNum=%d\n\r",size,parNum);
  1842. for(i=0;i<size;i++)
  1843. { //104遥调时,因管理机与级联间仍为101通讯,故管理机转发给级联的报文应去掉1位地址位(104为3位地址位,101为2位地址位)
  1844. if((ti==FOS_PAR_READ_MUL) || (ti==FOS_PAR_READ_ONE))
  1845. {
  1846. if(2 == i%7) //读定值时3位地址位+4位数据位共7位
  1847. continue; //跳过地址位第3位
  1848. else
  1849. {
  1850. out[j++]=in[i];
  1851. }
  1852. }
  1853. else if((ti==FOS_PAR_SET_MUL) || (ti==FOS_PAR_SET_ONE))
  1854. {
  1855. if(2 == i%8) //写定值时3位地址位+4位数据位+1位QOS位
  1856. continue; //跳过地址位第3位
  1857. else
  1858. {
  1859. out[j++]=in[i];
  1860. }
  1861. }
  1862. }
  1863. return (size-parNum);
  1864. }
  1865. //获取通道信息
  1866. bool get_par_ch_info(WORD parAddr,struct do_table *parTab)
  1867. {
  1868. WORD Addr=0;
  1869. int ykCp=0;
  1870. //判断遥参ID是否合法
  1871. if(parAddr<FOS_PAR_STATR_ADDR)
  1872. return false;
  1873. Addr = parAddr-FOS_PAR_STATR_ADDR;
  1874. #ifdef YC_QUANTITY
  1875. parTab->link_cp = (Addr/pRunSet->dYC_num)+1; //转发通信地址
  1876. #else
  1877. parTab->link_cp = (Addr/FOS_PAR_SW_NUM)+1; //转发通信地址
  1878. #endif
  1879. //通过遥控的级联地址去判断遥参是否合法
  1880. ykCp = get_yk_info_cp(parTab->link_cp);
  1881. if(ykCp<0)
  1882. {
  1883. rt_printf("定值参数未找到Yk对应的级联地址=%X link_ch=%x \r\n",parAddr,parTab->link_cp);
  1884. return false;
  1885. }
  1886. memcpy(parTab,&g_do_table[ykCp],sizeof(g_do_table[0])); //将遥控配置的转发信息赋到遥参
  1887. #if 0
  1888. parTab->cp = Addr%FOS_PAR_SW_NUM + FOS_PAR_STATR_ADDR; //转发点号
  1889. #endif
  1890. parTab->link_cp = parTab->cp = parAddr; //转发通信地址
  1891. #ifdef YC_QUANTITY
  1892. rt_printf("\n parAddr=%x link_cp=%x cp=%x link_ch=0X%X ykCp=%d linkAddr=%x\r\n",parAddr,parTab->link_cp,parTab->link_ch,parTab->cp,ykCp, Addr%pRunSet->dYC_num);
  1893. #else
  1894. rt_printf("\n parAddr=%x link_cp=%x cp=%x link_ch=0X%X ykCp=%d linkAddr=%x\r\n",parAddr,parTab->link_cp,parTab->link_ch,parTab->cp,ykCp, Addr%FOS_PAR_SW_NUM);
  1895. #endif
  1896. return true;
  1897. }
  1898. #ifdef FUNC_MORE_PRESET
  1899. YT_BUF PresetData101[256];
  1900. YT_BUF SetData101[256];
  1901. int WrongCount101[256];
  1902. int g_CountPreset101=0, g_CountSet101=0;
  1903. bool gb_101_yt=false;
  1904. #endif
  1905. static void IEC101_ParCtrl(IEC101_DEF *pt,u8 *pdat) // ps从传送原因开始
  1906. {
  1907. u8 cot,ykcot,ykvalue;
  1908. WORD parNum=1;
  1909. WORD ykno=0;
  1910. WORD yksave=0;
  1911. WORD parAddr=0;
  1912. u8 AppByte=0;
  1913. u8 CotByte=0;
  1914. u8 *ps=&pdat[2];
  1915. u8 ti=pdat[0]; //类型标示
  1916. struct do_table parTab;
  1917. BYTE buf[256];
  1918. BYTE len=0;
  1919. BYTE addrStart=0;
  1920. WORD sw=1;
  1921. static DWORD ctrlParTime=0; //系统定时器
  1922. static bool bSetParaDisable=false;
  1923. if(tRunPara.b101App2Byte) //应用单元双字节地址
  1924. {
  1925. AppByte=1;
  1926. }
  1927. if(tRunPara.b101Cot2Byte) //双字节传送原因
  1928. {
  1929. CotByte=1;
  1930. }
  1931. ykcot=(ps[0]&0x01f);
  1932. parNum=(pdat[1]&0xff);//遥参数量,支持遥调大于30个定值
  1933. ykno=ps[2+AppByte+CotByte]+(WORD)ps[3+AppByte+CotByte]*256;
  1934. addrStart = 2+AppByte+CotByte;
  1935. yksave=ykno;
  1936. cot=IEC_COT_UN_OA | IEC_COT_PN;
  1937. parAddr = (ps[addrStart+1]<<8)+ps[addrStart];//遥参通信地址
  1938. len = get_par_link_data(&buf[0],&ps[addrStart],parNum,ti);//2+(parNum*4);//2:点号 4:参数值
  1939. ykvalue=ps[AppByte+CotByte+2-1+7];//
  1940. rt_printf("ti=%d parAddr=%x parNum= %d recDataLen=%d addrStart=%d ykvalue=%x ykcot=%02x\r\n",ti,parAddr,parNum,len,addrStart,ykvalue,ykcot);
  1941. if(pRunSet->wEquTypeManager)// 通信管理机模式,转发
  1942. {
  1943. #ifdef YC_QUANTITY
  1944. if(!get_par_ch_info(parAddr,&parTab)||parNum>pRunSet->dYC_num)
  1945. #else
  1946. if(!get_par_ch_info(parAddr,&parTab)||parNum>FOS_PAR_SW_NUM)
  1947. #endif
  1948. {
  1949. cot = IEC_COT_ACTCON | IEC_COT_PN; // 否定应答
  1950. //refresh_co_file(true,ti,yktype,ykno,cot,yk_cmd);
  1951. return ;
  1952. }
  1953. //parTab.vsq = parNum;
  1954. if(lnk_master_par(&parTab ,ti,ps[0],len,&buf[0],parNum) == 0)
  1955. {
  1956. #ifdef FUNC_MORE_PREREAD /*级联遥参方式:0开关,1队列*/
  1957. pt->lnk_par_send_flag |= (1<<g_link_par_cnt);
  1958. rt_printf("-------lnk_par_send_flag=%x,g_link_par_cnt=%d\r\n",pt->lnk_par_send_flag,g_link_par_cnt);
  1959. g_link_par_cnt = (g_link_par_cnt+1)%SWITCH_NUM_EXT_PUB;
  1960. #else
  1961. pt->lnk_par_send_flag |= (1<<parTab.owner);
  1962. #endif
  1963. pt->us0_lnk_par = ustimer_get_origin();
  1964. }
  1965. }
  1966. else if (pRunSet->wEquTypeDFTU)// 测控装置遥参交互
  1967. {
  1968. WORD parCount;
  1969. WORD addLenParLen;
  1970. #ifdef FUNC_MORE_PRESET
  1971. int n;
  1972. #endif
  1973. cot=IEC_COT_ACTCON;
  1974. //ykvalue = (ti==FOS_PAR_SET_ONE) ? (ykvalue|0x80) :ykvalue;
  1975. #ifndef FUNC_MORE_PRESET
  1976. bfirst_sel = false;
  1977. #endif
  1978. #ifdef FUNC_MORE_PRESET
  1979. if((dTCounter-ctrlParTime) > tRunPara.dYKTime)
  1980. {//超时清零预置/执行/出错数据存储区
  1981. memset(SetData101,0,sizeof(SetData101));
  1982. g_CountSet101 = 0;
  1983. memset(PresetData101,0,sizeof(PresetData101));
  1984. g_CountPreset101 = 0;
  1985. memset(WrongCount101,0,sizeof(WrongCount101));
  1986. rt_printf("超时清除101报文缓存区\r\n");
  1987. }
  1988. #endif
  1989. if(ti==FOS_PAR_SET_ONE || ti==FOS_PAR_SET_MUL)
  1990. {
  1991. if(ykvalue&0x80)
  1992. {
  1993. #ifdef FUNC_MORE_PRESET
  1994. memcpy(&PresetData101[g_CountPreset101++].yc_data,&ps[addrStart],parNum*7);
  1995. rt_printf_time("101预置报文[第%d帧]:",g_CountPreset101);
  1996. for(n=0;n<parNum*7;n++)
  1997. {
  1998. rt_printf("%02x ",PresetData101[g_CountPreset101-1].yc_data[n]);
  1999. }
  2000. #else
  2001. //预置时先对buf_forCompare进行初始化,避免此数组有101/104共用的原因导致存储出错
  2002. memset(buf_forCompare,0,sizeof(buf_forCompare));
  2003. i_forCompare = 0;
  2004. j_forCompare = 0;
  2005. bfirst_sel = true; //为预置报文时才置1
  2006. #endif
  2007. }
  2008. #ifdef FUNC_MORE_PRESET
  2009. else
  2010. {
  2011. memcpy(&SetData101[g_CountSet101++].yc_data,&ps[addrStart],parNum*7);
  2012. rt_printf_time("101固化报文[第%d帧]:",g_CountSet101);
  2013. for(n=0;n<parNum*7;n++)
  2014. {
  2015. rt_printf("%02x ",SetData101[g_CountSet101-1].yc_data[n]);
  2016. }
  2017. }
  2018. #endif
  2019. }
  2020. for(parCount=0;parCount<parNum;parCount++)//多参数处理
  2021. {
  2022. #ifdef FUNC_MORE_PRESET
  2023. gb_101_yt = true;
  2024. #endif
  2025. if(ti == FOS_PAR_SET_MUL)//读取参数带品质描述
  2026. addLenParLen = (parCount)*(2+4+1);//ID=2,PAR=4,QDS=1
  2027. else
  2028. addLenParLen = (parCount)*(2+4);//ID=2,PAR=4
  2029. #ifdef YC_QUANTITY
  2030. parAddr = (ps[addrStart+1+addLenParLen]<<8)+ps[addrStart+addLenParLen]-((tRunPara.byAddr-1)*pRunSet->dYC_num);
  2031. #else
  2032. parAddr = (ps[addrStart+1+addLenParLen]<<8)+ps[addrStart+addLenParLen]-((tRunPara.byAddr-1)*FOS_PAR_SW_NUM);
  2033. #endif
  2034. //parAddr = (ps[addrStart+1]<<8)+ps[addrStart];//遥参通信地址
  2035. #ifdef YC_QUANTITY
  2036. if( ((ps[addrStart+1+addLenParLen]<<8)+ps[addrStart+addLenParLen]) >= FOS_PAR_STATR_ADDR
  2037. && ((ps[addrStart+1+addLenParLen]<<8)+ps[addrStart+addLenParLen]) < (FOS_PAR_STATR_ADDR+pRunSet->dYC_num))
  2038. #else
  2039. if( ((ps[addrStart+1+addLenParLen]<<8)+ps[addrStart+addLenParLen]) >= FOS_PAR_STATR_ADDR
  2040. && ((ps[addrStart+1+addLenParLen]<<8)+ps[addrStart+addLenParLen]) < (FOS_PAR_STATR_ADDR+FOS_PAR_SW_NUM))
  2041. #endif
  2042. {
  2043. parAddr = (ps[addrStart+1+addLenParLen]<<8)+ps[addrStart+addLenParLen];
  2044. }
  2045. rt_printf("parAddr=%x addr2=%X %x addrStart=%x\r\n",parAddr,(ps[addrStart+1]<<8)+ps[addrStart],addLenParLen,addrStart);
  2046. if(ti==FOS_PAR_READ_ONE || ti==FOS_PAR_READ_MUL)
  2047. {
  2048. rt_printf("读取遥参激活 parAddr=%x\r\n",parAddr);
  2049. if(!readRunParId(sw,parAddr,&ps[addrStart+2+addLenParLen]))//暂默认为0开关
  2050. cot = IEC_COT_ACTCON | IEC_COT_PN; // 否定应答// memcpy(&ps[addrStart+2],"1234",sizeof(float));//2:参数点表地址
  2051. }
  2052. else
  2053. {
  2054. #ifdef FUNC_FIT_QOS
  2055. if(ykcot == IEC_COT_DEACT)
  2056. {
  2057. cot = IEC_COT_DEACTCON; // 预置取消确认
  2058. bSetParaDisable = true; //取消预置时置1
  2059. rt_printf("QOS(101)=%02x,取消遥参预置...\r\n",ykvalue);
  2060. break;
  2061. }
  2062. #endif
  2063. if(ykvalue&0x80)
  2064. {
  2065. ctrlParTime = dTCounter; //系统时间戳
  2066. if(!selectRunParId(sw,parAddr,&ps[addrStart+2+addLenParLen]))
  2067. {
  2068. cot = IEC_COT_ACTCON | IEC_COT_PN;
  2069. #ifdef FUNC_MORE_PRESET
  2070. WrongCount101[g_CountPreset101-1] = g_CountPreset101;
  2071. #else
  2072. bSetParaDisable = true; //预置报文出错时置1,禁止固化定值
  2073. #endif
  2074. break;
  2075. }
  2076. else
  2077. {
  2078. bSetParaDisable = false; //重新预置时清0
  2079. }
  2080. }
  2081. else
  2082. {
  2083. #ifdef FUNC_MORE_PRESET
  2084. int s_stop;
  2085. s_stop = WrongCount101[g_CountSet101-1];
  2086. #endif
  2087. #if defined FUNC_MORE_PRESET
  2088. if(ykcot == IEC_COT_DEACT)
  2089. {
  2090. cot = IEC_COT_DEACTCON; // 预置取消确认
  2091. bSetParaDisable = true; //取消预置时置1
  2092. rt_printf("取消遥参预置...\r\n");
  2093. break;
  2094. }
  2095. else if( dTCounter-ctrlParTime > tRunPara.dYKTime || (0 != s_stop) || bSetParaDisable || !wirteRunParId(sw,parAddr,&ps[addrStart+2+addLenParLen],ti))//暂默认为0开关
  2096. #elif defined FUNC_FIT_QOS
  2097. if( dTCounter-ctrlParTime > tRunPara.dYKTime || bSetParaDisable || !wirteRunParId(sw,parAddr,&ps[addrStart+2+addLenParLen],ti))//暂默认为0开关
  2098. #else
  2099. if(ykcot == IEC_COT_DEACT)
  2100. {
  2101. cot = IEC_COT_DEACTCON; // 预置取消确认
  2102. bSetParaDisable = true; //取消预置时置1
  2103. rt_printf("取消遥参预置...\r\n");
  2104. break;
  2105. }
  2106. else if( dTCounter-ctrlParTime > tRunPara.dYKTime || bSetParaDisable || !wirteRunParId(sw,parAddr,&ps[addrStart+2+addLenParLen],ti))//暂默认为0开关
  2107. #endif
  2108. {
  2109. if(dTCounter-ctrlParTime > tRunPara.dYKTime)
  2110. {
  2111. bSetParaDisable = false; //超时后才清0,避免取消预置后在超时时间内多次发执行帧而误执行
  2112. rt_printf("设置遥参超时...\r\n");
  2113. }
  2114. #ifdef FUNC_MORE_PRESET
  2115. else if(0 != s_stop)
  2116. {
  2117. rt_printf("[第%d帧]101预置报文出错,请检查...\r\n",s_stop);
  2118. }
  2119. #endif
  2120. else if(bSetParaDisable)
  2121. {
  2122. #ifdef FUNC_MORE_PRESET
  2123. rt_printf("取消预置,禁止固化定值\r\n");
  2124. #else
  2125. rt_printf("预置报文出错或取消预置,禁止固化定值\r\n");
  2126. #endif
  2127. }
  2128. cot = IEC_COT_ACTCON | IEC_COT_PN; // 否定应答
  2129. //屏蔽break语句,除出错定值外均可修改,与104遥调统一做法
  2130. //break;
  2131. }
  2132. }
  2133. }
  2134. }
  2135. #ifdef FUNC_MORE_PRESET
  2136. gb_101_yt = false;
  2137. #endif
  2138. //parTab.vsq = parNum;
  2139. //
  2140. if(cot&IEC_COT_PN)
  2141. rt_printf("设置&&读取 遥参失败 parAddr=%x\r\n",parAddr);
  2142. else
  2143. rt_printf("设置&&读取 遥参OK parAddr=%x\r\n",parAddr);
  2144. #ifndef FUNC_MORE_PRESET
  2145. if((!(ykvalue&0x80) && ti==FOS_PAR_SET_MUL)
  2146. #ifdef FUNC_FIT_QOS
  2147. || (ykcot == IEC_COT_DEACT)
  2148. #endif
  2149. )
  2150. ctrlParTime = 0;
  2151. #endif
  2152. IEC101_Echo_PAR(pt,yksave,ti,cot,&ps[addrStart],len,parNum);
  2153. #ifndef FUNC_MORE_PRESET
  2154. if((!(ykvalue&0x80))
  2155. #ifdef FUNC_FIT_QOS
  2156. || (ykcot == IEC_COT_DEACT)
  2157. #endif
  2158. )
  2159. {
  2160. memset(buf_forCompare,0,sizeof(buf_forCompare));
  2161. i_forCompare = 0;
  2162. j_forCompare = 0;
  2163. }
  2164. #endif
  2165. return ;
  2166. }
  2167. cot = (ykcot == IEC_COT_ACT) ? IEC_COT_ACTCON : IEC_COT_DEACTCON;
  2168. cot |= IEC_COT_PN;
  2169. //rt_printf("设置遥参 error parAddr=%x\r\n",parAddr);
  2170. //IEC101_Echo_PAR(pt,yksave,ti,cot,&ps[addrStart],len);
  2171. }
  2172. static void IEC101_RmtCtrl(IEC101_DEF *pt,u8 *pdat) // ps从传送原因开始
  2173. {
  2174. u8 cot,ykcot,ykvalue,yktype,ykThz,v;
  2175. WORD ykno;
  2176. WORD yksave;
  2177. u8 AppByte=0;
  2178. u8 CotByte=0;
  2179. int i,ret;
  2180. bool bValidYk=false;
  2181. u8 *ps=&pdat[2];
  2182. u8 ti=pdat[0]; //类型标示
  2183. u8 yk_cmd;
  2184. yktype = 0;
  2185. if(tRunPara.b101App2Byte) //应用单元双字节地址
  2186. {
  2187. AppByte=1;
  2188. }
  2189. if(tRunPara.b101Cot2Byte) //双字节传送原因
  2190. {
  2191. CotByte=1;
  2192. }
  2193. ykcot=(ps[0]&0x01f);
  2194. ykvalue=ps[4+AppByte+CotByte];
  2195. yk_cmd = ykvalue&0x03;
  2196. ykno=ps[2+AppByte+CotByte]+(WORD)ps[3+AppByte+CotByte]*256;
  2197. yksave=ykno;
  2198. cot=IEC_COT_UN_OA | IEC_COT_PN;
  2199. v=ykvalue;
  2200. if(ti==45)
  2201. {
  2202. ykvalue+=1; //单点遥控转为双点遥控
  2203. }
  2204. for(i=0;i<g_table_head->do_num;i++) //查找遥控转发表,看是否有有效的遥控点
  2205. {
  2206. if(ykno != g_do_table[i].cp) // 遥控点号对应
  2207. {
  2208. continue;
  2209. }
  2210. // 如果配置了级联通道,转发
  2211. if(g_do_table[i].link_ch)
  2212. {
  2213. if(lnk_master_yk(&g_do_table[i] ,ti,ps[0],v) == 0)
  2214. {
  2215. pt->lnk_yk_send_flag |= (1<<g_do_table[i].owner);
  2216. pt->us0_lnk_yk = ustimer_get_origin();
  2217. }
  2218. else
  2219. { cot = (ykcot == IEC_COT_ACT) ? IEC_COT_ACTCON : IEC_COT_DEACTCON;
  2220. cot |= IEC_COT_PN;
  2221. IEC101_Echo_YK(pt,yksave,ti,cot,v);
  2222. }
  2223. if(ykvalue&0x80)
  2224. {
  2225. yktype=YK_TYPE_SEL;
  2226. }
  2227. else
  2228. {
  2229. yktype=YK_TYPE_EXE;
  2230. }
  2231. refresh_co_file(true,ti,yktype,ykno,cot,yk_cmd);
  2232. return;
  2233. }
  2234. // 本装置遥控
  2235. {
  2236. cot=IEC_COT_ACTCON;
  2237. bValidYk=true;
  2238. if(ykvalue&0x80)
  2239. {
  2240. yktype=YK_TYPE_SEL;
  2241. }
  2242. else
  2243. {
  2244. yktype=YK_TYPE_EXE;
  2245. }
  2246. if(ykcot==8) //遥控撤销
  2247. {
  2248. yktype=YK_TYPE_CANCEL;
  2249. cot=IEC_COT_DEACTCON;
  2250. }
  2251. if((ykvalue&0x03)==2)
  2252. {
  2253. ykThz=YK_VAL_HZ;
  2254. }
  2255. else
  2256. {
  2257. ykThz=YK_VAL_TZ;
  2258. }
  2259. ret = RemoteCtrl(yktype,i,ykThz,MASTER_101+pt->chnl);
  2260. if(ret != 0)
  2261. {
  2262. cot = IEC_COT_ACTCON | IEC_COT_PN; // 否定应答
  2263. }
  2264. //接收到主站的遥控信息:选择,执行,撤销
  2265. refresh_co_file(true,ti,yktype,ykno,cot,yk_cmd);
  2266. break;
  2267. }
  2268. }
  2269. // 没有找到对应遥控点
  2270. if(i == g_table_head->do_num)
  2271. {
  2272. char buf[128];
  2273. char log_info[128];
  2274. sprintf(buf,"遥控:转发点表未找到对应点(ykno=0x%04x,yktype=%d,ykvalue=%d)",ykno,yktype,ykvalue);
  2275. log_str_time(LOG_OPERATE,buf,0,0);
  2276. rt_printf_time("%s\r\n",buf);
  2277. sprintf(log_info,"IEC101(%d):Remote control:Corresponding di is not in the iectable(ykno=0x%04x,yktype=%d,ykvalue=%d)",pt->chnl+1,ykno,yktype,ykvalue);
  2278. load_hs_log_rcd(TYPE_COMM_ERR,true,NULL,log_info,1);
  2279. log_flag.com_err[pt->chnl] = true;
  2280. }
  2281. pt->bRmtSM2 = false;
  2282. IEC101_Echo_YK(pt,yksave,ti,cot,v);
  2283. //必须有对应点号
  2284. if(i != g_table_head->do_num)
  2285. {
  2286. //终端发出遥控信息:选择确认,执行确认
  2287. refresh_co_file(false,ti,yktype,ykno,cot,yk_cmd);
  2288. }
  2289. if((yktype==YK_TYPE_EXE)&&(cot==IEC_COT_ACTCON))
  2290. {
  2291. IEC101_Echo_YK(pt,yksave,ti,10,v);
  2292. refresh_co_file(false,ti,yktype,ykno,IEC_COT_ACTTERM,yk_cmd);
  2293. }
  2294. }
  2295. /**************************************************************************
  2296. 函数名称:IEC101_MFrameCall
  2297. 函数版本:1.00
  2298. 作者:
  2299. 创建日期:2008.9.1
  2300. 函数功能说明:应答短帧报文
  2301. 输入参数:平衡方式下,发送帧
  2302. 输出参数:
  2303. 返回值:
  2304. 更新信息:
  2305. 更新日志1:
  2306. 日期:
  2307. 修改者:
  2308. 修改内容:
  2309. 修改原因:
  2310. ***************************************************************************/
  2311. static void IEC101_MFrameCall(IEC101_DEF *pt,unsigned char ZoneByte)
  2312. {
  2313. u8 *pd=pt->tx_buf_m;
  2314. IEC101_SETPRM(ZoneByte);
  2315. if(!pt->bDIR)IEC101_SETDIR(ZoneByte);
  2316. if(!tRunPara.b101Addr2Byte)
  2317. {
  2318. pd[0]=5;
  2319. pd[1]=0x10;
  2320. pd[2]=ZoneByte;
  2321. pd[3]=(u8)tRunPara.byAddr;
  2322. pd[4]=pd[2]+pd[3];
  2323. pd[5]=0x16;
  2324. }
  2325. else
  2326. {
  2327. pd[0]=6;
  2328. pd[1]=0x10;
  2329. pd[2]=ZoneByte;
  2330. pd[3]=(u8)tRunPara.byAddr;
  2331. pd[4]=(u8)(tRunPara.byAddr>>8);
  2332. pd[5]=pd[2]+pd[3]+pd[4];
  2333. pd[6]=0x16;
  2334. }
  2335. }
  2336. static void IEC101_CallGprsInf(IEC101_DEF *pt)
  2337. {
  2338. u8 *pd=pt->tx_buf_s;
  2339. pd[0]=9;
  2340. pd[1]=0x55;
  2341. pd[2]=0xAA;
  2342. pd[3]=0x55;
  2343. pd[4]=0xAA;
  2344. pd[5]=0x1A;
  2345. pd[6]=0x00;
  2346. pd[7]=0x00;
  2347. pd[8]=0x9A;
  2348. pd[9]=0x7C;
  2349. }
  2350. /**************************************************************************
  2351. 函数名称:IEC101_link_par
  2352. 函数版本:1.00
  2353. 作者:
  2354. 创建日期:2019.4.19
  2355. 函数功能说明:101规约遥参级联处理
  2356. 输入参数:
  2357. 输出参数:
  2358. 返回值:
  2359. 更新信息:
  2360. 更新日志1:
  2361. 日期:
  2362. 修改者:
  2363. 修改内容:
  2364. 修改原因:
  2365. ***************************************************************************/
  2366. void IEC101_link_par(IEC101_DEF *pt)
  2367. {
  2368. int i;
  2369. LINKPAR_DEF *par;
  2370. LINK_PARDATA *yd;
  2371. if(pt->lnk_par_send_flag == 0)
  2372. {
  2373. return;
  2374. }
  2375. for(i=0; i<SWITCH_NUM_EXT_PUB; i++)
  2376. {
  2377. if(pt->lnk_par_send_flag & (1<<i))
  2378. {
  2379. par = &g_link_par[i];
  2380. // 遥控应答帧
  2381. if(par->flag[IECLINK_YK_ACK])
  2382. {
  2383. yd = &par->data[IECLINK_YK_ACK];
  2384. IEC101_Echo_PAR(pt, par->cp_m, yd->ti, yd->cot,&yd->buf[0], yd->len,yd->vsq);
  2385. par->flag[IECLINK_YK_ACK] = 0;
  2386. rt_printf("参数应答帧\r\n");
  2387. }
  2388. // 遥控结束帧
  2389. if(par->flag[IECLINK_YK_END])
  2390. {
  2391. yd = &par->data[IECLINK_YK_END];
  2392. IEC101_Echo_PAR(pt, par->cp_m, yd->ti, yd->cot,&yd->buf[0], yd->len,yd->vsq);
  2393. par->flag[IECLINK_YK_END] = 0;
  2394. pt->lnk_par_send_flag &= ~(1<<i);
  2395. rt_printf("参数结束帧\r\n");
  2396. }
  2397. // 遥控超时,复位
  2398. if(ustimer_get_duration(pt->us0_lnk_par) > tRunPara.dSM2Time*USTIMER_SEC)
  2399. {
  2400. yd = &par->data[IECLINK_YK_SND];
  2401. rt_printf("参数遥控超时复位:cp_m=%04x,cp_s=%04x,ti=%d,v=%d.\r\n",par->cp_m,par->cp_s,yd->ti,yd->len);
  2402. g_link_par[i].flag[IECLINK_YK_SND] = false;
  2403. pt->lnk_par_send_flag &= ~(1<<i);
  2404. }
  2405. }
  2406. }
  2407. }
  2408. /**************************************************************************
  2409. 函数名称:IEC101_Applay
  2410. 函数版本:1.00
  2411. 作者:
  2412. 创建日期:2008.9.1
  2413. 函数功能说明:101规约链路数据处理
  2414. 输入参数:
  2415. 输出参数:
  2416. 返回值:
  2417. 更新信息:
  2418. 更新日志1:
  2419. 日期:
  2420. 修改者:
  2421. 修改内容:
  2422. 修改原因:
  2423. ***************************************************************************/
  2424. void IEC101_lnk_yk(IEC101_DEF *pt)
  2425. {
  2426. int i;
  2427. LINKYK_DEF *yk;
  2428. LINK_YKDATA *yd;
  2429. if(pt->lnk_yk_send_flag == 0)
  2430. {
  2431. return;
  2432. }
  2433. for(i=0; i<SWITCH_NUM_EXT_PUB; i++)
  2434. {
  2435. if(pt->lnk_yk_send_flag & (1<<i))
  2436. {
  2437. u8 yktype,yk_cmd;
  2438. bool yk_hs=false;
  2439. yk = &g_lnk_yk[i];
  2440. // 遥控应答帧
  2441. if(yk->flag[IECLINK_YK_ACK])
  2442. {
  2443. yd = &yk->data[IECLINK_YK_ACK];
  2444. IEC101_Echo_YK(pt, yk->cp_m, yd->ti, yd->cot, yd->v);
  2445. yk->flag[IECLINK_YK_ACK] = 0;
  2446. }
  2447. // 遥控结束帧
  2448. if(yk->flag[IECLINK_YK_END])
  2449. {
  2450. yd = &yk->data[IECLINK_YK_END];
  2451. IEC101_Echo_YK(pt, yk->cp_m, yd->ti, yd->cot, yd->v);
  2452. yk->flag[IECLINK_YK_END] = 0;
  2453. pt->lnk_yk_send_flag &= ~(1<<i);
  2454. }
  2455. // 遥控超时,复位
  2456. if(ustimer_get_duration(pt->us0_lnk_yk) > tRunPara.dSM2Time*USTIMER_SEC)
  2457. {
  2458. yd = &yk->data[IECLINK_YK_SND];
  2459. rt_printf("级联遥控超时复位:cp_m=%04x,cp_s=%04x,ti=%d,v=%d.\r\n",yk->cp_m,yk->cp_s,yd->ti,yd->v);
  2460. pt->lnk_yk_send_flag &= ~(1<<i);
  2461. }
  2462. if(yk_hs)
  2463. {
  2464. if(yd->v&0x80)
  2465. {
  2466. yktype=YK_TYPE_SEL;
  2467. }
  2468. else
  2469. {
  2470. yktype=YK_TYPE_EXE;
  2471. }
  2472. if(yd->cot==IEC_COT_DEACT) //遥控撤销
  2473. {
  2474. yktype=YK_TYPE_CANCEL;
  2475. }
  2476. yk_cmd = yd->v&0x03;
  2477. refresh_co_file(false,yd->ti,yktype,yk->cp_m,yd->cot,yk_cmd);
  2478. }
  2479. }
  2480. }
  2481. }
  2482. #ifdef YPARA_LINK
  2483. void IEC101_lnk_msg_ypara(IEC101_DEF *pt101)
  2484. {
  2485. u8 *pd;
  2486. int num=0;
  2487. u8 pdi=0,cot=0,ti=0,vsq=0;
  2488. int index=0,i=0;
  2489. msg_data_struct *msg_data = &pt101->msg_ypara_recv;
  2490. pd = g_arrIECBuf;
  2491. #if 0
  2492. /*遥参是否超时*/
  2493. if(!pt101->msg_ypara_send.flag) return; /*没有下发遥参不返回*/
  2494. if(ustimer_get_duration(pt101->us0_msg_ypara) > tRunPara.dSM2Time*USTIMER_SEC)
  2495. {
  2496. pt101->msg_ypara_send.flag = 0; /*超时*/
  2497. return;
  2498. }
  2499. /*遥参是否超时*/
  2500. #endif
  2501. if(!msg_data->flag) return; /*有返回消息*/
  2502. msg_data->flag = 0;
  2503. if(msg_data->type == modify_set)
  2504. {
  2505. msg_ypara_data_struct *ypara_msg = &pt101->msg_ypara_recv.ypara_msg;
  2506. ti = 203;
  2507. /*该协议各类遥参返回格式一致,统一接口即可*/
  2508. switch(ypara_msg->cmd)
  2509. {
  2510. case YP_SEL_RETURN:
  2511. pdi = 0x80;
  2512. cot = IEC_COT_ACTCON;
  2513. break;
  2514. case YP_SEL_FAULT:
  2515. pdi = 0x80;
  2516. cot = IEC_COT_ACTCON|IEC_COT_PN;
  2517. break;
  2518. case YP_EXE_RETURN:
  2519. pdi = 0x00;
  2520. cot = IEC_COT_ACTCON;
  2521. break;
  2522. case YP_EXE_FAULT:
  2523. pdi = 0x00;
  2524. cot = IEC_COT_ACTCON|IEC_COT_PN;
  2525. break;
  2526. case YP_CANCEL_RETURN:
  2527. pdi = 0x40;
  2528. cot = IEC_COT_DEACTCON;
  2529. break;
  2530. case YP_CANCEL_FAULT:
  2531. pdi = 0x40;
  2532. cot = IEC_COT_DEACTCON|IEC_COT_PN;
  2533. break;
  2534. default:
  2535. break;
  2536. }
  2537. pd[num++]=(u8)m_runsection; //当前定值区
  2538. pd[num++]=(u8)(m_runsection>>8); //当前定值区
  2539. pd[num++] = pdi; /*特征符*/
  2540. //print_msg_base(ypara_msg);
  2541. for(i=0;i<ypara_msg->num;i++)
  2542. {
  2543. index = get_index_link(msg_data->sport,ypara_msg->base_data[i].cp_s);
  2544. if(index < 0) continue;
  2545. pd[num++]=(u8)tParaID[index].parId;
  2546. pd[num++]=(u8)(tParaID[index].parId>>8);
  2547. pd[num++]=ypara_msg->base_data[i].val_iec.tag;
  2548. pd[num++]=ypara_msg->base_data[i].val_iec.size;
  2549. if(ypara_msg->base_data[i].val_iec.size >0)
  2550. {
  2551. memcpy(&pd[num],ypara_msg->base_data[i].val_iec.value,ypara_msg->base_data[i].val_iec.size);
  2552. num += ypara_msg->base_data[i].val_iec.size;
  2553. }
  2554. vsq++;
  2555. }
  2556. IEC101_Asdu_Add(pt101,pd,num,vsq,cot,ti,FRAME_I);
  2557. }
  2558. }
  2559. void IEC101_Rmt_msg_ypara_write(IEC101_DEF *pt,BYTE *pdat,BYTE vsq,u8 link_cp)
  2560. {
  2561. WORD section=0;
  2562. BYTE *ps=0; //从点号开始
  2563. int i,j=0;
  2564. u16 di = 0;
  2565. msg_data_struct *msg_data;
  2566. msg_ypara_data_struct *msg;
  2567. iec_val_struct v;
  2568. BYTE pdi; //参数特征标识符
  2569. msg_data = &pt->msg_ypara_send;
  2570. msg = &pt->msg_ypara_send.ypara_msg;
  2571. memset(msg,0,sizeof(msg_ypara_data_struct));
  2572. pt->msg_ypara_send.dport = link_cp;
  2573. pt->msg_ypara_send.sport = pt->chnl;
  2574. pt->msg_ypara_send.flag = 1;
  2575. section=pdat[0]+(pdat[1]<<8); // 定值区号
  2576. pdi = pdat[2];
  2577. msg->section_p = section; //定值区
  2578. if((pdi&0xc0)==0) // 定值固化
  2579. {
  2580. msg->cmd = YP_EXE;
  2581. }
  2582. else if((pdi&0xc0)==0x40) /*撤销*/
  2583. {
  2584. msg->cmd = YP_CANCEL;
  2585. }
  2586. else // 参数预置
  2587. {
  2588. msg->cmd = YP_SEL;
  2589. ps=&pdat[3];
  2590. for(i=0;i<vsq;i++)
  2591. {
  2592. di=ps[0]+(ps[1]<<8);
  2593. ps += 2;
  2594. v.tag = *ps++;
  2595. v.size = *ps++;
  2596. memcpy(v.value,ps,v.size);
  2597. ps += v.size;
  2598. for(j=0;j<ParaIDNum;j++)
  2599. {
  2600. if(tParaID[j].link_ch == 0) continue;
  2601. if(di != tParaID[j].parId) continue;
  2602. msg->base_data[msg->num].cp_m = tParaID[j].parId;
  2603. msg->base_data[msg->num].cp_s = tParaID[j].link_cp;
  2604. msg->base_data[msg->num].val_iec = v;
  2605. msg->num++;
  2606. break;
  2607. }
  2608. }
  2609. }
  2610. msg_data->type = modify_set;
  2611. msg_data->sport = pt->chnl;
  2612. msg_data->dport = link_cp;
  2613. mananger_msg_ypara_s(msg_data,msg_data->sport,msg_data->dport);
  2614. pt->us0_msg_ypara = ustimer_get_origin();
  2615. }
  2616. #endif
  2617. int IEC101_TransFile(IEC101_DEF *pt,unsigned char *buf,int len);
  2618. int IEC101_Maintain(IEC101_DEF *pt,unsigned char *buf,int len);
  2619. #ifdef RCD_STRAN_S
  2620. static void IEC101_Rcd_Ack(IEC101_DEF *pt101) //发送新录波文件名
  2621. {
  2622. u8 *pd;
  2623. int num;
  2624. u8 rcd_num=0;
  2625. char tmp[128]={0};
  2626. char note[100];
  2627. //组织报文
  2628. pd=g_arrIECBuf;
  2629. num=0;
  2630. if(get_queue_count(&pt101->rcd_qt.queue) >0) /*有新录波*/
  2631. {
  2632. check_data_queque(&pt101->rcd_qt.queue,tmp);
  2633. sprintf(note, "%s----------准备\r\n",tmp);
  2634. log_str_time(LOG_OPERATE,note,0,1);
  2635. pd[num++]=0; //信息体地址
  2636. pd[num++]=0;
  2637. pd[num++]=1; /*文件数量*/
  2638. pd[num++]=strlen(tmp); /*文件名长度*/
  2639. memcpy(&pd[num],tmp,strlen(tmp));
  2640. num += strlen(tmp);
  2641. }
  2642. else
  2643. {
  2644. pd[num++]=0; //信息体地址
  2645. pd[num++]=0; //
  2646. pd[num++]=rcd_num;
  2647. }
  2648. IEC101_Asdu_Add(pt101,g_arrIECBuf,num,1,7,RCD_TYPE,FRAME_I|FRAME_I_PRIOR_LOW);//
  2649. }
  2650. #endif
  2651. void IEC101_Applay(IEC101_DEF *pt)
  2652. {
  2653. u8 *pd;
  2654. u8 AddByte=0;
  2655. u8 CotByte=0; //传送原因双字节
  2656. u8 AppByte=0; //应用单元地址双字节
  2657. u8 ti,vsq,cot,L,*info_addr,info_len;
  2658. bool bLFrame=false; //短帧标志
  2659. #ifdef FUNC_ENCRY_IN_ONE_SERIAL
  2660. if(tRunPara.tUartPara[0].wProtocol == PROTOCOL_WED_ENC)
  2661. {
  2662. if((pt->chnl != 1) && (pt->chnl != 3) && (pt->chnl != 4)) //投入海南加密时,固定串口2、4、5用于加密数据处理,不允许接收串口数据
  2663. {
  2664. // 接收报文
  2665. IEC101_Recv_App(pt);
  2666. if(pt->chnl == 0)
  2667. {
  2668. return;
  2669. }
  2670. }
  2671. }
  2672. else
  2673. #endif
  2674. {
  2675. // 接收报文
  2676. IEC101_Recv_App(pt);
  2677. }
  2678. #ifdef IEC_NOLINK_NO_CALLYX
  2679. if(g_link_comm.link_flag == false) return;
  2680. #endif
  2681. // 主动SOE处理,放在报文处理之前,使时间同步报文之前的SOE报文在时间报文应答前发送
  2682. IEC101_SendEvent(pt,tRunPara.bAutoCos);
  2683. // 处理级联遥控
  2684. IEC101_lnk_yk(pt);
  2685. // 处理级联遥参
  2686. IEC101_link_par(pt);
  2687. #ifdef YPARA_LINK
  2688. IEC101_lnk_msg_ypara(pt);
  2689. #endif
  2690. // 处理接收的加密报文
  2691. // 先处理加密报文,再处理普通报文,保证同一报文一个循环处理完
  2692. if(pt->bSM2Data)
  2693. {
  2694. if(pRunSet->bTT_SM2) //加密功能投入
  2695. {
  2696. #ifdef ENCRYPT_SM2
  2697. IEC101_SM2(pt);
  2698. #endif
  2699. }
  2700. pt->bSM2Data=false;
  2701. }
  2702. // 处理接收的普通报文
  2703. else if(pt->bData)
  2704. {
  2705. // 如果从动站buf有数据,说明至少有2帧报文还没有发送完,
  2706. // 在gprs网络,同时收到多帧报文后连续应答处理时会出现这种情况。
  2707. // 为了保证过程的完整性,待数据发送完后再处理接收的报文。
  2708. if(pt->btx_buf_s)
  2709. {
  2710. return;
  2711. }
  2712. // 报文长度调整变量赋值
  2713. if(tRunPara.b101Addr2Byte) AddByte=1;
  2714. if(tRunPara.b101Cot2Byte) CotByte=1;
  2715. if(tRunPara.b101App2Byte) AppByte=1;
  2716. // 打印接收的报文
  2717. if(g_print_101 && (g_print_port & (1<<pt->chnl)))
  2718. {
  2719. if(pt->recvbuf[0]==0x10)
  2720. {
  2721. rt_printf("RX_S101_%d:", pt->chnl);
  2722. print_msg("",pt->recvbuf,(5+AddByte));
  2723. }
  2724. else
  2725. {
  2726. rt_printf("RX_L101_%d:", pt->chnl);
  2727. print_msg("",pt->recvbuf,pt->recvbuf[1]+6);
  2728. }
  2729. }
  2730. // 由于101在本函数开始处接收数据,所以可以在此处复位接收标志
  2731. pt->bData=false;
  2732. // 检查帧标志并跳过固定报文头
  2733. if(pt->recvbuf[0]==0x10)
  2734. {
  2735. pd=&pt->recvbuf[1];//短帧
  2736. L = 2;
  2737. }
  2738. else if(pt->recvbuf[0]==0x68)
  2739. {
  2740. pd=&pt->recvbuf[4];//长帧
  2741. L = pt->recvbuf[1];
  2742. bLFrame=true;
  2743. }
  2744. else
  2745. {
  2746. return;
  2747. }
  2748. // 检查是否是GPRS维护信息
  2749. if(pd[0]==0x05)
  2750. {
  2751. memcpy(tGprsInf.data,&pd[1],64);
  2752. tGprsInf.bInf=true;
  2753. return;
  2754. }
  2755. // 检查地址
  2756. if(tRunPara.b101Addr2Byte) //双字节地址
  2757. {
  2758. WORD addr;
  2759. addr=pd[1]+(pd[2]<<8);
  2760. if(addr!=tRunPara.byAddr && addr!=0xffff)
  2761. return; //不是发给本装置的数据
  2762. }
  2763. else
  2764. {
  2765. if(pd[1]!=(u8)tRunPara.byAddr && pd[1]!=0xff)
  2766. return; //不是发给本装置的数据
  2767. }
  2768. // 通道空闲时间复位
  2769. pt->dValidTime=0;
  2770. // 私有101文件传输协议
  2771. if ((((pd[0]&0x0f) == 3) || ((pd[0]&0x0f) == 4))
  2772. && (pd[2+AddByte] ==137))
  2773. {
  2774. IEC101_TransFile(pt,&pd[2+AddByte],pt->recvbuf[1]-(2+AddByte));
  2775. pt->btx_buf_s = true;
  2776. return;
  2777. }
  2778. // 私有维护工具软件接口
  2779. if ((((pd[0]&0x0f) == 3) || ((pd[0]&0x0f) == 4))
  2780. && (pd[2+AddByte] ==138))
  2781. {
  2782. IEC101_Maintain(pt,&pd[2+AddByte],pt->recvbuf[1]-(2+AddByte));
  2783. pt->btx_buf_s = true;
  2784. return;
  2785. }
  2786. //主站主动发送数据PRM=1 master
  2787. if(pd[0]&0x40)
  2788. {
  2789. if(pd[0]&0x80)
  2790. {
  2791. pt->bDIR=true;
  2792. }
  2793. else
  2794. {
  2795. pt->bDIR=false;
  2796. }
  2797. // 非重复报文
  2798. if(!pRunSet->bTT_101FCB
  2799. ||(((pd[0]&0x10)&&pt->FCBSave!=(pd[0]&0x20)) // FCV位有效,FCB位变位
  2800. || (!(pd[0]&0x10)) // FCV位无效
  2801. || pt->bFirstFCV) ) // 该标志有效,不判断FCB位
  2802. {
  2803. //FCB位
  2804. if(pd[0]&0x10)
  2805. {
  2806. // 如果不是第一个FCB位且和以前FCB不同,确认发送BUF
  2807. if((pt->bFirstFCV == 0) && (pt->FCBSave != (pd[0]&0x20)))
  2808. {
  2809. IEC101_AckOneBuf(pt);
  2810. }
  2811. pt->FCBSave=pd[0]&0x20; // 保存帧记数位
  2812. pt->bFirstFCV = 0; // 如果FCV位有效,标志清0
  2813. }
  2814. switch((pd[0]&0x0f))
  2815. {
  2816. // 只有非平衡101才会请求一二级数据
  2817. case 10: //请求/响应(一级数据)
  2818. case 11: //请求/响应(二级数据)
  2819. // 如果不是数据状态,不应收到2、3、4、10、11,不进行任何应答,让主站超时复位
  2820. if(pt->st101!=IEC101_ST_DATA)
  2821. {
  2822. return;
  2823. }
  2824. if(!IEC101_SendOneBuf(pt))
  2825. {
  2826. if(pt->tfile.bSegtransing) // 文件传输,放入一级数据缓冲区
  2827. {
  2828. IEC101_SegmentContinue(pt);
  2829. }
  2830. else if(pt->tf.bTransing)
  2831. {
  2832. iec_readfile_send(pt,false);
  2833. }
  2834. if(!IEC101_SendOneBuf(pt))
  2835. {
  2836. pt->bycsend = IEC101_GetYc(pt);
  2837. if(!pt->bycsend) // add by sunxi
  2838. {
  2839. IEC101_FrameEcho(pt,IEC101_ECHO_NO_DATA);
  2840. }
  2841. }
  2842. }
  2843. break;
  2844. case 9: // 请求链路状态
  2845. IEC101_FrameEcho(pt,IEC101_ECHO_LINK_OK);
  2846. break;
  2847. case 3: //请求/确认
  2848. case 4: //请求/无应答
  2849. // 如果不是数据状态,不应收到2、3、4、10、11,不进行任何应答,让主站超时复位
  2850. // 如果是复位进程状态,不应答主站发送应用层报文
  2851. if(pt->st101!=IEC101_ST_DATA || pt->bResetProcess)
  2852. {
  2853. return;
  2854. }
  2855. ti = pd[2+AddByte];
  2856. vsq = pd[3+AddByte];
  2857. cot = pd[4+AddByte];
  2858. info_addr = pt->recvbuf + IEC101_InfoAddr();
  2859. info_len = L + 4 - IEC101_InfoAddr();
  2860. switch(ti) //类型标识判断
  2861. {
  2862. case 250: // 级联报文数据上送
  2863. IEC101_LinkInf(pt);
  2864. break;
  2865. case 106:
  2866. if(cot == 6) //延时获得
  2867. {
  2868. // 此处不修改报文,真正发送的时候再计算修改
  2869. IEC101_Asdu_Add(pt,info_addr,info_len,vsq,IEC_COT_ACTCON,ti,FRAME_I| FRAME_I_106);
  2870. }
  2871. else if(cot == 3) //延时传递
  2872. {
  2873. // 保存主站下发的传输延时
  2874. pt->ms_delay = info_addr[2] + (info_addr[3]<<8);
  2875. }
  2876. else
  2877. {
  2878. IEC101_Asdu_Add(pt,info_addr,info_len,vsq,IEC_COT_UN_COT|IEC_COT_PN,ti,FRAME_I);
  2879. }
  2880. IEC101_FrameEcho(pt,IEC101_ECHO_SURE); //链路应答确认
  2881. break;
  2882. case 103://0xFF: //set time ,BroadCast Command
  2883. // 检查COT
  2884. if(cot == IEC_COT_REQ||cot == IEC_COT_ACT)
  2885. {
  2886. IEC101_TimeSetEcho(pt,&pd[8+AddByte+AppByte+CotByte],cot);// Addbyte 链路地址和应用单元地址多了2个字节,传送原因多1个字节
  2887. }
  2888. else
  2889. {
  2890. IEC101_Asdu_Add(pt,info_addr,info_len,vsq,IEC_COT_UN_COT|IEC_COT_PN,ti,FRAME_I);
  2891. }
  2892. pt->bTimeSyn= true;
  2893. IEC101_FrameEcho(pt,IEC101_ECHO_SURE); //链路应答确认
  2894. break;
  2895. case 100: //总查询
  2896. // 检查COT
  2897. if(cot != IEC_COT_ACT)
  2898. {
  2899. IEC101_Asdu_Add(pt,info_addr,info_len,vsq,IEC_COT_UN_COT|IEC_COT_PN,ti,FRAME_I);
  2900. }
  2901. else
  2902. {
  2903. IEC101_CallAll(pt,pd[8+AddByte+AppByte+CotByte]);// Addbyte 链路地址和应用单元地址多了2个字节,传送原因多1个字节
  2904. lnk_call_all();
  2905. }
  2906. IEC101_FrameEcho(pt,IEC101_ECHO_SURE); //链路应答确认
  2907. break;
  2908. case 101: //电度总召
  2909. // 检查COT
  2910. if(cot != IEC_COT_ACT)
  2911. {
  2912. IEC101_Asdu_Add(pt,info_addr,info_len,vsq,IEC_COT_UN_COT|IEC_COT_PN,ti,FRAME_I);
  2913. }
  2914. else
  2915. {
  2916. IEC101_DDAll(pt,pd[8+AddByte+AppByte+CotByte]);// Addbyte 链路地址和应用单元地址多了2个字节,传送原因多1个字节
  2917. }
  2918. IEC101_FrameEcho(pt,IEC101_ECHO_SURE); //链路应答确认
  2919. break;
  2920. case 104: //测试帧
  2921. IEC101_TestFrame(pt,&pd[8+AddByte+AppByte+CotByte]);
  2922. IEC101_FrameEcho(pt,IEC101_ECHO_SURE);
  2923. break;
  2924. case 105:
  2925. // 检查COT
  2926. if(cot != IEC_COT_ACT)
  2927. {
  2928. IEC101_Asdu_Add(pt,info_addr,info_len,vsq,IEC_COT_UN_COT|IEC_COT_PN,ti,FRAME_I);
  2929. }
  2930. else
  2931. {
  2932. u8 qrp;
  2933. qrp = pd[8+AddByte+AppByte+CotByte];
  2934. #ifdef FUNC_RESET_EQU
  2935. gb_ResetEqu = true;
  2936. #endif
  2937. switch(qrp)//复位进程命令限定词 QRP
  2938. {
  2939. //进程的总复位
  2940. case 1:
  2941. rt_printf_time("IEC101(%d) Reset: 进程的总复位!\r\n",pt->chnl);
  2942. IEC101_ResetTxBuf(pt);
  2943. // 记录复位计时起点和设置复位进程标志
  2944. pt->us0_ResetProcess = ustimer_get_origin();
  2945. pt->bResetProcess = true;
  2946. break;
  2947. //复位事件缓冲区等待处理的带时标信息
  2948. case 2:
  2949. rt_printf_time("IEC101(%d) Reset: 复位事件缓冲区!\r\n",pt->chnl);
  2950. g_soe_queue.tail_send[pt->chnl].n = g_soe_queue.head.n;
  2951. g_soe_queue.tail_ack[pt->chnl].n = g_soe_queue.tail_send[pt->chnl].n;
  2952. break;
  2953. }
  2954. IEC101_ResetProcess(pt,qrp);
  2955. }
  2956. IEC101_FrameEcho(pt,IEC101_ECHO_SURE);
  2957. break;
  2958. case 45: //单点遥控
  2959. case 46: //双点遥控
  2960. // 检查单双点是否和参数设置相符
  2961. if((ti == 45 && tRunPara.YKtype == 1) || (ti == 46 && tRunPara.YKtype == 0) )
  2962. {
  2963. // 对不支持的类型标识,否定应答
  2964. IEC101_FrameEcho(pt,IEC101_ECHO_DENY);
  2965. rt_printf("101遥控类型不符(ti=%d,YKtype=%d)\r\n",ti,tRunPara.YKtype);
  2966. break;
  2967. }
  2968. // 检查COT
  2969. if(cot != IEC_COT_ACT && cot != IEC_COT_DEACT)
  2970. {
  2971. IEC101_Asdu_Add(pt,info_addr,info_len,vsq,IEC_COT_UN_COT|IEC_COT_PN,ti,FRAME_I|FRAME_I_PRIOR_HIGH);
  2972. }
  2973. else
  2974. {
  2975. IEC101_RmtCtrl(pt, &pd[2+AddByte]);
  2976. }
  2977. IEC101_FrameEcho(pt,IEC101_ECHO_SURE); //链路应答确认
  2978. break;
  2979. case 122: //召目录,选择文件,召唤文件,召唤节
  2980. IEC101_File_Echo(pt,&pd[2+AddByte]); //响应文件召唤
  2981. IEC101_FrameEcho(pt,IEC101_ECHO_SURE); //链路应答确认
  2982. break;
  2983. case 124: //确认文件,确认节的应答
  2984. IEC101_File_Sure(pt,&pd[2+AddByte]); //对文件操作确认
  2985. IEC101_FrameEcho(pt,IEC101_ECHO_SURE); //链路应答确认
  2986. break;
  2987. case 176: // 本装置复归
  2988. ResetHzLed(0);
  2989. SignalReset(0,false);
  2990. IEC101_FrameEcho(pt,IEC101_ECHO_SURE); //链路应答确认
  2991. break;
  2992. #ifdef RCD_STRAN_S
  2993. case RCD_TYPE: // 本装置复归
  2994. IEC101_Rcd_Ack(pt);
  2995. IEC101_FrameEcho(pt,IEC101_ECHO_SURE); //链路应答确认
  2996. break;
  2997. #endif
  2998. case 200: // 切换定值区
  2999. if(cot == IEC_COT_ACT)
  3000. {
  3001. IEC101_SectionWrite(pt,&pd[8+AddByte+AppByte+CotByte]);// Addbyte 链路地址和应用单元地址多了2个字节,传送原因多1个字节
  3002. }
  3003. else
  3004. {
  3005. IEC101_Asdu_Add(pt,info_addr,info_len,vsq,IEC_COT_UN_COT|IEC_COT_PN,ti,FRAME_I);
  3006. }
  3007. IEC101_FrameEcho(pt,IEC101_ECHO_SURE); //链路应答确认
  3008. break;
  3009. case 201: // 读取当前定值区号
  3010. if(cot == IEC_COT_ACT)
  3011. {
  3012. IEC101_SectionRead(pt);// Addbyte 链路地址和应用单元地址多了2个字节,传送原因多1个字节
  3013. }
  3014. else
  3015. {
  3016. IEC101_Asdu_Add(pt,info_addr,info_len,vsq,IEC_COT_UN_COT|IEC_COT_PN,ti,FRAME_I);
  3017. }
  3018. IEC101_FrameEcho(pt,IEC101_ECHO_SURE); //链路应答确认
  3019. break;
  3020. break;
  3021. case FOS_PAR_READ_ONE://南网佛山局 读取单个参数
  3022. case FOS_PAR_READ_MUL://南网 读取多个参数
  3023. case FOS_PAR_SET_ONE: //南网佛山局 设置单个参数
  3024. case FOS_PAR_SET_MUL://南网 设置多数参数
  3025. // 检查COT
  3026. if(cot != IEC_COT_ACT && cot != IEC_COT_DEACT)
  3027. {
  3028. IEC101_Asdu_Add(pt,info_addr,info_len,vsq,IEC_COT_UN_COT|IEC_COT_PN,ti,FRAME_I);
  3029. }
  3030. else
  3031. {
  3032. IEC101_ParCtrl(pt, &pd[2+AddByte]);
  3033. }
  3034. IEC101_FrameEcho(pt,IEC101_ECHO_SURE); //链路应答确认
  3035. break;
  3036. case 202: // 读参数
  3037. if(cot == IEC_COT_ACT)
  3038. {
  3039. int ret;
  3040. #ifdef YPARA_LINK
  3041. ret=iec_setread_mananger((void*)pt,&pd[6+AddByte+AppByte+CotByte],vsq,false);
  3042. #else
  3043. ret=iec_setread((void*)pt,&pd[6+AddByte+AppByte+CotByte],vsq,false);//vsq为需读参数的个数,0,代表读全部参数,参数为从定值区开始的数据
  3044. #endif
  3045. if(ret!=0) // 读定值出错,否定应答
  3046. {
  3047. IEC101_Asdu_Add(pt,info_addr,info_len,vsq,IEC_COT_UN_OA,ti,FRAME_I);
  3048. }
  3049. }
  3050. else
  3051. {
  3052. IEC101_Asdu_Add(pt,info_addr,info_len,vsq,IEC_COT_UN_COT|IEC_COT_PN,ti,FRAME_I);
  3053. }
  3054. IEC101_FrameEcho(pt,IEC101_ECHO_SURE); //链路应答确认
  3055. break;
  3056. case 203: // 修改参数
  3057. if(cot == IEC_COT_ACT||cot==IEC_COT_DEACT)
  3058. {
  3059. int ret;
  3060. #ifdef YPARA_LINK
  3061. int link_ch;
  3062. link_ch = get_ypara_linkch_write((void*)pt,&pd[6+AddByte+AppByte+CotByte],vsq,false);
  3063. if(link_ch == 0)
  3064. {
  3065. rt_printf("101------写本地定值\r\n");
  3066. ret=iec_setwrite((void*)pt,&pd[6+AddByte+AppByte+CotByte],cot,vsq,false);//vsq为需读参数的个数,0,代表固化参数,参数为从定值区开始的数据
  3067. if(ret!=0) // 写定值出错,否定应答
  3068. {
  3069. BYTE rcot=IEC_COT_ACTCON|IEC_COT_PN;
  3070. if(cot==IEC_COT_DEACT)rcot=IEC_COT_DEACTCON|IEC_COT_PN;
  3071. IEC101_Asdu_Add(pt,info_addr,info_len,vsq,rcot,ti,FRAME_I);
  3072. }
  3073. else
  3074. {
  3075. BYTE rcot=IEC_COT_ACTCON;
  3076. if(cot==IEC_COT_DEACT)rcot=IEC_COT_DEACTCON;
  3077. IEC101_Asdu_Add(pt,info_addr,info_len,vsq,rcot,ti,FRAME_I);
  3078. }
  3079. }
  3080. else
  3081. {
  3082. rt_printf("101------写级联定值\r\n");
  3083. IEC101_Rmt_msg_ypara_write((void*)pt,&pd[6+AddByte+AppByte+CotByte],vsq,link_ch);
  3084. if((link_ch&0x1f) == 0x1f) /*广播写直接返回确认*/
  3085. {
  3086. BYTE rcot= IEC_COT_ACTCON;
  3087. if(cot==IEC_COT_DEACT)rcot=IEC_COT_DEACTCON;
  3088. IEC101_Asdu_Add(pt,info_addr,info_len,vsq,rcot,ti,FRAME_I);
  3089. }
  3090. }
  3091. #else
  3092. ret=iec_setwrite((void*)pt,&pd[6+AddByte+AppByte+CotByte],cot,vsq,false);//vsq为需读参数的个数,0,代表固化参数,参数为从定值区开始的数据
  3093. if(ret!=0) // 写定值出错,否定应答
  3094. {
  3095. BYTE rcot=IEC_COT_ACTCON|IEC_COT_PN;
  3096. if(cot==IEC_COT_DEACT)rcot=IEC_COT_DEACTCON|IEC_COT_PN;
  3097. IEC101_Asdu_Add(pt,info_addr,info_len,vsq,rcot,ti,FRAME_I);
  3098. }
  3099. else
  3100. {
  3101. BYTE rcot=IEC_COT_ACTCON;
  3102. if(cot==IEC_COT_DEACT)rcot=IEC_COT_DEACTCON;
  3103. IEC101_Asdu_Add(pt,info_addr,info_len,vsq,rcot,ti,FRAME_I);
  3104. }
  3105. #endif
  3106. }
  3107. else
  3108. {
  3109. IEC101_Asdu_Add(pt,info_addr,info_len,vsq,IEC_COT_UN_COT|IEC_COT_PN,ti,FRAME_I);
  3110. }
  3111. IEC101_FrameEcho(pt,IEC101_ECHO_SURE); //链路应答确认
  3112. break;
  3113. case 210: // 文件传输
  3114. {
  3115. pt->tf.vsq=vsq;
  3116. if(cot == IEC_COT_ACT||cot == IEC_COT_REQ)
  3117. { int ret;
  3118. ret=iec_file_app((void*)pt,&pt->recvbuf[12+AddByte+AppByte+CotByte],cot,pt->recvbuf[1]-(AddByte+CotByte+AppByte)-9,false);// 从操作标识开始
  3119. if(ret!=0) // 文件处理错误
  3120. {
  3121. BYTE rcot=IEC_COT_UN_OA;
  3122. if(ret==-2)rcot=IEC_COT_UN_COT;
  3123. IEC101_Asdu_Add(pt,info_addr,info_len,vsq,rcot,ti,FRAME_I);
  3124. }
  3125. }
  3126. else
  3127. {
  3128. IEC101_Asdu_Add(pt,info_addr,info_len,vsq,IEC_COT_UN_COT|IEC_COT_PN,ti,FRAME_I);
  3129. }
  3130. IEC101_FrameEcho(pt,IEC101_ECHO_SURE); //链路应答确认
  3131. }
  3132. break;
  3133. case 211: // 文件升级
  3134. {
  3135. if(cot == IEC_COT_ACT||cot == IEC_COT_DEACT)
  3136. { int ret;
  3137. ret=iec_pro_update((void*)pt,cot,pd[8+AddByte+CotByte+AppByte],false);// 从操作标识开始
  3138. if(ret!=0) // 文件处理错误
  3139. {
  3140. BYTE rcot=IEC_COT_UN_OA;
  3141. IEC101_Asdu_Add(pt,info_addr,info_len,vsq,rcot,ti,FRAME_I);
  3142. }
  3143. }
  3144. else
  3145. {
  3146. IEC101_Asdu_Add(pt,info_addr,info_len,vsq,IEC_COT_UN_COT|IEC_COT_PN,ti,FRAME_I);
  3147. }
  3148. IEC101_FrameEcho(pt,IEC101_ECHO_SURE); //链路应答确认
  3149. }
  3150. break;
  3151. default:
  3152. IEC101_FrameEcho(pt,IEC101_ECHO_DENY);
  3153. break;
  3154. }
  3155. break;
  3156. case 0: //复位通信单元
  3157. // 复位通道
  3158. IEC101_Reset(pt);
  3159. if(pd[0]&0x80) // add by sunxi 防止IEC101_Reset调用后,bDIR变为默认值,后续发送报文,标示出错
  3160. {
  3161. pt->bDIR=true;
  3162. }
  3163. else
  3164. {
  3165. pt->bDIR=false;
  3166. }
  3167. g_comm_link_status |= (1<<pt->chnl);
  3168. IEC101_State(pt,tRunPara.tUartPara[pt->chnl].b101PH ? IEC101_ST_LINK : IEC101_ST_DATA);
  3169. pt->LinkCount++;
  3170. // 应答报文
  3171. IEC101_InitOK(pt);
  3172. IEC101_FrameEcho(pt,IEC101_ECHO_SURE);
  3173. // "重新连接后,总召前,发送完所有老的SOE,不发送COS"
  3174. IEC101_SendEvent(pt,0);
  3175. break;
  3176. case 2: //链路测试功能
  3177. // 如果不是数据状态,不应收到2、3、4、10、11,不进行任何应答,让主站超时复位
  3178. if(pt->st101!=IEC101_ST_DATA)
  3179. {
  3180. return;
  3181. }
  3182. // 南瑞主站,功能码是2,发送长帧测试帧
  3183. if(bLFrame)
  3184. {
  3185. ti = pd[2+AddByte];
  3186. if(ti==104)
  3187. {
  3188. IEC101_TestFrame(pt,&pd[8+AddByte+AppByte+CotByte]);
  3189. }
  3190. }
  3191. IEC101_FrameEcho(pt,IEC101_ECHO_SURE);
  3192. break;
  3193. default:
  3194. IEC101_FrameEcho(pt,IEC101_ECHO_DENY);
  3195. break;
  3196. } //类型判断结束
  3197. // 广播地址不用应答
  3198. if( (pd[1]!=0xff)
  3199. || (tRunPara.b101Addr2Byte && (pd[2]!=0xff))
  3200. // 平衡101广播查询链路状态回本机地址,江西吉安博威主站要求
  3201. || (tRunPara.tUartPara[pt->chnl].b101PH && (pd[0]&0x0f) == 9))
  3202. {
  3203. pt->btx_buf_s = true;
  3204. }
  3205. }
  3206. // FCV位有效,FCB没有变位,重发保存的确认帧。
  3207. else
  3208. {
  3209. //重发数据
  3210. if(pt->st101 == IEC101_ST_DATA)
  3211. {
  3212. if(pt->btx_buf_s)
  3213. {
  3214. rt_printf_time("IEC101_Applay:,btx_buf_s==1.\r\n");
  3215. }
  3216. pt->btx_buf_s = true;
  3217. }
  3218. }
  3219. }
  3220. //平衡101 ,接收到主站回复的数据
  3221. else
  3222. {
  3223. if(!tRunPara.tUartPara[pt->chnl].b101PH)
  3224. return;
  3225. switch(pt->st101)
  3226. {
  3227. case IEC101_ST_LINK:
  3228. {
  3229. if((pd[0]&0x0f)==11) //应答链路状态
  3230. {
  3231. IEC101_State(pt,IEC101_ST_RSTLINK);
  3232. pt->bMSend=false;
  3233. }
  3234. break;
  3235. }
  3236. case IEC101_ST_RSTLINK:
  3237. {
  3238. if((pd[0]&0x0f)==0) //应答链路状态
  3239. {
  3240. IEC101_State(pt,IEC101_ST_DATA);
  3241. pt->bMSend=false;
  3242. }
  3243. break;
  3244. }
  3245. case IEC101_ST_DATA:
  3246. {
  3247. if((pd[0]&0x0f)==0) // 确认应答,调整一级数据缓冲区
  3248. {
  3249. IEC101_AckOneBuf(pt);
  3250. pt->bMSend=false;
  3251. }
  3252. break;
  3253. }
  3254. }
  3255. }
  3256. }
  3257. // 获取GPRS信息
  3258. else if(pt->bCallGprsInf)
  3259. {
  3260. if(g_tRsComm[pt->chnl].bextsend|| pt->btx_buf_s|| pt->btx_buf_m)
  3261. return; //正在发送数据,不处理
  3262. pt->bCallGprsInf=false;
  3263. IEC101_CallGprsInf(pt);
  3264. pt->btx_buf_s = true;
  3265. }
  3266. //无有效数据接收,平衡式101处理自动发送数据
  3267. else
  3268. {
  3269. if(!tRunPara.tUartPara[pt->chnl].b101PH)return;
  3270. //如果启动了主站发送,必须先处理应答
  3271. if(pt->bMSend)
  3272. {
  3273. bool bRtn=true;
  3274. // 20秒后,未收到应答报文
  3275. if(ustimer_get_duration(pt->us0_msend) > pRunSet->dT101Resend*USTIMER_SEC)
  3276. {
  3277. pt->us0_msend=ustimer_get_origin();
  3278. if(++pt->msend_retries>2) //重发三次后,重新初始化
  3279. {
  3280. //rt_printf_time("IEC101(%d):启动帧重发错误!\r\n",pt->chnl);
  3281. char log_info[128];
  3282. sprintf(log_info,"IEC101(%d):Restart the frame to make three errors",pt->chnl+1);
  3283. load_hs_log_rcd(TYPE_COMM_ERR,true,NULL,log_info,1);
  3284. log_flag.com_err[pt->chnl] = true;
  3285. IEC101_Info_Printf_One(pt);
  3286. IEC101_Reset(pt);
  3287. }
  3288. else
  3289. {
  3290. //需重新组织发送
  3291. pt->btx_buf_m = true;
  3292. }
  3293. return;
  3294. }
  3295. #ifdef COMM_STATION_NR
  3296. if(pt->tx_buf[0].tb_head!=pt->tx_buf[0].tb_tail_send) //有遥控报文要发送
  3297. {
  3298. if(ustimer_get_duration(pt->us0_msend) > 2*USTIMER_SEC) //且上帧报文发送超过2秒,不等待应道报文,直接发送
  3299. {
  3300. IEC101_AckOneBuf(pt);
  3301. pt->bMSend=false;
  3302. bRtn=false;
  3303. }
  3304. }
  3305. if(pt->bTestFrameL||pt->bSoeResume||pt->bTimeSyn)//总召前有SOE续传不需要主站确认
  3306. {
  3307. pt->bTestFrameL = false;
  3308. pt->bSoeResume = false;
  3309. pt->bTimeSyn =false;
  3310. IEC101_AckOneBuf(pt);
  3311. pt->bMSend=false;
  3312. bRtn=false;
  3313. }
  3314. #endif
  3315. if(bRtn)
  3316. {
  3317. return; // 发送,未收到数据,返回
  3318. }
  3319. }
  3320. // 平衡101应答完成
  3321. // 先复位应答相关变量
  3322. pt->msend_retries=0;
  3323. pt->us0_msend=ustimer_get_origin();
  3324. // 开始主动发送流程
  3325. switch(pt->st101)
  3326. {
  3327. case IEC101_ST_LINK:
  3328. {
  3329. IEC101_MFrameCall(pt,IEC101_CALL_LINK);
  3330. pt->bMFCB=false;
  3331. pt->bMSend=true;
  3332. break;
  3333. }
  3334. case IEC101_ST_RSTLINK:
  3335. {
  3336. IEC101_MFrameCall(pt,IEC101_CALL_RSTLINK);
  3337. pt->bMFCB=false;
  3338. pt->bMSend=true;
  3339. break;
  3340. }
  3341. case IEC101_ST_DATA:
  3342. {
  3343. pt->bMSend=IEC101_SendOneBuf(pt);
  3344. if(!pt->bMSend) // 无数据 判断
  3345. {
  3346. if(pt->tfile.bSegtransing) // 文件传输,放入一级数据缓冲区
  3347. {
  3348. IEC101_SegmentContinue(pt);
  3349. }
  3350. else if(pt->tf.bTransing) // 国网新标准文件传输
  3351. {
  3352. iec_readfile_send(pt,false);
  3353. }
  3354. else
  3355. {
  3356. pt->bycsend=IEC101_GetYc(pt);
  3357. if (pt->bycsend)pt->bMSend = TRUE;
  3358. }
  3359. }
  3360. break;
  3361. }
  3362. }
  3363. //有数据要发送
  3364. if(pt->bMSend)
  3365. {
  3366. if(pt->btx_buf_m)
  3367. {
  3368. //rt_printf_time("IEC101_Applay:bMSend==1,btx_buf_m==1.\r\n");
  3369. }
  3370. pt->bMFCB=!pt->bMFCB;
  3371. pt->btx_buf_m = true;
  3372. }
  3373. }
  3374. }
  3375. /**************************************************************************
  3376. 函数名称:IEC101_SendEvent
  3377. 函数版本:1.00
  3378. 作者:
  3379. 创建日期:2008.9.1
  3380. 函数功能说明:上送事件记录及变位信息,在RS485定时处理任务(IEC101_AutoTimer)中调用
  3381. 输入参数:
  3382. 输出参数:
  3383. 返回值:
  3384. 更新信息:
  3385. 更新日志1:
  3386. 日期:
  3387. 修改者:
  3388. 修改内容:
  3389. 修改原因:
  3390. ***************************************************************************/
  3391. EVENT_STRUCT event_p[64];
  3392. u32 IEC101_SendEvent(IEC101_DEF *pt,int is_send_cos)
  3393. {
  3394. u8 type;
  3395. int vsq=0, num_vsp;
  3396. u8 arrCos[200],arrSoe[200];
  3397. u8 arrCos1[200],arrSoe1[200];
  3398. u16 head,cnt;
  3399. u16 soe_no_s,soe_no_d,arg_index[64];
  3400. bool bFault;
  3401. FAULT_PARA_BUF *tf=&pt->tfault;
  3402. // 主动上送条件:
  3403. // 1、是IEC101_ST_DATA状态
  3404. // 2、没有在处理加密遥控报文
  3405. // 3、不是复位进程状态
  3406. if((pt->st101 != IEC101_ST_DATA) || pt->bRmtSM2 || pt->bResetProcess)
  3407. {
  3408. return 0;
  3409. }
  3410. // 不允许通讯续传的情况下,总召后才允许上送事件
  3411. if(pt->bSendChange == 0)// && pRunSet->bTT_SoeResumeComm == 0)
  3412. {
  3413. return 0;
  3414. }
  3415. #ifdef FUN_SOE_DELAY_TIME
  3416. if((pt->bfirst_call) && (dTCounter - pt->DTSendChange <= 15*T_1s))
  3417. {
  3418. return 0;
  3419. }
  3420. pt->bfirst_call = false;
  3421. #endif
  3422. //一级缓冲区未空,不添加事件记录
  3423. if(pt->tx_buf[0].tb_head != pt->tx_buf[0].tb_tail_send)
  3424. {
  3425. //rt_printf("%s(0):tb_head=%d,tb_tail_send=%d\r\n",__func__,pt->tx_buf[0].tb_head,pt->tx_buf[0].tb_tail_send);
  3426. return 0;
  3427. }
  3428. if(pt->tx_buf[1].tb_head != pt->tx_buf[1].tb_tail_send)
  3429. {
  3430. return 0;
  3431. }
  3432. #ifndef IEC_JXYB_DEAL
  3433. if(g_run_stu.bjx) //检修压板投入,不发送变化的事件记录
  3434. {
  3435. g_soe_queue.tail_send[pt->chnl].n = g_soe_queue.tail_eep.n; //soe cos
  3436. tf->head = tf->tail;//故障参数
  3437. return 0;
  3438. }
  3439. #endif
  3440. //发送级联来的故障参数
  3441. if(tRunPara.bEvPara)
  3442. {
  3443. if(tf->head!=tf->tail)
  3444. {
  3445. u8 index=tf->tail;
  3446. IEC101_Asdu_Add_sts(pt,&tf->data[index][1],tf->data[index][0],0,3,42,FRAME_I_PRIOR_LOW ,0);
  3447. tf->tail++;
  3448. return 0;
  3449. }
  3450. }
  3451. // 等SOE保存后再发送,避免通讯确认没有保存的事件
  3452. head = g_soe_queue.tail_eep.n;
  3453. // 一次调用,将事件池中所有事件发送完,
  3454. // 已保证满足"重新连接后,总召前,发送完所有老的SOE,不发送COS"的需求。
  3455. cnt = 0;
  3456. while(1)
  3457. {
  3458. u8 yxtype=0;
  3459. u8 pcosnum=0,pcosnum1=0;
  3460. // 检查发送队列空间,空间应大于1/4,防止发送缓冲区满
  3461. if(IEC101_BufFreeNum(&pt->tx_buf[0]) < (IEC_TBUF_NUM>>2))
  3462. {
  3463. rt_printf("IEC101_SendEvent:BufFreeNum=%d.\r\n",IEC101_BufFreeNum(&pt->tx_buf[0]));
  3464. break;
  3465. }
  3466. // 获取一帧报文的事件
  3467. bFault=false;
  3468. num_vsp = asdu_get_event(pt->chnl,head,arrCos,arrSoe,arrCos1,arrSoe1,&soe_no_s,&soe_no_d,0,&bFault,&event_p[0],&arg_index[0],&yxtype,&pcosnum,&pcosnum1);
  3469. if(num_vsp==0)
  3470. break;
  3471. //rt_printf("%s:vsq_s=%d\r\n",__func__,vsq);
  3472. if(pcosnum != 0)
  3473. {
  3474. // 发送COS
  3475. if(is_send_cos&&pt->bSendChange)
  3476. {
  3477. type = 1;
  3478. IEC101_Asdu_Add(pt,arrCos,pcosnum*3,pcosnum,3,type,FRAME_I_COS);
  3479. }
  3480. }
  3481. vsq=(u8)(num_vsp&0xff);
  3482. if(vsq != 0)
  3483. {
  3484. cnt += vsq;
  3485. // 发送SOE
  3486. type = 30;
  3487. IEC101_Asdu_Add_sts(pt,arrSoe,vsq*10,vsq,3,type,FRAME_I_SOE ,soe_no_s);
  3488. }
  3489. if(pcosnum1 != 0)
  3490. {
  3491. // 发送COS
  3492. if(is_send_cos)
  3493. {
  3494. type = 3;
  3495. IEC101_Asdu_Add(pt,arrCos1,pcosnum1*3,pcosnum1,3,type,FRAME_I_COS);
  3496. }
  3497. }
  3498. vsq=(u8)((num_vsp>>8)&0xff);
  3499. //rt_printf("%s:vsq_d=%d\r\n",__func__,vsq);
  3500. if(vsq != 0)
  3501. {
  3502. cnt += vsq;
  3503. // 发送SOE
  3504. type = 31 ;
  3505. IEC101_Asdu_Add_sts(pt,arrSoe1,vsq*10,vsq,3,type,FRAME_I_SOE ,soe_no_d);
  3506. // rt_printf_time("IEC101_SendEvent:soe_no=%d.\r\n",soe_no);
  3507. }
  3508. vsq=(u8)((num_vsp>>16)&0xff);
  3509. //rt_printf("%s:vsq_e=%d\r\n",__func__,vsq);
  3510. if(vsq>0 && tRunPara.bEvPara) // 上送故障信息
  3511. {
  3512. int i;
  3513. u16 no;
  3514. u8 SIQ,week;
  3515. struct rtc_time_t rt;
  3516. for(i=0;i<vsq;i++)
  3517. {
  3518. u8 *pd=g_arrIECBuf;
  3519. u8 yc_num;
  3520. no = soe_lp2cp(event_p[i].ev_type,event_p[i].ev_code,event_p[i].ev_arg[1]);
  3521. SIQ = event_p[i].ev_value;
  3522. if((yxtype==1) )
  3523. {
  3524. SIQ+=1; //转为双点信息
  3525. }
  3526. #if !defined FUNC_JX_YC_SIQ00
  3527. if(g_run_stu.bjx)
  3528. {
  3529. SIQ|=0x80;//带品质描述,有效 <1>:=无效
  3530. }
  3531. #endif
  3532. timespec_to_rtc(event_p[i].ts,&rt,1);
  3533. week = WEEK_DAY(event_p[i].ts.tv_sec);
  3534. //if(pRunSet->bTT_faultparaDKY)
  3535. //{
  3536. yc_num=asdu_get_event_yc(arrSoe,0,arg_index[i]); // 101规约是6个字节 按照规约规定,101 及104 遥信信息体地址都是两个字节
  3537. //}
  3538. //else
  3539. //{
  3540. // vsq=asdu_get_event_yc(arrSoe,1,arg_index); // 101规约是6个字节 按照规约规定,101 及104 遥信信息体地址都是两个字节
  3541. //}
  3542. *pd++=1; //遥信个数
  3543. *pd++ =( yxtype==1) ? 31 : 30; //类型标识
  3544. *pd++=(u8)no; // 信息体地址L
  3545. *pd++=(u8)(no>>8); // 信息体地址H
  3546. if(pRunSet->bTT_faultparaDKY)
  3547. {
  3548. *pd++=0; // 信息体地址H2 按照规约规定,101 及104 遥信信息体地址都是两个字节
  3549. }
  3550. *pd++=SIQ; // 遥信
  3551. *pd++=(u8)rt.ms;
  3552. *pd++=(u8)(rt.ms>>8);
  3553. *pd++=(u8)rt.min;
  3554. *pd++=(u8)rt.hour;
  3555. *pd++=((week<<5) | rt.day);
  3556. *pd++=(u8)rt.month;
  3557. *pd++=(u8)rt.year;
  3558. *pd++=yc_num; //遥 测个数
  3559. *pd++ =13; //类型标识 浮点值
  3560. //if(pRunSet->bTT_faultparaDKY)
  3561. //{
  3562. memcpy(pd,arrSoe,yc_num*6); // 标准规定,遥测点号是2个字节
  3563. IEC101_Asdu_Add_sts(pt, g_arrIECBuf, yc_num * 6 + (pd - g_arrIECBuf), 0, 3, 42, FRAME_I_PRIOR_LOW, 0);
  3564. //}
  3565. // else
  3566. //{
  3567. // memcpy(pd,arrSoe,vsq*7); // 标准规定,遥测点号是3个字节
  3568. // IEC101_Asdu_Add_sts(pt,g_arrIECBuf,vsq*7+14,0,3,42,FRAME_I_PRIOR_LOW ,0);
  3569. //}
  3570. }
  3571. }
  3572. //pt->bSoeRelink=false;
  3573. }
  3574. return cnt;
  3575. }
  3576. /**************************************************************************
  3577. 函数名称:IEC101_Recv_Rst
  3578. 函数版本:1.00
  3579. 作者:
  3580. 创建日期:2008.9.1
  3581. 函数功能说明:复归数据的接受
  3582. 输入参数:
  3583. 输出参数:
  3584. 返回值:
  3585. 更新信息:
  3586. 更新日志1:
  3587. 日期:
  3588. 修改者:
  3589. 修改内容:
  3590. 修改原因:
  3591. ***************************************************************************/
  3592. static void IEC101_Recv_Rst(IEC101_DEF *pt)
  3593. {
  3594. if(pt->nTypeCounter)
  3595. {
  3596. rt_printf_time("IEC101_Recv_Rst:state=%d,counter=%d\r\n",pt->nTypeCounter,pt->nRecvCounter);
  3597. }
  3598. pt->nTypeCounter=0;
  3599. pt->nRecvLenth=0;
  3600. pt->nRecvCounter=0;
  3601. }
  3602. /**************************************************************************
  3603. 函数名称:IEC101_AutoTimer
  3604. 函数版本:1.00
  3605. 作者:
  3606. 创建日期:2008.9.1
  3607. 函数功能说明:101规约链路内容定时处理部分,100毫秒调用1次
  3608. 输入参数:
  3609. 输出参数:
  3610. 返回值:
  3611. 更新信息:
  3612. 更新日志1:
  3613. 日期:
  3614. 修改者:
  3615. 修改内容:
  3616. 修改原因:
  3617. ***************************************************************************/
  3618. void IEC101_AutoTimer(IEC101_DEF *pt)
  3619. {
  3620. // 如果有数据就发送
  3621. IEC101_Send_Polling(pt);
  3622. // 配电终端在发送复位进程确认命令后需等待3秒,然后重启进程
  3623. if(pt->bResetProcess && ustimer_get_duration(pt->us0_ResetProcess) > 3*USTIMER_SEC)
  3624. {
  3625. IEC101_Reset(pt);
  3626. #ifdef IEC_RESET_PROCESS
  3627. rt_printf("装置重启\r\n");
  3628. watchdog_reset_cpu(2); //装置复位
  3629. #endif
  3630. }
  3631. // 如果连接没有建立,不处理下面流程
  3632. if(pt->st101 == IEC101_ST_NONE)
  3633. {
  3634. return;
  3635. }
  3636. // 处理加密遥控报文标志超时返回
  3637. if(pRunSet->bTT_SM2)
  3638. {
  3639. if(ustimer_get_duration(pt->us0_SM2Over)>60*USTIMER_SEC)
  3640. {
  3641. pt->bRmtSM2 = false;
  3642. }
  3643. }
  3644. // 1秒处理任务
  3645. if(ustimer_get_duration(pt->us0_sec) > USTIMER_SEC)
  3646. {
  3647. pt->us0_sec += USTIMER_SEC;
  3648. pt->secs++;
  3649. // 通道检查 默认10分钟没有收到数据,认为通道错误
  3650. if(pt->dValidTime++>pRunSet->dT101Check)
  3651. {
  3652. char log_info[128];
  3653. rt_printf_time("IEC101(%d):通道超时\r\n",pt->chnl);
  3654. sprintf(log_info,"IEC101(%d):Channel timeout",pt->chnl+1);
  3655. load_hs_log_rcd(TYPE_COMM_ERR,true,NULL,log_info,1);
  3656. log_flag.com_err[pt->chnl] = true;
  3657. IEC101_Info_Printf_One(pt);
  3658. IEC101_Reset(pt);
  3659. }
  3660. }
  3661. if(pt->tf.bTransing||pt->tf.bdatTraned) // 文件启动了传输,在3次重发间隔内,未有文件内容传输更新,释放已申请的文件
  3662. {
  3663. if(ustimer_get_duration(pt->tf.us0_file_trans)>(pRunSet->dT101Resend*USTIMER_SEC*3))
  3664. {
  3665. #ifdef RCD_STRAN_S
  3666. log_str_time(LOG_OPERATE,"读文件传输超时!!!!!!!",0,1);
  3667. #endif
  3668. iec_freefile(&pt->tf);
  3669. pt->tf.bTransing=false;
  3670. pt->tf.bdatTraned=false;
  3671. }
  3672. }
  3673. if(pt->tf.bdatwriting) // 文件启动了传输,在3次重发间隔内,未有文件内容传输更新,释放已申请的写文件内存
  3674. {
  3675. if(ustimer_get_duration(pt->tf.us0_file_write)>(pRunSet->dT101Resend*USTIMER_SEC*3))
  3676. {
  3677. if(!pt->tf.writebuf)
  3678. {
  3679. rt_free(&pt->tf.writebuf);
  3680. pt->tf.writebuf=NULL;
  3681. }
  3682. pt->tf.bdatwriting=false;
  3683. }
  3684. }
  3685. if(pt->tf.bUpdateReset) // 文件启动了传输,在3次重发间隔内,未有文件内容传输更新,释放已申请的写文件内存
  3686. {
  3687. if(ustimer_get_duration(pt->tf.us0_updatereset)>(USTIMER_SEC*2))
  3688. {
  3689. rt_printf("101远程升级,装置复位\r\n");
  3690. pt->tf.bUpdateReset=false;
  3691. watchdog_reset_cpu(2); //装置复位
  3692. }
  3693. }
  3694. if(pt->tr.bpreset) // 参数预置
  3695. {
  3696. if(ustimer_get_duration(pt->tr.us0_preset)>(tRunPara.dSM2Time*USTIMER_SEC))
  3697. {
  3698. int i;
  3699. rt_printf("101预置参数超时清除\r\n");
  3700. pt->tr.bpreset=false;
  3701. for(i=0;i<RMT_SET_NUMBER;i++)
  3702. {
  3703. pt->tr.di[i]=0;
  3704. }
  3705. }
  3706. }
  3707. }
  3708. static bool IEC101_RmtCheck(IEC101_DEF *pt) //判断是否是遥控报文
  3709. {
  3710. u8 AddByte=0;
  3711. if(!pRunSet->bTT_SM2)return false; //加密功能未投入
  3712. if(tRunPara.b101Addr2Byte) AddByte=1;
  3713. if((pt->recvbuf[0]==0x68)
  3714. &&(pt->recvbuf[4]&0x40)
  3715. &&((pt->recvbuf[6+AddByte]==45)||(pt->recvbuf[6+AddByte]==46))) // 遥控报文
  3716. {
  3717. return true;
  3718. }
  3719. return false;
  3720. }
  3721. /**************************************************************************
  3722. 函数名称:IEC101_Recv
  3723. 函数版本:1.00
  3724. 作者:
  3725. 创建日期:2008.9.1
  3726. 函数功能说明:101规约数据接受判断,只判断是否满足报文格式
  3727. 输入参数:
  3728. 输出参数:有完整帧接受,返回1,否则返回 0
  3729. 返回值:
  3730. 更新信息:
  3731. 更新日志1:
  3732. 日期:
  3733. 修改者:
  3734. 修改内容:
  3735. 修改原因:
  3736. ***************************************************************************/
  3737. static int IEC101_Recv(IEC101_DEF *pt,u8 byRevData)
  3738. {
  3739. #ifdef FUNC_ENCRY_IN_ONE_SERIAL
  3740. IEC101_DEF *pt1;
  3741. static int iCount=0,enc_tunnel=0;
  3742. #endif
  3743. // 帧内字符间隔超时检测
  3744. if(g_tRsComm[pt->chnl].b_recv_reset)
  3745. {
  3746. // 不能复位fifo rt_fifo_reset(&pt->recv_fifo);
  3747. //IEC101_Recv_Rst(pt);
  3748. g_tRsComm[pt->chnl].b_recv_reset = 0;
  3749. }
  3750. pt->recvbuf[pt->nRecvCounter++]=byRevData;
  3751. pt->dTRecvPiece=dTCounter; //接收字符时的时刻,在大循环中判断,是否需要复归
  3752. switch(pt->nTypeCounter)
  3753. {
  3754. case 0:
  3755. //统计接收帧数
  3756. s_stat_rx_frame(pt->chnl);
  3757. if(byRevData==0x68)
  3758. {
  3759. pt->nTypeCounter=1;
  3760. }
  3761. else if(byRevData==0x10)
  3762. {
  3763. if(!tRunPara.b101Addr2Byte)
  3764. {
  3765. pt->nRecvLenth=2;
  3766. }
  3767. else
  3768. {
  3769. pt->nRecvLenth=3;
  3770. }
  3771. pt->nTypeCounter=6;
  3772. pt->nRecvCnt=0;
  3773. pt->sum=0;
  3774. }
  3775. else if(byRevData==0x16) //SM2 报文
  3776. {
  3777. pt->nTypeCounter=20;
  3778. pt->nRecvCounter=256;
  3779. pt->recvbuf[pt->nRecvCounter++]=byRevData;
  3780. pt->recvbuf[0]=0x68; //恢复被0x16 覆盖的第一字节数据
  3781. if(!pRunSet->bTT_SM2) //加密功能未投入
  3782. {
  3783. IEC101_Recv_Rst(pt);
  3784. //统计接收错误帧数
  3785. s_stat_rx_errframe(pt->chnl);
  3786. }
  3787. }
  3788. #ifdef FUNC_ENCRY_IN_ONE_SERIAL
  3789. else if(byRevData==0xAA)//海南101规约报文
  3790. {
  3791. pt->nTypeCounter=26;
  3792. pt->sum=0;
  3793. }
  3794. #endif
  3795. else
  3796. {
  3797. rt_printf_time("IEC101_Recv(%d):0x%02x.\r\n",pt->chnl,byRevData);
  3798. IEC101_Recv_Rst(pt);
  3799. //统计接收错误帧数
  3800. s_stat_rx_errframe(pt->chnl);
  3801. }
  3802. break;
  3803. case 1:
  3804. pt->nTypeCounter=2;
  3805. pt->nRecvLenth=byRevData; //长帧长度
  3806. if(pt->nRecvLenth>IEC101_RECVBUF_MAX)
  3807. {
  3808. IEC101_Recv_Rst(pt);
  3809. //统计接收错误帧数
  3810. s_stat_rx_errframe(pt->chnl);
  3811. }
  3812. break;
  3813. case 2:
  3814. if(pt->nRecvLenth==byRevData)
  3815. {
  3816. pt->nTypeCounter=3;
  3817. }
  3818. else
  3819. {
  3820. IEC101_Recv_Rst(pt);
  3821. //统计接收错误帧数
  3822. s_stat_rx_errframe(pt->chnl);
  3823. }
  3824. break;
  3825. case 3:
  3826. if(byRevData==0x68)
  3827. {
  3828. pt->nTypeCounter=6;
  3829. pt->nRecvCnt=0;
  3830. pt->sum=0;
  3831. }
  3832. else
  3833. {
  3834. IEC101_Recv_Rst(pt);
  3835. //统计接收错误帧数
  3836. s_stat_rx_errframe(pt->chnl);
  3837. }
  3838. break;
  3839. //case 4: //控制域
  3840. // pt->sum=byRevData;
  3841. // pt->nTypeCounter=5;
  3842. // break;
  3843. //case 5: //目标地址
  3844. // pt->sum+=byRevData;
  3845. // pt->nRecvCnt=0;
  3846. // pt->nTypeCounter=6;
  3847. // if(pt->nRecvLenth==2)//短帧
  3848. // pt->nTypeCounter=7;
  3849. // break;
  3850. case 6: //有效数据 //有效数据
  3851. if(pt->recvbuf[4]==0x05&&pt->recvbuf[0]==0x68) // 映翰通 GPRS信息返回报文,同101不同,需特殊处理
  3852. {
  3853. pt->nRecvLenth=0x30+1;
  3854. }
  3855. if(++pt->nRecvCnt>=pt->nRecvLenth)
  3856. {
  3857. pt->nTypeCounter=7;
  3858. }
  3859. pt->sum+=byRevData;
  3860. break;
  3861. case 7: //校验和
  3862. pt->recvsum=byRevData;
  3863. pt->nTypeCounter=8;
  3864. break;
  3865. case 8: //结束符
  3866. pt->nTypeCounter = 0;
  3867. IEC101_Recv_Rst(pt);
  3868. if(byRevData==0x16) //校验结束字符,报文接收完毕,
  3869. {
  3870. if((pt->sum != pt->recvsum)&&(pt->recvbuf[4]!=0x05)) // 映翰通 GPRS信息返回报文,同101不同,需特殊处理
  3871. {
  3872. s_stat_rx_errframe(pt->chnl);//统计接收帧错误计数
  3873. }
  3874. else if(IEC101_RmtCheck(pt)) //是遥控报文
  3875. {
  3876. pt->bData=false; //应用层暂不处理,等解密完成后处理
  3877. if(pRunSet->bTT_SM2)
  3878. {
  3879. pt->bRmtSM2 = true;
  3880. pt->us0_SM2Over=ustimer_get_origin();
  3881. }
  3882. }
  3883. else
  3884. {
  3885. pt->bData=true;
  3886. if (uart_test_begin)
  3887. {
  3888. uart_test_flag[pt->chnl][1] = 1;
  3889. }
  3890. // 唤醒主循环
  3891. mainloop_wakeup();
  3892. return 1;
  3893. }
  3894. }
  3895. break;
  3896. case 20: // SM2报文 L2长度
  3897. pt->SM2L2=byRevData;
  3898. pt->nTypeCounter++;
  3899. break;
  3900. case 21: // SM2报文 L2长度
  3901. pt->nTypeCounter++;
  3902. if(byRevData>=pt->SM2L2) //L2长度包含L3长度,L3<L2,做一简单校验
  3903. {
  3904. //统计接收错误帧数
  3905. s_stat_rx_errframe(pt->chnl);
  3906. IEC101_Recv_Rst(pt);
  3907. }
  3908. break;
  3909. case 22:
  3910. if(byRevData==0x16)
  3911. {
  3912. pt->nTypeCounter++;
  3913. pt->nRecvCnt=0;
  3914. }
  3915. else
  3916. {
  3917. //统计接收错误帧数
  3918. s_stat_rx_errframe(pt->chnl);
  3919. IEC101_Recv_Rst(pt);
  3920. }
  3921. break;
  3922. case 23:
  3923. if(++pt->nRecvCnt>=pt->SM2L2)
  3924. {
  3925. pt->nTypeCounter++;
  3926. }
  3927. break;
  3928. case 24: //校验和
  3929. pt->nTypeCounter++;
  3930. break;
  3931. case 25: //结束符
  3932. pt->nTypeCounter = 0;
  3933. IEC101_Recv_Rst(pt);
  3934. if(byRevData==0x16) //校验结束字符,报文接收完毕,
  3935. {
  3936. pt->bSM2Data=true;
  3937. mainloop_wakeup();
  3938. return 1;
  3939. }
  3940. else
  3941. {
  3942. s_stat_rx_errframe(pt->chnl);
  3943. }
  3944. break;
  3945. #ifdef FUNC_ENCRY_IN_ONE_SERIAL
  3946. case 26: //帧长低字节
  3947. pt->nTypeCounter++;
  3948. pt->nRecvLenth = byRevData;
  3949. pt->sum += byRevData;
  3950. break;
  3951. case 27: //帧长高字节
  3952. pt->nTypeCounter++;
  3953. pt->nRecvLenth = (byRevData<<8) | pt->nRecvLenth;
  3954. pt->sum += byRevData;
  3955. break;
  3956. case 28: //加密隧道编号
  3957. pt->nTypeCounter++;
  3958. pt->enc_tunnel = byRevData;
  3959. if(pt->enc_tunnel>1)
  3960. {
  3961. enc_tunnel = pt->enc_tunnel + 1;
  3962. }
  3963. else
  3964. {
  3965. enc_tunnel = pt->enc_tunnel;
  3966. }
  3967. pt->sum += byRevData;
  3968. pt->nRecvCnt=0;
  3969. break;
  3970. case 29: //数据
  3971. if(++pt->nRecvCnt>=pt->nRecvLenth)
  3972. {
  3973. pt->nTypeCounter++;
  3974. }
  3975. pt->sum += byRevData;
  3976. if(tRunPara.tUartPara[0].wProtocol == PROTOCOL_WED_ENC)
  3977. {
  3978. pt1 = (IEC101_DEF *)g_tRsComm[enc_tunnel].ptBuf;
  3979. pt1->recvbuf[iCount] = byRevData;
  3980. pt1->enc_tunnel = pt->enc_tunnel;
  3981. pt1->nRecvLenth = pt->nRecvLenth;
  3982. iCount++;
  3983. }
  3984. break;
  3985. case 30: //校验和
  3986. pt->recvsum = byRevData;
  3987. pt->nTypeCounter++;
  3988. break;
  3989. case 31: //帧尾
  3990. pt->nTypeCounter = 0;
  3991. IEC101_Recv_Rst(pt);
  3992. iCount = 0;
  3993. if(byRevData==0x55) //校验结束字符,报文接收完毕,
  3994. {
  3995. if(pt->sum != pt->recvsum)
  3996. {
  3997. s_stat_rx_errframe(pt->chnl);//统计接收帧错误计数
  3998. }
  3999. else
  4000. {
  4001. pt1 = (IEC101_DEF *)g_tRsComm[enc_tunnel].ptBuf;
  4002. pt1->bData=true;
  4003. enc_tunnel = 0;
  4004. // 唤醒主循环
  4005. mainloop_wakeup();
  4006. return 1;
  4007. }
  4008. }
  4009. break;
  4010. #endif
  4011. default:
  4012. //统计接收错误帧数
  4013. s_stat_rx_errframe(pt->chnl);
  4014. IEC101_Recv_Rst(pt);
  4015. break;
  4016. } //类型校验结束
  4017. return 0;
  4018. }
  4019. void IEC101_Recv_App(IEC101_DEF *pt)
  4020. {
  4021. u8 c;
  4022. // 接收数据
  4023. while(pt->bSM2Data== false && pt->bData == false)
  4024. {
  4025. if(rt_fifo_get(&pt->recv_fifo,&c,1) == 0)
  4026. {
  4027. if(g_tRsComm[pt->chnl].b_recv_reset)
  4028. {
  4029. IEC101_Recv_Rst(pt);
  4030. g_tRsComm[pt->chnl].b_recv_reset = 0;
  4031. }
  4032. break;
  4033. }
  4034. if(pRunSet->bTT_ESAM&&(!pt->bMaintainComm))
  4035. {
  4036. int ret;
  4037. ret = sec_recv(&pt->rx_buf,c,pt->extsendbuf,true);
  4038. if(ret==SEC_FRAME_OK_APP) // 带规约的报文
  4039. {
  4040. pt->bData = 1;
  4041. }
  4042. else if(ret==SEC_FRAME_OK_EXT) //纯安全扩展报文 发送
  4043. {
  4044. IEC101_ext_send(pt,pt->extsendbuf+2,((pt->extsendbuf[0]<<8)+pt->extsendbuf[1]));
  4045. }
  4046. }
  4047. else
  4048. {
  4049. #ifdef FUNC_ENCRY_IN_ONE_SERIAL
  4050. int ret;
  4051. ret = IEC101_Recv(pt,c);
  4052. if(ret == 1)
  4053. break;
  4054. #else
  4055. IEC101_Recv(pt,c);
  4056. #endif
  4057. }
  4058. }
  4059. }
  4060. void IEC101_Recv_Int(IEC101_DEF *pt,u8 byRevData)
  4061. {
  4062. //记录每个不定长帧报文的接收时刻
  4063. if(!pRunSet->bTT_ESAM||pt->bMaintainComm)
  4064. {
  4065. if(byRevData == 0x68)
  4066. {
  4067. struct rt_fifo *f;
  4068. f = &pt->recv_fifo;
  4069. // 判断不定帧长报头 0x68 L L 0X68
  4070. if( (f->buffer[(f->in-1)&(f->size - 1)]) == (f->buffer[(f->in-2)&(f->size - 1)])
  4071. && (f->buffer[(f->in-3)&(f->size - 1)]) == 0x68)
  4072. {
  4073. pt->us0_frame = ustimer_get_origin();
  4074. }
  4075. }
  4076. }
  4077. rt_fifo_put(&pt->recv_fifo,&byRevData,1);
  4078. }
  4079. int IEC101_PH_GprsInfo(void)
  4080. {
  4081. int i;
  4082. for(i=0;i<CFG_UART_NUM_MAX;i++)
  4083. {
  4084. if(UART_CHANNEL[i]< 0)
  4085. {
  4086. continue;
  4087. }
  4088. //外部通信报文处理
  4089. if(tRunPara.tUartPara[i].wProtocol==PROTOCOL_101_PH) // 101规约
  4090. {
  4091. IEC101_DEF *pt=(IEC101_DEF *)g_tRsComm[i].ptBuf;
  4092. pt->bCallGprsInf=true;
  4093. }
  4094. }
  4095. return 0;
  4096. }
  4097. void IEC101_Info_Printf_One(IEC101_DEF *p)
  4098. {
  4099. iec_tbuf_t *pt ;
  4100. rt_printf("\r\n 通道属性:type=%d,chnl=%d\r\n",p->type,p->chnl);
  4101. if(p->st101 == 0)
  4102. {
  4103. return;
  4104. }
  4105. rt_printf(" 规约状态:state=%d,bSendChange=%d\r\n",p->st101,p->bSendChange);
  4106. rt_printf(" 连接计时:LinkCount(%d):%d秒\r\n",p->LinkCount,p->secs);
  4107. pt= &p->tx_buf[0];
  4108. rt_printf("发送BUF[0]:head=%d,tail_send=%d,tail_ack=%d\r\n",pt->tb_head,pt->tb_tail_send,pt->tb_tail_ack);
  4109. pt= &p->tx_buf[1];
  4110. rt_printf("发送BUF[1]:head=%d,tail_send=%d,tail_ack=%d\r\n",pt->tb_head,pt->tb_tail_send,pt->tb_tail_ack);
  4111. rt_printf("SOE通讯BUF:head=%d,tail_send=%d,tail_ack=%d\r\n",g_soe_queue.head.n,g_soe_queue.tail_send[p->chnl].n,g_soe_queue.tail_ack[p->chnl].n);
  4112. rt_printf("SOE事件BUF:head=%d,tail_send=%d\r\n",
  4113. g_soe_queue.head.n,g_soe_queue.tail_eep.n);
  4114. pt= &p->tx_buf[2];
  4115. rt_printf("发送BUF[1]:head=%d,tail_send=%d,tail_ack=%d\r\n",pt->tb_head,pt->tb_tail_send,pt->tb_tail_ack);
  4116. rt_printf("SOE通讯BUF:head=%d,tail_send=%d,tail_ack=%d\r\n",g_soe_queue.head.n,g_soe_queue.tail_send[p->chnl].n,g_soe_queue.tail_ack[p->chnl].n);
  4117. rt_printf("SOE事件BUF:head=%d,tail_send=%d\r\n",
  4118. g_soe_queue.head.n,g_soe_queue.tail_eep.n);
  4119. return;
  4120. }
  4121. int IEC101_Info_Printf(void)
  4122. {
  4123. int i;
  4124. IEC101_DEF *p;
  4125. //串口101
  4126. rt_printf("\r\n串口101:");
  4127. for(i=0;i<CFG_UART_NUM_MAX;i++)
  4128. {
  4129. // 如果串口不存在,跳过
  4130. if(UART_CHANNEL[i]< 0)
  4131. {
  4132. continue;
  4133. }
  4134. if(tRunPara.tUartPara[i].wProtocol != PROTOCOL_101 && tRunPara.tUartPara[i].wProtocol != PROTOCOL_101_PH&&tRunPara.tUartPara[i].wProtocol != PROTOCOL_MAINTAIN)
  4135. {
  4136. rt_printf("\r\n通道属性:非104通道(chnl=%d)\r\n",i);
  4137. continue;
  4138. }
  4139. p = (IEC101_DEF *)g_tRsComm[i].ptBuf;
  4140. IEC101_Info_Printf_One(p);
  4141. }
  4142. return 0;
  4143. }
  4144. /************************************************下面是远方修改定值代码******************************************************/
  4145. void IEC101_setion_chg_msg(IEC101_DEF *pt101,u8 *ps)
  4146. {
  4147. #ifdef YPARA_LINK
  4148. WORD section;
  4149. msg_data_struct *msg_data = &temp_par;
  4150. msg_oper_setion_struct *setion_msg = &msg_data->setion_msg;
  4151. section=ps[0]+(ps[1]<<8); // 定值区号
  4152. msg_data->sport = pt101->chnl;
  4153. msg_data->dport = 0x1F; //进行广播
  4154. msg_data->type = settion_swht;
  4155. setion_msg->section_p = section;
  4156. mananger_msg_ypara_s(msg_data,msg_data->sport,msg_data->dport);
  4157. #endif
  4158. }
  4159. void IEC101_SectionWrite(IEC101_DEF *pt101,u8 *ps) //确认帧
  4160. {
  4161. u8 *pd;
  4162. int num;
  4163. u8 cot;
  4164. WORD section;
  4165. if(pRunSet->wEquTypeManager) IEC101_setion_chg_msg(pt101,ps);
  4166. //组包
  4167. section=ps[0]+(ps[1]<<8); // 定值区号
  4168. cot=0x47;
  4169. if(section<SEC_NUMBER)
  4170. {
  4171. m_dstsection=section;
  4172. if(mmd_changesection(section)==M_JUMP0) cot =0x07;
  4173. }
  4174. //组织报文
  4175. pd=g_arrIECBuf;
  4176. num=0;
  4177. pd[num++]=0; //信息体地址
  4178. pd[num++]=0; //信息体地址
  4179. pd[num++]=ps[0]; //当前定值区
  4180. pd[num++]=ps[1]; //当前定值区
  4181. IEC101_Asdu_Add(pt101,g_arrIECBuf,num,1,cot,200,FRAME_I);//
  4182. }
  4183. void IEC101_SectionRead(IEC101_DEF *pt101) // 读定值区
  4184. {
  4185. u8 *pd;
  4186. int num;
  4187. u8 cot;
  4188. //组织报文
  4189. pd=g_arrIECBuf;
  4190. num=0;
  4191. pd[num++]=0; //信息体地址
  4192. pd[num++]=0; //信息体地址
  4193. pd[num++]=(u8)m_runsection; //当前定值区
  4194. pd[num++]=(u8)(m_runsection>>8); //当前定值区
  4195. pd[num++]=0; //最小定值区
  4196. pd[num++]=0; //最小定值区
  4197. pd[num++]=SEC_NUMBER-1; //最大定值区 1 标准上是7个字节,暂时认为是2个字节
  4198. pd[num++]=0; //最大定值区 2
  4199. cot =IEC_COT_ACTCON;
  4200. IEC101_Asdu_Add(pt101,g_arrIECBuf,num,1,cot,201,FRAME_I);//
  4201. }
  4202. /**************************************************远方修改定值结束*****************************************************/
  4203. /***********************************************下面是101规约文件传输部分代码2016-8-10**************************************************/
  4204. /**************************************************************************
  4205. 函数名称:IEC101_Direct_Echo
  4206. 函数版本:1.00
  4207. 作者:
  4208. 创建日期:2007.9.1
  4209. 函数功能说明:101规约目录响应
  4210. 输出参数:pt101缓冲区地址,COT 传送原因
  4211. 返回值:
  4212. 更新信息:
  4213. 更新日志1:
  4214. 日期:
  4215. 修改者:
  4216. 修改内容:
  4217. 修改原因:
  4218. ***************************************************************************/
  4219. void IEC101_Direct_Echo(IEC101_DEF *pt101,DWORD InfoAddr)
  4220. {
  4221. BYTE *pd=g_arrIECBuf; //从第7个字节开始
  4222. BYTE vsq;
  4223. int filenum;
  4224. struct dir_file_struct *pdir,*pdirfree;
  4225. int i;
  4226. vsq=0;
  4227. pdir=hf_get_dir_file(IEC_Getdir(InfoAddr),&filenum); // 根据信息体地址,判断读读哪个目录,获取目录信息
  4228. if(pdir==NULL)
  4229. {
  4230. IEC101_Asdu_Add(pt101,g_arrIECBuf,0,vsq,5,126, FRAME_I); //无文件应答
  4231. return;
  4232. }
  4233. pdirfree=pdir;
  4234. *pd++ =(BYTE)InfoAddr;
  4235. *pd++ =(BYTE)(InfoAddr>>8);
  4236. for(i=0;i<filenum;i++)
  4237. {
  4238. struct rtc_time_t rtc;
  4239. /*文件名称*/
  4240. *pd++ = (BYTE)(pdir->file_name);
  4241. *pd++ = (BYTE)(pdir->file_name>>8);
  4242. /*文件长度*/
  4243. *pd++ = (BYTE)(pdir->file_size);
  4244. *pd++ = (BYTE)(pdir->file_size>>8);
  4245. *pd++ = (BYTE)(pdir->file_size>>16);
  4246. /*文件的状态SOF*/
  4247. *pd++ = 0;
  4248. /*日历时钟*/
  4249. timespec_to_rtc(pdir->file_time,&rtc,1);
  4250. *pd++ = (BYTE)(rtc.ms);
  4251. *pd++ = (BYTE)(rtc.ms>>8);
  4252. *pd++ = (BYTE)(rtc.min);
  4253. *pd++ = (BYTE)(rtc.hour);
  4254. *pd++ = (BYTE)(rtc.day);
  4255. *pd++ = (BYTE)(rtc.month);
  4256. *pd++ = (BYTE)(rtc.year);
  4257. vsq++;
  4258. if((vsq>=15)&&i<(pdir->file_size-1))// 目录超出一帧上送范围,分帧,VSQ置后续标准位
  4259. {
  4260. vsq|=0x80;
  4261. IEC101_Asdu_Add(pt101,g_arrIECBuf,(vsq&0x7f)*13+2,vsq,5,126, FRAME_I); //无文件应答
  4262. vsq=0;
  4263. pd=g_arrIECBuf;
  4264. }
  4265. pdir++;
  4266. }
  4267. rt_free(pdirfree);
  4268. if(vsq>0)
  4269. {
  4270. if(vsq>1)
  4271. {
  4272. vsq|=0x80;
  4273. }
  4274. IEC101_Asdu_Add(pt101,g_arrIECBuf,(vsq&0x7f)*13,vsq,5,126, FRAME_I); //无文件应答
  4275. }
  4276. else
  4277. {
  4278. IEC101_Asdu_Add(pt101,g_arrIECBuf,0,vsq,5,126, FRAME_I); //无文件应答
  4279. }
  4280. }
  4281. /**************************************************************************
  4282. 函数名称:IEC101_EchoFileReady
  4283. 函数版本:1.00
  4284. 作者:
  4285. 创建日期:2007.9.1
  4286. 函数功能说明:应答文件准备好
  4287. 输出参数:pt101缓冲区地址,filename 文件名
  4288. 返回值:
  4289. 更新信息:
  4290. 更新日志1:
  4291. 日期:
  4292. 修改者:
  4293. 修改内容:
  4294. 修改原因:
  4295. ***************************************************************************/
  4296. static void IEC101_EchoFileReady(IEC101_DEF *pt101,DWORD InfoAddr,WORD filename)
  4297. {
  4298. BYTE *pd=g_arrIECBuf; //从第7个字节开始
  4299. int filelenth,sectionnum;
  4300. filelenth=hf_get_file_inf(IEC_Getdir(InfoAddr),filename,&sectionnum);
  4301. /*文件名称*/
  4302. *pd++ =(BYTE)InfoAddr;
  4303. *pd++ =(BYTE)(InfoAddr>>8);
  4304. *pd++ = (BYTE)(filename); // 10
  4305. *pd++ = (BYTE)(filename>>8); // 11
  4306. *pd++=(BYTE)filelenth; // 文件长度
  4307. *pd++=(BYTE)(filelenth>>8); //文件长度
  4308. *pd++=(BYTE)(filelenth>>16); //文件长度
  4309. if(filelenth>0)
  4310. {
  4311. *pd++ = 0; /*FRQ=0肯定认可*/
  4312. }
  4313. else
  4314. {
  4315. *pd++ = 0x80; /*FRQ=0否定定认可*/
  4316. }
  4317. pt101->tfile.filelenth=filelenth;
  4318. pt101->tfile.setctionnum=sectionnum;
  4319. pt101->tfile.filename=filename;
  4320. pt101->tfile.InfoAddr=InfoAddr;
  4321. pt101->tfile.filechecksum=0;
  4322. IEC101_Asdu_Add(pt101,g_arrIECBuf,8,1,13,120, FRAME_I); //无文件应答
  4323. }
  4324. /**************************************************************************
  4325. 函数名称:IEC101_EchoSectionReady
  4326. 函数版本:1.00
  4327. 作者:
  4328. 创建日期:2007.9.1
  4329. 函数功能说明:应答节准备好
  4330. 输出参数:pt101缓冲区地址,filename 文件名
  4331. 返回值:
  4332. 更新信息:
  4333. 更新日志1:
  4334. 日期:
  4335. 修改者:
  4336. 修改内容:
  4337. 修改原因:
  4338. ***************************************************************************/
  4339. static void IEC101_EchoSectionReady(IEC101_DEF *pt101,DWORD InfoAddr,WORD filename,BYTE section)
  4340. {
  4341. BYTE *pd=g_arrIECBuf; //从第7个字节开始
  4342. int setctionlenth;
  4343. char *pdat=NULL;
  4344. IEC101_FreeFile(pt101);
  4345. *pd++ =(BYTE)InfoAddr;
  4346. *pd++ =(BYTE)(InfoAddr>>8);
  4347. /*文件名称*/
  4348. *pd++ = (BYTE)(filename); // 10
  4349. *pd++ = (BYTE)(filename>>8); // 11
  4350. if(pt101->tfile.InfoAddr==InfoAddr&&pt101->tfile.filename==filename&&section<=pt101->tfile.setctionnum) //文件名相同文件有效
  4351. {
  4352. pdat=hf_get_file_part(IEC_Getdir(InfoAddr), filename, section, &setctionlenth);
  4353. }
  4354. *pd++=section; //节名
  4355. /*节长度长度*/
  4356. *pd++ = (BYTE)(setctionlenth); //12
  4357. *pd++ = (BYTE)(setctionlenth>>8); // 13
  4358. *pd++ = (BYTE)(setctionlenth>>16); // 14
  4359. if(pdat==NULL||setctionlenth==0)
  4360. {
  4361. *pd++ = 0x80; /*FRQ=0否定定认可*/
  4362. }
  4363. else
  4364. {
  4365. *pd++ = 0x0; /*FRQ=0 肯定认可*/ // 15
  4366. pt101->tfile.pdat=pdat; //保存节内容地址,后续需要释放
  4367. pt101->tfile.sectionlenth=setctionlenth;
  4368. pt101->tfile.transsection=section;
  4369. pt101->tfile.bFiletransing=true;
  4370. pt101->tfile.bSegtransing=false;
  4371. pt101->tfile.us0_file_trans=ustimer_get_origin();
  4372. pt101->tfile.transBytes=0;
  4373. pt101->tfile.sectionchecksum=0;
  4374. }
  4375. IEC101_Asdu_Add(pt101,g_arrIECBuf,9,1,13,121, FRAME_I); //无文件应答
  4376. }
  4377. /**************************************************************************
  4378. 函数名称:IEC101_SegmentSend
  4379. 函数版本:1.00
  4380. 作者:
  4381. 创建日期:2007.9.1
  4382. 函数功能说明:应答节传输中段的数据
  4383. 输出参数:pt101缓冲区地址,filename 文件名,section 节名
  4384. 返回值:
  4385. 更新信息:
  4386. 更新日志1:
  4387. 日期:
  4388. 修改者:
  4389. 修改内容:
  4390. 修改原因:
  4391. ***************************************************************************/
  4392. static void IEC101_SegmentSend(IEC101_DEF *pt101,DWORD InfoAddr,WORD filename,BYTE section)
  4393. {
  4394. BYTE *pd=g_arrIECBuf; //从第7个字节开始
  4395. BYTE sectionchecksum=0; //节校验和
  4396. BYTE segmentbytes;
  4397. BYTE cot;
  4398. int i;
  4399. cot=13;
  4400. segmentbytes=0;
  4401. if(pt101->tfile.bFiletransing
  4402. &&pt101->tfile.InfoAddr==InfoAddr
  4403. &&pt101->tfile.filename==filename
  4404. &&section==pt101->tfile.transsection) //文件名相同 节相同
  4405. {
  4406. if(pt101->tfile.transBytes+FILE_SEGMENT_BYTES>=pt101->tfile.sectionlenth)
  4407. {
  4408. segmentbytes=pt101->tfile.sectionlenth%FILE_SEGMENT_BYTES; // 最后的段的字节数
  4409. }
  4410. else
  4411. {
  4412. segmentbytes=FILE_SEGMENT_BYTES;
  4413. }
  4414. pt101->tfile.sectionchecksum=sectionchecksum;
  4415. pt101->tfile.us0_file_trans=ustimer_get_origin();
  4416. pt101->tfile.bSegtransing=true;
  4417. }
  4418. else
  4419. {
  4420. cot|=0x40;
  4421. segmentbytes=0;
  4422. IEC101_FreeFile(pt101);
  4423. }
  4424. /*文件名称*/
  4425. *pd++ =(BYTE)InfoAddr;
  4426. *pd++ =(BYTE)(InfoAddr>>8);
  4427. *pd++ = (BYTE)(filename); // 10
  4428. *pd++ = (BYTE)(filename>>8); // 11
  4429. *pd++=section; //节名 12
  4430. *pd++=segmentbytes; //段的长度 13
  4431. for(i=0;i<segmentbytes;i++)
  4432. {
  4433. *pd=pt101->tfile.pdat[pt101->tfile.transBytes++];
  4434. sectionchecksum+=*pd++;
  4435. }
  4436. IEC101_Asdu_Add(pt101,g_arrIECBuf,6+segmentbytes,1,cot,125, FRAME_I); //无文件应答
  4437. }
  4438. /**************************************************************************
  4439. 函数名称:IEC101_EchoLastSection
  4440. 函数版本:1.00
  4441. 作者:
  4442. 创建日期:2007.9.1
  4443. 函数功能说明:应答最后的节或段
  4444. 输出参数:pt101缓冲区地址,filename 文件名,section 节名,LSQ限定词
  4445. 返回值:
  4446. 更新信息:
  4447. 更新日志1:
  4448. 日期:
  4449. 修改者:
  4450. 修改内容:
  4451. 修改原因:
  4452. ***************************************************************************/
  4453. static void IEC101_EchoLastSection(IEC101_DEF *pt101,WORD filename,BYTE section,BYTE LSQ)
  4454. {
  4455. BYTE *pd=g_arrIECBuf; //从第7个字节开始
  4456. /*文件名称*/
  4457. *pd++ =(BYTE)pt101->tfile.InfoAddr;
  4458. *pd++ =(BYTE)(pt101->tfile.InfoAddr>>8);
  4459. *pd++ = (BYTE)(filename); // 10
  4460. *pd++ = (BYTE)(filename>>8); // 11
  4461. *pd++=section; //节名 12
  4462. switch(LSQ)
  4463. {
  4464. case 1:
  4465. *pd++=1; //LSQ=1:不带停止激活文件传输13
  4466. *pd++=pt101->tfile.filechecksum; //文件校验和 14
  4467. break;
  4468. case 3:
  4469. *pd++=3; //LSQ=3:不带停止激活的节传输
  4470. *pd++=pt101->tfile.sectionchecksum; //节校验和
  4471. break;
  4472. }
  4473. IEC101_Asdu_Add(pt101,g_arrIECBuf,7,1,13,123, FRAME_I); //无文件应答
  4474. }
  4475. /**************************************************************************
  4476. 函数名称:IEC101_SegmentContinue
  4477. 函数版本:1.00
  4478. 作者:
  4479. 创建日期:2007.9.1
  4480. 函数功能说明:主循环中继续发送节中剩余的段
  4481. 输出参数:pt101缓冲区地址,filename 文件名,section 节名
  4482. 返回值:
  4483. 更新信息:
  4484. 更新日志1:
  4485. 日期:
  4486. 修改者:
  4487. 修改内容:
  4488. 修改原因:
  4489. ***************************************************************************/
  4490. void IEC101_SegmentContinue(IEC101_DEF *pt101)
  4491. {
  4492. BYTE *pd=g_arrIECBuf; //从第7个字节开始
  4493. BYTE sectionchecksum=0; //节校验和
  4494. BYTE segmentbytes;
  4495. int i;
  4496. if(!pt101->tfile.bSegtransing)return;
  4497. if(pt101->tfile.transBytes<pt101->tfile.sectionlenth) // 段还未传输完毕
  4498. {
  4499. if(pt101->tfile.transBytes+FILE_SEGMENT_BYTES>=pt101->tfile.sectionlenth)
  4500. {
  4501. segmentbytes=pt101->tfile.sectionlenth%FILE_SEGMENT_BYTES; // 最后的段的字节数
  4502. }
  4503. else
  4504. {
  4505. segmentbytes=FILE_SEGMENT_BYTES;
  4506. }
  4507. *pd++ =(BYTE)pt101->tfile.InfoAddr;
  4508. *pd++ =(BYTE)(pt101->tfile.InfoAddr>>8);
  4509. /*文件名称*/
  4510. *pd++ = (BYTE)(pt101->tfile.filename); // 10
  4511. *pd++ = (BYTE)(pt101->tfile.filename>>8); // 11
  4512. *pd++=pt101->tfile.transsection; //节名 12
  4513. *pd++=segmentbytes; //段的长度 13
  4514. for(i=0;i<segmentbytes;i++)
  4515. {
  4516. *pd=pt101->tfile.pdat[pt101->tfile.transBytes++];
  4517. sectionchecksum+=*pd++;
  4518. }
  4519. pt101->tfile.sectionchecksum+=sectionchecksum;
  4520. pt101->tfile.us0_file_trans=ustimer_get_origin();
  4521. IEC101_Asdu_Add(pt101,g_arrIECBuf,6+segmentbytes,1,13,125, FRAME_I); //无文件应答
  4522. }
  4523. else
  4524. {
  4525. IEC101_EchoLastSection(pt101,pt101->tfile.filename,pt101->tfile.transsection,3);
  4526. IEC101_FreeFile(pt101);
  4527. }
  4528. }
  4529. void IEC101_File_Respone(IEC101_DEF *pt101,BYTE *dat,BYTE cot,BYTE SCAFQ) //
  4530. {
  4531. BYTE *pd=g_arrIECBuf; //从第7个字节开始
  4532. u8 vsq,type;
  4533. u8 CotByte=0; //传送原因双字节
  4534. u8 AppByte=0; //应用单元地址双字节
  4535. if(tRunPara.b101Cot2Byte) CotByte=1;
  4536. if(tRunPara.b101App2Byte) AppByte=1;
  4537. type=dat[0];
  4538. vsq=dat[1];
  4539. *pd++=dat[4+CotByte+AppByte]; // 应用单元地址
  4540. *pd++=dat[5+CotByte+AppByte]; //
  4541. *pd++=dat[6+CotByte+AppByte]; // 文件名
  4542. *pd++=dat[7+CotByte+AppByte]; //
  4543. *pd++=dat[8+CotByte+AppByte]; //节名 12
  4544. *pd++=SCAFQ; //限定词
  4545. IEC101_Asdu_Add(pt101,g_arrIECBuf,6,vsq,cot,type, FRAME_I); //无文件应答
  4546. }
  4547. /**************************************************************************
  4548. 函数名称:IEC101_File_Echo
  4549. 函数版本:1.00
  4550. 作者:
  4551. 创建日期:2007.9.1
  4552. 函数功能说明:对文件召唤的应答处理
  4553. 输出参数:pt101缓冲区地址,dat报文缓冲区地址从报文的帧类型开始
  4554. 返回值:
  4555. 更新信息:
  4556. 更新日志1:
  4557. 日期:
  4558. 修改者:
  4559. 修改内容:
  4560. 修改原因:
  4561. ***************************************************************************/
  4562. void IEC101_File_App(IEC101_DEF *pt101,BYTE *dat) //dat 从报文的帧类型开始
  4563. {
  4564. BYTE COT,SCQ; //传送原因
  4565. WORD filename,section; //文件名 节名
  4566. DWORD InfoAddr; //信息体地址
  4567. u8 CotByte=0; //传送原因双字节
  4568. u8 AppByte=0; //应用单元地址双字节
  4569. if(tRunPara.b101Cot2Byte) CotByte=1;
  4570. if(tRunPara.b101App2Byte) AppByte=1;
  4571. COT=dat[2];
  4572. InfoAddr=dat[4+CotByte+AppByte]+(dat[5+CotByte+AppByte]<<8);
  4573. filename=dat[6+CotByte+AppByte]+(dat[7+CotByte+AppByte]<<8); //文件名
  4574. section=dat[8+CotByte+AppByte]; //节名
  4575. SCQ = dat[9+CotByte+AppByte]; //选择和召唤限定词
  4576. //rt_printf("\r\n COT=%d addr=%4x filename=%d,section=%d,SCQ=%d",COT,InfoAddr,filename,section,SCQ);
  4577. if(IEC_Getdir(InfoAddr)==NULL)
  4578. {
  4579. IEC101_File_Respone(pt101,dat,(47|0x40),SCQ); // 否定应答,非所希望的通信服务
  4580. return;
  4581. }
  4582. if(COT == 5) /*请求目录 */
  4583. {
  4584. IEC101_Direct_Echo(pt101,InfoAddr); /*目录响应 cot =5代表召唤目录*/
  4585. }
  4586. else if(COT == 13)
  4587. {
  4588. switch(SCQ)
  4589. {
  4590. case 1: /*选择文件*/
  4591. IEC101_EchoFileReady(pt101,InfoAddr,filename);
  4592. break;
  4593. case 2: /*请求文件*/
  4594. IEC101_EchoSectionReady(pt101,InfoAddr,filename,section);//节准备好报文
  4595. break;
  4596. case 6: /*请求节*/
  4597. IEC101_SegmentSend(pt101,InfoAddr,filename,section); //发送本节中所有的段
  4598. break;
  4599. default:
  4600. IEC101_File_Respone(pt101,dat,COT,SCQ|0x30); // 否定应答,非所希望的通信服务
  4601. break;
  4602. }
  4603. }
  4604. else
  4605. {
  4606. IEC101_File_Respone(pt101,dat,(45|0x40),SCQ); // 否定应答,未知的传送原因
  4607. }
  4608. }
  4609. /**************************************************************************
  4610. 函数名称:IEC101_File_Echo
  4611. 函数版本:1.00
  4612. 作者:
  4613. 创建日期:2007.9.1
  4614. 函数功能说明:对文件召唤的应答处理
  4615. 输出参数:pt101缓冲区地址,dat报文缓冲区地址从报文的帧类型开始
  4616. 返回值:
  4617. 更新信息:
  4618. 更新日志1:
  4619. 日期:
  4620. 修改者:
  4621. 修改内容:
  4622. 修改原因:
  4623. ***************************************************************************/
  4624. void IEC101_File_Echo(IEC101_DEF *pt101,BYTE *dat) //dat 从报文的帧类型开始
  4625. {
  4626. BYTE COT,SCQ; //传送原因
  4627. WORD filename,section; //文件名 节名
  4628. DWORD InfoAddr; //信息体地址
  4629. u8 CotByte=0; //传送原因双字节
  4630. u8 AppByte=0; //应用单元地址双字节
  4631. if(tRunPara.b101Cot2Byte) CotByte=1;
  4632. if(tRunPara.b101App2Byte) AppByte=1;
  4633. COT=dat[2];
  4634. InfoAddr=dat[4+CotByte+AppByte]+(dat[5+CotByte+AppByte]<<8);
  4635. filename=dat[6+CotByte+AppByte]+(dat[7+CotByte+AppByte]<<8); //文件名
  4636. section=dat[8+CotByte+AppByte]; //节名
  4637. SCQ = dat[9+CotByte+AppByte]; //选择和召唤限定词
  4638. //rt_printf("\r\n COT=%d addr=%4x filename=%d,section=%d,SCQ=%d",COT,InfoAddr,filename,section,SCQ);
  4639. if(IEC_Getdir(InfoAddr)==NULL)
  4640. {
  4641. IEC101_File_Respone(pt101,dat,(47|0x40),SCQ); // 否定应答,非所希望的通信服务
  4642. return;
  4643. }
  4644. if(COT == 5) /*请求目录 */
  4645. {
  4646. IEC101_Direct_Echo(pt101,InfoAddr); /*目录响应 cot =5代表召唤目录*/
  4647. }
  4648. else if(COT == 13)
  4649. {
  4650. switch(SCQ)
  4651. {
  4652. case 1: /*选择文件*/
  4653. IEC101_EchoFileReady(pt101,InfoAddr,filename);
  4654. break;
  4655. case 2: /*请求文件*/
  4656. IEC101_EchoSectionReady(pt101,InfoAddr,filename,section);//节准备好报文
  4657. break;
  4658. case 6: /*请求节*/
  4659. IEC101_SegmentSend(pt101,InfoAddr,filename,section); //发送本节中所有的段
  4660. break;
  4661. default:
  4662. IEC101_File_Respone(pt101,dat,COT,SCQ|0x30); // 否定应答,非所希望的通信服务
  4663. break;
  4664. }
  4665. }
  4666. else
  4667. {
  4668. IEC101_File_Respone(pt101,dat,(45|0x40),SCQ); // 否定应答,未知的传送原因
  4669. }
  4670. }
  4671. /**************************************************************************
  4672. 函数名称:IEC101_File_Sure
  4673. 函数版本:1.00
  4674. 作者:
  4675. 创建日期:2007.9.1
  4676. 函数功能说明:对文件处理的确认应答
  4677. 输出参数:pt缓冲区地址,dat报文缓冲区地址从报文的帧类型开始
  4678. 返回值:
  4679. 更新信息:
  4680. 更新日志1:
  4681. 日期:
  4682. 修改者:
  4683. 修改内容:
  4684. 修改原因:
  4685. ***************************************************************************/
  4686. void IEC101_File_Sure(IEC101_DEF *pt101,BYTE *dat) //dat 从报文的帧类型开始
  4687. {
  4688. BYTE COT,AFQ; //传送原因
  4689. WORD filename,section; //文件名 节名
  4690. DWORD InfoAddr; //信息体地址
  4691. u8 CotByte=0; //传送原因双字节
  4692. u8 AppByte=0; //应用单元地址双字节
  4693. if(tRunPara.b101Cot2Byte) CotByte=1;
  4694. if(tRunPara.b101App2Byte) AppByte=1;
  4695. COT=dat[2];
  4696. InfoAddr=dat[4+CotByte+AppByte]+(dat[5+CotByte+AppByte]<<8);
  4697. filename=dat[6+CotByte+AppByte]+(dat[7+CotByte+AppByte]<<8); //文件名
  4698. section=dat[8+CotByte+AppByte]; //节名
  4699. AFQ = dat[9+CotByte+AppByte]; //选择和召唤限定词
  4700. if(IEC_Getdir(InfoAddr)==NULL)
  4701. {
  4702. IEC101_File_Respone(pt101,dat,(47|0x40),AFQ); // 否定应答,未知的信息体地址
  4703. return;
  4704. }
  4705. if(COT != 13)
  4706. {
  4707. IEC101_File_Respone(pt101,dat,(45|0x40),AFQ); // 否定应答,未知的传送原因
  4708. }
  4709. switch(AFQ) /*AFQ文件确认或节确认*/
  4710. {
  4711. case 1: //文件传输的正确认可
  4712. IEC101_FreeFile(pt101);
  4713. IEC101_File_Respone(pt101,dat,COT,AFQ); // 需商讨,文件传输完毕后,对文件的确认,需要上送什么信息合适,以前是上送更新后的目录 sunxi
  4714. break;
  4715. case 2: //文件传输的否定认可
  4716. IEC101_FreeFile(pt101);
  4717. IEC101_File_Respone(pt101,dat,COT,AFQ); // 需商讨,文件传输完毕后,对文件的确认,需要上送什么信息合适,以前是上送更新后的目录 sunxi
  4718. break;
  4719. case 3: //节传输的正确认可
  4720. IEC101_FreeFile(pt101);
  4721. if(pt101->tfile.transsection<pt101->tfile.setctionnum-1)//现有调试工具UTDEBU,节名从0开始, tfile.setctionnum 需减1 sunxi ,后续程序恢复
  4722. {
  4723. pt101->tfile.filechecksum+=pt101->tfile.sectionchecksum; //文件校验和
  4724. section+=1;
  4725. IEC101_EchoSectionReady(pt101,InfoAddr,filename,section);//下一节准备好
  4726. }
  4727. else if(section>=pt101->tfile.setctionnum-1) // //现有调试工具UTDEBU,节名从0开始, tfile.setctionnum 需减1 sunxi,后续程序恢复
  4728. {
  4729. IEC101_EchoLastSection(pt101,filename,section,1); //LSQ = 3; 最后的段
  4730. }
  4731. break;
  4732. case 4: //节传输的否定认可
  4733. IEC101_FreeFile(pt101);
  4734. IEC101_EchoSectionReady(pt101,InfoAddr,filename,section);//节准备好报文
  4735. break;
  4736. default:
  4737. break;
  4738. }
  4739. }
  4740. void IEC101_FreeFile(IEC101_DEF *pt101)
  4741. {
  4742. if(pt101->tfile.bFiletransing)
  4743. {
  4744. pt101->tfile.bFiletransing=false;
  4745. pt101->tfile.bSegtransing=false;
  4746. if(!pt101->tfile.pdat)
  4747. {
  4748. rt_free(pt101->tfile.pdat);
  4749. pt101->tfile.pdat=NULL;
  4750. }
  4751. rt_printf("\r\nIEC101文件节传输完毕,释放内存,文件:%d 节:%d\r\n",pt101->tfile.filename,pt101->tfile.transsection);
  4752. }
  4753. }