scd_node_rule.go 125 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650
  1. package bo
  2. import (
  3. "errors"
  4. "fmt"
  5. "log"
  6. "os"
  7. "runtime"
  8. "scd_check_tools/global"
  9. "scd_check_tools/logger"
  10. "scd_check_tools/models/enum"
  11. "scd_check_tools/models/node_attr"
  12. "scd_check_tools/mqtt"
  13. "scd_check_tools/tools"
  14. "strconv"
  15. "strings"
  16. "sync"
  17. "time"
  18. "github.com/astaxie/beego/orm"
  19. )
  20. //节点规则解析管理
  21. //单独启用专用解析进程,与节点入库操作为异步关系。该进程在没有新scd入库时为睡眠状态,当有新scd需要解析时,需要外部将其唤醒
  22. //进程被唤醒后,定时查询节点表中未被解析的节点进行规则有效性验证,如果验证不通过,则将结果写入规则解析结果表
  23. //每个节点状态都将按以下状态进行切换:0 未解析->1 解析中-> 2已解析
  24. type ScdNodeRule struct {
  25. ScdID int64
  26. ScdName string
  27. DeviceBaseModel
  28. doiMap *sync.Map
  29. daMap *sync.Map
  30. lnodeTypeMap *sync.Map // map[string]*node_attr.NLNodeType{}
  31. doTypeMap *sync.Map // map[string]*node_attr.NDOType{}
  32. daTypeMap *sync.Map // map[string]*node_attr.NDOType{}
  33. //当前未通过验证的节点列表
  34. CheckFailList []map[string]interface{}
  35. //等待解析的队列
  36. NodeRuleList map[string]orm.Params
  37. //
  38. NodeRuleFunctionList []orm.Params
  39. //是否正在解析节点。默认为0
  40. isRun int
  41. parseLock sync.RWMutex
  42. checkFailListLock sync.RWMutex
  43. scdXmlObject *node_attr.SCL
  44. }
  45. type t_scd_node_rule_parse struct {
  46. Id int64 `orm:"pk"`
  47. ScdId int64
  48. NodeId int64
  49. RuleId int64
  50. ParseResult string
  51. CreatedBy int
  52. CreatedTime string
  53. }
  54. //语法语义规则模型
  55. type t_scd_scl_check struct {
  56. Id int64 `orm:"pk"`
  57. CheckName string
  58. CheckType string
  59. HintText string
  60. ApplyStandard string
  61. ApplyStandardNo string
  62. ObjectType string
  63. ObjectName string
  64. FuncName string
  65. CheckDesc string
  66. CheckArea string
  67. AlertLevel string
  68. NodePath string
  69. IsExists string
  70. IsRef string
  71. IsNotnull string
  72. DataType string
  73. MinLen string
  74. MaxLen string
  75. MinValue string
  76. MaxValue string
  77. IsuniqueByParent string
  78. IsuniqueByGlobal string
  79. ConstValue string
  80. EmunValue string
  81. RegexpValue string
  82. Enable string
  83. CreatedBy int
  84. CreatedTime string
  85. }
  86. //逻辑规则模型.(已不使用)
  87. type t_scd_node_check struct {
  88. Id int64 `orm:"pk"`
  89. CheckObject string
  90. CheckDesc string
  91. CheckArea string
  92. AlertLevel string
  93. IsExists string
  94. IsRef string
  95. IsUnique string
  96. HintText string
  97. Enable string
  98. CreatedBy int
  99. CreatedTime string
  100. }
  101. func init() {
  102. orm.RegisterModel(new(t_scd_node_rule_parse))
  103. orm.RegisterModel(new(t_scd_node_check))
  104. orm.RegisterModel(new(t_scd_scl_check))
  105. }
  106. var checktopic = "/jujutong/scd_check_tools/ruleparse"
  107. func (c *ScdNodeRule) TestCheckRule() {
  108. c.scdXmlObject, _ = new(ScdParse).GetScdXmlObjectBySCDID(tools.IsEmpty(c.ScdID))
  109. if c.scdXmlObject == nil {
  110. logger.Logger.Error(errors.New("无效的SCD"))
  111. mqtt.PublishMessage(fmt.Sprintf("%s/%d", checktopic, c.ScdID), `{"code":0,"scdid":"`+tools.IsEmpty(c.ScdID)+`","state":0,"msg":"无效的SCD"}`)
  112. return
  113. }
  114. if _, h := global.CheckingScd.Load(c.ScdID); h {
  115. logger.Logger.Debug(fmt.Sprintf("%d文件正在校验中", c.ScdID))
  116. mqtt.PublishMessage(fmt.Sprintf("%s/%d", checktopic, c.ScdID), `{"code":0,"scdid":"`+tools.IsEmpty(c.ScdID)+`","state":0,"msg":"该SCD正在校验中"}`)
  117. return
  118. }
  119. c.doiMap = &sync.Map{}
  120. c.daMap = &sync.Map{}
  121. c.lnodeTypeMap = &sync.Map{}
  122. c.doTypeMap = &sync.Map{}
  123. c.daTypeMap = &sync.Map{}
  124. c.NodeRuleList = map[string]orm.Params{}
  125. c.NodeRuleFunctionList = []orm.Params{}
  126. db := orm.NewOrm()
  127. lst := []orm.Params{}
  128. db.Raw("select * from t_scd_scl_check where enable=1").Values(&lst)
  129. for _, r := range lst {
  130. //object_name := r["object_name"].(string)
  131. //object_type := r["object_type"].(string)
  132. checkname := tools.IsEmpty(r["check_name"])
  133. if checkname != "" {
  134. c.NodeRuleList[checkname] = r
  135. }
  136. }
  137. mqtt.PublishMessage(fmt.Sprintf("%s/%d", checktopic, c.ScdID), `{"code":1,"scdid":"`+tools.IsEmpty(c.ScdID)+`","state":0,"msg":"SCD正在校验中"}`)
  138. global.CheckingScd.Store(c.ScdID, "1")
  139. c.StartFunctionNodeParse()
  140. }
  141. //查询规则定义列表
  142. func (c *ScdNodeRule) GetDefList(param map[string]interface{}, pageno, pagesize int) ([]orm.Params, int, error) {
  143. db := orm.NewOrm()
  144. rule_type := param["rule_type"]
  145. sqlParams := []interface{}{}
  146. sql := "select t.*,ifnull(c.name,'其它') check_type_name from t_scd_scl_check t left join global_const_code c on t.check_type=c.id and c.parentcode='checkrule_type' where 1=1"
  147. if v1, ok := param["rule_id"]; ok {
  148. v := tools.IsEmpty(v1)
  149. if v != "" {
  150. sql = sql + " and t.id=?"
  151. sqlParams = append(sqlParams, v)
  152. }
  153. }
  154. if v1, ok := param["check_type"]; ok {
  155. v := tools.IsEmpty(v1)
  156. if v != "" {
  157. sql = sql + " and t.check_type=?"
  158. sqlParams = append(sqlParams, v)
  159. }
  160. }
  161. if v1, ok := param["check_name"]; ok {
  162. v := tools.IsEmpty(v1)
  163. if v != "" {
  164. sql = sql + " and t.check_name like ?"
  165. sqlParams = append(sqlParams, "%"+v+"%")
  166. }
  167. }
  168. if v1, ok := param["enable"]; ok {
  169. v := tools.IsEmpty(v1)
  170. if v != "" {
  171. sql = sql + " and t.enable=?"
  172. sqlParams = append(sqlParams, v)
  173. }
  174. }
  175. if v1, ok := param["object_type"]; ok {
  176. v := tools.IsEmpty(v1)
  177. if v != "" {
  178. sql = sql + " and t.object_type=?"
  179. sqlParams = append(sqlParams, v)
  180. }
  181. }
  182. if v1, ok := param["object_name"]; ok {
  183. v := tools.IsEmpty(v1)
  184. if v != "" {
  185. if rule_type == "logic" {
  186. sql = sql + " and t.check_object like ?"
  187. sqlParams = append(sqlParams, v+"%")
  188. } else {
  189. sql = sql + " and t.object_name like ?"
  190. sqlParams = append(sqlParams, v+"%")
  191. }
  192. }
  193. }
  194. if v1, ok := param["apply_standard"]; ok {
  195. v := tools.IsEmpty(v1)
  196. if v != "" {
  197. sql = sql + " and t.apply_standard like ?"
  198. sqlParams = append(sqlParams, "%"+v+"%")
  199. }
  200. }
  201. if v1, ok := param["alert_level"]; ok {
  202. v := tools.IsEmpty(v1)
  203. if v != "" {
  204. sql = sql + " and t.alert_level=?"
  205. sqlParams = append(sqlParams, v)
  206. }
  207. }
  208. limit := fmt.Sprintf(" order by t.check_type desc,t.id limit %d,%d", (pageno-1)*pagesize, pagesize)
  209. rowset := []orm.Params{}
  210. _, err := db.Raw(sql+limit, sqlParams).Values(&rowset)
  211. if err != nil {
  212. logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql+limit, sqlParams))
  213. return nil, 0, err
  214. }
  215. totalSql := "select count(1) cnt " + sql[strings.Index(sql, "from "):]
  216. tmpRowset := []orm.Params{}
  217. _, err = db.Raw(totalSql, sqlParams).Values(&tmpRowset)
  218. if err != nil {
  219. logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", totalSql, sqlParams))
  220. return nil, 0, err
  221. }
  222. totalCnt, _ := strconv.Atoi(tools.IsEmpty(tmpRowset[0]["cnt"]))
  223. return rowset, totalCnt, err
  224. }
  225. //删除指定的规则定义
  226. func (c *ScdNodeRule) DeleteRuleDef(id, rule_type string) error {
  227. db := orm.NewOrm()
  228. sql := ""
  229. sql2 := ""
  230. if rule_type == "logic" {
  231. //逻辑规则
  232. sql = "delete from t_scd_node_check t where id=?"
  233. sql2 = "delete from t_scd_node_rule_parse where rule_target='node' and rule_id=?"
  234. } else {
  235. //语法规则
  236. sql = "delete from t_scd_scl_check t where id=?"
  237. sql2 = "delete from t_scd_node_rule_parse where rule_target='attr' and rule_id=?"
  238. }
  239. dblog := new(SystemLog)
  240. dblog.SetUserInfo(c.GetUserInfo())
  241. dblog.Audittype = enum.AuditType_admin_rule
  242. dblog.Logtype = enum.LogType_Delete
  243. dblog.Eventtype = enum.OptEventType_Bus
  244. dblog.Eventlevel = enum.OptEventLevel_Hight
  245. _, err := db.Raw(sql, id).Exec()
  246. if err != nil {
  247. logger.Logger.Error(err)
  248. dblog.Description = fmt.Sprintf("删除scd校验规则(id=%s)失败:%s", id, err.Error())
  249. dblog.Fail2()
  250. return err
  251. }
  252. _, err = db.Raw(sql2, id).Exec()
  253. if err != nil {
  254. logger.Logger.Error(err)
  255. dblog.Description = fmt.Sprintf("删除scd校验规则(id=%s)失败:%s", id, err.Error())
  256. dblog.Fail2()
  257. return err
  258. }
  259. dblog.Description = fmt.Sprintf("删除scd校验规则(id=%s)成功", id)
  260. dblog.Success2()
  261. return nil
  262. }
  263. //添加新的规则定义
  264. func (c *ScdNodeRule) AddRuleDef(param map[string]string, rule_type string) error {
  265. db := orm.NewOrm()
  266. id, _ := strconv.Atoi(param["id"])
  267. dblog := new(SystemLog)
  268. dblog.SetUserInfo(c.GetUserInfo())
  269. dblog.Audittype = enum.AuditType_admin_rule
  270. dblog.Logtype = enum.LogType_Insert
  271. dblog.Eventtype = enum.OptEventType_Bus
  272. dblog.Eventlevel = enum.OptEventLevel_Hight
  273. if rule_type == "logic" {
  274. //逻辑规则
  275. mo := t_scd_node_check{}
  276. mo.CreatedBy, _ = strconv.Atoi(c.GetUserId())
  277. mo.CreatedTime = tools.NowTime()
  278. mo.Enable = param["enable"]
  279. mo.AlertLevel = param["alert_level"]
  280. mo.CheckArea = param["check_area"]
  281. mo.CheckDesc = param["check_desc"]
  282. mo.CheckObject = param["check_object"]
  283. mo.HintText = param["hint_text"]
  284. mo.IsExists = param["is_exists"]
  285. mo.IsRef = param["is_ref"]
  286. mo.IsUnique = param["is_unique"]
  287. if id != 0 {
  288. mo.Id = int64(id)
  289. _, err := db.Update(&mo)
  290. if err != nil {
  291. dblog.Description = fmt.Sprintf("编辑scd逻辑校验规则(id=%d)失败:%s", id, err.Error())
  292. dblog.Fail2()
  293. return err
  294. }
  295. dblog.Description = fmt.Sprintf("编辑scd逻辑校验规则(id=%d)成功", id)
  296. dblog.Success2()
  297. return nil
  298. } else {
  299. _, err := db.Insert(&mo)
  300. if err != nil {
  301. dblog.Description = fmt.Sprintf("新增scd逻辑校验规则(id=%d)失败:%s", id, err.Error())
  302. dblog.Fail2()
  303. return err
  304. }
  305. dblog.Description = fmt.Sprintf("新增scd逻辑校验规则(id=%d)成功", id)
  306. dblog.Success2()
  307. return nil
  308. }
  309. } else {
  310. //语法规则
  311. mo := t_scd_scl_check{}
  312. mo.FuncName = param["func_name"]
  313. mo.CheckType = tools.IsEmpty(param["check_type"], "0")
  314. mo.CheckName = param["check_name"]
  315. mo.CheckArea = param["check_area"]
  316. mo.CheckDesc = param["check_desc"]
  317. mo.HintText = param["hint_text"]
  318. mo.ApplyStandard = tools.IsEmpty(param["apply_standard"], "")
  319. mo.ApplyStandardNo = tools.IsEmpty(param["apply_standard_no"], "")
  320. mo.IsExists = tools.IsEmpty(param["is_exists"], "0")
  321. mo.IsRef = tools.IsEmpty(param["is_ref"], "0")
  322. mo.AlertLevel = param["alert_level"]
  323. mo.ConstValue = param["const_value"]
  324. mo.CreatedBy, _ = strconv.Atoi(c.GetUserId())
  325. mo.CreatedTime = tools.NowTime()
  326. mo.DataType = param["data_type"]
  327. mo.EmunValue = param["emun_value"]
  328. mo.Enable = param["enable"]
  329. mo.IsNotnull = tools.IsEmpty(param["is_notnull"], "0")
  330. mo.IsuniqueByGlobal = tools.IsEmpty(param["isunique_by_global"], "0")
  331. mo.IsuniqueByParent = tools.IsEmpty(param["isunique_by_parent"], "0")
  332. mo.MaxLen = tools.IsEmpty(param["max_len"], "0")
  333. mo.MinLen = tools.IsEmpty(param["min_len"], "0")
  334. mo.MaxValue = tools.IsEmpty(param["max_value"], "")
  335. mo.MinValue = tools.IsEmpty(param["min_value"], "")
  336. mo.NodePath = param["node_path"]
  337. mo.ObjectName = param["object_name"]
  338. mo.ObjectType = param["object_type"]
  339. mo.RegexpValue = param["regexp_value"]
  340. syslog := new(SystemLog)
  341. syslog.SetUserInfo(c.GetUserInfo())
  342. mo.CreatedBy, _ = strconv.Atoi(c.GetUserId())
  343. mo.CreatedTime = tools.NowTime()
  344. if id != 0 {
  345. mo.Id = int64(id)
  346. _, err := db.Update(&mo)
  347. if err != nil {
  348. dblog.Description = fmt.Sprintf("编辑scd语法语义校验规则(id=%d)失败:%s", id, err.Error())
  349. dblog.Fail2()
  350. //syslog.Fail("规则管理", fmt.Sprintf("编辑scd语法语义校验规则(id=%d)失败:%s", id, err.Error()))
  351. //SaveSyslog(fmt.Sprintf("编辑scd语法语义校验规则(id=%d)失败:%s", id, err.Error()), "规则管理", false, tools.IsEmpty(c.UserInfo["name"]))
  352. return err
  353. }
  354. dblog.Description = fmt.Sprintf("编辑scd语法语义校验规则(id=%d)成功", id)
  355. dblog.Fail2()
  356. return nil
  357. } else {
  358. _, err := db.Insert(&mo)
  359. if err != nil {
  360. dblog.Description = fmt.Sprintf("新增scd语法语义校验规则(id=%d)失败:%s", id, err.Error())
  361. dblog.Fail2()
  362. return err
  363. }
  364. dblog.Description = fmt.Sprintf("新增scd语法语义校验规则(id=%d)成功", id)
  365. dblog.Success2()
  366. return nil
  367. }
  368. }
  369. }
  370. //按校验等级统计数量
  371. func (c *ScdNodeRule) ResultStatByLevel(scdname, scdpath, ied_name, node_name, node_id string) ([]orm.Params, error) {
  372. if c.ScdID == 0 {
  373. fline := string(os.PathSeparator)
  374. fileFirstChar := scdpath[0:1]
  375. if fileFirstChar != "." {
  376. if fileFirstChar == fline {
  377. scdpath = "." + scdpath
  378. } else {
  379. scdpath = "." + fline + scdpath
  380. }
  381. }
  382. if scdname == "" && scdpath == "" {
  383. return nil, errors.New("scd名称和路径不能为空")
  384. }
  385. db := orm.NewOrm()
  386. sql := "select id from t_scd_scl where scd_name=? and path=? limit 0,1"
  387. tmpRowset := []orm.Params{}
  388. db.Raw(sql, scdname, scdpath).Values(&tmpRowset)
  389. if len(tmpRowset) == 0 {
  390. return nil, errors.New("无效的scd名称和路径")
  391. }
  392. cScdID, _ := strconv.Atoi(tools.IsEmpty(tmpRowset[0]["id"]))
  393. c.ScdID = int64(cScdID)
  394. }
  395. where := ""
  396. param := []interface{}{}
  397. param = append(param, c.ScdID)
  398. if ied_name != "" {
  399. where += " and t.ied_name=?"
  400. param = append(param, ied_name)
  401. }
  402. if node_name != "" {
  403. if node_name == "area" {
  404. //间隔
  405. where += " and EXISTS(select 1 from t_area_ied_relation a where a.ied_name=t.ied_name and a.area_id=? )"
  406. param = append(param, node_id)
  407. } else if node_name == "voltage_level" {
  408. //电压等级
  409. where += " and EXISTS(select 1 from t_substation_area v1, t_area_ied_relation v2 where v1.id=v2.area_id and v2.ied_name=t.ied_name and v1.voltage_level=? and v1.scd_id=? )"
  410. param = append(param, node_id)
  411. param = append(param, c.ScdID)
  412. } else if node_name == "Communication" {
  413. //通讯类
  414. where += " and t1.object_name=?"
  415. param = append(param, "Communication")
  416. } else if node_name == "DataTypeTemplates" {
  417. //通讯类
  418. where += " and t1.object_name=?"
  419. param = append(param, "DataTypeTemplates")
  420. } else if node_name == "SCLSyntax" {
  421. //语法类
  422. where += " and t1.object_name=?"
  423. param = append(param, "SCLSyntax")
  424. }
  425. }
  426. db := orm.NewOrm()
  427. sql := `select t1.alert_level, count(0) cnt from t_scd_scl_check t1 ,t_scd_node_rule_parse t where t.scd_id=? ` + where + ` and t.rule_id=t1.id GROUP BY alert_level`
  428. rowset := []orm.Params{}
  429. _, err := db.Raw(sql, param).Values(&rowset)
  430. if err != nil {
  431. logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql, c.ScdID))
  432. }
  433. return rowset, err
  434. }
  435. //汇总统计校验结果数量
  436. func (c *ScdNodeRule) SumCheckResult() ([]orm.Params, error) {
  437. db := orm.NewOrm()
  438. sql := `SELECT t1.object_name, t1.alert_level ,a.ied_name from t_scd_node_rule_parse a ,t_scd_scl_check t1 where a.rule_id=t1.id and a.scd_id=? GROUP BY t1.object_name,a.ied_name ,t1.alert_level`
  439. rowset := []orm.Params{}
  440. _, err := db.Raw(sql, c.ScdID).Values(&rowset)
  441. if err != nil {
  442. logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql, []interface{}{c.ScdID, c.ScdID, c.ScdID}))
  443. return rowset, err
  444. }
  445. return rowset, nil
  446. }
  447. //统计指定站当前scd的正确率
  448. func (c *ScdNodeRule) RightRateStat(stationid string) (orm.Params, error) {
  449. db := orm.NewOrm()
  450. sql := `select a.* from ( select t1.node_cnt nodetotal, max(t2.id) station_id,max(t2.AREA_NAME) station_name,max(t1.id) scd_id, count(t.id) cnt
  451. from t_scd_node_rule_parse t,t_scd_scl t1,t_data_area t2
  452. where t.scd_id=t1.id and t1.station_id=t2.id and t1.station_id=? and t1.version like '在运版%') a `
  453. rowset := []orm.Params{}
  454. _, err := db.Raw(sql, stationid).Values(&rowset)
  455. if err != nil {
  456. logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql, stationid))
  457. return nil, err
  458. }
  459. if len(rowset) == 0 {
  460. return nil, nil
  461. }
  462. return rowset[0], nil
  463. }
  464. func (c *ScdNodeRule) ExportData(level, ied_name string) ([]orm.Params, error) {
  465. sql := "select t.*,g.alert_level,g.apply_standard,g.apply_standard_no from t_scd_node_rule_parse t inner join t_scd_scl_check g on t.rule_id=g.id where t.scd_id=? and t.rule_target='attr' "
  466. param := []interface{}{}
  467. param = append(param, c.ScdID)
  468. if level != "" {
  469. sql += " and g.alert_level=? "
  470. param = append(param, level)
  471. }
  472. if ied_name != "" {
  473. sql += " and t.ied_name=?"
  474. param = append(param, ied_name)
  475. }
  476. limit := fmt.Sprintf(" order by id ")
  477. rowset := []orm.Params{}
  478. db := orm.NewOrm()
  479. _, err := db.Raw(sql+limit, param).Values(&rowset)
  480. if err != nil {
  481. logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql+limit, param))
  482. }
  483. return rowset, err
  484. }
  485. //查询校验规则列表
  486. //level 规则检查结果级别 为空时查询所有的结果
  487. func (c *ScdNodeRule) ResultList(scdname, scdpath string, level, ied_name, node_name, node_id string, pageno, pagesize int) ([]orm.Params, int, error) {
  488. if c.ScdID == 0 {
  489. fline := string(os.PathSeparator)
  490. fileFirstChar := scdpath[0:1]
  491. if fileFirstChar != "." {
  492. if fileFirstChar == fline {
  493. scdpath = "." + scdpath
  494. } else {
  495. scdpath = "." + fline + scdpath
  496. }
  497. }
  498. if scdname == "" && scdpath == "" {
  499. return nil, 0, errors.New("scd名称和路径不能为空")
  500. }
  501. db := orm.NewOrm()
  502. sql := "select id from t_scd_scl where scd_name=? and path=? limit 0,1"
  503. tmpRowset := []orm.Params{}
  504. db.Raw(sql, scdname, scdpath).Values(&tmpRowset)
  505. if len(tmpRowset) == 0 {
  506. return nil, 0, errors.New("无效的scd名称和路径")
  507. }
  508. cScdID, _ := strconv.Atoi(tools.IsEmpty(tmpRowset[0]["id"]))
  509. c.ScdID = int64(cScdID)
  510. }
  511. sql := "select t.*,g.alert_level,g.apply_standard,g.apply_standard_no from t_scd_node_rule_parse t inner join t_scd_scl_check g on t.rule_id=g.id where t.scd_id=? "
  512. where := ""
  513. param := []interface{}{}
  514. param = append(param, c.ScdID)
  515. if level != "" {
  516. where += " and g.alert_level=? "
  517. param = append(param, level)
  518. }
  519. if ied_name != "" {
  520. where += " and t.ied_name=?"
  521. param = append(param, ied_name)
  522. }
  523. if node_name != "" {
  524. if node_name == "area" {
  525. //间隔
  526. where += " and EXISTS(select 1 from t_area_ied_relation a where a.ied_name=t.ied_name and a.area_id=? )"
  527. param = append(param, node_id)
  528. } else if node_name == "voltage_level" {
  529. //电压等级
  530. where += " and EXISTS(select 1 from t_substation_area v1, t_area_ied_relation v2 where v1.id=v2.area_id and v2.ied_name=t.ied_name and v1.voltage_level=? and v1.scd_id=? )"
  531. param = append(param, node_id)
  532. param = append(param, c.ScdID)
  533. } else if node_name == "Communication" {
  534. //通讯类
  535. where += " and g.object_name=?"
  536. param = append(param, "Communication")
  537. } else if node_name == "DataTypeTemplates" {
  538. //通讯类
  539. where += " and g.object_name=?"
  540. param = append(param, "DataTypeTemplates")
  541. } else if node_name == "SCLSyntax" {
  542. //语法类
  543. where += " and g.object_name=?"
  544. param = append(param, "SCLSyntax")
  545. }
  546. }
  547. sql += where
  548. limit := fmt.Sprintf(" order by g.alert_level limit %d,%d", (pageno-1)*pagesize, pagesize)
  549. rowset := []orm.Params{}
  550. db := orm.NewOrm()
  551. _, err := db.Raw(sql+limit, param).Values(&rowset)
  552. if err != nil {
  553. logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql+limit, param))
  554. return rowset, 0, err
  555. }
  556. totalNum := 0
  557. if err == nil {
  558. tmpRowset := []orm.Params{}
  559. _, err = db.Raw(strings.ReplaceAll(sql, "t.*,g.alert_level", "count(1) cnt"), param).Values(&tmpRowset)
  560. if err != nil {
  561. logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql, param))
  562. } else if len(tmpRowset) > 0 {
  563. for _, r1 := range tmpRowset {
  564. totalNumi, _ := strconv.Atoi(tools.IsEmpty(r1["cnt"]))
  565. totalNum += totalNumi
  566. }
  567. }
  568. }
  569. return rowset, totalNum, err
  570. }
  571. //启动自定义校验
  572. func (c *ScdNodeRule) StartFunctionNodeParse() {
  573. c.CheckFunc_header_number(nil)
  574. c.CheckFunc_header_name_structure(nil)
  575. c.CheckFunc_header_toolid(nil)
  576. c.CheckFunc_header_complete(nil)
  577. c.CheckFunc_header_version(nil)
  578. c.CheckFunc_header_hitem_complete(nil)
  579. c.CheckFunc_substation_number(nil)
  580. c.CheckFunc_substation_name(nil)
  581. c.CheckFunc_voltagelevel_complete(nil)
  582. c.CheckFunc_communication_connectedap(nil)
  583. dATypeMap := c.CheckFunc_datatypetemplates(nil)
  584. c.CheckFunc_ied(dATypeMap)
  585. //在crc校验完成后将所有校验结果写入数据库
  586. go c.CheckFunc_crc()
  587. c.doiMap = nil
  588. c.daMap = nil
  589. }
  590. //----------------------自定义的规则校验方法------------------
  591. func (c *ScdNodeRule) CheckFunc_header_number(para orm.Params) {
  592. ruleid := c.getRuleIdByName("Header元素完备性校验")
  593. if ruleid != "" {
  594. if c.scdXmlObject.Header == nil {
  595. parse_result := fmt.Sprintf("Header元素缺失")
  596. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.NodeId, "parse_result": parse_result}
  597. c.AppendPaseResult(r)
  598. }
  599. }
  600. }
  601. func (c *ScdNodeRule) CheckFunc_header_name_structure(para orm.Params) {
  602. ruleid := c.getRuleIdByName("Header元素完备性校验")
  603. if ruleid != "" {
  604. if c.scdXmlObject.Header != nil && c.scdXmlObject.Header.NameStructure != "IEDName" {
  605. parse_result := fmt.Sprintf("Header元素中的属性nameStructure值不正确,其值只能为IEDName")
  606. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Header.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Header.NodeId, "parse_result": parse_result}
  607. //唯一性检查未通过
  608. c.AppendPaseResult(r)
  609. }
  610. }
  611. }
  612. func (c *ScdNodeRule) CheckFunc_header_toolid(para orm.Params) {
  613. ruleid := c.getRuleIdByName("toolID属性检查")
  614. if ruleid != "" {
  615. if c.scdXmlObject.Header != nil && c.scdXmlObject.Header.ToolID == "" {
  616. parse_result := fmt.Sprintf("Header元素中的属性toolID配置不规范,其值为空")
  617. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Header.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Header.NodeId, "parse_result": parse_result}
  618. //唯一性检查未通过
  619. c.AppendPaseResult(r)
  620. }
  621. if c.scdXmlObject.Header != nil && c.scdXmlObject.Header.ToolID != "" {
  622. ary := strings.Split(c.scdXmlObject.Header.ToolID, "_")
  623. if len(ary) != 3 {
  624. parse_result := fmt.Sprintf("Header元素属性toolID配置不规范,格式应为:厂商编码_配置工具名称_工具软件版本")
  625. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Header.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Header.NodeId, "parse_result": parse_result}
  626. //唯一性检查未通过
  627. c.AppendPaseResult(r)
  628. }
  629. }
  630. }
  631. }
  632. //完整性校验
  633. func (c *ScdNodeRule) CheckFunc_header_complete(para orm.Params) {
  634. if c.scdXmlObject.Header == nil {
  635. return
  636. }
  637. ruleid := c.getRuleIdByName("Header元素完备性校验")
  638. if ruleid != "" {
  639. if c.scdXmlObject.Header.Id == "" {
  640. //验证不通过
  641. parse_result := fmt.Sprintf("Header元素中id属性缺失")
  642. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Header.NodeId, "parse_result": parse_result}
  643. //唯一性检查未通过
  644. c.AppendPaseResult(r)
  645. }
  646. if c.scdXmlObject.Header.Version == "" {
  647. //验证不通过
  648. parse_result := fmt.Sprintf("Header元素中version属性缺失")
  649. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Header.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Header.NodeId, "parse_result": parse_result}
  650. //唯一性检查未通过
  651. c.AppendPaseResult(r)
  652. }
  653. if c.scdXmlObject.Header.Revision == "" {
  654. //验证不通过
  655. parse_result := fmt.Sprintf("Header元素中revision属性缺失")
  656. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Header.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Header.NodeId, "parse_result": parse_result}
  657. //唯一性检查未通过
  658. c.AppendPaseResult(r)
  659. }
  660. }
  661. }
  662. func (c *ScdNodeRule) CheckFunc_header_version(para orm.Params) {
  663. if c.scdXmlObject.Header == nil {
  664. return
  665. }
  666. ruleid := c.getRuleIdByName("Header版本一致性")
  667. if ruleid != "" {
  668. ver := c.scdXmlObject.Header.Version
  669. rever := c.scdXmlObject.Header.Revision
  670. if c.scdXmlObject.Header.History != nil {
  671. hitems := c.scdXmlObject.Header.History.Hitem
  672. if len(hitems) > 0 {
  673. lastHitem := hitems[len(hitems)-1]
  674. if ver != lastHitem.Version && rever != lastHitem.Revision {
  675. //验证不通过
  676. parse_result := fmt.Sprintf("Header中的version=%s、revision=%s与History中的最后一个Item不一致", ver, rever)
  677. r := map[string]interface{}{"scdid": c.ScdID, "lineno": lastHitem.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Header.NodeId, "parse_result": parse_result}
  678. //唯一性检查未通过
  679. c.AppendPaseResult(r)
  680. }
  681. }
  682. }
  683. }
  684. }
  685. func (c *ScdNodeRule) CheckFunc_header_hitem_complete(para orm.Params) {
  686. if c.scdXmlObject.Header == nil {
  687. return
  688. }
  689. if c.scdXmlObject.Header.History != nil {
  690. hitems := c.scdXmlObject.Header.History.Hitem
  691. if len(hitems) > 0 {
  692. ver := ""
  693. rever := ""
  694. hitemruleid1 := c.getRuleIdByName("Hitem元素完备性校验")
  695. hitemruleid2 := c.getRuleIdByName("History版本连续性")
  696. for _, hitem := range hitems {
  697. if hitemruleid1 != "" {
  698. errattr := []string{}
  699. if hitem.Version == "" {
  700. errattr = append(errattr, "version")
  701. }
  702. if hitem.Revision == "" {
  703. errattr = append(errattr, "revision")
  704. }
  705. if hitem.When == "" {
  706. errattr = append(errattr, "when")
  707. }
  708. if len(errattr) > 0 {
  709. //验证不通过
  710. parse_result := fmt.Sprintf("Hitem元素中%s属性缺失", strings.Join(errattr, ","))
  711. r := map[string]interface{}{"scdid": c.ScdID, "lineno": hitem.Lineno, "ruleid": hitemruleid1, "nodeid": hitem.NodeId, "parse_result": parse_result}
  712. c.AppendPaseResult(r)
  713. }
  714. }
  715. if hitemruleid2 != "" {
  716. //连续性判断
  717. if ver == "" {
  718. ver = hitem.Version
  719. rever = hitem.Revision
  720. } else {
  721. v1, _ := strconv.Atoi(hitem.Version)
  722. v2, _ := strconv.Atoi(hitem.Revision)
  723. v3, _ := strconv.Atoi(ver)
  724. v4, _ := strconv.Atoi(rever)
  725. if v1 == v3 && int(float64(v2)-float64(v4)-0.1) != 0 {
  726. //验证不通过
  727. parse_result := fmt.Sprintf("History版本元素中版本信息不连续:version=%s,revison=%s->version=%s,revison=%s", ver, rever, hitem.Version, hitem.Revision)
  728. r := map[string]interface{}{"scdid": c.ScdID, "lineno": hitem.Lineno, "ruleid": hitemruleid2, "nodeid": hitem.NodeId, "parse_result": parse_result}
  729. c.AppendPaseResult(r)
  730. }
  731. if v1 != v3 && hitem.Revision != "1.0" {
  732. //验证不通过
  733. parse_result := fmt.Sprintf("History版本元素中版本信息不规范:文件版本增加时,文件修订版本应置为1.0")
  734. r := map[string]interface{}{"scdid": c.ScdID, "lineno": hitem.Lineno, "ruleid": hitemruleid2, "nodeid": hitem.NodeId, "parse_result": parse_result}
  735. c.AppendPaseResult(r)
  736. }
  737. ver = hitem.Version
  738. rever = hitem.Revision
  739. }
  740. }
  741. }
  742. }
  743. }
  744. }
  745. func (c *ScdNodeRule) CheckFunc_substation_number(para orm.Params) {
  746. ruleid := c.getRuleIdByName("Substation完备性校验")
  747. if ruleid != "" {
  748. if c.scdXmlObject.Substation == nil {
  749. //验证不通过
  750. parse_result := fmt.Sprintf("Substation元素缺失")
  751. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.NodeId, "parse_result": parse_result}
  752. c.AppendPaseResult(r)
  753. return
  754. }
  755. }
  756. ruleid = c.getRuleIdByName("Substation对象缺失CIME-dtype元素")
  757. ruleid2 := c.getRuleIdByName("Substation对象缺失CIME-area元素")
  758. if ruleid != "" || ruleid2 != "" {
  759. if len(c.scdXmlObject.Substation.Private) == 0 {
  760. parse_result := fmt.Sprintf("Substation对象缺失CIME-dtype元素")
  761. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Substation.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  762. c.AppendPaseResult(r)
  763. return
  764. }
  765. isFound := false
  766. isFoundCIMEArea := false
  767. for _, pr := range c.scdXmlObject.Substation.Private {
  768. if pr.Type == "CIME-dtype" {
  769. isFound = true
  770. ruleid3 := c.getRuleIdByName("Substation对象对应CIME-dtype中属性缺失")
  771. if ruleid3 != "" && (pr.Desc == "") {
  772. parse_result := fmt.Sprintf("Substation对象对应CIME-dtype中属性(desc)缺失")
  773. r := map[string]interface{}{"scdid": c.ScdID, "lineno": pr.Lineno, "ruleid": ruleid3, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  774. c.AppendPaseResult(r)
  775. }
  776. }
  777. if pr.Type == "CIME-area" {
  778. isFoundCIMEArea = true
  779. ruleid3 := c.getRuleIdByName("Substation对象对应CIME-area中属性缺失")
  780. if ruleid3 != "" && (pr.Name == "" || pr.Desc == "") {
  781. parse_result := fmt.Sprintf("Substation对象对应CIME-area中属性(name或desc)缺失")
  782. r := map[string]interface{}{"scdid": c.ScdID, "lineno": pr.Lineno, "ruleid": ruleid3, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  783. c.AppendPaseResult(r)
  784. }
  785. }
  786. }
  787. if !isFound {
  788. parse_result := fmt.Sprintf("Substation对象缺失CIME-dtype元素")
  789. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Substation.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  790. c.AppendPaseResult(r)
  791. }
  792. if !isFoundCIMEArea {
  793. parse_result := fmt.Sprintf("Substation对象缺失CIME-area元素")
  794. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Substation.Lineno, "ruleid": ruleid2, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  795. c.AppendPaseResult(r)
  796. }
  797. }
  798. }
  799. func (c *ScdNodeRule) CheckFunc_substation_name(para orm.Params) {
  800. if c.scdXmlObject.Substation == nil {
  801. return
  802. }
  803. ruleid := c.getRuleIdByName("变电站名称一致性")
  804. if ruleid != "" {
  805. if c.scdXmlObject.Substation.Name != c.scdXmlObject.Header.Id {
  806. //验证不通过
  807. parse_result := fmt.Sprintf("Substation的name(%s)与Header中的id(%s)不一致", c.scdXmlObject.Substation.Name, c.scdXmlObject.Header.Id)
  808. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Substation.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  809. c.AppendPaseResult(r)
  810. }
  811. }
  812. }
  813. //VoltageLevel 对象的命名 name 应按“‘额定电压’ kV”形式命名,如“ 1000kV”“110kV”等,并且全站唯一。 desc 描述参照 name 命名方式
  814. func (c *ScdNodeRule) CheckFunc_voltagelevel_complete(para orm.Params) {
  815. if c.scdXmlObject.Substation == nil {
  816. return
  817. }
  818. ruleid1 := c.getRuleIdByName("VoltageLevel命名错误")
  819. ruleid2 := c.getRuleIdByName("VoltageLevel下Voltage缺失")
  820. ruleid3 := c.getRuleIdByName("Voltage对象的取值/属性错误")
  821. ruleid4 := c.getRuleIdByName("SSD关联关系错误")
  822. if len(c.scdXmlObject.Substation.VoltageLevel) == 0 {
  823. parse_result := fmt.Sprintf("Substation中存在层级关系错误:未定义VoltageLevel")
  824. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Substation.Lineno, "ruleid": ruleid4, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  825. c.AppendPaseResult(r)
  826. return
  827. }
  828. priMap := map[string]string{}
  829. for _, item := range c.scdXmlObject.Substation.VoltageLevel {
  830. name := item.Name
  831. //desc := item.Desc
  832. if ruleid1 != "" {
  833. if _, h := priMap[name]; h {
  834. //验证不通过
  835. parse_result := fmt.Sprintf("VoltageLevel命名错误:name应该全站唯一")
  836. r := map[string]interface{}{"scdid": c.ScdID, "lineno": item.Lineno, "ruleid": ruleid1, "nodeid": item.NodeId, "parse_result": parse_result}
  837. c.AppendPaseResult(r)
  838. continue
  839. }
  840. priMap[name] = ""
  841. if name == "" || len(name) < 3 || !strings.HasSuffix(name, "kV") {
  842. //验证不通过
  843. parse_result := fmt.Sprintf("VoltageLevel命名错误:name应按“‘额定电压’ kV”形式命名,如“1000kV”“110kV”等,并且全站唯一")
  844. r := map[string]interface{}{"scdid": c.ScdID, "lineno": item.Lineno, "ruleid": ruleid1, "nodeid": item.NodeId, "parse_result": parse_result}
  845. c.AppendPaseResult(r)
  846. }
  847. }
  848. if ruleid2 != "" {
  849. if item.Voltage == nil {
  850. //验证不通过
  851. parse_result := fmt.Sprintf("VoltageLevel(%s)下缺失Voltage对象", item.Name)
  852. r := map[string]interface{}{"scdid": c.ScdID, "lineno": item.Lineno, "ruleid": ruleid2, "nodeid": item.NodeId, "parse_result": parse_result}
  853. c.AppendPaseResult(r)
  854. }
  855. }
  856. if ruleid3 != "" && item.Voltage != nil {
  857. if item.Voltage.InnerText != item.Name[0:len(item.Name)-2] {
  858. //验证不通过
  859. parse_result := fmt.Sprintf("VoltageLevel(%s)下属Voltage对象的取值错误", item.Name)
  860. r := map[string]interface{}{"scdid": c.ScdID, "lineno": item.Voltage.Lineno, "ruleid": ruleid3, "nodeid": item.NodeId, "parse_result": parse_result}
  861. c.AppendPaseResult(r)
  862. }
  863. if item.Voltage.Multiplier != "k" {
  864. //验证不通过
  865. parse_result := fmt.Sprintf("VoltageLevel(%s)下属Voltage对象属性(%s=%s)错误", item.Name, "multiplier", item.Voltage.Multiplier)
  866. r := map[string]interface{}{"scdid": c.ScdID, "lineno": item.Voltage.Lineno, "ruleid": ruleid3, "nodeid": item.NodeId, "parse_result": parse_result}
  867. c.AppendPaseResult(r)
  868. }
  869. if item.Voltage.Unit != "V" {
  870. //验证不通过
  871. parse_result := fmt.Sprintf("VoltageLevel(%s)下属Voltage对象属性(%s=%s)错误", item.Name, "unit", item.Voltage.Unit)
  872. r := map[string]interface{}{"scdid": c.ScdID, "lineno": item.Voltage.Lineno, "ruleid": ruleid3, "nodeid": item.NodeId, "parse_result": parse_result}
  873. c.AppendPaseResult(r)
  874. }
  875. }
  876. //Bay校验
  877. if len(item.Bay) > 0 {
  878. ruleid5 := c.getRuleIdByName("Bay对象缺失CIME-dtype元素")
  879. ruleid6 := c.getRuleIdByName("Bay对象对应CIME-dtype中desc属性值错误")
  880. if ruleid5 != "" {
  881. for _, bayrow := range item.Bay {
  882. if bayrow.Private == nil {
  883. parse_result := fmt.Sprintf("Bay对象缺失CIME-dtype元素")
  884. r := map[string]interface{}{"scdid": c.ScdID, "lineno": bayrow.Lineno, "ruleid": ruleid5, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  885. c.AppendPaseResult(r)
  886. } else {
  887. if ruleid6 != "" && bayrow.Private.Desc == "" {
  888. parse_result := fmt.Sprintf("Bay对象对应CIME-dtype中desc属性值错误")
  889. r := map[string]interface{}{"scdid": c.ScdID, "lineno": bayrow.Lineno, "ruleid": ruleid6, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  890. c.AppendPaseResult(r)
  891. }
  892. }
  893. bayRule1 := c.getRuleIdByName("间隔关联逻辑节点不存在")
  894. if len(bayrow.PowerTransformer) > 0 {
  895. ruleid7 := c.getRuleIdByName("PowerTransformer对象命名错误")
  896. ruleid8 := c.getRuleIdByName("PowerTransformer对象type错误")
  897. for _, tmpr := range bayrow.PowerTransformer {
  898. if ruleid7 != "" && (tmpr.Name == "" || !strings.HasPrefix(tmpr.Name, "PTR")) {
  899. parse_result := fmt.Sprintf("PowerTransformer对象命名(%s)错误", tmpr.Name)
  900. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpr.Lineno, "ruleid": ruleid7, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  901. c.AppendPaseResult(r)
  902. }
  903. if ruleid8 != "" && tmpr.Type != "PTR" {
  904. parse_result := fmt.Sprintf("PowerTransformer对象(%s)type(%s)不为PTR", tmpr.Name, tmpr.Type)
  905. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpr.Lineno, "ruleid": ruleid8, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  906. c.AppendPaseResult(r)
  907. }
  908. if len(tmpr.TransformerWinding) > 0 {
  909. ruleid9 := c.getRuleIdByName("TransformerWinding对象缺失:CIME-voltageLevel")
  910. ruleid10 := c.getRuleIdByName("TransformerWinding对象中CIME-voltageLevel属性错误或缺失")
  911. for _, rw := range tmpr.TransformerWinding {
  912. if ruleid9 != "" && (rw.Private != nil || rw.Private.Type != "CIME-voltageLevel") {
  913. parse_result := fmt.Sprintf("TransformerWinding对象(%s)缺失:CIME-voltageLevel", rw.Name)
  914. r := map[string]interface{}{"scdid": c.ScdID, "lineno": rw.Lineno, "ruleid": ruleid9, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  915. c.AppendPaseResult(r)
  916. }
  917. if ruleid10 != "" && rw.Private != nil && rw.Private.Desc == "" {
  918. parse_result := fmt.Sprintf("TransformerWinding对象(%s)中的CIME-voltageLevel的desc属性缺失", rw.Desc)
  919. r := map[string]interface{}{"scdid": c.ScdID, "lineno": rw.Lineno, "ruleid": ruleid10, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  920. c.AppendPaseResult(r)
  921. }
  922. if ruleid10 != "" && rw.Private != nil && rw.Private.Name == "" {
  923. parse_result := fmt.Sprintf("TransformerWinding对象(%s)中的CIME-voltageLevel的name属性缺失", rw.Name)
  924. r := map[string]interface{}{"scdid": c.ScdID, "lineno": rw.Lineno, "ruleid": ruleid10, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  925. c.AppendPaseResult(r)
  926. }
  927. if ruleid10 != "" && rw.Private != nil && rw.Private.Name != item.Name {
  928. parse_result := fmt.Sprintf("TransformerWinding对象(%s)中的CIME-voltageLevel的name属性(%s)与已有电压等级(%s)不一致", rw.Name, rw.Private.Name, item.Name)
  929. r := map[string]interface{}{"scdid": c.ScdID, "lineno": rw.Lineno, "ruleid": ruleid10, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  930. c.AppendPaseResult(r)
  931. }
  932. }
  933. }
  934. if bayRule1 != "" && len(tmpr.LNode) > 0 {
  935. scdnode := new(ScdNode)
  936. for _, i1 := range tmpr.LNode {
  937. if scdnode.GetIed(c.scdXmlObject, tools.IsEmpty(c.ScdID), i1.IedName) == nil {
  938. parse_result := fmt.Sprintf("间隔(%s)关联逻辑节点(%s)不存在", bayrow.Name, i1.IedName)
  939. r := map[string]interface{}{"scdid": c.ScdID, "lineno": i1.Lineno, "ruleid": bayRule1, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  940. c.AppendPaseResult(r)
  941. }
  942. }
  943. }
  944. }
  945. }
  946. if len(bayrow.ConductingEquipment) > 0 {
  947. ruleid7 := c.getRuleIdByName("ConductingEquipment命名错误")
  948. condmap := map[string]int{}
  949. for _, r := range bayrow.ConductingEquipment {
  950. if ruleid7 != "" {
  951. if r.Name == "" {
  952. parse_result := fmt.Sprintf("ConductingEquipment命名错误:name不能为空")
  953. rt := map[string]interface{}{"scdid": c.ScdID, "lineno": r.Lineno, "ruleid": ruleid7, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  954. c.AppendPaseResult(rt)
  955. continue
  956. }
  957. if condmap[r.Name] == 1 {
  958. parse_result := fmt.Sprintf("在同一Bay内不应有两个同名的ConductingEquipment(%s)元素", r.Name)
  959. rt := map[string]interface{}{"scdid": c.ScdID, "lineno": r.Lineno, "ruleid": ruleid7, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  960. c.AppendPaseResult(rt)
  961. continue
  962. }
  963. condmap[r.Name] = 1
  964. }
  965. ruleid8 := c.getRuleIdByName("ConductingEquipment对象缺失CIME-dtype元素")
  966. if ruleid8 != "" && (r.Private == nil || r.Private.Type != "CIME-dtype") {
  967. parse_result := fmt.Sprintf("ConductingEquipment对象(%s)缺失CIME-dtype元素", r.Name)
  968. rt := map[string]interface{}{"scdid": c.ScdID, "lineno": r.Private.Lineno, "ruleid": ruleid8, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  969. c.AppendPaseResult(rt)
  970. }
  971. ruleid9 := c.getRuleIdByName("ConductingEquipment对象对应CIME-dtype中desc属性值错误")
  972. if ruleid9 != "" && r.Private != nil && r.Private.Type == "CIME-dtype" {
  973. if r.Private.Desc == "" {
  974. parse_result := fmt.Sprintf("ConductingEquipment对象(%s)对应CIME-dtype元素中desc属性值错误", r.Name)
  975. rt := map[string]interface{}{"scdid": c.ScdID, "lineno": r.Private.Lineno, "ruleid": ruleid9, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  976. c.AppendPaseResult(rt)
  977. }
  978. }
  979. if bayRule1 != "" && len(r.LNode) > 0 {
  980. scdnode := new(ScdNode)
  981. for _, i1 := range r.LNode {
  982. if scdnode.GetIed(c.scdXmlObject, tools.IsEmpty(c.ScdID), i1.IedName) == nil {
  983. parse_result := fmt.Sprintf("间隔(%s)关联逻辑节点(%s)不存在", bayrow.Name, i1.IedName)
  984. rt := map[string]interface{}{"scdid": c.ScdID, "lineno": i1.Lineno, "ruleid": bayRule1, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  985. c.AppendPaseResult(rt)
  986. }
  987. }
  988. }
  989. }
  990. }
  991. if len(bayrow.ConnectivityNode) > 0 {
  992. ruleid10 := c.getRuleIdByName("ConnectivityNode对象命名错误")
  993. if ruleid10 != "" {
  994. for _, r := range bayrow.ConnectivityNode {
  995. if r.Name == "" {
  996. parse_result := fmt.Sprintf("ConnectivityNode对象命名错误:不能为空")
  997. rt := map[string]interface{}{"scdid": c.ScdID, "lineno": r.Lineno, "ruleid": ruleid10, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  998. c.AppendPaseResult(rt)
  999. continue
  1000. }
  1001. if r.Name[0:1] != "C" {
  1002. parse_result := fmt.Sprintf("ConnectivityNode对象(%s)命名不符合规范:Cn进行命名(n)为间隔内ConnectivityNode实例的序号", r.Name)
  1003. rt := map[string]interface{}{"scdid": c.ScdID, "lineno": r.Lineno, "ruleid": ruleid10, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  1004. c.AppendPaseResult(rt)
  1005. } else {
  1006. no := r.Name[1:]
  1007. _, er := strconv.Atoi(no)
  1008. if er != nil {
  1009. parse_result := fmt.Sprintf("ConnectivityNode对象(%s)命名不符合规范:Cn进行命名(n)为间隔内ConnectivityNode实例的序号", r.Name)
  1010. rt := map[string]interface{}{"scdid": c.ScdID, "lineno": r.Lineno, "ruleid": ruleid10, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  1011. c.AppendPaseResult(rt)
  1012. }
  1013. }
  1014. }
  1015. }
  1016. }
  1017. }
  1018. }
  1019. }
  1020. }
  1021. }
  1022. //主要校验以下规则
  1023. //访问点命名一致性校验:〈Communication)下<ConnectedAP>的apName届性值是否指向已存在的TED访问点
  1024. //IED命名一致性校验:〈Communication)下(ConnectedAP>的iedName属性值是否指向己存在的IED
  1025. //GSE命名一致性校验:〈Communication)下<GSE>的cbName、Idlnst属性值是否指向已存在的GOOSE控制块
  1026. //SMV命名一致性校验:〈Communication)下<SMV>的cbName、Idlnst属性值是否指向已存在的SMV控制块
  1027. //ConnectedAP唯一性校验:ConnectedAP 不应重复配置
  1028. //
  1029. func (c *ScdNodeRule) CheckFunc_communication_connectedap(para orm.Params) {
  1030. logger.Logger.Debug(fmt.Sprintf("校验SCD %d的通信节点", c.ScdID))
  1031. if c.scdXmlObject.Communication == nil {
  1032. //验证不通过
  1033. parse_result := fmt.Sprintf("Communication未定义")
  1034. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Lineno, "ruleid": c.getRuleIdByName("Communication元素完备性校验"), "nodeid": c.scdXmlObject.NodeId, "parse_result": parse_result}
  1035. c.AppendPaseResult(r)
  1036. return
  1037. }
  1038. if len(c.scdXmlObject.Communication.SubNetwork) == 0 {
  1039. //验证不通过
  1040. parse_result := fmt.Sprintf("SubNetwork未定义")
  1041. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Communication.Lineno, "ruleid": c.getRuleIdByName("SubNetwork元素完备性校验"), "nodeid": c.scdXmlObject.NodeId, "parse_result": parse_result}
  1042. c.AppendPaseResult(r)
  1043. return
  1044. }
  1045. gseP := map[string]string{}
  1046. smvP := map[string]string{}
  1047. ipAddressIp := map[string]string{}
  1048. gseAppidMap := map[string]string{}
  1049. for _, subnet := range c.scdXmlObject.Communication.SubNetwork {
  1050. apPri := map[string]int{}
  1051. for _, apitem := range subnet.ConnectedAP {
  1052. if apPri[apitem.ApName+apitem.IedName] == 1 {
  1053. parse_result := fmt.Sprintf("%s子网下ConnectedAP(apName=%s,iedName=%s)重复配置", subnet.Name, apitem.ApName, apitem.IedName)
  1054. r := map[string]interface{}{"scdid": c.ScdID, "lineno": apitem.Lineno, "ruleid": c.getRuleIdByName("ConnectedAP唯一性校验"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1055. c.AppendPaseResult(r)
  1056. continue
  1057. }
  1058. apPri[apitem.ApName+apitem.IedName] = 1
  1059. ied := new(ScdNode).GetIed(c.scdXmlObject, "", apitem.IedName)
  1060. if ied == nil {
  1061. parse_result := fmt.Sprintf("%s子网下ConnectedAP(%s)的iedName(%s)未指向已存在的IED", subnet.Name, apitem.ApName, apitem.IedName)
  1062. r := map[string]interface{}{"scdid": c.ScdID, "lineno": apitem.Lineno, "ruleid": c.getRuleIdByName("IED命名一致性校验"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1063. c.AppendPaseResult(r)
  1064. continue
  1065. }
  1066. apHas := false
  1067. if ied.AccessPoint != nil {
  1068. for _, iedap := range ied.AccessPoint {
  1069. if iedap.Name == apitem.ApName {
  1070. apHas = true
  1071. break
  1072. }
  1073. }
  1074. }
  1075. if !apHas {
  1076. parse_result := fmt.Sprintf("%s子网下ConnectedAP(%s)的apName未指向已存在的IED访问点", subnet.Name, apitem.ApName)
  1077. r := map[string]interface{}{"scdid": c.ScdID, "lineno": apitem.Lineno, "ruleid": c.getRuleIdByName("访问点命名一致性校验"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1078. c.AppendPaseResult(r)
  1079. }
  1080. if len(apitem.SMV) > 0 {
  1081. for _, apsmvitem := range apitem.SMV {
  1082. foundLdInst := false
  1083. foundCbname := false
  1084. if ied.AccessPoint != nil {
  1085. for _, iedap := range ied.AccessPoint {
  1086. if iedap.Server == nil {
  1087. continue
  1088. }
  1089. for _, iedld := range iedap.Server.LDevice {
  1090. if iedld.Inst == apsmvitem.LdInst {
  1091. //查找控制块
  1092. if iedld.LN0 != nil {
  1093. for _, iedSmvCb := range iedld.LN0.SampledValueControl {
  1094. if iedSmvCb.Name == apsmvitem.CbName {
  1095. foundCbname = true
  1096. if iedSmvCb.SmvID == "" {
  1097. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的通信参数(svmID)缺失", apitem.IedName, subnet.Name, iedSmvCb.Name)
  1098. r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedSmvCb.Lineno, "ruleid": c.getRuleIdByName("SV通信参数缺失"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1099. c.AppendPaseResult(r, ied)
  1100. } else {
  1101. if v, h := gseAppidMap[iedSmvCb.SmvID]; h {
  1102. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的smvID(%s)与IED(%s)重复", apitem.IedName, subnet.Name, iedSmvCb.Name, iedSmvCb.SmvID, v)
  1103. r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedSmvCb.Lineno, "ruleid": c.getRuleIdByName("SV通信参数唯一性"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1104. c.AppendPaseResult(r, ied)
  1105. }
  1106. gseAppidMap[iedSmvCb.SmvID] = ied.Name
  1107. }
  1108. if iedSmvCb.ConfRev == "" {
  1109. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的通信参数(confRev)缺失", apitem.IedName, subnet.Name, iedSmvCb.Name)
  1110. r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedSmvCb.Lineno, "ruleid": c.getRuleIdByName("SV通信参数缺失"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1111. c.AppendPaseResult(r, ied)
  1112. }
  1113. break
  1114. }
  1115. }
  1116. }
  1117. foundLdInst = true
  1118. break
  1119. }
  1120. }
  1121. if foundLdInst {
  1122. break
  1123. }
  1124. }
  1125. }
  1126. if !foundLdInst {
  1127. parse_result := fmt.Sprintf("%s子网下ConnectedAP(%s,%s)的SMV(cbName=%s,ldInst=%s)中的ldInst未指向已存在的IED逻辑设备inst", subnet.Name, apitem.ApName, apitem.IedName, apsmvitem.CbName, apsmvitem.LdInst)
  1128. r := map[string]interface{}{"scdid": c.ScdID, "lineno": apsmvitem.Lineno, "ruleid": c.getRuleIdByName("SMV命名一致性校验"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1129. c.AppendPaseResult(r, ied)
  1130. } else {
  1131. if !foundCbname {
  1132. parse_result := fmt.Sprintf("%s子网下ConnectedAP(%s,%s)的SMV(cbName=%s,ldInst=%s)中的cbName未指向已存在的IED SMV控制块", subnet.Name, apitem.ApName, apitem.IedName, apsmvitem.CbName, apsmvitem.LdInst)
  1133. r := map[string]interface{}{"scdid": c.ScdID, "lineno": apsmvitem.Lineno, "ruleid": c.getRuleIdByName("SMV命名一致性校验"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1134. c.AppendPaseResult(r, ied)
  1135. }
  1136. }
  1137. if apsmvitem.Address != nil {
  1138. mACAddress := ""
  1139. for _, tmpP := range apsmvitem.Address.P {
  1140. if tmpP.InnerText == "" {
  1141. parse_result := fmt.Sprintf("IED(%s)下的LD(%s)在%s子网下的控制块(%s)的通信参数(%s)缺失", apitem.IedName, apsmvitem.LdInst, subnet.Name, apsmvitem.CbName, tmpP.Type)
  1142. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数缺失"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1143. c.AppendPaseResult(r, ied)
  1144. continue
  1145. }
  1146. key := tmpP.Type + tmpP.InnerText
  1147. tmpIednameV := smvP[key]
  1148. switch tmpP.Type {
  1149. case "MAC-Address":
  1150. if tmpIednameV != "" {
  1151. parse_result := fmt.Sprintf("IED(%s)在%s子网(%s)下的控制块(cbName=%s,ldInst=%s)的MAC地址(%s)与IED(%s)重复", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText, tmpIednameV)
  1152. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数唯一性"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1153. c.AppendPaseResult(r, ied)
  1154. break
  1155. }
  1156. ary := strings.Split(tmpP.InnerText, "-")
  1157. if len(ary) == 6 && strings.HasPrefix(tmpP.InnerText, "01-0C-CD-04-") {
  1158. //校验是否越界
  1159. p1, er1 := strconv.ParseUint(ary[4], 16, 32) //16进制转10进制
  1160. p2, er2 := strconv.ParseUint(ary[5], 16, 32) //16进制转10进制
  1161. if er1 != nil || er2 != nil {
  1162. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的MAC地址(%s)配置不规范", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1163. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数Mac地址越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1164. c.AppendPaseResult(r)
  1165. } else {
  1166. p00, _ := strconv.ParseUint("00", 16, 32)
  1167. pff, _ := strconv.ParseUint("FF", 16, 32)
  1168. if p1 < p00 || p1 > pff || p2 < p00 || p2 > pff {
  1169. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的MAC地址(%s)越界", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1170. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数Mac地址越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1171. c.AppendPaseResult(r)
  1172. } else {
  1173. mACAddress = tmpP.InnerText
  1174. }
  1175. }
  1176. } else {
  1177. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的MAC地址(%s)配置不规范", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1178. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数Mac地址越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1179. c.AppendPaseResult(r, ied)
  1180. }
  1181. break
  1182. case "APPID":
  1183. if tmpIednameV != "" {
  1184. parse_result := fmt.Sprintf("IED(%s)在%s子网(%s)下的控制块(cbName=%s,ldInst=%s)的APPID(%s)与IED(%s)重复", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText, tmpIednameV)
  1185. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数唯一性"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1186. c.AppendPaseResult(r, ied)
  1187. } else {
  1188. //校验APPID是否越界
  1189. p16, er := strconv.ParseUint(tmpP.InnerText, 16, 32)
  1190. if len(tmpP.InnerText) != 4 || er != nil {
  1191. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的APPID(%s)配置不规范,应为4位16进制值", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1192. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数APPID越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1193. c.AppendPaseResult(r, ied)
  1194. } else {
  1195. p1000, _ := strconv.ParseUint("4000", 16, 32)
  1196. p1fff, _ := strconv.ParseUint("4FFF", 16, 32)
  1197. if p16 < p1000 || p16 > p1fff {
  1198. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的APPID(%s)越界,其范围为0x4000~0x4FFF", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1199. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数APPID越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1200. c.AppendPaseResult(r, ied)
  1201. }
  1202. if mACAddress != "" {
  1203. //校验appid生成是否正确
  1204. macAry := strings.Split(mACAddress, "-")
  1205. tmpAppid := macAry[3][1:] + macAry[4][1:] + macAry[5]
  1206. if tmpP.InnerText != tmpAppid {
  1207. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的APPID(%s)与mac地址不匹配", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1208. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数APPID与Mac地址不匹配"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1209. c.AppendPaseResult(r, ied)
  1210. }
  1211. }
  1212. }
  1213. }
  1214. break
  1215. case "VLAN-ID":
  1216. p16, er := strconv.ParseUint(tmpP.InnerText, 16, 32)
  1217. if er != nil || len(tmpP.InnerText) < 3 {
  1218. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的VLAN-ID(%s)配置不规范,应为3位16进制值", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1219. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数VLAN-ID越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1220. c.AppendPaseResult(r, ied)
  1221. } else {
  1222. p1000, _ := strconv.ParseUint("000", 16, 32)
  1223. p1fff, _ := strconv.ParseUint("FFF", 16, 32)
  1224. if p16 < p1000 || p16 > p1fff {
  1225. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的VLAN-ID(%s)越界,其范围为0x000~0xFFF", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1226. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数VLAN-ID越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1227. c.AppendPaseResult(r, ied)
  1228. }
  1229. }
  1230. break
  1231. case "VLAN-Priority":
  1232. p16, er := strconv.ParseUint(tmpP.InnerText, 16, 32)
  1233. if len(tmpP.InnerText) != 1 || er != nil {
  1234. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的VLAN-Priority(%s)配置不规范,应为1位16进制值", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1235. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数VLAN-Priority越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1236. c.AppendPaseResult(r, ied)
  1237. } else {
  1238. if p16 < 0 || p16 > 7 {
  1239. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的VLAN-Priority(%s)越界,其范围为0~7", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1240. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数VLAN-Priority越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1241. c.AppendPaseResult(r, ied)
  1242. }
  1243. }
  1244. break
  1245. }
  1246. smvP[key] = apitem.IedName
  1247. }
  1248. }
  1249. }
  1250. }
  1251. if len(apitem.GSE) > 0 {
  1252. for _, apsmvitem := range apitem.GSE {
  1253. foundLdInst := false
  1254. foundCbname := false
  1255. if ied.AccessPoint != nil {
  1256. for _, iedap := range ied.AccessPoint {
  1257. if iedap.Server == nil {
  1258. continue
  1259. }
  1260. for _, iedld := range iedap.Server.LDevice {
  1261. if iedld.Inst == apsmvitem.LdInst {
  1262. //查找控制块
  1263. if iedld.LN0 != nil {
  1264. for _, iedCb := range iedld.LN0.GSEControl {
  1265. if iedCb.Name == apsmvitem.CbName {
  1266. foundCbname = true
  1267. if iedCb.AppID == "" {
  1268. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的通信参数(appID)缺失", apitem.IedName, subnet.Name, iedCb.Name)
  1269. r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedCb.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数缺失"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1270. c.AppendPaseResult(r, ied)
  1271. } else {
  1272. if v, h := gseAppidMap[iedCb.AppID]; h {
  1273. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的appID(%s)与IED(%s)重复", apitem.IedName, subnet.Name, iedCb.Name, iedCb.AppID, v)
  1274. r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedCb.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数唯一性"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1275. c.AppendPaseResult(r, ied)
  1276. }
  1277. gseAppidMap[iedCb.AppID] = ied.Name
  1278. }
  1279. if iedCb.ConfRev == "" {
  1280. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的通信参数(confRev)缺失", apitem.IedName, subnet.Name, iedCb.Name)
  1281. r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedCb.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数缺失"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1282. c.AppendPaseResult(r, ied)
  1283. }
  1284. break
  1285. }
  1286. }
  1287. }
  1288. foundLdInst = true
  1289. break
  1290. }
  1291. }
  1292. if foundLdInst {
  1293. break
  1294. }
  1295. }
  1296. }
  1297. if !foundLdInst {
  1298. parse_result := fmt.Sprintf("%s子网下ConnectedAP(%s,%s)的GSE(cbName=%s,ldInst=%s)中的ldInst未指向已存在的IED逻辑设备inst", subnet.Name, apitem.ApName, apitem.IedName, apsmvitem.CbName, apsmvitem.LdInst)
  1299. r := map[string]interface{}{"scdid": c.ScdID, "lineno": apsmvitem.Lineno, "ruleid": c.getRuleIdByName("GSE命名一致性校验"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1300. c.AppendPaseResult(r, ied)
  1301. } else {
  1302. if !foundCbname {
  1303. parse_result := fmt.Sprintf("%s子网下ConnectedAP(%s,%s)的GSE(cbName=%s,ldInst=%s)中的cbName未指向已存在的IED GOOSE控制块", subnet.Name, apitem.ApName, apitem.IedName, apsmvitem.CbName, apsmvitem.LdInst)
  1304. r := map[string]interface{}{"scdid": c.ScdID, "lineno": apsmvitem.Lineno, "ruleid": c.getRuleIdByName("GSE命名一致性校验"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1305. c.AppendPaseResult(r, ied)
  1306. }
  1307. }
  1308. //GOOSE通信参数校验:GOOSE通信参数唯一性、GOOSE通信参数Mac地址越界、GOOSE通信参数APPID越界、GOOSE通信参数APPID与Mac地址不匹配、GOOSE通信参数VLAN-ID越界、GOOSE通信参数VLAN-Priority越界、GOOSE通信参数MinTime 和 MaxTime 不为推荐值、GOOSE通信参数缺失
  1309. if apsmvitem.Address != nil {
  1310. mACAddress := ""
  1311. for _, tmpP := range apsmvitem.Address.P {
  1312. if tmpP.InnerText == "" {
  1313. parse_result := fmt.Sprintf("IED(%s)下的LD(%s)在%s子网控制块(%s)的通信参数(%s)缺失", apitem.IedName, apsmvitem.LdInst, subnet.Name, apsmvitem.CbName, tmpP.Type)
  1314. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数缺失"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1315. c.AppendPaseResult(r, ied)
  1316. continue
  1317. }
  1318. key := tmpP.Type + tmpP.InnerText
  1319. tmpIednameV := gseP[key]
  1320. switch tmpP.Type {
  1321. case "MAC-Address":
  1322. if tmpIednameV != "" {
  1323. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的MAC地址(%s)与IED(%s)重复", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText, tmpIednameV)
  1324. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数唯一性"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1325. c.AppendPaseResult(r, ied)
  1326. break
  1327. }
  1328. ary := strings.Split(tmpP.InnerText, "-")
  1329. if len(ary) == 6 && strings.HasPrefix(tmpP.InnerText, "01-0C-CD-01-") {
  1330. //校验是否越界
  1331. p1, er1 := strconv.ParseUint(ary[4], 16, 32) //16进制转10进制
  1332. p2, er2 := strconv.ParseUint(ary[5], 16, 32) //16进制转10进制
  1333. if er1 != nil || er2 != nil {
  1334. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的MAC地址(%s)配置不规范", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1335. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数Mac地址越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1336. c.AppendPaseResult(r)
  1337. } else {
  1338. p00, _ := strconv.ParseUint("00", 16, 32)
  1339. pff, _ := strconv.ParseUint("FF", 16, 32)
  1340. if p1 < p00 || p1 > pff || p2 < p00 || p2 > pff {
  1341. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的MAC地址(%s)越界", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1342. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数Mac地址越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1343. c.AppendPaseResult(r)
  1344. } else {
  1345. mACAddress = tmpP.InnerText
  1346. }
  1347. }
  1348. } else {
  1349. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的MAC地址(%s)配置不规范", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1350. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数Mac地址越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1351. c.AppendPaseResult(r, ied)
  1352. }
  1353. break
  1354. case "APPID":
  1355. if tmpIednameV != "" {
  1356. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的APPID(%s)与IED(%s)重复", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText, tmpIednameV)
  1357. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数唯一性"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1358. c.AppendPaseResult(r, ied)
  1359. } else {
  1360. //校验APPID是否越界
  1361. p16, er := strconv.ParseUint(tmpP.InnerText, 16, 32)
  1362. if len(tmpP.InnerText) != 4 || er != nil {
  1363. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的APPID(%s)配置不规范,应为4位16进制值", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1364. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数APPID越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1365. c.AppendPaseResult(r, ied)
  1366. } else {
  1367. p1000, _ := strconv.ParseUint("1000", 16, 32)
  1368. p1fff, _ := strconv.ParseUint("1FFF", 16, 32)
  1369. if p16 < p1000 || p16 > p1fff {
  1370. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的APPID(%s)越界,其范围为0x1000~0x1FFF", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1371. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数APPID越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1372. c.AppendPaseResult(r, ied)
  1373. }
  1374. if mACAddress != "" {
  1375. //校验appid生成是否正确
  1376. macAry := strings.Split(mACAddress, "-")
  1377. tmpAppid := macAry[3][1:] + macAry[4][1:] + macAry[5]
  1378. if tmpP.InnerText != tmpAppid {
  1379. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的APPID(%s)与mac地址不匹配", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1380. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数APPID与Mac地址不匹配"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1381. c.AppendPaseResult(r, ied)
  1382. }
  1383. }
  1384. }
  1385. }
  1386. break
  1387. case "VLAN-ID":
  1388. p16, er := strconv.ParseUint(tmpP.InnerText, 16, 32)
  1389. if er != nil || len(tmpP.InnerText) < 3 {
  1390. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的VLAN-ID(%s)配置不规范,应为3位16进制值", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1391. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数VLAN-ID越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1392. c.AppendPaseResult(r, ied)
  1393. } else {
  1394. p1000, _ := strconv.ParseUint("000", 16, 32)
  1395. p1fff, _ := strconv.ParseUint("FFF", 16, 32)
  1396. if p16 < p1000 || p16 > p1fff {
  1397. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的VLAN-ID(%s)越界,其范围为0x000~0xFFF", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1398. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数VLAN-ID越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1399. c.AppendPaseResult(r, ied)
  1400. }
  1401. }
  1402. break
  1403. case "VLAN-Priority":
  1404. p16, er := strconv.ParseUint(tmpP.InnerText, 16, 32)
  1405. if len(tmpP.InnerText) != 1 || er != nil {
  1406. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的VLAN-Priority(%s)配置不规范,应为1位16进制值", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1407. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数VLAN-Priority越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1408. c.AppendPaseResult(r, ied)
  1409. } else {
  1410. if p16 < 0 || p16 > 7 {
  1411. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的VLAN-Priority(%s)越界,其范围为0~7", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1412. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数VLAN-Priority越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1413. c.AppendPaseResult(r, ied)
  1414. }
  1415. }
  1416. break
  1417. }
  1418. gseP[key] = apitem.IedName
  1419. }
  1420. }
  1421. if apsmvitem.MaxTime == nil {
  1422. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的通信参数(MaxTime)缺失", apitem.IedName, subnet.Name, apsmvitem.CbName)
  1423. r := map[string]interface{}{"scdid": c.ScdID, "lineno": apsmvitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数缺失"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1424. c.AppendPaseResult(r, ied)
  1425. } else {
  1426. if apsmvitem.MaxTime.InnerText != "5000" {
  1427. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的通信参数MaxTime(%s)不为标准值5000", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.MaxTime.InnerText)
  1428. r := map[string]interface{}{"scdid": c.ScdID, "lineno": apsmvitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数MinTime和MaxTime不为推荐值"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1429. c.AppendPaseResult(r, ied)
  1430. }
  1431. }
  1432. if apsmvitem.MinTime == nil {
  1433. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的通信参数(MinTime)缺失", apitem.IedName, subnet.Name, apsmvitem.CbName)
  1434. r := map[string]interface{}{"scdid": c.ScdID, "lineno": apsmvitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数缺失"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1435. c.AppendPaseResult(r, ied)
  1436. } else {
  1437. if apsmvitem.MinTime.InnerText != "2" {
  1438. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的通信参数MinTime(%s)不为标准值2", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.MinTime.InnerText)
  1439. r := map[string]interface{}{"scdid": c.ScdID, "lineno": apsmvitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数MinTime和MaxTime不为推荐值"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1440. c.AppendPaseResult(r, ied)
  1441. }
  1442. }
  1443. }
  1444. }
  1445. //检查站控层通信参数校验
  1446. //1、IP地址同一子网内唯一性
  1447. if apitem.Address != nil {
  1448. for _, ips := range apitem.Address.P {
  1449. if ips.Type == "IP" {
  1450. if ips.InnerText == "" {
  1451. parse_result := fmt.Sprintf("IED(%s)在%s子网下未配置IP地址", apitem.ApName, subnet.Name, subnet.Desc)
  1452. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ips.Lineno, "ruleid": c.getRuleIdByName("IP地址未配置"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1453. c.AppendPaseResult(r, ied)
  1454. } else {
  1455. //判断IP是否越界
  1456. ipparts := strings.Split(ips.InnerText, ".")
  1457. if len(ipparts) != 4 {
  1458. parse_result := fmt.Sprintf("IED(%s)在%s子网下IP地址(%s)无效", apitem.ApName, subnet.Name, ips.InnerText)
  1459. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ips.Lineno, "ruleid": c.getRuleIdByName("IP地址配置不规范"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1460. c.AppendPaseResult(r, ied)
  1461. } else {
  1462. ip1, _ := strconv.Atoi(ipparts[0])
  1463. ip2, _ := strconv.Atoi(ipparts[1])
  1464. ip3, _ := strconv.Atoi(ipparts[2])
  1465. ip4, _ := strconv.Atoi(ipparts[3])
  1466. if (ip1 < 0 && ip1 > 255) || (ip2 < 0 && ip2 > 255) || (ip3 < 0 && ip3 > 255) || (ip4 < 0 && ip4 > 255) {
  1467. parse_result := fmt.Sprintf("IED(%s)在%s子网下IP地址(%s)越界", apitem.ApName, subnet.Name, ips.InnerText)
  1468. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ips.Lineno, "ruleid": c.getRuleIdByName("IP地址越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1469. c.AppendPaseResult(r, ied)
  1470. }
  1471. }
  1472. }
  1473. if tmpIednameV, h := ipAddressIp[ips.InnerText]; h {
  1474. parse_result := fmt.Sprintf("IED(%s)在%s子网下的IP地址与IED(%s)重复", apitem.ApName, subnet.Name, tmpIednameV)
  1475. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ips.Lineno, "ruleid": c.getRuleIdByName("IP地址唯一性"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1476. c.AppendPaseResult(r, ied)
  1477. }
  1478. ipAddressIp[ips.InnerText] = apitem.IedName
  1479. }
  1480. if ips.Type == "IP-SUBNET" {
  1481. if ips.InnerText == "" {
  1482. parse_result := fmt.Sprintf("IED(%s)在%s子网下未配置IP-SUBNET地址", apitem.ApName, subnet.Name, subnet.Desc)
  1483. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ips.Lineno, "ruleid": c.getRuleIdByName("IP-SUBNET地址未配置"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1484. c.AppendPaseResult(r, ied)
  1485. } else {
  1486. ipparts := strings.Split(ips.InnerText, ".")
  1487. if len(ipparts) != 4 {
  1488. parse_result := fmt.Sprintf("IED(%s)在%s子网下IP-SUBNET地址(%s)无效", apitem.ApName, subnet.Name, ips.InnerText)
  1489. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ips.Lineno, "ruleid": c.getRuleIdByName("IP-SUBNET地址配置不规范"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1490. c.AppendPaseResult(r, ied)
  1491. } else {
  1492. ip1, _ := strconv.Atoi(ipparts[0])
  1493. ip2, _ := strconv.Atoi(ipparts[1])
  1494. ip3, _ := strconv.Atoi(ipparts[2])
  1495. ip4, _ := strconv.Atoi(ipparts[3])
  1496. if (ip1 < 0 && ip1 > 255) || (ip2 < 0 && ip2 > 255) || (ip3 < 0 && ip3 > 255) || (ip4 < 0 && ip4 > 255) {
  1497. parse_result := fmt.Sprintf("IED(%s)在%s子网下IP-SUBNET地址(%s)越界", apitem.ApName, subnet.Name, ips.InnerText)
  1498. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ips.Lineno, "ruleid": c.getRuleIdByName("IP-SUBNET地址越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1499. c.AppendPaseResult(r, ied)
  1500. }
  1501. }
  1502. }
  1503. }
  1504. }
  1505. }
  1506. }
  1507. }
  1508. }
  1509. //IED校验
  1510. //.IED(XXX)中Server对象缺失
  1511. //.IED(XXX)中访问点***中的Server缺失LD对象
  1512. //.IED(XXX)中LD***中缺失LLN0
  1513. //.IED(XXX)中LD***中缺失LPHD
  1514. //.IED(XXX)中LD***中缺失非LPHD外其他LN
  1515. func (c *ScdNodeRule) CheckFunc_ied(dATypeMap map[string]*node_attr.NDAType) {
  1516. logger.Logger.Debug(fmt.Sprintf("校验SCD %d的IED节点", c.ScdID))
  1517. if c.scdXmlObject == nil {
  1518. return
  1519. }
  1520. //fcdaMap := map[string]string{}
  1521. gooseAppidMap := sync.Map{} // map[string]*node_attr.NIED{}
  1522. smvAppidMap := sync.Map{} // map[string]*node_attr.NIED{}
  1523. reportRptIDMap := sync.Map{}
  1524. var confDataSet *node_attr.NConfDataSet
  1525. for _, iedObj := range c.scdXmlObject.IED {
  1526. //判断ccd校验码 需要在生成crc校验码后进行
  1527. ccdCrc := ""
  1528. for _, iedPrivate := range iedObj.Priavate {
  1529. if iedPrivate.Type == "IED virtual terminal conection CRC" {
  1530. ccdCrc = iedPrivate.InnerText
  1531. break
  1532. }
  1533. }
  1534. if ccdCrc == "" {
  1535. parse_result := fmt.Sprintf("IED(%s)不存在ICD文件CRC校验码", iedObj.Name)
  1536. r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedObj.Lineno, "ruleid": c.getRuleIdByName("ICD文件校验码存在性"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1537. c.AppendPaseResult(r, iedObj)
  1538. }
  1539. if iedObj.Services != nil {
  1540. confDataSet = iedObj.Services.ConfDataSet
  1541. }
  1542. signalMapFound := false
  1543. for _, iedPrivate := range iedObj.Priavate {
  1544. if iedPrivate.Type == "Signal Map" {
  1545. signalMapFound = true
  1546. break
  1547. }
  1548. }
  1549. if !signalMapFound {
  1550. parse_result := fmt.Sprintf("IED(%s)定义关联关系的信号或软压板不存在", iedObj.Name)
  1551. r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedObj.Lineno, "ruleid": c.getRuleIdByName("信号关联关系格式检查"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1552. c.AppendPaseResult(r, iedObj)
  1553. }
  1554. if len(iedObj.Name) < 5 || len(iedObj.Name) > 8 {
  1555. //IED 的 name 由 5 部分共 8 位合法可视字符组成,分别代表: IED 类型、归属设备类型、电压等级、归属设备编号、 IED 编号,具体要求如附录 B 所示
  1556. parse_result := fmt.Sprintf("IED(%s)名称不符合规范要求", iedObj.Name)
  1557. r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedObj.Lineno, "ruleid": c.getRuleIdByName("IEDName合法性校验"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1558. c.AppendPaseResult(r, iedObj)
  1559. }
  1560. if len(iedObj.AccessPoint) == 0 {
  1561. parse_result := fmt.Sprintf("IED(%s)中AccessPoint对象缺失", iedObj.Name)
  1562. r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedObj.Lineno, "ruleid": c.getRuleIdByName("访问点(AccessPoint)名称校验"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1563. c.AppendPaseResult(r, iedObj)
  1564. continue
  1565. }
  1566. for _, ap := range iedObj.AccessPoint {
  1567. if ap.Server == nil {
  1568. parse_result := fmt.Sprintf("IED(%s)中Server对象缺失", iedObj.Name)
  1569. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ap.Lineno, "ruleid": c.getRuleIdByName("逻辑设备建模正确性"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1570. c.AppendPaseResult(r, iedObj)
  1571. continue
  1572. }
  1573. if len(ap.Server.LDevice) == 0 {
  1574. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)缺失LD对象", iedObj.Name, ap.Name, ap.Desc)
  1575. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ap.Server.Lineno, "ruleid": c.getRuleIdByName("逻辑设备建模正确性"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1576. c.AppendPaseResult(r, iedObj)
  1577. continue
  1578. }
  1579. for _, ld := range ap.Server.LDevice {
  1580. //校验DOI/SDI引用模板不一致、DAI引用模板不一致
  1581. c.check_ln_doidai(iedObj, dATypeMap, ld)
  1582. if ld.LN0 == nil {
  1583. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)缺失对象LLN0", iedObj.Name, ap.Name, ap.Desc, ld.Desc)
  1584. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ld.Lineno, "ruleid": c.getRuleIdByName("逻辑设备建模正确性"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1585. c.AppendPaseResult(r, iedObj)
  1586. continue
  1587. } else {
  1588. if _, h := c.lnodeTypeMap.Load(ld.LN0.LnType); !h {
  1589. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)下的LN0(%s)引用的LNodeType(%s)在模板中不存在", iedObj.Name, ap.Name, ap.Desc, ld.Inst, ld.LN0.Desc, ld.LN0.LnType)
  1590. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ld.LN0.Lineno, "ruleid": c.getRuleIdByName("LN引用LNodeType不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1591. c.AppendPaseResult(r, iedObj)
  1592. }
  1593. if confDataSet != nil {
  1594. max, _ := strconv.Atoi(confDataSet.Max)
  1595. if len(ld.LN0.DataSet) > max {
  1596. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)数据集个数超过允许的最大值(当前数=%d, 最大值=%s)", iedObj.Name, ap.Name, ap.Desc, ld.Inst, len(ld.LN0.DataSet), confDataSet.Max)
  1597. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ld.LN0.Lineno, "ruleid": c.getRuleIdByName("数据集数目校验"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1598. c.AppendPaseResult(r, iedObj)
  1599. }
  1600. }
  1601. datsetList := map[string]*node_attr.NDataSet{}
  1602. //校验FCDA唯一性
  1603. for _, datset := range ld.LN0.DataSet {
  1604. datsetList[datset.Name] = datset
  1605. if confDataSet != nil {
  1606. max, _ := strconv.Atoi(confDataSet.MaxAttributes)
  1607. if len(datset.FCDA) > max {
  1608. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)数据集(%s)成员FCDA个数超过允许的最大值(当前数=%d, 最大值=%s)", iedObj.Name, ap.Name, ap.Desc, ld.Inst, datset.Name, len(datset.FCDA), confDataSet.MaxAttributes)
  1609. r := map[string]interface{}{"scdid": c.ScdID, "lineno": datset.Lineno, "ruleid": c.getRuleIdByName("数据集成员数目校验"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1610. c.AppendPaseResult(r, iedObj)
  1611. }
  1612. }
  1613. //dsGOOSE 数据集成员总数不应超过256个
  1614. if strings.HasPrefix(datset.Name, "dsGOOSE") && len(datset.FCDA) > 256 {
  1615. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)数据集(%s)成员FCDA个数%d不能超过256", iedObj.Name, ap.Name, ap.Desc, ld.Inst, datset.Name, len(datset.FCDA))
  1616. r := map[string]interface{}{"scdid": c.ScdID, "lineno": datset.Lineno, "ruleid": c.getRuleIdByName("校验数据集成员构成"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1617. c.AppendPaseResult(r, iedObj)
  1618. }
  1619. for _, fcdaitem := range datset.FCDA {
  1620. key := fmt.Sprintf("%s/%s%s%s.%s", fcdaitem.LdInst, fcdaitem.Prefix, fcdaitem.LnClass, fcdaitem.LnInst, fcdaitem.DoName)
  1621. if fcdaitem.DaName != "" {
  1622. key = key + "." + fcdaitem.DaName
  1623. }
  1624. if fcdaitem.LdInst != ld.Inst {
  1625. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)数据集(%s)FCDA成员(%s)不允许跨LD", iedObj.Name, ap.Name, ap.Desc, ld.Inst, datset.Name, key)
  1626. r := map[string]interface{}{"scdid": c.ScdID, "lineno": fcdaitem.Lineno, "ruleid": c.getRuleIdByName("数据集成员跨LD校验"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1627. c.AppendPaseResult(r, iedObj)
  1628. continue
  1629. }
  1630. //成员有效性
  1631. has1, _ := c.iedFcdaExist(iedObj.Name, fcdaitem.LdInst, fcdaitem.LnClass, fcdaitem.LnInst, fcdaitem.Prefix, fcdaitem.DoName, fcdaitem.DaName)
  1632. if has1 == nil {
  1633. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)数据集(%s)FCDA成员(%s)不存在", iedObj.Name, ap.Name, ap.Desc, ld.Inst, datset.Name, key)
  1634. r := map[string]interface{}{"scdid": c.ScdID, "lineno": fcdaitem.Lineno, "ruleid": c.getRuleIdByName("数据集成员有效性校验"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1635. c.AppendPaseResult(r, iedObj)
  1636. }
  1637. //dsGOOSE 数据集的所有成员都应采用FCDA构成方式,其它数据集成员都应采用FCD构成方式。
  1638. if strings.HasPrefix(datset.Name, "dsGOOSE") && fcdaitem.DaName == "" {
  1639. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)数据集(%s)成员(%s)不是FCDA格式", iedObj.Name, ap.Name, ap.Desc, ld.Inst, datset.Name, key)
  1640. r := map[string]interface{}{"scdid": c.ScdID, "lineno": fcdaitem.Lineno, "ruleid": c.getRuleIdByName("校验数据集成员构成"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1641. c.AppendPaseResult(r, iedObj)
  1642. }
  1643. if !strings.HasPrefix(datset.Name, "dsGOOSE") && fcdaitem.DaName != "" {
  1644. //parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)数据集(%s)成员(%s)不是FCD格式", iedObj.Name, ap.Name, ap.Desc, ld.Inst, datset.Name, key)
  1645. //r := map[string]interface{}{"scdid": c.ScdID, "ruleid": c.getRuleIdByName("校验数据集成员构成"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1646. //c.AppendPaseResult(r, iedObj)
  1647. }
  1648. }
  1649. }
  1650. //虚回路校验
  1651. if ld.LN0.Inputs != nil {
  1652. for _, extref := range ld.LN0.Inputs.ExtRef {
  1653. //检查端子2端模型是否相同:DO对应DO,DA对应DA
  1654. hasinsideda := extref.DaName != ""
  1655. hasoutsideda := strings.Count(extref.IntAddr, ".") > 1
  1656. if hasinsideda != hasoutsideda {
  1657. extrefstr := fmt.Sprintf("IED=%s,addr=%s/%s%s%s.%s", extref.IedName, extref.LdInst, extref.Prefix, extref.LnClass, extref.LnInst, extref.DoName)
  1658. if extref.DaName != "" {
  1659. extrefstr = extrefstr + "." + extref.DaName
  1660. }
  1661. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)中LD(%s)的关联内(%s)外部虚端子(%s)类型不一致", iedObj.Name, ap.Name, ap.Desc, ld.Inst, extref.IntAddr, extrefstr)
  1662. r := map[string]interface{}{"scdid": c.ScdID, "lineno": extref.Lineno, "ruleid": c.getRuleIdByName("连线两端数据不匹配"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1663. c.AppendPaseResult(r, iedObj)
  1664. }
  1665. has1, cdc1 := c.iedFcdaExist(extref.IedName, extref.LdInst, extref.LnClass, extref.LnInst, extref.Prefix, extref.DoName, extref.DaName)
  1666. if has1 == nil {
  1667. extrefstr := fmt.Sprintf("IED=%s,addr=%s/%s%s%s.%s", extref.IedName, extref.LdInst, extref.Prefix, extref.LnClass, extref.LnInst, extref.DoName)
  1668. if extref.DaName != "" {
  1669. extrefstr = extrefstr + "." + extref.DaName
  1670. }
  1671. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)中LD(%s)的关联外部虚端子(%s)不存在", iedObj.Name, ap.Name, ap.Desc, ld.Inst, extrefstr)
  1672. r := map[string]interface{}{"scdid": c.ScdID, "lineno": extref.Lineno, "ruleid": c.getRuleIdByName("连线外部虚端子合法性"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1673. c.AppendPaseResult(r, iedObj)
  1674. }
  1675. //内部地址对应的定义是否存在校验
  1676. /*
  1677. has2 := c.iedIntAddrExist(iedObj.Name, extref.IntAddr)
  1678. if has2 == nil {
  1679. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)中LD(%s)的虚回路关联内部虚端子(%s)不存在", iedObj.Name, ap.Name, ap.Desc, ld.Inst, extref.IntAddr)
  1680. r := map[string]interface{}{"scdid": c.ScdID, "lineno": extref.Lineno, "ruleid": c.getRuleIdByName("连线内部参引对应数据不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1681. c.AppendPaseResult(r, iedObj)
  1682. }
  1683. */
  1684. //da或do实例化校验
  1685. has2, cdc2 := c.iedIntAddrDoiOrDaiExist(iedObj.Name, extref.IntAddr)
  1686. if has2 == nil {
  1687. //parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)中LD(%s)的虚回路关联内部虚端子(%s)属性值与实例化不匹配", iedObj.Name, ap.Name, ap.Desc, ld.Inst, extref.IntAddr)
  1688. //r := map[string]interface{}{"scdid": c.ScdID, "lineno": extref.Lineno, "ruleid": c.getRuleIdByName("连线内部参引对应数据不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1689. //c.AppendPaseResult(r, iedObj)
  1690. }
  1691. //连接2端端子数据类型匹配检查。即DO数据模板的cdc属性值以及Da的bType
  1692. if has1 != nil && has2 != nil && cdc1 != cdc2 {
  1693. tmpTypeName := "CDC"
  1694. if extref.DaName != "" {
  1695. tmpTypeName = "bType"
  1696. }
  1697. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)中LD(%s)的虚端子(%s)%s类型(%s)与关联外部虚端子(%s %s/%s%s%s.%s)的类型(%s)不匹配", iedObj.Name, ap.Name, ap.Desc, ld.Inst, extref.IntAddr, tmpTypeName, cdc2, extref.IedName, extref.LdInst, extref.Prefix, extref.LnClass, extref.LnInst, extref.DoName, cdc1)
  1698. r := map[string]interface{}{"scdid": c.ScdID, "lineno": extref.Lineno, "ruleid": c.getRuleIdByName("连线两端数据不匹配"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1699. c.AppendPaseResult(r, iedObj)
  1700. }
  1701. }
  1702. }
  1703. //GOOSE控制块校验
  1704. gooseitemMap := map[string]int{}
  1705. if iedObj.Services.GOOSE != nil {
  1706. max, _ := strconv.Atoi(iedObj.Services.GOOSE.Max)
  1707. if len(ld.LN0.GSEControl) > max {
  1708. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)GOOSE控制块个数%d超出声明的最大值(%d)", iedObj.Name, ap.Name, ap.Desc, ld.Inst, len(ld.LN0.GSEControl), max)
  1709. r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedObj.Services.GOOSE.Lineno, "ruleid": c.getRuleIdByName("GOOSE控制块的个数超出声明的最大值"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1710. c.AppendPaseResult(r, iedObj)
  1711. }
  1712. }
  1713. for _, gooseitem := range ld.LN0.GSEControl {
  1714. if gooseitemMap[gooseitem.Name] == 1 {
  1715. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)GOOSE控制块(%s)name属性值在LN内重复配置", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
  1716. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE控制块的name属性值在LN内重复配置"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1717. c.AppendPaseResult(r)
  1718. continue
  1719. }
  1720. gooseitemMap[gooseitem.Name] = 1
  1721. if datsetList[gooseitem.DatSet] == nil {
  1722. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)GOOSE控制块(%s)引用的数据集(%s)不存在", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name, gooseitem.DatSet)
  1723. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE控制块引用的数据集不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1724. c.AppendPaseResult(r, iedObj)
  1725. }
  1726. if gooseitem.AppID == "" {
  1727. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)GOOSE控制块(%s)appID属性配置错误", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
  1728. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE控制块的appID属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1729. c.AppendPaseResult(r, iedObj)
  1730. } else {
  1731. if tmpIED, h := gooseAppidMap.Load(gooseitem.AppID); h {
  1732. iedPointer := tmpIED.(*node_attr.NIED)
  1733. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)GOOSE控制块(%s)的appID(%s)与IED(%s)中重复定义", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name, gooseitem.AppID, iedPointer.Name)
  1734. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE控制块的appID唯一性"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1735. c.AppendPaseResult(r, iedObj)
  1736. }
  1737. //格式校验
  1738. newGooseAppid := fmt.Sprintf("%s%s/LLN0.%s", iedObj.Name, ld.Inst, gooseitem.Name)
  1739. if gooseitem.AppID != newGooseAppid {
  1740. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)GOOSE控制块(%s)的appID(%s)格式不符合规范", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name, gooseitem.AppID)
  1741. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE控制块appID格式校验"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1742. c.AppendPaseResult(r, iedObj)
  1743. }
  1744. gooseAppidMap.Store(gooseitem.AppID, iedObj)
  1745. if gooseitem.ConfRev == "" {
  1746. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)GOOSE控制块(%s)的confRev属性配置错误", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
  1747. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE控制块的confRev属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1748. c.AppendPaseResult(r, iedObj)
  1749. }
  1750. //是否配置网络参数
  1751. gseNetFound := false
  1752. for _, net := range c.scdXmlObject.Communication.SubNetwork {
  1753. if net.Type != gooseitem.Type && net.Type != "IECGOOSE" {
  1754. continue
  1755. }
  1756. for _, connAp := range net.ConnectedAP {
  1757. if connAp.IedName == iedObj.Name {
  1758. for _, gseNet := range connAp.GSE {
  1759. if gseNet.CbName == gooseitem.Name && gseNet.LdInst == ld.Inst {
  1760. gseNetFound = true
  1761. }
  1762. }
  1763. }
  1764. }
  1765. }
  1766. if !gseNetFound {
  1767. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)GOOSE控制块(%s)未配置网络参数", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
  1768. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE控制块未配置网络参数"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1769. c.AppendPaseResult(r, iedObj)
  1770. }
  1771. }
  1772. }
  1773. //SV控制块
  1774. smvitemMap := map[string]int{}
  1775. for _, gooseitem := range ld.LN0.SampledValueControl {
  1776. if smvitemMap[gooseitem.Name] == 1 {
  1777. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)SV控制块(%s)name属性值在LN内重复配置", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
  1778. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("SV控制块的name属性值在LN内重复配置"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1779. c.AppendPaseResult(r, iedObj)
  1780. continue
  1781. }
  1782. smvitemMap[gooseitem.Name] = 1
  1783. if datsetList[gooseitem.DatSet] == nil {
  1784. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)SV控制块(%s)引用的数据集(%s)不存在", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name, gooseitem.DatSet)
  1785. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("SV控制块引用的数据集不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1786. c.AppendPaseResult(r, iedObj)
  1787. }
  1788. if gooseitem.SmvID == "" {
  1789. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)SV控制块(%s)smvID属性配置错误", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
  1790. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("SV控制块的smvID属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1791. c.AppendPaseResult(r, iedObj)
  1792. } else {
  1793. if tmpIED, h := smvAppidMap.Load(gooseitem.SmvID); h {
  1794. iedPointer := tmpIED.(*node_attr.NIED)
  1795. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)SV控制块(%s)的smvID(%s)与IED(%s)中重复定义", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name, gooseitem.SmvID, iedPointer.Name)
  1796. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("SV控制块的smvID唯一性"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1797. c.AppendPaseResult(r, iedObj)
  1798. }
  1799. //格式校验
  1800. newGooseAppid := fmt.Sprintf("%s%s/LLN0.%s", iedObj.Name, ld.Inst, gooseitem.Name)
  1801. if gooseitem.SmvID != newGooseAppid {
  1802. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)SV控制块(%s)的appID(%s)格式不符合规范", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name, gooseitem.SmvID)
  1803. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("SV控制块appID格式校验"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1804. c.AppendPaseResult(r, iedObj)
  1805. }
  1806. smvAppidMap.Store(gooseitem.SmvID, iedObj)
  1807. if gooseitem.ConfRev == "" {
  1808. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)SV控制块(%s)的confRev属性配置错误", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
  1809. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("SV控制块的confRev属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1810. c.AppendPaseResult(r, iedObj)
  1811. }
  1812. if gooseitem.SmpRate == "" {
  1813. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)SV控制块(%s)的smpRate属性配置错误", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
  1814. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("SV控制块的smpRate属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1815. c.AppendPaseResult(r, iedObj)
  1816. }
  1817. if gooseitem.NofASDU == "" {
  1818. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)SV控制块(%s)的nofASDU属性配置错误", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
  1819. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("SV控制块的nofASDU属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1820. c.AppendPaseResult(r, iedObj)
  1821. }
  1822. //是否配置网络参数
  1823. gseNetFound := false
  1824. for _, net := range c.scdXmlObject.Communication.SubNetwork {
  1825. if net.Type != "SMV" {
  1826. continue
  1827. }
  1828. for _, connAp := range net.ConnectedAP {
  1829. if connAp.IedName == iedObj.Name {
  1830. for _, gseNet := range connAp.SMV {
  1831. if gseNet.CbName == gooseitem.Name && gseNet.LdInst == ld.Inst {
  1832. gseNetFound = true
  1833. }
  1834. }
  1835. }
  1836. }
  1837. }
  1838. if !gseNetFound {
  1839. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)SV控制块(%s)未配置网络参数", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
  1840. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("SV控制块未配置网络参数"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1841. c.AppendPaseResult(r, iedObj)
  1842. }
  1843. }
  1844. }
  1845. //日志控制块校验
  1846. logNameMap := map[string]int{}
  1847. for _, logItem := range ld.LN0.LogControl {
  1848. if logItem.DatSet == "" {
  1849. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)日志控制块(%s)datSet属性配置错误(缺失、值为空)", iedObj.Name, ap.Name, ap.Desc, ld.Inst, logItem.Name)
  1850. r := map[string]interface{}{"scdid": c.ScdID, "lineno": logItem.Lineno, "ruleid": c.getRuleIdByName("日志控制块的datSet属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1851. c.AppendPaseResult(r, iedObj)
  1852. } else {
  1853. logDatsetFound := false
  1854. for _, dsitem := range ld.LN0.DataSet {
  1855. if dsitem.Name == logItem.DatSet {
  1856. logDatsetFound = true
  1857. break
  1858. }
  1859. }
  1860. if !logDatsetFound {
  1861. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)日志控制块(%s)引用的数据集(%s)不存在", iedObj.Name, ap.Name, ap.Desc, ld.Inst, logItem.Name, logItem.DatSet)
  1862. r := map[string]interface{}{"scdid": c.ScdID, "lineno": logItem.Lineno, "ruleid": c.getRuleIdByName("日志控制块引用的数据集不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1863. c.AppendPaseResult(r, iedObj)
  1864. }
  1865. }
  1866. if logItem.IntgPd == "" {
  1867. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)日志控制块(%s)intgPd属性配置错误(缺失、值为空)", iedObj.Name, ap.Name, ap.Desc, ld.Inst, logItem.Name)
  1868. r := map[string]interface{}{"scdid": c.ScdID, "lineno": logItem.Lineno, "ruleid": c.getRuleIdByName("日志控制块的intgPd属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1869. c.AppendPaseResult(r, iedObj)
  1870. }
  1871. logLdnameFound := false
  1872. for _, logLd := range ap.Server.LDevice {
  1873. if logLd.Inst == logItem.LogName {
  1874. logLdnameFound = true
  1875. break
  1876. }
  1877. }
  1878. if !logLdnameFound {
  1879. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)日志控制块(%s)对应的日志名(%s)不存在", iedObj.Name, ap.Name, ap.Desc, ld.Inst, logItem.Name, logItem.LogName)
  1880. r := map[string]interface{}{"scdid": c.ScdID, "lineno": logItem.Lineno, "ruleid": c.getRuleIdByName("日志控制块对应的日志名不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1881. c.AppendPaseResult(r, iedObj)
  1882. }
  1883. if _, h := logNameMap[logItem.Name]; h {
  1884. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)日志控制块的name(%s)属性在LN下配置重复", iedObj.Name, ap.Name, ap.Desc, ld.Inst, logItem.Name)
  1885. r := map[string]interface{}{"scdid": c.ScdID, "lineno": logItem.Lineno, "ruleid": c.getRuleIdByName("日志控制块的name属性在LN下配置重复"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1886. c.AppendPaseResult(r, iedObj)
  1887. }
  1888. logNameMap[logItem.Name] = 1
  1889. }
  1890. //报告控制块校验
  1891. reportNameMap := map[string]int{}
  1892. for _, reportItem := range ld.LN0.ReportControl {
  1893. if reportItem.DatSet != "" {
  1894. datsetFound := false
  1895. for _, dsitem := range ld.LN0.DataSet {
  1896. if dsitem.Name == reportItem.DatSet {
  1897. datsetFound = true
  1898. break
  1899. }
  1900. }
  1901. if !datsetFound {
  1902. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)报告控制块(%s)引用的数据集(%s)不存在", iedObj.Name, ap.Name, ap.Desc, ld.Inst, reportItem.Name, reportItem.DatSet)
  1903. r := map[string]interface{}{"scdid": c.ScdID, "lineno": reportItem.Lineno, "ruleid": c.getRuleIdByName("报告控制块引用的数据集不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1904. c.AppendPaseResult(r, iedObj)
  1905. }
  1906. }
  1907. if reportItem.RptID == "" {
  1908. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)报告控制块(%s)中的rptID属性配置错误(缺失、值为空)", iedObj.Name, ap.Name, ap.Desc, ld.Inst, reportItem.Name)
  1909. r := map[string]interface{}{"scdid": c.ScdID, "lineno": reportItem.Lineno, "ruleid": c.getRuleIdByName("报告控制块的rptID属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1910. c.AppendPaseResult(r, iedObj)
  1911. } else {
  1912. if v, h := reportRptIDMap.Load(iedObj.Name + reportItem.RptID); h {
  1913. v1 := v.(map[string]interface{})
  1914. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)报告控制块(%s)属性rptID(%s)与IED(%s)中报告控制块(%s)rptID重复", iedObj.Name, ap.Name, ap.Desc, ld.Inst, reportItem.Name, reportItem.RptID, tools.IsEmpty(v1["iedname"]), tools.IsEmpty(v1["reportcontrol"]))
  1915. r := map[string]interface{}{"scdid": c.ScdID, "lineno": reportItem.Lineno, "ruleid": c.getRuleIdByName("报告控制块的rptID重复"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1916. c.AppendPaseResult(r, iedObj)
  1917. }
  1918. reportRptIDMap.Store(iedObj.Name+reportItem.RptID, map[string]interface{}{"iedname": iedObj.Name, "reportcontrol": reportItem.Name})
  1919. }
  1920. if reportItem.ConfRev == "" {
  1921. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)报告控制块(%s)中的confRev属性配置错误(缺失、值为空)", iedObj.Name, ap.Name, ap.Desc, ld.Inst, reportItem.Name)
  1922. r := map[string]interface{}{"scdid": c.ScdID, "lineno": reportItem.Lineno, "ruleid": c.getRuleIdByName("报告控制块的confRev属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1923. c.AppendPaseResult(r, iedObj)
  1924. }
  1925. if _, h := reportNameMap[iedObj.Name+reportItem.Name]; h {
  1926. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)报告控制块的name(%s)属性在LN下配置重复", iedObj.Name, ap.Name, ap.Desc, ld.Inst, reportItem.Name)
  1927. r := map[string]interface{}{"scdid": c.ScdID, "lineno": reportItem.Lineno, "ruleid": c.getRuleIdByName("报告控制块的name属性在LN下配置重复"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1928. c.AppendPaseResult(r, iedObj)
  1929. }
  1930. reportNameMap[iedObj.Name+reportItem.Name] = 1
  1931. if len(reportItem.Name) >= 4 && (reportItem.Name[0:4] == "brcb" || reportItem.Name[0:4] == "urcb") {
  1932. //名称符合规范
  1933. } else {
  1934. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)报告控制块的name(%s)属性未按规范命名", iedObj.Name, ap.Name, ap.Desc, ld.Inst, reportItem.Name)
  1935. r := map[string]interface{}{"scdid": c.ScdID, "lineno": reportItem.Lineno, "ruleid": c.getRuleIdByName("报告控制块属性正确性及规范性检查"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1936. c.AppendPaseResult(r, iedObj)
  1937. }
  1938. }
  1939. //定值控制块校验
  1940. if ld.LN0.SettingControl != nil {
  1941. if ld.LN0.SettingControl.ActSG == "" {
  1942. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)定值控制块actSG属性配置值不正确", iedObj.Name, ap.Name, ap.Desc, ld.Inst)
  1943. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ld.LN0.SettingControl.Lineno, "ruleid": c.getRuleIdByName("定值控制块的actSG属性配置错误(值不正确)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1944. c.AppendPaseResult(r, iedObj)
  1945. }
  1946. if ld.LN0.SettingControl.NumOfSGs == "" {
  1947. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)定值控制块numOfSGs属性配置值不正确", iedObj.Name, ap.Name, ap.Desc, ld.Inst)
  1948. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ld.LN0.SettingControl.Lineno, "ruleid": c.getRuleIdByName("定值控制块的numOfSGs属性配置错误(值不正确)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1949. c.AppendPaseResult(r, iedObj)
  1950. }
  1951. }
  1952. }
  1953. lphdFound := false
  1954. otherLnFound := false
  1955. for _, lns := range ld.LN {
  1956. if _, h := c.lnodeTypeMap.Load(lns.LnType); !h {
  1957. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)中LD(%s)下的LN(%s)引用的LNodeType(%s)在模板中不存在", iedObj.Name, ap.Name, ap.Desc, ld.Inst, lns.Desc, lns.LnType)
  1958. r := map[string]interface{}{"scdid": c.ScdID, "lineno": lns.Lineno, "ruleid": c.getRuleIdByName("LN引用LNodeType不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1959. c.AppendPaseResult(r, iedObj)
  1960. }
  1961. if lns.LnClass == "LPHD" {
  1962. lphdFound = true
  1963. } else {
  1964. otherLnFound = true
  1965. }
  1966. }
  1967. if !lphdFound {
  1968. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)中LD(%s)的缺失对象LPHD", iedObj.Name, ap.Name, ap.Desc, ld.Inst)
  1969. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ld.Lineno, "ruleid": c.getRuleIdByName("逻辑设备建模正确性"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1970. c.AppendPaseResult(r, iedObj)
  1971. }
  1972. if !otherLnFound {
  1973. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)中LD(%s)的缺失非LPHD外其他LN", iedObj.Name, ap.Name, ap.Desc, ld.Inst)
  1974. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ld.Lineno, "ruleid": c.getRuleIdByName("逻辑设备建模正确性"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1975. c.AppendPaseResult(r, iedObj)
  1976. }
  1977. }
  1978. }
  1979. }
  1980. }
  1981. //校验IED crc一致性
  1982. func (c *ScdNodeRule) CheckFunc_crc() {
  1983. defer func() {
  1984. c.isRun = 2 //校验完成标识
  1985. c.Flush() //将校验结果写数据库
  1986. }()
  1987. logger.Logger.Debug(fmt.Sprintf("校验SCD %d的IED Crc", c.ScdID))
  1988. if c.scdXmlObject == nil {
  1989. return
  1990. }
  1991. checkcnt := 1
  1992. timeoutTotal := len(c.scdXmlObject.IED) * 3
  1993. for {
  1994. //检查crc提取是否完成
  1995. if v, h := global.IedCrcMakeState.Load(fmt.Sprintf("crc_%d", c.ScdID)); h {
  1996. v1 := tools.IsEmpty(v)
  1997. if v1 == "0" || v1 == "2" {
  1998. //提取失败0或者已完成2
  1999. break
  2000. }
  2001. }
  2002. time.Sleep(500 * time.Millisecond)
  2003. checkcnt = checkcnt + 1
  2004. if checkcnt > timeoutTotal {
  2005. //crc提取超时
  2006. logger.Logger.Error(errors.New(fmt.Sprintf("SCD %d的IED Crc提取超时", c.ScdID)))
  2007. break
  2008. }
  2009. }
  2010. crclist, _ := global.CachedScdCrc.Load(fmt.Sprintf("crc_%d", c.ScdID))
  2011. if crclist == nil {
  2012. logger.Logger.Debug(fmt.Sprintf("未找到SCD %d的IED Crc提取结果数据", c.ScdID))
  2013. return
  2014. }
  2015. crcmap := crclist.(map[string]string)
  2016. for _, iedObj := range c.scdXmlObject.IED {
  2017. crc := ""
  2018. p := new(node_attr.NPrivate)
  2019. for _, p = range iedObj.Priavate {
  2020. if p.Type == "IED virtual terminal conection CRC" {
  2021. crc = p.InnerText
  2022. break
  2023. }
  2024. }
  2025. iedcrc2 := crcmap[iedObj.Name]
  2026. if crc != "" && iedcrc2 != crc {
  2027. parse_result := fmt.Sprintf("IED(%s)中存储的CCD校验码(%s)与实际校验码(%s)不一致", iedObj.Name, crc, iedcrc2)
  2028. r := map[string]interface{}{"scdid": c.ScdID, "lineno": p.Lineno, "ruleid": c.getRuleIdByName("CCD校验码校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
  2029. c.AppendPaseResult(r, iedObj)
  2030. }
  2031. }
  2032. }
  2033. func (c *ScdNodeRule) check_ln_doidai(iedObj *node_attr.NIED, dATypeMap map[string]*node_attr.NDAType, ld *node_attr.NLDevice) {
  2034. if c.daMap == nil {
  2035. c.daMap = &sync.Map{}
  2036. }
  2037. if c.doiMap == nil {
  2038. c.doiMap = &sync.Map{}
  2039. }
  2040. if ld.LN0 != nil {
  2041. vlnnode, _ := c.lnodeTypeMap.Load(ld.LN0.LnType)
  2042. if vlnnode == nil {
  2043. parse_result := fmt.Sprintf("IED(%s)中LD(%s%s)下的LN(%s%s)引用的LNodeType(%s)在模板中不存在", iedObj.Name, ld.Desc, ld.Inst, ld.LN0.Desc, ld.LN0.Inst, ld.LN0.LnType)
  2044. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ld.LN0.Lineno, "ruleid": c.getRuleIdByName("LN引用LNodeType不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  2045. c.AppendPaseResult(r, iedObj)
  2046. } else {
  2047. lnnode := vlnnode.(*node_attr.NLNodeType)
  2048. lnchilderdoi := map[string]string{}
  2049. v_lnchilderdoi, _ := c.doiMap.Load(ld.LN0.LnType)
  2050. if v_lnchilderdoi == nil {
  2051. for _, do := range lnnode.DO {
  2052. lnchilderdoi[do.Name] = do.Type
  2053. }
  2054. c.doiMap.Store(ld.LN0.LnType, lnchilderdoi)
  2055. } else {
  2056. lnchilderdoi = v_lnchilderdoi.(map[string]string)
  2057. }
  2058. for _, doi := range ld.LN0.DOI {
  2059. if lnchilderdoi[doi.Name] == "" {
  2060. //fmt.Println(fmt.Sprintf("ied:%s LN0.LnType:%s doi.Name:%s %+v", iedObj.Name, ld.LN0.LnType, doi.Name, lnchilderdoi))
  2061. parse_result := fmt.Sprintf("IED(%s)中LD(%s%s)下的LN(%s%s)引用的DOI/SDI(%s)在模板中不存在", iedObj.Name, ld.Desc, ld.Inst, ld.LN0.Desc, ld.LN0.Inst, doi.Name)
  2062. r := map[string]interface{}{"scdid": c.ScdID, "lineno": doi.Lineno, "ruleid": c.getRuleIdByName("DOI/SDI引用模板不一致"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  2063. c.AppendPaseResult(r, iedObj)
  2064. }
  2065. }
  2066. }
  2067. }
  2068. for _, ln := range ld.LN {
  2069. vlnnode, _ := c.lnodeTypeMap.Load(ln.LnType)
  2070. if vlnnode == nil {
  2071. parse_result := fmt.Sprintf("IED(%s)中LD(%s%s)下的LN(%s%s)引用的LNodeType(%s)在模板中不存在", iedObj.Name, ld.Desc, ld.Inst, ln.Desc, ln.Inst, ln.LnType)
  2072. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ln.Lineno, "ruleid": c.getRuleIdByName("LN引用LNodeType不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  2073. c.AppendPaseResult(r, iedObj)
  2074. } else {
  2075. lnnode := vlnnode.(*node_attr.NLNodeType)
  2076. lnchilderdoi := map[string]string{}
  2077. v_lnchilderdoi, _ := c.doiMap.Load(ln.LnType)
  2078. if v_lnchilderdoi == nil {
  2079. for _, do := range lnnode.DO {
  2080. lnchilderdoi[do.Name] = do.Type
  2081. }
  2082. c.doiMap.Store(ln.LnType, lnchilderdoi)
  2083. } else {
  2084. lnchilderdoi = v_lnchilderdoi.(map[string]string)
  2085. }
  2086. for _, doi := range ln.DOI {
  2087. if lnchilderdoi[doi.Name] == "" {
  2088. //fmt.Println(fmt.Sprintf("ied:%s LN.LnType:%s doi.Name:%s %+v", iedObj.Name, ln.LnType, doi.Name, lnchilderdoi))
  2089. parse_result := fmt.Sprintf("IED(%s)中LD(%s%s)下的LN(%s%s)引用的DOI/SDI(%s)在模板中不存在", iedObj.Name, ld.Desc, ld.Inst, ln.Desc, ln.Inst, doi.Name)
  2090. r := map[string]interface{}{"scdid": c.ScdID, "lineno": doi.Lineno, "ruleid": c.getRuleIdByName("DOI/SDI引用模板不一致"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  2091. c.AppendPaseResult(r)
  2092. continue
  2093. }
  2094. dotype := lnchilderdoi[doi.Name]
  2095. dalist := map[string]string{}
  2096. v_dalist, _ := c.daMap.Load(dotype)
  2097. if v_dalist == nil {
  2098. v, _ := c.doTypeMap.Load(dotype)
  2099. if v == nil {
  2100. //do模板不存在
  2101. continue
  2102. }
  2103. for _, daitem := range v.(*node_attr.NDOType).DA {
  2104. dalist[daitem.Name] = "1"
  2105. }
  2106. c.daMap.Store(dotype, dalist)
  2107. } else {
  2108. dalist = v_dalist.(map[string]string)
  2109. }
  2110. for _, da := range doi.DAI {
  2111. if dalist[da.Name] == "" {
  2112. //fmt.Println(fmt.Sprintf("IED(%s)中LD(%s%s)下的LN(%s%s)引用的DAI(%s) %+v", iedObj.Name, ld.Desc, ld.Inst, ln.Desc, ln.Inst, da.Name, daMap[dotype]))
  2113. parse_result := fmt.Sprintf("IED(%s)中LD(%s%s)下的LN(%s%s)引用的DAI(%s)在模板中不存在", iedObj.Name, ld.Desc, ld.Inst, ln.Desc, ln.Inst, da.Name)
  2114. r := map[string]interface{}{"scdid": c.ScdID, "lineno": da.Lineno, "ruleid": c.getRuleIdByName("DAI引用模板不一致"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  2115. c.AppendPaseResult(r, iedObj)
  2116. }
  2117. }
  2118. }
  2119. }
  2120. }
  2121. }
  2122. //DataTypeTemplates校验
  2123. //数据实例引用模板正确性检查
  2124. //数据类型模板引用正确性检查
  2125. //模板重复定义校验
  2126. //冗余模板校验
  2127. func (c *ScdNodeRule) CheckFunc_datatypetemplates(para orm.Params) (a3 map[string]*node_attr.NDAType) {
  2128. logger.Logger.Debug(fmt.Sprintf("校验SCD %d的数据模板节点", c.ScdID))
  2129. if c.scdXmlObject == nil {
  2130. return
  2131. }
  2132. usedLNodeTypeMap := map[string]int{}
  2133. for _, iedObj := range c.scdXmlObject.IED {
  2134. for _, acc := range iedObj.AccessPoint {
  2135. if acc.Server == nil {
  2136. continue
  2137. }
  2138. for _, ld := range acc.Server.LDevice {
  2139. usedLNodeTypeMap[ld.LN0.LnType] = 1
  2140. for _, ln := range ld.LN {
  2141. usedLNodeTypeMap[ln.LnType] = 1
  2142. }
  2143. }
  2144. }
  2145. }
  2146. usedDoTypeMap := map[string]int{}
  2147. daTypeMap := map[string]*node_attr.NDAType{}
  2148. usedDaTypeMap := map[string]int{}
  2149. enumTypeMap := map[string]*node_attr.NEnumType{}
  2150. usedEnumTypeMap := map[string]int{}
  2151. for _, enumtype := range c.scdXmlObject.DataTypeTemplates.EnumType {
  2152. if enumTypeMap[enumtype.Id] != nil {
  2153. parse_result := fmt.Sprintf("EnumType(%s)定义重复", enumtype.Id)
  2154. r := map[string]interface{}{"scdid": c.ScdID, "lineno": enumtype.Lineno, "ruleid": c.getRuleIdByName("模板重复定义校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
  2155. c.AppendPaseResult(r)
  2156. continue
  2157. }
  2158. enumTypeMap[enumtype.Id] = enumtype
  2159. }
  2160. for _, datype := range c.scdXmlObject.DataTypeTemplates.DAType {
  2161. if daTypeMap[datype.Id] != nil {
  2162. parse_result := fmt.Sprintf("DAType(%s)定义重复", datype.Id)
  2163. r := map[string]interface{}{"scdid": c.ScdID, "lineno": datype.Lineno, "ruleid": c.getRuleIdByName("模板重复定义校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
  2164. c.AppendPaseResult(r)
  2165. continue
  2166. }
  2167. daTypeMap[datype.Id] = datype
  2168. c.daTypeMap.Store(datype.Id, datype)
  2169. for _, enum := range datype.BDA {
  2170. if enum.Type == "" {
  2171. continue
  2172. }
  2173. if enum.BType == "Enum" {
  2174. usedEnumTypeMap[enum.Type] = 1 //使用的模板
  2175. if enumTypeMap[enum.Type] == nil {
  2176. parse_result := fmt.Sprintf("DAType(%s)中引用的EnumType(%s)不存在", datype.Id, enum.Type)
  2177. r := map[string]interface{}{"scdid": c.ScdID, "lineno": enum.Lineno, "ruleid": c.getRuleIdByName("EnumType模板引用合法性校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
  2178. c.AppendPaseResult(r)
  2179. }
  2180. }
  2181. }
  2182. }
  2183. for _, dotype := range c.scdXmlObject.DataTypeTemplates.DOType {
  2184. if v, _ := c.doTypeMap.Load(dotype.Id); v != nil {
  2185. parse_result := fmt.Sprintf("DOType(%s)定义重复", dotype.Id)
  2186. r := map[string]interface{}{"scdid": c.ScdID, "lineno": dotype.Lineno, "ruleid": c.getRuleIdByName("模板重复定义校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
  2187. c.AppendPaseResult(r)
  2188. continue
  2189. }
  2190. c.doTypeMap.Store(dotype.Id, dotype)
  2191. for _, da := range dotype.DA {
  2192. if da.Type == "" {
  2193. continue
  2194. }
  2195. if da.BType == "Enum" {
  2196. usedEnumTypeMap[da.Type] = 1 //使用的模板
  2197. if enumTypeMap[da.Type] == nil {
  2198. parse_result := fmt.Sprintf("DOType(%s)中引用的btype为Enum的DAType(%s)不存在", dotype.Id, da.Type)
  2199. r := map[string]interface{}{"scdid": c.ScdID, "lineno": da.Lineno, "ruleid": c.getRuleIdByName("EnumType模板引用合法性校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
  2200. c.AppendPaseResult(r)
  2201. }
  2202. } else {
  2203. usedDaTypeMap[da.Type] = 1
  2204. if daTypeMap[da.Type] == nil {
  2205. parse_result := fmt.Sprintf("DOType(%s)中引用的DAType(%s)不存在", dotype.Id, da.Type)
  2206. r := map[string]interface{}{"scdid": c.ScdID, "lineno": da.Lineno, "ruleid": c.getRuleIdByName("DaType模板引用合法性校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
  2207. c.AppendPaseResult(r)
  2208. }
  2209. }
  2210. }
  2211. }
  2212. //查找未被引用的enum模板
  2213. for enumtype, obj := range enumTypeMap {
  2214. if _, h := usedEnumTypeMap[enumtype]; !h {
  2215. parse_result := fmt.Sprintf("EnumType(%s)未被引用", enumtype)
  2216. r := map[string]interface{}{"scdid": c.ScdID, "lineno": obj.Lineno, "ruleid": c.getRuleIdByName("冗余模板校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
  2217. c.AppendPaseResult(r)
  2218. }
  2219. }
  2220. //查找未被引用的da模板
  2221. //fmt.Println(fmt.Sprintf("%+v", daTypeMap))
  2222. for datype, obj := range daTypeMap {
  2223. if _, h := usedDaTypeMap[datype]; !h {
  2224. parse_result := fmt.Sprintf("DAType(%s)未被引用", datype)
  2225. r := map[string]interface{}{"scdid": c.ScdID, "lineno": obj.Lineno, "ruleid": c.getRuleIdByName("冗余模板校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
  2226. c.AppendPaseResult(r)
  2227. }
  2228. }
  2229. for _, lntype := range c.scdXmlObject.DataTypeTemplates.LNodeType {
  2230. if v, _ := c.lnodeTypeMap.Load(lntype.Id); v != nil {
  2231. parse_result := fmt.Sprintf("LNodeType(%s)定义重复", lntype.Id)
  2232. r := map[string]interface{}{"scdid": c.ScdID, "lineno": lntype.Lineno, "ruleid": c.getRuleIdByName("模板重复定义校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
  2233. c.AppendPaseResult(r)
  2234. continue
  2235. }
  2236. //查找未被引用的LNodeType模板
  2237. if _, h := usedLNodeTypeMap[lntype.Id]; !h {
  2238. parse_result := fmt.Sprintf("LNodeType(%s)未被引用", lntype.Id)
  2239. r := map[string]interface{}{"scdid": c.ScdID, "lineno": lntype.Lineno, "ruleid": c.getRuleIdByName("冗余模板校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
  2240. c.AppendPaseResult(r)
  2241. continue
  2242. }
  2243. c.lnodeTypeMap.Store(lntype.Id, lntype)
  2244. for _, do := range lntype.DO {
  2245. if do.Type == "" {
  2246. continue
  2247. }
  2248. usedDoTypeMap[do.Type] = 1
  2249. if v, _ := c.doTypeMap.Load(do.Type); v == nil {
  2250. parse_result := fmt.Sprintf("LNodeType(%s)中引用的DoType(%s)不存在", lntype.Id, do.Type)
  2251. r := map[string]interface{}{"scdid": c.ScdID, "lineno": do.Lineno, "ruleid": c.getRuleIdByName("DoType模板引用合法性校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
  2252. c.AppendPaseResult(r)
  2253. }
  2254. }
  2255. }
  2256. //查找未被引用的DOtype模板
  2257. c.doTypeMap.Range(func(k, v any) bool {
  2258. dotype := tools.IsEmpty(k)
  2259. if _, h := usedDoTypeMap[dotype]; !h {
  2260. parse_result := fmt.Sprintf("DOType(%s)未被引用", dotype)
  2261. r := map[string]interface{}{"scdid": c.ScdID, "lineno": v.(*node_attr.NDOType).Lineno, "ruleid": c.getRuleIdByName("冗余模板校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
  2262. c.AppendPaseResult(r)
  2263. }
  2264. return true
  2265. })
  2266. return daTypeMap
  2267. }
  2268. //发送端虚端子检查
  2269. //存在性检查
  2270. //cdc检查
  2271. //
  2272. func (c *ScdNodeRule) iedFcdaExist(iedname, ldinst, lnclass, lninst, prefix, doname, daname string) (obj interface{}, cdc string) {
  2273. if c.scdXmlObject == nil {
  2274. return nil, ""
  2275. }
  2276. donames := strings.Split(doname, ".") //检查是否是sdi定义
  2277. doname = donames[0]
  2278. sdiname := ""
  2279. if len(donames) > 1 {
  2280. sdiname = donames[1]
  2281. }
  2282. for _, iedObj := range c.scdXmlObject.IED {
  2283. if iedObj.Name != iedname {
  2284. continue
  2285. }
  2286. for _, ap := range iedObj.AccessPoint {
  2287. if ap.Server == nil {
  2288. continue
  2289. }
  2290. for _, ld := range ap.Server.LDevice {
  2291. if ld.Inst != ldinst {
  2292. continue
  2293. }
  2294. if ld.LN0 != nil && lnclass == ld.LN0.LnClass && lninst == ld.LN0.Inst && prefix == ld.LN0.Prefix {
  2295. for _, doi := range ld.LN0.DOI {
  2296. if doi.Name == doname {
  2297. if sdiname != "" {
  2298. foundsdi := false
  2299. for _, sdi := range doi.SDI {
  2300. if sdi.Name == sdiname {
  2301. foundsdi = true
  2302. }
  2303. }
  2304. if !foundsdi {
  2305. return nil, ""
  2306. }
  2307. }
  2308. cdc := c.getDoICdc(ld.LN0.LnType, doname, daname)
  2309. return doi, cdc
  2310. }
  2311. }
  2312. }
  2313. for _, ln := range ld.LN {
  2314. if lnclass == ln.LnClass && lninst == ln.Inst && prefix == ln.Prefix {
  2315. for _, doi := range ln.DOI {
  2316. if doi.Name == doname {
  2317. if sdiname != "" {
  2318. foundsdi := false
  2319. for _, sdi := range doi.SDI {
  2320. if sdi.Name == sdiname {
  2321. foundsdi = true
  2322. }
  2323. }
  2324. if !foundsdi {
  2325. return nil, ""
  2326. }
  2327. }
  2328. cdc := c.getDoICdc(ln.LnType, doname, daname)
  2329. return doi, cdc
  2330. }
  2331. }
  2332. }
  2333. }
  2334. }
  2335. }
  2336. }
  2337. return nil, ""
  2338. }
  2339. func (c *ScdNodeRule) iedIntAddrExist(iedname, intAddr string) (obj interface{}) {
  2340. if c.scdXmlObject == nil {
  2341. return nil
  2342. }
  2343. //intaddr格式:2-B:PIGO1/GOINGGIO1.SPCSO8.stVal
  2344. addrs := strings.Split(intAddr, ":")
  2345. if len(addrs) == 2 {
  2346. intAddr = addrs[1]
  2347. }
  2348. intAddrs := strings.Split(intAddr, "/")
  2349. if len(intAddrs) == 1 {
  2350. logger.Logger.Error(errors.New(fmt.Sprintf("装置%s发现无效的intAddr:%s", iedname, intAddr)))
  2351. return nil
  2352. }
  2353. ldinst := intAddrs[0]
  2354. lnstr := intAddrs[1]
  2355. v_tmpAry := strings.Split(lnstr, ".")
  2356. if len(v_tmpAry) < 2 {
  2357. logger.Logger.Error(errors.New(fmt.Sprintf("装置%s发现无效的intAddr:%s", iedname, intAddr)))
  2358. return nil
  2359. }
  2360. doda := v_tmpAry[1:]
  2361. //doname := ""
  2362. daname := ""
  2363. if len(doda) == 1 {
  2364. //只有do
  2365. //doname = doda[0]
  2366. } else {
  2367. //doname = doda[0]
  2368. daname = strings.Join(doda[1:], ".") //还原da
  2369. }
  2370. for _, iedObj := range c.scdXmlObject.IED {
  2371. if iedObj.Name != iedname {
  2372. continue
  2373. }
  2374. for _, ap := range iedObj.AccessPoint {
  2375. if ap.Server != nil {
  2376. for _, ld := range ap.Server.LDevice {
  2377. if ld.Inst == ldinst && ld.LN0 != nil {
  2378. for _, ln := range ld.LN0.DataSet {
  2379. for _, fcda := range ln.FCDA {
  2380. str := fmt.Sprintf("%s%s%s.%s", fcda.Prefix, fcda.LnClass, fcda.LnInst, fcda.DoName)
  2381. if daname != "" {
  2382. str = str + "." + fcda.DaName
  2383. }
  2384. if str == lnstr {
  2385. return fcda
  2386. }
  2387. }
  2388. }
  2389. return nil
  2390. }
  2391. }
  2392. }
  2393. }
  2394. }
  2395. return nil
  2396. }
  2397. //校验内部端子的DO或DA实例是否存在
  2398. func (c *ScdNodeRule) iedIntAddrDoiOrDaiExist(iedname, intAddr string) (obj interface{}, cdc string) {
  2399. if c.scdXmlObject == nil {
  2400. return nil, ""
  2401. }
  2402. //intaddr格式:2-B:PIGO1/GOINGGIO1.SPCSO8.stVal
  2403. addrs := strings.Split(intAddr, ":")
  2404. if len(addrs) == 2 {
  2405. intAddr = addrs[1]
  2406. }
  2407. intAddrs := strings.Split(intAddr, "/")
  2408. if len(intAddrs) == 1 {
  2409. logger.Logger.Error(errors.New(fmt.Sprintf("装置%s发现无效的intAddr:%s", iedname, intAddr)))
  2410. return nil, ""
  2411. }
  2412. ldinst := intAddrs[0]
  2413. lnstr := intAddrs[1]
  2414. for _, iedObj := range c.scdXmlObject.IED {
  2415. if iedObj.Name != iedname {
  2416. continue
  2417. }
  2418. for _, ap := range iedObj.AccessPoint {
  2419. if ap.Server != nil {
  2420. for _, ld := range ap.Server.LDevice {
  2421. if ld.Inst == ldinst {
  2422. for _, ln := range ld.LN {
  2423. str := fmt.Sprintf("%s%s%s", ln.Prefix, ln.LnClass, ln.Inst)
  2424. v_tmpAry := strings.Split(lnstr, ".")
  2425. if v_tmpAry[0] == str {
  2426. doda := v_tmpAry[1:]
  2427. doname := ""
  2428. daname := ""
  2429. if len(doda) == 1 {
  2430. //只有do
  2431. doname = doda[0]
  2432. } else {
  2433. doname = doda[0]
  2434. daname = strings.Join(doda[1:], ".") //还原da
  2435. }
  2436. for _, doi := range ln.DOI {
  2437. if doi.Name == doname {
  2438. cdc := c.getDoICdc(ln.LnType, doi.Name, daname)
  2439. if daname == "" {
  2440. return doi, cdc
  2441. }
  2442. for _, dai := range doi.DAI {
  2443. if dai.Name == daname {
  2444. return dai, cdc
  2445. }
  2446. }
  2447. das := strings.Split(daname, ".")
  2448. if len(das) > 1 {
  2449. for _, sdi := range doi.SDI {
  2450. if sdi.Name == das[0] {
  2451. for _, dai := range sdi.DAI {
  2452. if dai.Name == das[1] {
  2453. return dai, cdc
  2454. }
  2455. }
  2456. for _, sdi2 := range sdi.SDI {
  2457. for _, dai := range sdi2.DAI {
  2458. if dai.Name == das[1] {
  2459. return dai, cdc
  2460. }
  2461. }
  2462. }
  2463. return nil, cdc
  2464. }
  2465. }
  2466. }
  2467. return nil, cdc
  2468. }
  2469. }
  2470. return nil, ""
  2471. }
  2472. }
  2473. return nil, ""
  2474. }
  2475. }
  2476. }
  2477. }
  2478. }
  2479. return nil, ""
  2480. }
  2481. //根据LNtype和doi名称返回其cdc属性值
  2482. func (c *ScdNodeRule) getDoICdc(lntype, doiname, daname string) string {
  2483. v, _ := c.lnodeTypeMap.Load(lntype)
  2484. if v == nil {
  2485. return ""
  2486. }
  2487. for _, do := range v.(*node_attr.NLNodeType).DO {
  2488. if do.Name == doiname {
  2489. if do.Type == "" {
  2490. return ""
  2491. }
  2492. d1, _ := c.doTypeMap.Load(do.Type)
  2493. if d1 == nil {
  2494. return ""
  2495. }
  2496. if daname == "" {
  2497. return d1.(*node_attr.NDOType).Cdc
  2498. }
  2499. das := strings.Split(daname, ".") //多层da
  2500. for _, daitem := range d1.(*node_attr.NDOType).DA {
  2501. if daitem.Name == das[0] {
  2502. if len(das) == 1 {
  2503. return daitem.BType
  2504. } else {
  2505. bdatype := daitem.Type
  2506. da1, _ := c.daTypeMap.Load(bdatype)
  2507. if da1 == nil {
  2508. return ""
  2509. }
  2510. for _, dbaitem := range da1.(*node_attr.NDAType).BDA {
  2511. if dbaitem.Name == das[1] {
  2512. return dbaitem.BType
  2513. }
  2514. }
  2515. }
  2516. return ""
  2517. }
  2518. }
  2519. }
  2520. }
  2521. return ""
  2522. }
  2523. //---------------------------------------------------------
  2524. func (c *ScdNodeRule) AppendPaseResult(r map[string]interface{}, ied ...*node_attr.NIED) {
  2525. var iedobj *node_attr.NIED
  2526. if len(ied) > 0 {
  2527. iedobj = ied[0]
  2528. r["ied_name"] = iedobj.Name
  2529. r["ied_desc"] = iedobj.Desc
  2530. }
  2531. c.checkFailListLock.Lock()
  2532. c.CheckFailList = append(c.CheckFailList, r)
  2533. c.checkFailListLock.Unlock()
  2534. //logger.Logger.Info(fmt.Sprintf("========校验结果:%v", r))
  2535. //实时将结果通过mqtt发送解析结果
  2536. //结果处理客户端需要订阅/jujutong/scd_check_tools/ruleparse/{scdid}
  2537. //go mqtt.PublishMessage("/jujutong/scd_check_tools/ruleparse/"+fmt.Sprintf("%d", c.ScdID), r["parse_result"].(string))
  2538. }
  2539. //节点规则验证完成
  2540. func (c *ScdNodeRule) Flush() {
  2541. //判断等待验证队列中的数据是否已处理完,没有处理完则一直等待
  2542. if c.isRun != 2 {
  2543. for {
  2544. time.Sleep(100 * time.Millisecond)
  2545. if c.isRun == 2 {
  2546. break
  2547. }
  2548. }
  2549. }
  2550. logger.Logger.Debug(fmt.Sprintln("规则校验结果,共%d条!", len(c.CheckFailList)))
  2551. c.writeNodeDB()
  2552. }
  2553. //根据规则名称获取规则ID.返回为""时表示还未定义该规则名称
  2554. func (c *ScdNodeRule) getRuleIdByName(name string) string {
  2555. row := c.NodeRuleList[name]
  2556. if row == nil {
  2557. return "0"
  2558. }
  2559. return tools.IsEmpty(row["id"])
  2560. }
  2561. //将验证结果写入数据库。仅写入验证不通过的结果
  2562. //每5000条写入一次
  2563. func (c *ScdNodeRule) writeNodeDB() {
  2564. if len(c.CheckFailList) == 0 {
  2565. return
  2566. }
  2567. db := orm.NewOrm()
  2568. s1 := time.Now().Unix()
  2569. nodeCols := "(scd_id,node_id,line_no,rule_target,rule_id,parse_result,ied_name,ied_desc)"
  2570. loadedRec := 0
  2571. nodeSqlValuesAry := []string{}
  2572. for _, m := range c.CheckFailList {
  2573. nodeSqlValuesAry = append(nodeSqlValuesAry, "("+tools.IsEmpty(m["scdid"])+","+tools.IsEmpty(m["nodeid"], "0")+","+tools.IsEmpty(m["lineno"], "0")+",'"+tools.IsEmpty(m["rule_target"])+"',"+tools.IsEmpty(m["ruleid"], "0")+",'"+tools.IsEmpty(m["parse_result"])+"','"+tools.IsEmpty(m["ied_name"])+"','"+tools.IsEmpty(m["ied_desc"])+"')")
  2574. if len(nodeSqlValuesAry) == 5000 {
  2575. sql := "insert into t_scd_node_rule_parse" + nodeCols + "values" + strings.Join(nodeSqlValuesAry, ",")
  2576. _, err := db.Raw(sql).Exec()
  2577. if err != nil {
  2578. log.Println(err)
  2579. }
  2580. loadedRec = loadedRec + 5000
  2581. nodeSqlValuesAry = nil
  2582. nodeSqlValuesAry = []string{}
  2583. }
  2584. }
  2585. if len(nodeSqlValuesAry) > 0 {
  2586. sql := "insert into t_scd_node_rule_parse" + nodeCols + "values" + strings.Join(nodeSqlValuesAry, ",")
  2587. _, err := db.Raw(sql).Exec()
  2588. if err != nil {
  2589. log.Println(err)
  2590. }
  2591. nodeSqlValuesAry = nil
  2592. }
  2593. c.CheckFailList = nil
  2594. runtime.GC()
  2595. s2 := time.Now().Unix()
  2596. fmt.Println(fmt.Sprintf("===================Flush NodeAttrParse 完成!。耗时:%d秒", s2-s1))
  2597. fmt.Println("===========节点属性验证完成")
  2598. mqtt.PublishMessage(fmt.Sprintf("%s/%d", checktopic, c.ScdID), `{"code":1,"scdid":"`+tools.IsEmpty(c.ScdID)+`","state":1,"msg":"该SCD校验完成"}`)
  2599. global.CheckingScd.Delete(c.ScdID)
  2600. }