1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704 |
- package bo
- import (
- "errors"
- "fmt"
- "log"
- "os"
- "runtime"
- "scd_check_tools/global"
- "scd_check_tools/logger"
- "scd_check_tools/models/enum"
- "scd_check_tools/models/node_attr"
- "scd_check_tools/mqtt"
- "scd_check_tools/tools"
- "strconv"
- "strings"
- "sync"
- "time"
- "github.com/astaxie/beego/orm"
- )
- //节点规则解析管理
- //单独启用专用解析进程,与节点入库操作为异步关系。该进程在没有新scd入库时为睡眠状态,当有新scd需要解析时,需要外部将其唤醒
- //进程被唤醒后,定时查询节点表中未被解析的节点进行规则有效性验证,如果验证不通过,则将结果写入规则解析结果表
- //每个节点状态都将按以下状态进行切换:0 未解析->1 解析中-> 2已解析
- type ScdNodeRule struct {
- ScdID int64
- ScdName string
- DeviceBaseModel
- doiMap *sync.Map
- daMap *sync.Map
- lnodeTypeMap *sync.Map // map[string]*node_attr.NLNodeType{}
- doTypeMap *sync.Map // map[string]*node_attr.NDOType{}
- daTypeMap *sync.Map // map[string]*node_attr.NDOType{}
- //当前未通过验证的节点列表
- CheckFailList []map[string]interface{}
- //等待解析的队列
- NodeRuleList map[string]orm.Params
- //
- NodeRuleFunctionList []orm.Params
- //是否正在解析节点。默认为0
- isRun int
- parseLock sync.RWMutex
- checkFailListLock sync.RWMutex
- scdXmlObject *node_attr.SCL
- }
- type t_scd_node_rule_parse struct {
- Id int64 `orm:"pk"`
- ScdId int64
- NodeId int64
- RuleId int64
- ParseResult string
- CreatedBy int
- CreatedTime string
- }
- //语法语义规则模型
- type t_scd_scl_check struct {
- Id int64 `orm:"pk"`
- CheckName string
- CheckType string
- HintText string
- ApplyStandard string
- ApplyStandardNo string
- ObjectType string
- ObjectName string
- FuncName string
- CheckDesc string
- CheckArea string
- AlertLevel string
- NodePath string
- IsExists string
- IsRef string
- IsNotnull string
- DataType string
- MinLen string
- MaxLen string
- MinValue string
- MaxValue string
- IsuniqueByParent string
- IsuniqueByGlobal string
- ConstValue string
- EmunValue string
- RegexpValue string
- Enable string
- CreatedBy int
- CreatedTime string
- }
- //逻辑规则模型.(已不使用)
- type t_scd_node_check struct {
- Id int64 `orm:"pk"`
- CheckObject string
- CheckDesc string
- CheckArea string
- AlertLevel string
- IsExists string
- IsRef string
- IsUnique string
- HintText string
- Enable string
- CreatedBy int
- CreatedTime string
- }
- func init() {
- orm.RegisterModel(new(t_scd_node_rule_parse))
- orm.RegisterModel(new(t_scd_node_check))
- orm.RegisterModel(new(t_scd_scl_check))
- }
- var checktopic = "/jujutong/scd_check_tools/ruleparse"
- func (c *ScdNodeRule) SetScdXmlObject(obj *node_attr.SCL) {
- c.scdXmlObject = obj
- }
- func (c *ScdNodeRule) TestCheckRule() {
- c.scdXmlObject, _ = new(ScdParse).GetScdXmlObjectBySCDID(tools.IsEmpty(c.ScdID))
- if c.scdXmlObject == nil {
- logger.Logger.Error(errors.New("无效的SCD"))
- mqtt.PublishMessage(fmt.Sprintf("%s/%d", checktopic, c.ScdID), `{"code":0,"scdid":"`+tools.IsEmpty(c.ScdID)+`","state":0,"msg":"无效的SCD"}`)
- return
- }
- if _, h := global.CheckingScd.Load(c.ScdID); h {
- logger.Logger.Debug(fmt.Sprintf("%d文件正在校验中", c.ScdID))
- mqtt.PublishMessage(fmt.Sprintf("%s/%d", checktopic, c.ScdID), `{"code":0,"scdid":"`+tools.IsEmpty(c.ScdID)+`","state":0,"msg":"该SCD正在校验中"}`)
- return
- }
- c.doiMap = &sync.Map{}
- c.daMap = &sync.Map{}
- c.lnodeTypeMap = &sync.Map{}
- c.doTypeMap = &sync.Map{}
- c.daTypeMap = &sync.Map{}
- c.NodeRuleList = map[string]orm.Params{}
- c.NodeRuleFunctionList = []orm.Params{}
- db := orm.NewOrm()
- lst := []orm.Params{}
- db.Raw("select * from t_scd_scl_check where enable=1").Values(&lst)
- for _, r := range lst {
- //object_name := r["object_name"].(string)
- //object_type := r["object_type"].(string)
- checkname := tools.IsEmpty(r["check_name"])
- if checkname != "" {
- c.NodeRuleList[checkname] = r
- }
- }
- mqtt.PublishMessage(fmt.Sprintf("%s/%d", checktopic, c.ScdID), `{"code":1,"scdid":"`+tools.IsEmpty(c.ScdID)+`","state":0,"msg":"SCD正在校验中"}`)
- global.CheckingScd.Store(c.ScdID, "1")
- c.StartFunctionNodeParse()
- }
- //查询规则定义列表
- func (c *ScdNodeRule) GetDefList(param map[string]interface{}, pageno, pagesize int) ([]orm.Params, int, error) {
- db := orm.NewOrm()
- rule_type := param["rule_type"]
- sqlParams := []interface{}{}
- 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"
- if v1, ok := param["rule_id"]; ok {
- v := tools.IsEmpty(v1)
- if v != "" {
- sql = sql + " and t.id=?"
- sqlParams = append(sqlParams, v)
- }
- }
- if v1, ok := param["check_type"]; ok {
- v := tools.IsEmpty(v1)
- if v != "" {
- sql = sql + " and t.check_type=?"
- sqlParams = append(sqlParams, v)
- }
- }
- if v1, ok := param["check_name"]; ok {
- v := tools.IsEmpty(v1)
- if v != "" {
- sql = sql + " and t.check_name like ?"
- sqlParams = append(sqlParams, "%"+v+"%")
- }
- }
- if v1, ok := param["enable"]; ok {
- v := tools.IsEmpty(v1)
- if v != "" {
- sql = sql + " and t.enable=?"
- sqlParams = append(sqlParams, v)
- }
- }
- if v1, ok := param["object_type"]; ok {
- v := tools.IsEmpty(v1)
- if v != "" {
- sql = sql + " and t.object_type=?"
- sqlParams = append(sqlParams, v)
- }
- }
- if v1, ok := param["object_name"]; ok {
- v := tools.IsEmpty(v1)
- if v != "" {
- if rule_type == "logic" {
- sql = sql + " and t.check_object like ?"
- sqlParams = append(sqlParams, v+"%")
- } else {
- sql = sql + " and t.object_name like ?"
- sqlParams = append(sqlParams, v+"%")
- }
- }
- }
- if v1, ok := param["apply_standard"]; ok {
- v := tools.IsEmpty(v1)
- if v != "" {
- sql = sql + " and t.apply_standard like ?"
- sqlParams = append(sqlParams, "%"+v+"%")
- }
- }
- if v1, ok := param["alert_level"]; ok {
- v := tools.IsEmpty(v1)
- if v != "" {
- sql = sql + " and t.alert_level=?"
- sqlParams = append(sqlParams, v)
- }
- }
- limit := fmt.Sprintf(" order by t.check_type desc,t.id limit %d,%d", (pageno-1)*pagesize, pagesize)
- rowset := []orm.Params{}
- _, err := db.Raw(sql+limit, sqlParams).Values(&rowset)
- if err != nil {
- logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql+limit, sqlParams))
- return nil, 0, err
- }
- totalSql := "select count(1) cnt " + sql[strings.Index(sql, "from "):]
- tmpRowset := []orm.Params{}
- _, err = db.Raw(totalSql, sqlParams).Values(&tmpRowset)
- if err != nil {
- logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", totalSql, sqlParams))
- return nil, 0, err
- }
- totalCnt, _ := strconv.Atoi(tools.IsEmpty(tmpRowset[0]["cnt"]))
- return rowset, totalCnt, err
- }
- //删除指定的规则定义
- func (c *ScdNodeRule) DeleteRuleDef(id, rule_type string) error {
- db := orm.NewOrm()
- sql := ""
- sql2 := ""
- if rule_type == "logic" {
- //逻辑规则
- sql = "delete from t_scd_node_check t where id=?"
- sql2 = "delete from t_scd_node_rule_parse where rule_target='node' and rule_id=?"
- } else {
- //语法规则
- sql = "delete from t_scd_scl_check t where id=?"
- sql2 = "delete from t_scd_node_rule_parse where rule_target='attr' and rule_id=?"
- }
- dblog := new(SystemLog)
- dblog.SetUserInfo(c.GetUserInfo())
- dblog.Audittype = enum.AuditType_admin_rule
- dblog.Logtype = enum.LogType_Delete
- dblog.Eventtype = enum.OptEventType_Bus
- dblog.Eventlevel = enum.OptEventLevel_Hight
- _, err := db.Raw(sql, id).Exec()
- if err != nil {
- logger.Logger.Error(err)
- dblog.Description = fmt.Sprintf("删除scd校验规则(id=%s)失败:%s", id, err.Error())
- dblog.Fail2()
- return err
- }
- _, err = db.Raw(sql2, id).Exec()
- if err != nil {
- logger.Logger.Error(err)
- dblog.Description = fmt.Sprintf("删除scd校验规则(id=%s)失败:%s", id, err.Error())
- dblog.Fail2()
- return err
- }
- dblog.Description = fmt.Sprintf("删除scd校验规则(id=%s)成功", id)
- dblog.Success2()
- return nil
- }
- //添加新的规则定义
- func (c *ScdNodeRule) AddRuleDef(param map[string]string, rule_type string) error {
- db := orm.NewOrm()
- id, _ := strconv.Atoi(param["id"])
- dblog := new(SystemLog)
- dblog.SetUserInfo(c.GetUserInfo())
- dblog.Audittype = enum.AuditType_admin_rule
- dblog.Logtype = enum.LogType_Insert
- dblog.Eventtype = enum.OptEventType_Bus
- dblog.Eventlevel = enum.OptEventLevel_Hight
- if rule_type == "logic" {
- //逻辑规则
- mo := t_scd_node_check{}
- mo.CreatedBy, _ = strconv.Atoi(c.GetUserId())
- mo.CreatedTime = tools.NowTime()
- mo.Enable = param["enable"]
- mo.AlertLevel = param["alert_level"]
- mo.CheckArea = param["check_area"]
- mo.CheckDesc = param["check_desc"]
- mo.CheckObject = param["check_object"]
- mo.HintText = param["hint_text"]
- mo.IsExists = param["is_exists"]
- mo.IsRef = param["is_ref"]
- mo.IsUnique = param["is_unique"]
- if id != 0 {
- mo.Id = int64(id)
- _, err := db.Update(&mo)
- if err != nil {
- dblog.Description = fmt.Sprintf("编辑scd逻辑校验规则(id=%d)失败:%s", id, err.Error())
- dblog.Fail2()
- return err
- }
- dblog.Description = fmt.Sprintf("编辑scd逻辑校验规则(id=%d)成功", id)
- dblog.Success2()
- return nil
- } else {
- _, err := db.Insert(&mo)
- if err != nil {
- dblog.Description = fmt.Sprintf("新增scd逻辑校验规则(id=%d)失败:%s", id, err.Error())
- dblog.Fail2()
- return err
- }
- dblog.Description = fmt.Sprintf("新增scd逻辑校验规则(id=%d)成功", id)
- dblog.Success2()
- return nil
- }
- } else {
- //语法规则
- mo := t_scd_scl_check{}
- mo.FuncName = param["func_name"]
- mo.CheckType = tools.IsEmpty(param["check_type"], "0")
- mo.CheckName = param["check_name"]
- mo.CheckArea = param["check_area"]
- mo.CheckDesc = param["check_desc"]
- mo.HintText = param["hint_text"]
- mo.ApplyStandard = tools.IsEmpty(param["apply_standard"], "")
- mo.ApplyStandardNo = tools.IsEmpty(param["apply_standard_no"], "")
- mo.IsExists = tools.IsEmpty(param["is_exists"], "0")
- mo.IsRef = tools.IsEmpty(param["is_ref"], "0")
- mo.AlertLevel = param["alert_level"]
- mo.ConstValue = param["const_value"]
- mo.CreatedBy, _ = strconv.Atoi(c.GetUserId())
- mo.CreatedTime = tools.NowTime()
- mo.DataType = param["data_type"]
- mo.EmunValue = param["emun_value"]
- mo.Enable = param["enable"]
- mo.IsNotnull = tools.IsEmpty(param["is_notnull"], "0")
- mo.IsuniqueByGlobal = tools.IsEmpty(param["isunique_by_global"], "0")
- mo.IsuniqueByParent = tools.IsEmpty(param["isunique_by_parent"], "0")
- mo.MaxLen = tools.IsEmpty(param["max_len"], "0")
- mo.MinLen = tools.IsEmpty(param["min_len"], "0")
- mo.MaxValue = tools.IsEmpty(param["max_value"], "")
- mo.MinValue = tools.IsEmpty(param["min_value"], "")
- mo.NodePath = param["node_path"]
- mo.ObjectName = param["object_name"]
- mo.ObjectType = param["object_type"]
- mo.RegexpValue = param["regexp_value"]
- syslog := new(SystemLog)
- syslog.SetUserInfo(c.GetUserInfo())
- mo.CreatedBy, _ = strconv.Atoi(c.GetUserId())
- mo.CreatedTime = tools.NowTime()
- if id != 0 {
- mo.Id = int64(id)
- _, err := db.Update(&mo)
- if err != nil {
- dblog.Description = fmt.Sprintf("编辑scd语法语义校验规则(id=%d)失败:%s", id, err.Error())
- dblog.Fail2()
- //syslog.Fail("规则管理", fmt.Sprintf("编辑scd语法语义校验规则(id=%d)失败:%s", id, err.Error()))
- //SaveSyslog(fmt.Sprintf("编辑scd语法语义校验规则(id=%d)失败:%s", id, err.Error()), "规则管理", false, tools.IsEmpty(c.UserInfo["name"]))
- return err
- }
- dblog.Description = fmt.Sprintf("编辑scd语法语义校验规则(id=%d)成功", id)
- dblog.Fail2()
- return nil
- } else {
- _, err := db.Insert(&mo)
- if err != nil {
- dblog.Description = fmt.Sprintf("新增scd语法语义校验规则(id=%d)失败:%s", id, err.Error())
- dblog.Fail2()
- return err
- }
- dblog.Description = fmt.Sprintf("新增scd语法语义校验规则(id=%d)成功", id)
- dblog.Success2()
- return nil
- }
- }
- }
- //按校验等级统计数量
- func (c *ScdNodeRule) ResultStatByLevel(scdname, scdpath, ied_name, node_name, node_id string) ([]orm.Params, error) {
- if c.ScdID == 0 {
- fline := string(os.PathSeparator)
- fileFirstChar := scdpath[0:1]
- if fileFirstChar != "." {
- if fileFirstChar == fline {
- scdpath = "." + scdpath
- } else {
- scdpath = "." + fline + scdpath
- }
- }
- if scdname == "" && scdpath == "" {
- return nil, errors.New("scd名称和路径不能为空")
- }
- db := orm.NewOrm()
- sql := "select id from t_scd_scl where scd_name=? and path=? limit 0,1"
- tmpRowset := []orm.Params{}
- db.Raw(sql, scdname, scdpath).Values(&tmpRowset)
- if len(tmpRowset) == 0 {
- return nil, errors.New("无效的scd名称和路径")
- }
- cScdID, _ := strconv.Atoi(tools.IsEmpty(tmpRowset[0]["id"]))
- c.ScdID = int64(cScdID)
- }
- where := ""
- param := []interface{}{}
- param = append(param, c.ScdID)
- if ied_name != "" {
- where += " and t.ied_name=?"
- param = append(param, ied_name)
- }
- if node_name != "" {
- if node_name == "area" {
- //间隔
- where += " and EXISTS(select 1 from t_area_ied_relation a where a.ied_name=t.ied_name and a.area_id=? )"
- param = append(param, node_id)
- } else if node_name == "voltage_level" {
- //电压等级
- 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=? )"
- param = append(param, node_id)
- param = append(param, c.ScdID)
- } else if node_name == "Communication" {
- //通讯类
- where += " and t1.object_name=?"
- param = append(param, "Communication")
- } else if node_name == "DataTypeTemplates" {
- //通讯类
- where += " and t1.object_name=?"
- param = append(param, "DataTypeTemplates")
- } else if node_name == "SCLSyntax" {
- //语法类
- where += " and t1.object_name=?"
- param = append(param, "SCLSyntax")
- }
- }
- db := orm.NewOrm()
- 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`
- rowset := []orm.Params{}
- _, err := db.Raw(sql, param).Values(&rowset)
- if err != nil {
- logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql, c.ScdID))
- }
- return rowset, err
- }
- //汇总统计校验结果数量
- func (c *ScdNodeRule) SumCheckResult() ([]orm.Params, error) {
- db := orm.NewOrm()
- 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`
- rowset := []orm.Params{}
- _, err := db.Raw(sql, c.ScdID).Values(&rowset)
- if err != nil {
- logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql, []interface{}{c.ScdID, c.ScdID, c.ScdID}))
- return rowset, err
- }
- return rowset, nil
- }
- //统计指定站当前scd的正确率
- func (c *ScdNodeRule) RightRateStat(stationid string) (orm.Params, error) {
- db := orm.NewOrm()
- 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
- from t_scd_node_rule_parse t,t_scd_scl t1,t_data_area t2
- where t.scd_id=t1.id and t1.station_id=t2.id and t1.station_id=? and t1.version like '在运版%') a `
- rowset := []orm.Params{}
- _, err := db.Raw(sql, stationid).Values(&rowset)
- if err != nil {
- logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql, stationid))
- return nil, err
- }
- if len(rowset) == 0 {
- return nil, nil
- }
- return rowset[0], nil
- }
- func (c *ScdNodeRule) ExportData(level, ied_name string) ([]orm.Params, error) {
- 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' "
- param := []interface{}{}
- param = append(param, c.ScdID)
- if level != "" {
- sql += " and g.alert_level=? "
- param = append(param, level)
- }
- if ied_name != "" {
- sql += " and t.ied_name=?"
- param = append(param, ied_name)
- }
- limit := fmt.Sprintf(" order by id ")
- rowset := []orm.Params{}
- db := orm.NewOrm()
- _, err := db.Raw(sql+limit, param).Values(&rowset)
- if err != nil {
- logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql+limit, param))
- }
- return rowset, err
- }
- //查询校验规则列表
- //level 规则检查结果级别 为空时查询所有的结果
- func (c *ScdNodeRule) ResultList(scdname, scdpath string, level, ied_name, node_name, node_id string, pageno, pagesize int) ([]orm.Params, int, error) {
- if c.ScdID == 0 {
- fline := string(os.PathSeparator)
- fileFirstChar := scdpath[0:1]
- if fileFirstChar != "." {
- if fileFirstChar == fline {
- scdpath = "." + scdpath
- } else {
- scdpath = "." + fline + scdpath
- }
- }
- if scdname == "" && scdpath == "" {
- return nil, 0, errors.New("scd名称和路径不能为空")
- }
- db := orm.NewOrm()
- sql := "select id from t_scd_scl where scd_name=? and path=? limit 0,1"
- tmpRowset := []orm.Params{}
- db.Raw(sql, scdname, scdpath).Values(&tmpRowset)
- if len(tmpRowset) == 0 {
- return nil, 0, errors.New("无效的scd名称和路径")
- }
- cScdID, _ := strconv.Atoi(tools.IsEmpty(tmpRowset[0]["id"]))
- c.ScdID = int64(cScdID)
- }
- 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=? "
- where := ""
- param := []interface{}{}
- param = append(param, c.ScdID)
- if level != "" {
- where += " and g.alert_level=? "
- param = append(param, level)
- }
- if ied_name != "" {
- where += " and t.ied_name=?"
- param = append(param, ied_name)
- }
- if node_name != "" {
- if node_name == "area" {
- //间隔
- where += " and EXISTS(select 1 from t_area_ied_relation a where a.ied_name=t.ied_name and a.area_id=? )"
- param = append(param, node_id)
- } else if node_name == "voltage_level" {
- //电压等级
- 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=? )"
- param = append(param, node_id)
- param = append(param, c.ScdID)
- } else if node_name == "Communication" {
- //通讯类
- where += " and g.object_name=?"
- param = append(param, "Communication")
- } else if node_name == "DataTypeTemplates" {
- //通讯类
- where += " and g.object_name=?"
- param = append(param, "DataTypeTemplates")
- } else if node_name == "SCLSyntax" {
- //语法类
- where += " and g.object_name=?"
- param = append(param, "SCLSyntax")
- }
- }
- sql += where
- limit := fmt.Sprintf(" order by g.alert_level limit %d,%d", (pageno-1)*pagesize, pagesize)
- rowset := []orm.Params{}
- db := orm.NewOrm()
- _, err := db.Raw(sql+limit, param).Values(&rowset)
- if err != nil {
- logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql+limit, param))
- return rowset, 0, err
- }
- totalNum := 0
- if err == nil {
- tmpRowset := []orm.Params{}
- _, err = db.Raw(strings.ReplaceAll(sql, "t.*,g.alert_level", "count(1) cnt"), param).Values(&tmpRowset)
- if err != nil {
- logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql, param))
- } else if len(tmpRowset) > 0 {
- for _, r1 := range tmpRowset {
- totalNumi, _ := strconv.Atoi(tools.IsEmpty(r1["cnt"]))
- totalNum += totalNumi
- }
- }
- }
- return rowset, totalNum, err
- }
- //启动自定义校验
- func (c *ScdNodeRule) StartFunctionNodeParse() {
- new(TaskMgr).SetStep(tools.IsEmpty(c.ScdID), enum.TaskStep_SCD_rule_parse.Code(), 1)
- c.CheckFunc_header_number(nil)
- c.CheckFunc_header_name_structure(nil)
- c.CheckFunc_header_toolid(nil)
- c.CheckFunc_header_complete(nil)
- c.CheckFunc_header_version(nil)
- c.CheckFunc_header_hitem_complete(nil)
- c.CheckFunc_substation_number(nil)
- c.CheckFunc_substation_name(nil)
- c.CheckFunc_voltagelevel_complete(nil)
- c.CheckFunc_communication_connectedap(nil)
- dATypeMap := c.CheckFunc_datatypetemplates(nil)
- c.CheckFunc_ied(dATypeMap)
- new(TaskMgr).SetStep(tools.IsEmpty(c.ScdID), enum.TaskStep_SCD_rule_parse.Code(), 2)
- //在crc校验完成后将所有校验结果写入数据库
- go c.CheckFunc_crc()
- c.doiMap = nil
- c.daMap = nil
- }
- //----------------------自定义的规则校验方法------------------
- func (c *ScdNodeRule) CheckFunc_header_number(para orm.Params) {
- ruleid := c.getRuleIdByName("Header元素完备性校验")
- if ruleid != "" {
- if c.scdXmlObject.Header == nil {
- parse_result := fmt.Sprintf("Header元素缺失")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- }
- }
- func (c *ScdNodeRule) CheckFunc_header_name_structure(para orm.Params) {
- ruleid := c.getRuleIdByName("Header元素完备性校验")
- if ruleid != "" {
- if c.scdXmlObject.Header != nil && c.scdXmlObject.Header.NameStructure != "IEDName" {
- parse_result := fmt.Sprintf("Header元素中的属性nameStructure值不正确,其值只能为IEDName")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Header.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Header.NodeId, "parse_result": parse_result}
- //唯一性检查未通过
- c.AppendPaseResult(r)
- }
- }
- }
- func (c *ScdNodeRule) CheckFunc_header_toolid(para orm.Params) {
- ruleid := c.getRuleIdByName("toolID属性检查")
- if ruleid != "" {
- if c.scdXmlObject.Header != nil && c.scdXmlObject.Header.ToolID == "" {
- parse_result := fmt.Sprintf("Header元素中的属性toolID配置不规范,其值为空")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Header.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Header.NodeId, "parse_result": parse_result}
- //唯一性检查未通过
- c.AppendPaseResult(r)
- }
- if c.scdXmlObject.Header != nil && c.scdXmlObject.Header.ToolID != "" {
- ary := strings.Split(c.scdXmlObject.Header.ToolID, "_")
- if len(ary) != 3 {
- parse_result := fmt.Sprintf("Header元素属性toolID配置不规范,格式应为:厂商编码_配置工具名称_工具软件版本")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Header.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Header.NodeId, "parse_result": parse_result}
- //唯一性检查未通过
- c.AppendPaseResult(r)
- }
- }
- }
- }
- //完整性校验
- func (c *ScdNodeRule) CheckFunc_header_complete(para orm.Params) {
- if c.scdXmlObject.Header == nil {
- return
- }
- ruleid := c.getRuleIdByName("Header元素完备性校验")
- if ruleid != "" {
- if c.scdXmlObject.Header.Id == "" {
- //验证不通过
- parse_result := fmt.Sprintf("Header元素中id属性缺失")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Header.NodeId, "parse_result": parse_result}
- //唯一性检查未通过
- c.AppendPaseResult(r)
- }
- if c.scdXmlObject.Header.Version == "" {
- //验证不通过
- parse_result := fmt.Sprintf("Header元素中version属性缺失")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Header.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Header.NodeId, "parse_result": parse_result}
- //唯一性检查未通过
- c.AppendPaseResult(r)
- }
- if c.scdXmlObject.Header.Revision == "" {
- //验证不通过
- parse_result := fmt.Sprintf("Header元素中revision属性缺失")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Header.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Header.NodeId, "parse_result": parse_result}
- //唯一性检查未通过
- c.AppendPaseResult(r)
- }
- }
- }
- func (c *ScdNodeRule) CheckFunc_header_version(para orm.Params) {
- if c.scdXmlObject.Header == nil {
- return
- }
- ruleid := c.getRuleIdByName("Header版本一致性")
- if ruleid != "" {
- ver := c.scdXmlObject.Header.Version
- rever := c.scdXmlObject.Header.Revision
- if c.scdXmlObject.Header.History != nil {
- hitems := c.scdXmlObject.Header.History.Hitem
- if len(hitems) > 0 {
- lastHitem := hitems[len(hitems)-1]
- if ver != lastHitem.Version && rever != lastHitem.Revision {
- //验证不通过
- parse_result := fmt.Sprintf("Header中的version=%s、revision=%s与History中的最后一个Item不一致", ver, rever)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": lastHitem.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Header.NodeId, "parse_result": parse_result}
- //唯一性检查未通过
- c.AppendPaseResult(r)
- }
- }
- }
- }
- }
- func (c *ScdNodeRule) CheckFunc_header_hitem_complete(para orm.Params) {
- if c.scdXmlObject.Header == nil {
- return
- }
- if c.scdXmlObject.Header.History != nil {
- hitems := c.scdXmlObject.Header.History.Hitem
- if len(hitems) > 0 {
- ver := ""
- rever := ""
- hitemruleid1 := c.getRuleIdByName("Hitem元素完备性校验")
- hitemruleid2 := c.getRuleIdByName("History版本连续性")
- for _, hitem := range hitems {
- if hitemruleid1 != "" {
- errattr := []string{}
- if hitem.Version == "" {
- errattr = append(errattr, "version")
- }
- if hitem.Revision == "" {
- errattr = append(errattr, "revision")
- }
- if hitem.When == "" {
- errattr = append(errattr, "when")
- }
- if len(errattr) > 0 {
- //验证不通过
- parse_result := fmt.Sprintf("Hitem元素中%s属性缺失", strings.Join(errattr, ","))
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": hitem.Lineno, "ruleid": hitemruleid1, "nodeid": hitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- }
- if hitemruleid2 != "" {
- //连续性判断
- if ver == "" {
- ver = hitem.Version
- rever = hitem.Revision
- } else {
- v1, _ := strconv.Atoi(hitem.Version)
- v2, _ := strconv.Atoi(hitem.Revision)
- v3, _ := strconv.Atoi(ver)
- v4, _ := strconv.Atoi(rever)
- if v1 == v3 && int(float64(v2)-float64(v4)-0.1) != 0 {
- //验证不通过
- parse_result := fmt.Sprintf("History版本元素中版本信息不连续:version=%s,revison=%s->version=%s,revison=%s", ver, rever, hitem.Version, hitem.Revision)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": hitem.Lineno, "ruleid": hitemruleid2, "nodeid": hitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- if v1 != v3 && hitem.Revision != "1.0" {
- //验证不通过
- parse_result := fmt.Sprintf("History版本元素中版本信息不规范:文件版本增加时,文件修订版本应置为1.0")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": hitem.Lineno, "ruleid": hitemruleid2, "nodeid": hitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- ver = hitem.Version
- rever = hitem.Revision
- }
- }
- }
- }
- }
- }
- func (c *ScdNodeRule) CheckFunc_substation_number(para orm.Params) {
- ruleid := c.getRuleIdByName("Substation完备性校验")
- if ruleid != "" {
- if c.scdXmlObject.Substation == nil {
- //验证不通过
- parse_result := fmt.Sprintf("Substation元素缺失")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- return
- }
- }
- ruleid = c.getRuleIdByName("Substation对象缺失CIME-dtype元素")
- ruleid2 := c.getRuleIdByName("Substation对象缺失CIME-area元素")
- if ruleid != "" || ruleid2 != "" {
- if len(c.scdXmlObject.Substation.Private) == 0 {
- parse_result := fmt.Sprintf("Substation对象缺失CIME-dtype元素")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Substation.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- return
- }
- isFound := false
- isFoundCIMEArea := false
- for _, pr := range c.scdXmlObject.Substation.Private {
- if pr.Type == "CIME-dtype" {
- isFound = true
- ruleid3 := c.getRuleIdByName("Substation对象对应CIME-dtype中属性缺失")
- if ruleid3 != "" && (pr.Desc == "") {
- parse_result := fmt.Sprintf("Substation对象对应CIME-dtype中属性(desc)缺失")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": pr.Lineno, "ruleid": ruleid3, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- }
- if pr.Type == "CIME-area" {
- isFoundCIMEArea = true
- ruleid3 := c.getRuleIdByName("Substation对象对应CIME-area中属性缺失")
- if ruleid3 != "" && (pr.Name == "" || pr.Desc == "") {
- parse_result := fmt.Sprintf("Substation对象对应CIME-area中属性(name或desc)缺失")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": pr.Lineno, "ruleid": ruleid3, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- }
- }
- if !isFound {
- parse_result := fmt.Sprintf("Substation对象缺失CIME-dtype元素")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Substation.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- if !isFoundCIMEArea {
- parse_result := fmt.Sprintf("Substation对象缺失CIME-area元素")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Substation.Lineno, "ruleid": ruleid2, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- }
- }
- func (c *ScdNodeRule) CheckFunc_substation_name(para orm.Params) {
- if c.scdXmlObject.Substation == nil {
- return
- }
- ruleid := c.getRuleIdByName("变电站名称一致性")
- if ruleid != "" {
- if c.scdXmlObject.Substation.Name != c.scdXmlObject.Header.Id {
- //验证不通过
- parse_result := fmt.Sprintf("Substation的name(%s)与Header中的id(%s)不一致", c.scdXmlObject.Substation.Name, c.scdXmlObject.Header.Id)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Substation.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- }
- }
- //VoltageLevel 对象的命名 name 应按“‘额定电压’ kV”形式命名,如“ 1000kV”“110kV”等,并且全站唯一。 desc 描述参照 name 命名方式
- func (c *ScdNodeRule) CheckFunc_voltagelevel_complete(para orm.Params) {
- if c.scdXmlObject.Substation == nil {
- return
- }
- ruleid1 := c.getRuleIdByName("VoltageLevel命名错误")
- ruleid2 := c.getRuleIdByName("VoltageLevel下Voltage缺失")
- ruleid3 := c.getRuleIdByName("Voltage对象的取值/属性错误")
- ruleid4 := c.getRuleIdByName("SSD关联关系错误")
- if len(c.scdXmlObject.Substation.VoltageLevel) == 0 {
- parse_result := fmt.Sprintf("Substation中存在层级关系错误:未定义VoltageLevel")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Substation.Lineno, "ruleid": ruleid4, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- return
- }
- priMap := map[string]string{}
- for _, item := range c.scdXmlObject.Substation.VoltageLevel {
- name := item.Name
- //desc := item.Desc
- if ruleid1 != "" {
- if _, h := priMap[name]; h {
- //验证不通过
- parse_result := fmt.Sprintf("VoltageLevel命名错误:name应该全站唯一")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": item.Lineno, "ruleid": ruleid1, "nodeid": item.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- continue
- }
- priMap[name] = ""
- if name == "" || len(name) < 3 || !strings.HasSuffix(name, "kV") {
- //验证不通过
- parse_result := fmt.Sprintf("VoltageLevel命名错误:name应按“‘额定电压’ kV”形式命名,如“1000kV”“110kV”等,并且全站唯一")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": item.Lineno, "ruleid": ruleid1, "nodeid": item.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- }
- if ruleid2 != "" {
- if item.Voltage == nil {
- //验证不通过
- parse_result := fmt.Sprintf("VoltageLevel(%s)下缺失Voltage对象", item.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": item.Lineno, "ruleid": ruleid2, "nodeid": item.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- }
- if ruleid3 != "" && item.Voltage != nil {
- if item.Voltage.InnerText != item.Name[0:len(item.Name)-2] {
- //验证不通过
- parse_result := fmt.Sprintf("VoltageLevel(%s)下属Voltage对象的取值错误", item.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": item.Voltage.Lineno, "ruleid": ruleid3, "nodeid": item.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- if item.Voltage.Multiplier != "k" {
- //验证不通过
- parse_result := fmt.Sprintf("VoltageLevel(%s)下属Voltage对象属性(%s=%s)错误", item.Name, "multiplier", item.Voltage.Multiplier)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": item.Voltage.Lineno, "ruleid": ruleid3, "nodeid": item.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- if item.Voltage.Unit != "V" {
- //验证不通过
- parse_result := fmt.Sprintf("VoltageLevel(%s)下属Voltage对象属性(%s=%s)错误", item.Name, "unit", item.Voltage.Unit)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": item.Voltage.Lineno, "ruleid": ruleid3, "nodeid": item.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- }
- //Bay校验
- if len(item.Bay) > 0 {
- ruleid5 := c.getRuleIdByName("Bay对象缺失CIME-dtype元素")
- ruleid6 := c.getRuleIdByName("Bay对象对应CIME-dtype中desc属性值错误")
- if ruleid5 != "" {
- for _, bayrow := range item.Bay {
- if bayrow.Private == nil {
- parse_result := fmt.Sprintf("Bay对象缺失CIME-dtype元素")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": bayrow.Lineno, "ruleid": ruleid5, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- } else {
- if ruleid6 != "" && bayrow.Private.Desc == "" {
- parse_result := fmt.Sprintf("Bay对象对应CIME-dtype中desc属性值错误")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": bayrow.Lineno, "ruleid": ruleid6, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- }
- bayRule1 := c.getRuleIdByName("间隔关联逻辑节点不存在")
- if len(bayrow.PowerTransformer) > 0 {
- ruleid7 := c.getRuleIdByName("PowerTransformer对象命名错误")
- ruleid8 := c.getRuleIdByName("PowerTransformer对象type错误")
- for _, tmpr := range bayrow.PowerTransformer {
- if ruleid7 != "" && (tmpr.Name == "" || !strings.HasPrefix(tmpr.Name, "PTR")) {
- parse_result := fmt.Sprintf("PowerTransformer对象命名(%s)错误", tmpr.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpr.Lineno, "ruleid": ruleid7, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- if ruleid8 != "" && tmpr.Type != "PTR" {
- parse_result := fmt.Sprintf("PowerTransformer对象(%s)type(%s)不为PTR", tmpr.Name, tmpr.Type)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpr.Lineno, "ruleid": ruleid8, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- if len(tmpr.TransformerWinding) > 0 {
- ruleid9 := c.getRuleIdByName("TransformerWinding对象缺失:CIME-voltageLevel")
- ruleid10 := c.getRuleIdByName("TransformerWinding对象中CIME-voltageLevel属性错误或缺失")
- for _, rw := range tmpr.TransformerWinding {
- if ruleid9 != "" && (rw.Private != nil || rw.Private.Type != "CIME-voltageLevel") {
- parse_result := fmt.Sprintf("TransformerWinding对象(%s)缺失:CIME-voltageLevel", rw.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": rw.Lineno, "ruleid": ruleid9, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- if ruleid10 != "" && rw.Private != nil && rw.Private.Desc == "" {
- parse_result := fmt.Sprintf("TransformerWinding对象(%s)中的CIME-voltageLevel的desc属性缺失", rw.Desc)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": rw.Lineno, "ruleid": ruleid10, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- if ruleid10 != "" && rw.Private != nil && rw.Private.Name == "" {
- parse_result := fmt.Sprintf("TransformerWinding对象(%s)中的CIME-voltageLevel的name属性缺失", rw.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": rw.Lineno, "ruleid": ruleid10, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- if ruleid10 != "" && rw.Private != nil && rw.Private.Name != item.Name {
- parse_result := fmt.Sprintf("TransformerWinding对象(%s)中的CIME-voltageLevel的name属性(%s)与已有电压等级(%s)不一致", rw.Name, rw.Private.Name, item.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": rw.Lineno, "ruleid": ruleid10, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- }
- }
- if bayRule1 != "" && len(tmpr.LNode) > 0 {
- scdnode := new(ScdNode)
- for _, i1 := range tmpr.LNode {
- if scdnode.GetIed(c.scdXmlObject, tools.IsEmpty(c.ScdID), i1.IedName) == nil {
- parse_result := fmt.Sprintf("间隔(%s)关联逻辑节点(%s)不存在", bayrow.Name, i1.IedName)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": i1.Lineno, "ruleid": bayRule1, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- }
- }
- }
- }
- if len(bayrow.ConductingEquipment) > 0 {
- ruleid7 := c.getRuleIdByName("ConductingEquipment命名错误")
- condmap := map[string]int{}
- for _, r := range bayrow.ConductingEquipment {
- if ruleid7 != "" {
- if r.Name == "" {
- parse_result := fmt.Sprintf("ConductingEquipment命名错误:name不能为空")
- rt := map[string]interface{}{"scdid": c.ScdID, "lineno": r.Lineno, "ruleid": ruleid7, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(rt)
- continue
- }
- if condmap[r.Name] == 1 {
- parse_result := fmt.Sprintf("在同一Bay内不应有两个同名的ConductingEquipment(%s)元素", r.Name)
- rt := map[string]interface{}{"scdid": c.ScdID, "lineno": r.Lineno, "ruleid": ruleid7, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(rt)
- continue
- }
- condmap[r.Name] = 1
- }
- ruleid8 := c.getRuleIdByName("ConductingEquipment对象缺失CIME-dtype元素")
- if ruleid8 != "" && (r.Private == nil || r.Private.Type != "CIME-dtype") {
- parse_result := fmt.Sprintf("ConductingEquipment对象(%s)缺失CIME-dtype元素", r.Name)
- rt := map[string]interface{}{"scdid": c.ScdID, "lineno": r.Private.Lineno, "ruleid": ruleid8, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(rt)
- }
- ruleid9 := c.getRuleIdByName("ConductingEquipment对象对应CIME-dtype中desc属性值错误")
- if ruleid9 != "" && r.Private != nil && r.Private.Type == "CIME-dtype" {
- if r.Private.Desc == "" {
- parse_result := fmt.Sprintf("ConductingEquipment对象(%s)对应CIME-dtype元素中desc属性值错误", r.Name)
- rt := map[string]interface{}{"scdid": c.ScdID, "lineno": r.Private.Lineno, "ruleid": ruleid9, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(rt)
- }
- }
- if bayRule1 != "" && len(r.LNode) > 0 {
- scdnode := new(ScdNode)
- for _, i1 := range r.LNode {
- if scdnode.GetIed(c.scdXmlObject, tools.IsEmpty(c.ScdID), i1.IedName) == nil {
- parse_result := fmt.Sprintf("间隔(%s)关联逻辑节点(%s)不存在", bayrow.Name, i1.IedName)
- rt := map[string]interface{}{"scdid": c.ScdID, "lineno": i1.Lineno, "ruleid": bayRule1, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(rt)
- }
- }
- }
- }
- }
- if len(bayrow.ConnectivityNode) > 0 {
- ruleid10 := c.getRuleIdByName("ConnectivityNode对象命名错误")
- if ruleid10 != "" {
- for _, r := range bayrow.ConnectivityNode {
- if r.Name == "" {
- parse_result := fmt.Sprintf("ConnectivityNode对象命名错误:不能为空")
- rt := map[string]interface{}{"scdid": c.ScdID, "lineno": r.Lineno, "ruleid": ruleid10, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(rt)
- continue
- }
- if r.Name[0:1] != "C" {
- parse_result := fmt.Sprintf("ConnectivityNode对象(%s)命名不符合规范:Cn进行命名(n)为间隔内ConnectivityNode实例的序号", r.Name)
- rt := map[string]interface{}{"scdid": c.ScdID, "lineno": r.Lineno, "ruleid": ruleid10, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(rt)
- } else {
- no := r.Name[1:]
- _, er := strconv.Atoi(no)
- if er != nil {
- parse_result := fmt.Sprintf("ConnectivityNode对象(%s)命名不符合规范:Cn进行命名(n)为间隔内ConnectivityNode实例的序号", r.Name)
- rt := map[string]interface{}{"scdid": c.ScdID, "lineno": r.Lineno, "ruleid": ruleid10, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(rt)
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- //主要校验以下规则
- //访问点命名一致性校验:〈Communication)下<ConnectedAP>的apName届性值是否指向已存在的TED访问点
- //IED命名一致性校验:〈Communication)下(ConnectedAP>的iedName属性值是否指向己存在的IED
- //GSE命名一致性校验:〈Communication)下<GSE>的cbName、Idlnst属性值是否指向已存在的GOOSE控制块
- //SMV命名一致性校验:〈Communication)下<SMV>的cbName、Idlnst属性值是否指向已存在的SMV控制块
- //ConnectedAP唯一性校验:ConnectedAP 不应重复配置
- //
- func (c *ScdNodeRule) CheckFunc_communication_connectedap(para orm.Params) {
- logger.Logger.Debug(fmt.Sprintf("校验SCD %d的通信节点", c.ScdID))
- if c.scdXmlObject.Communication == nil {
- //验证不通过
- parse_result := fmt.Sprintf("Communication未定义")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Lineno, "ruleid": c.getRuleIdByName("Communication元素完备性校验"), "nodeid": c.scdXmlObject.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- return
- }
- if len(c.scdXmlObject.Communication.SubNetwork) == 0 {
- //验证不通过
- parse_result := fmt.Sprintf("SubNetwork未定义")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Communication.Lineno, "ruleid": c.getRuleIdByName("SubNetwork元素完备性校验"), "nodeid": c.scdXmlObject.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- return
- }
- gseP := map[string]string{}
- smvP := map[string]string{}
- ipAddressIp := map[string]string{}
- gseAppidMap := map[string]string{}
- for _, subnet := range c.scdXmlObject.Communication.SubNetwork {
- apPri := map[string]int{}
- for _, apitem := range subnet.ConnectedAP {
- if apPri[apitem.ApName+apitem.IedName] == 1 {
- parse_result := fmt.Sprintf("%s子网下ConnectedAP(apName=%s,iedName=%s)重复配置", subnet.Name, apitem.ApName, apitem.IedName)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": apitem.Lineno, "ruleid": c.getRuleIdByName("ConnectedAP唯一性校验"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- continue
- }
- apPri[apitem.ApName+apitem.IedName] = 1
- ied := new(ScdNode).GetIed(c.scdXmlObject, "", apitem.IedName)
- if ied == nil {
- parse_result := fmt.Sprintf("%s子网下ConnectedAP(%s)的iedName(%s)未指向已存在的IED", subnet.Name, apitem.ApName, apitem.IedName)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": apitem.Lineno, "ruleid": c.getRuleIdByName("IED命名一致性校验"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- continue
- }
- apHas := false
- if ied.AccessPoint != nil {
- for _, iedap := range ied.AccessPoint {
- if iedap.Name == apitem.ApName {
- apHas = true
- break
- }
- }
- }
- if !apHas {
- parse_result := fmt.Sprintf("%s子网下ConnectedAP(%s)的apName未指向已存在的IED访问点", subnet.Name, apitem.ApName)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": apitem.Lineno, "ruleid": c.getRuleIdByName("访问点命名一致性校验"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- if len(apitem.SMV) > 0 {
- for _, apsmvitem := range apitem.SMV {
- foundLdInst := false
- foundCbname := false
- if ied.AccessPoint != nil {
- for _, iedap := range ied.AccessPoint {
- if iedap.Server == nil {
- continue
- }
- for _, iedld := range iedap.Server.LDevice {
- if iedld.Inst == apsmvitem.LdInst {
- //查找控制块
- if iedld.LN0 != nil {
- for _, iedSmvCb := range iedld.LN0.SampledValueControl {
- if iedSmvCb.Name == apsmvitem.CbName {
- foundCbname = true
- if iedSmvCb.SmvID == "" {
- parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的通信参数(svmID)缺失", apitem.IedName, subnet.Name, iedSmvCb.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedSmvCb.Lineno, "ruleid": c.getRuleIdByName("SV通信参数缺失"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- } else {
- if v, h := gseAppidMap[iedSmvCb.SmvID]; h {
- parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的smvID(%s)与IED(%s)重复", apitem.IedName, subnet.Name, iedSmvCb.Name, iedSmvCb.SmvID, v)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedSmvCb.Lineno, "ruleid": c.getRuleIdByName("SV通信参数唯一性"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- }
- gseAppidMap[iedSmvCb.SmvID] = ied.Name
- }
- if iedSmvCb.ConfRev == "" {
- parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的通信参数(confRev)缺失", apitem.IedName, subnet.Name, iedSmvCb.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedSmvCb.Lineno, "ruleid": c.getRuleIdByName("SV通信参数缺失"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- }
- break
- }
- }
- }
- foundLdInst = true
- break
- }
- }
- if foundLdInst {
- break
- }
- }
- }
- if !foundLdInst {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": apsmvitem.Lineno, "ruleid": c.getRuleIdByName("SMV命名一致性校验"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- } else {
- if !foundCbname {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": apsmvitem.Lineno, "ruleid": c.getRuleIdByName("SMV命名一致性校验"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- }
- }
- if apsmvitem.Address != nil {
- mACAddress := ""
- for _, tmpP := range apsmvitem.Address.P {
- if tmpP.InnerText == "" {
- parse_result := fmt.Sprintf("IED(%s)下的LD(%s)在%s子网下的控制块(%s)的通信参数(%s)缺失", apitem.IedName, apsmvitem.LdInst, subnet.Name, apsmvitem.CbName, tmpP.Type)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数缺失"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- continue
- }
- key := tmpP.Type + tmpP.InnerText
- tmpIednameV := smvP[key]
- switch tmpP.Type {
- case "MAC-Address":
- if tmpIednameV != "" {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数唯一性"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- break
- }
- ary := strings.Split(tmpP.InnerText, "-")
- if len(ary) == 6 && strings.HasPrefix(tmpP.InnerText, "01-0C-CD-04-") {
- //校验是否越界
- p1, er1 := strconv.ParseUint(ary[4], 16, 32) //16进制转10进制
- p2, er2 := strconv.ParseUint(ary[5], 16, 32) //16进制转10进制
- if er1 != nil || er2 != nil {
- parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的MAC地址(%s)配置不规范", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数Mac地址越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- } else {
- p00, _ := strconv.ParseUint("00", 16, 32)
- pff, _ := strconv.ParseUint("FF", 16, 32)
- if p1 < p00 || p1 > pff || p2 < p00 || p2 > pff {
- parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的MAC地址(%s)越界", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数Mac地址越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- } else {
- mACAddress = tmpP.InnerText
- }
- }
- } else {
- parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的MAC地址(%s)配置不规范", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数Mac地址越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- }
- break
- case "APPID":
- if tmpIednameV != "" {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数唯一性"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- } else {
- //校验APPID是否越界
- p16, er := strconv.ParseUint(tmpP.InnerText, 16, 32)
- if len(tmpP.InnerText) != 4 || er != nil {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数APPID越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- } else {
- p1000, _ := strconv.ParseUint("4000", 16, 32)
- p1fff, _ := strconv.ParseUint("4FFF", 16, 32)
- if p16 < p1000 || p16 > p1fff {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数APPID越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- }
- if mACAddress != "" {
- //校验appid生成是否正确
- macAry := strings.Split(mACAddress, "-")
- tmpAppid := macAry[3][1:] + macAry[4][1:] + macAry[5]
- if tmpP.InnerText != tmpAppid {
- parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的APPID(%s)与mac地址不匹配", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数APPID与Mac地址不匹配"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- }
- }
- }
- }
- break
- case "VLAN-ID":
- p16, er := strconv.ParseUint(tmpP.InnerText, 16, 32)
- if er != nil || len(tmpP.InnerText) < 3 {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数VLAN-ID越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- } else {
- p1000, _ := strconv.ParseUint("000", 16, 32)
- p1fff, _ := strconv.ParseUint("FFF", 16, 32)
- if p16 < p1000 || p16 > p1fff {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数VLAN-ID越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- }
- }
- break
- case "VLAN-Priority":
- p16, er := strconv.ParseUint(tmpP.InnerText, 16, 32)
- if len(tmpP.InnerText) != 1 || er != nil {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数VLAN-Priority越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- } else {
- if p16 < 0 || p16 > 7 {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数VLAN-Priority越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- }
- }
- break
- }
- smvP[key] = apitem.IedName
- }
- }
- }
- }
- if len(apitem.GSE) > 0 {
- for _, apsmvitem := range apitem.GSE {
- foundLdInst := false
- foundCbname := false
- if ied.AccessPoint != nil {
- for _, iedap := range ied.AccessPoint {
- if iedap.Server == nil {
- continue
- }
- for _, iedld := range iedap.Server.LDevice {
- if iedld.Inst == apsmvitem.LdInst {
- //查找控制块
- if iedld.LN0 != nil {
- for _, iedCb := range iedld.LN0.GSEControl {
- if iedCb.Name == apsmvitem.CbName {
- foundCbname = true
- if iedCb.AppID == "" {
- parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的通信参数(appID)缺失", apitem.IedName, subnet.Name, iedCb.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedCb.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数缺失"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- } else {
- if v, h := gseAppidMap[iedCb.AppID]; h {
- parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的appID(%s)与IED(%s)重复", apitem.IedName, subnet.Name, iedCb.Name, iedCb.AppID, v)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedCb.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数唯一性"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- }
- gseAppidMap[iedCb.AppID] = ied.Name
- }
- if iedCb.ConfRev == "" {
- parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的通信参数(confRev)缺失", apitem.IedName, subnet.Name, iedCb.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedCb.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数缺失"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- }
- break
- }
- }
- }
- foundLdInst = true
- break
- }
- }
- if foundLdInst {
- break
- }
- }
- }
- if !foundLdInst {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": apsmvitem.Lineno, "ruleid": c.getRuleIdByName("GSE命名一致性校验"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- } else {
- if !foundCbname {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": apsmvitem.Lineno, "ruleid": c.getRuleIdByName("GSE命名一致性校验"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- }
- }
- //GOOSE通信参数校验:GOOSE通信参数唯一性、GOOSE通信参数Mac地址越界、GOOSE通信参数APPID越界、GOOSE通信参数APPID与Mac地址不匹配、GOOSE通信参数VLAN-ID越界、GOOSE通信参数VLAN-Priority越界、GOOSE通信参数MinTime 和 MaxTime 不为推荐值、GOOSE通信参数缺失
- if apsmvitem.Address != nil {
- mACAddress := ""
- for _, tmpP := range apsmvitem.Address.P {
- if tmpP.InnerText == "" {
- parse_result := fmt.Sprintf("IED(%s)下的LD(%s)在%s子网控制块(%s)的通信参数(%s)缺失", apitem.IedName, apsmvitem.LdInst, subnet.Name, apsmvitem.CbName, tmpP.Type)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数缺失"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- continue
- }
- key := tmpP.Type + tmpP.InnerText
- tmpIednameV := gseP[key]
- switch tmpP.Type {
- case "MAC-Address":
- if tmpIednameV != "" {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数唯一性"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- break
- }
- ary := strings.Split(tmpP.InnerText, "-")
- if len(ary) == 6 && strings.HasPrefix(tmpP.InnerText, "01-0C-CD-01-") {
- //校验是否越界
- p1, er1 := strconv.ParseUint(ary[4], 16, 32) //16进制转10进制
- p2, er2 := strconv.ParseUint(ary[5], 16, 32) //16进制转10进制
- if er1 != nil || er2 != nil {
- parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的MAC地址(%s)配置不规范", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数Mac地址越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- } else {
- p00, _ := strconv.ParseUint("00", 16, 32)
- pff, _ := strconv.ParseUint("FF", 16, 32)
- if p1 < p00 || p1 > pff || p2 < p00 || p2 > pff {
- parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的MAC地址(%s)越界", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数Mac地址越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- } else {
- mACAddress = tmpP.InnerText
- }
- }
- } else {
- parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的MAC地址(%s)配置不规范", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数Mac地址越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- }
- break
- case "APPID":
- if tmpIednameV != "" {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数唯一性"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- } else {
- //校验APPID是否越界
- p16, er := strconv.ParseUint(tmpP.InnerText, 16, 32)
- if len(tmpP.InnerText) != 4 || er != nil {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数APPID越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- } else {
- p1000, _ := strconv.ParseUint("1000", 16, 32)
- p1fff, _ := strconv.ParseUint("1FFF", 16, 32)
- if p16 < p1000 || p16 > p1fff {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数APPID越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- }
- if mACAddress != "" {
- //校验appid生成是否正确
- macAry := strings.Split(mACAddress, "-")
- tmpAppid := macAry[3][1:] + macAry[4][1:] + macAry[5]
- if tmpP.InnerText != tmpAppid {
- parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的APPID(%s)与mac地址不匹配", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数APPID与Mac地址不匹配"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- }
- }
- }
- }
- break
- case "VLAN-ID":
- p16, er := strconv.ParseUint(tmpP.InnerText, 16, 32)
- if er != nil || len(tmpP.InnerText) < 3 {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数VLAN-ID越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- } else {
- p1000, _ := strconv.ParseUint("000", 16, 32)
- p1fff, _ := strconv.ParseUint("FFF", 16, 32)
- if p16 < p1000 || p16 > p1fff {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数VLAN-ID越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- }
- }
- break
- case "VLAN-Priority":
- p16, er := strconv.ParseUint(tmpP.InnerText, 16, 32)
- if len(tmpP.InnerText) != 1 || er != nil {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数VLAN-Priority越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- } else {
- if p16 < 0 || p16 > 7 {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数VLAN-Priority越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- }
- }
- break
- }
- gseP[key] = apitem.IedName
- }
- }
- if apsmvitem.MaxTime == nil {
- parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的通信参数(MaxTime)缺失", apitem.IedName, subnet.Name, apsmvitem.CbName)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": apsmvitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数缺失"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- } else {
- if apsmvitem.MaxTime.InnerText != "5000" {
- parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的通信参数MaxTime(%s)不为标准值5000", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.MaxTime.InnerText)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": apsmvitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数MinTime和MaxTime不为推荐值"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- }
- }
- if apsmvitem.MinTime == nil {
- parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的通信参数(MinTime)缺失", apitem.IedName, subnet.Name, apsmvitem.CbName)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": apsmvitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数缺失"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- } else {
- if apsmvitem.MinTime.InnerText != "2" {
- parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的通信参数MinTime(%s)不为标准值2", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.MinTime.InnerText)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": apsmvitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数MinTime和MaxTime不为推荐值"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- }
- }
- }
- }
- //检查站控层通信参数校验
- //1、IP地址同一子网内唯一性
- if apitem.Address != nil {
- for _, ips := range apitem.Address.P {
- if ips.Type == "IP" {
- if ips.InnerText == "" {
- parse_result := fmt.Sprintf("IED(%s)在%s子网下未配置IP地址", apitem.ApName, subnet.Name, subnet.Desc)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": ips.Lineno, "ruleid": c.getRuleIdByName("IP地址未配置"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- } else {
- //判断IP是否越界
- ipparts := strings.Split(ips.InnerText, ".")
- if len(ipparts) != 4 {
- parse_result := fmt.Sprintf("IED(%s)在%s子网下IP地址(%s)无效", apitem.ApName, subnet.Name, ips.InnerText)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": ips.Lineno, "ruleid": c.getRuleIdByName("IP地址配置不规范"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- } else {
- ip1, _ := strconv.Atoi(ipparts[0])
- ip2, _ := strconv.Atoi(ipparts[1])
- ip3, _ := strconv.Atoi(ipparts[2])
- ip4, _ := strconv.Atoi(ipparts[3])
- if (ip1 < 0 && ip1 > 255) || (ip2 < 0 && ip2 > 255) || (ip3 < 0 && ip3 > 255) || (ip4 < 0 && ip4 > 255) {
- parse_result := fmt.Sprintf("IED(%s)在%s子网下IP地址(%s)越界", apitem.ApName, subnet.Name, ips.InnerText)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": ips.Lineno, "ruleid": c.getRuleIdByName("IP地址越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- }
- }
- }
- if tmpIednameV, h := ipAddressIp[ips.InnerText]; h {
- parse_result := fmt.Sprintf("IED(%s)在%s子网下的IP地址与IED(%s)重复", apitem.ApName, subnet.Name, tmpIednameV)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": ips.Lineno, "ruleid": c.getRuleIdByName("IP地址唯一性"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- }
- ipAddressIp[ips.InnerText] = apitem.IedName
- }
- if ips.Type == "IP-SUBNET" {
- if ips.InnerText == "" {
- parse_result := fmt.Sprintf("IED(%s)在%s子网下未配置IP-SUBNET地址", apitem.ApName, subnet.Name, subnet.Desc)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": ips.Lineno, "ruleid": c.getRuleIdByName("IP-SUBNET地址未配置"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- } else {
- ipparts := strings.Split(ips.InnerText, ".")
- if len(ipparts) != 4 {
- parse_result := fmt.Sprintf("IED(%s)在%s子网下IP-SUBNET地址(%s)无效", apitem.ApName, subnet.Name, ips.InnerText)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": ips.Lineno, "ruleid": c.getRuleIdByName("IP-SUBNET地址配置不规范"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- } else {
- ip1, _ := strconv.Atoi(ipparts[0])
- ip2, _ := strconv.Atoi(ipparts[1])
- ip3, _ := strconv.Atoi(ipparts[2])
- ip4, _ := strconv.Atoi(ipparts[3])
- if (ip1 < 0 && ip1 > 255) || (ip2 < 0 && ip2 > 255) || (ip3 < 0 && ip3 > 255) || (ip4 < 0 && ip4 > 255) {
- parse_result := fmt.Sprintf("IED(%s)在%s子网下IP-SUBNET地址(%s)越界", apitem.ApName, subnet.Name, ips.InnerText)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": ips.Lineno, "ruleid": c.getRuleIdByName("IP-SUBNET地址越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, ied)
- }
- }
- }
- }
- }
- }
- }
- }
- }
- //IED校验
- //.IED(XXX)中Server对象缺失
- //.IED(XXX)中访问点***中的Server缺失LD对象
- //.IED(XXX)中LD***中缺失LLN0
- //.IED(XXX)中LD***中缺失LPHD
- //.IED(XXX)中LD***中缺失非LPHD外其他LN
- func (c *ScdNodeRule) CheckFunc_ied(dATypeMap map[string]*node_attr.NDAType) {
- logger.Logger.Debug(fmt.Sprintf("校验SCD %d的IED节点", c.ScdID))
- if c.scdXmlObject == nil {
- return
- }
- //fcdaMap := map[string]string{}
- gooseAppidMap := sync.Map{} // map[string]*node_attr.NIED{}
- smvAppidMap := sync.Map{} // map[string]*node_attr.NIED{}
- reportRptIDMap := sync.Map{}
- var confDataSet *node_attr.NConfDataSet
- for _, iedObj := range c.scdXmlObject.IED {
- //判断ccd校验码 需要在生成crc校验码后进行
- ccdCrc := ""
- for _, iedPrivate := range iedObj.Priavate {
- if iedPrivate.Type == "IED virtual terminal conection CRC" {
- ccdCrc = iedPrivate.InnerText
- break
- }
- }
- if ccdCrc == "" {
- parse_result := fmt.Sprintf("IED(%s)不存在ICD文件CRC校验码", iedObj.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedObj.Lineno, "ruleid": c.getRuleIdByName("ICD文件校验码存在性"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- if iedObj.Services != nil {
- confDataSet = iedObj.Services.ConfDataSet
- }
- signalMapFound := false
- for _, iedPrivate := range iedObj.Priavate {
- if iedPrivate.Type == "Signal Map" {
- signalMapFound = true
- break
- }
- }
- if !signalMapFound {
- parse_result := fmt.Sprintf("IED(%s)定义关联关系的信号或软压板不存在", iedObj.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedObj.Lineno, "ruleid": c.getRuleIdByName("信号关联关系格式检查"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- if len(iedObj.Name) < 5 || len(iedObj.Name) > 8 {
- //IED 的 name 由 5 部分共 8 位合法可视字符组成,分别代表: IED 类型、归属设备类型、电压等级、归属设备编号、 IED 编号,具体要求如附录 B 所示
- parse_result := fmt.Sprintf("IED(%s)名称不符合规范要求", iedObj.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedObj.Lineno, "ruleid": c.getRuleIdByName("IEDName合法性校验"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- if len(iedObj.AccessPoint) == 0 {
- parse_result := fmt.Sprintf("IED(%s)中AccessPoint对象缺失", iedObj.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedObj.Lineno, "ruleid": c.getRuleIdByName("访问点(AccessPoint)名称校验"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- continue
- }
- for _, ap := range iedObj.AccessPoint {
- if ap.Server == nil {
- parse_result := fmt.Sprintf("IED(%s)中Server对象缺失", iedObj.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": ap.Lineno, "ruleid": c.getRuleIdByName("逻辑设备建模正确性"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- continue
- }
- if len(ap.Server.LDevice) == 0 {
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)缺失LD对象", iedObj.Name, ap.Name, ap.Desc)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": ap.Server.Lineno, "ruleid": c.getRuleIdByName("逻辑设备建模正确性"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- continue
- }
- for _, ld := range ap.Server.LDevice {
- //校验DOI/SDI引用模板不一致、DAI引用模板不一致
- c.check_ln_doidai(iedObj, dATypeMap, ld)
- if ld.LN0 == nil {
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)缺失对象LLN0", iedObj.Name, ap.Name, ap.Desc, ld.Desc)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": ld.Lineno, "ruleid": c.getRuleIdByName("逻辑设备建模正确性"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- continue
- } else {
- if _, h := c.lnodeTypeMap.Load(ld.LN0.LnType); !h {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": ld.LN0.Lineno, "ruleid": c.getRuleIdByName("LN引用LNodeType不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- if confDataSet != nil {
- max, _ := strconv.Atoi(confDataSet.Max)
- if len(ld.LN0.DataSet) > max {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": ld.LN0.Lineno, "ruleid": c.getRuleIdByName("数据集数目校验"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- }
- datsetList := map[string]*node_attr.NDataSet{}
- //校验FCDA唯一性
- for _, datset := range ld.LN0.DataSet {
- datsetList[datset.Name] = datset
- if confDataSet != nil {
- max, _ := strconv.Atoi(confDataSet.MaxAttributes)
- if len(datset.FCDA) > max {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": datset.Lineno, "ruleid": c.getRuleIdByName("数据集成员数目校验"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- }
- //dsGOOSE 数据集成员总数不应超过256个
- if strings.HasPrefix(datset.Name, "dsGOOSE") && len(datset.FCDA) > 256 {
- 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))
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": datset.Lineno, "ruleid": c.getRuleIdByName("校验数据集成员构成"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- for _, fcdaitem := range datset.FCDA {
- key := fmt.Sprintf("%s/%s%s%s.%s", fcdaitem.LdInst, fcdaitem.Prefix, fcdaitem.LnClass, fcdaitem.LnInst, fcdaitem.DoName)
- if fcdaitem.DaName != "" {
- key = key + "." + fcdaitem.DaName
- }
- if fcdaitem.LdInst != ld.Inst {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": fcdaitem.Lineno, "ruleid": c.getRuleIdByName("数据集成员跨LD校验"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- continue
- }
- //成员有效性
- has1, _ := c.IedFcdaExist(iedObj.Name, fcdaitem.LdInst, fcdaitem.LnClass, fcdaitem.LnInst, fcdaitem.Prefix, fcdaitem.DoName, fcdaitem.DaName)
- if has1 == nil {
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)数据集(%s)FCDA成员(%s)不存在", iedObj.Name, ap.Name, ap.Desc, ld.Inst, datset.Name, key)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": fcdaitem.Lineno, "ruleid": c.getRuleIdByName("数据集成员有效性校验"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- //dsGOOSE 数据集的所有成员都应采用FCDA构成方式,其它数据集成员都应采用FCD构成方式。
- if strings.HasPrefix(datset.Name, "dsGOOSE") && fcdaitem.DaName == "" {
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)数据集(%s)成员(%s)不是FCDA格式", iedObj.Name, ap.Name, ap.Desc, ld.Inst, datset.Name, key)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": fcdaitem.Lineno, "ruleid": c.getRuleIdByName("校验数据集成员构成"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- if !strings.HasPrefix(datset.Name, "dsGOOSE") && fcdaitem.DaName != "" {
- //parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)数据集(%s)成员(%s)不是FCD格式", iedObj.Name, ap.Name, ap.Desc, ld.Inst, datset.Name, key)
- //r := map[string]interface{}{"scdid": c.ScdID, "ruleid": c.getRuleIdByName("校验数据集成员构成"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- //c.AppendPaseResult(r, iedObj)
- }
- }
- }
- //虚回路校验
- if ld.LN0.Inputs != nil {
- for _, extref := range ld.LN0.Inputs.ExtRef {
- //检查端子2端模型是否相同:DO对应DO,DA对应DA
- hasinsideda := extref.DaName != ""
- hasoutsideda := strings.Count(extref.IntAddr, ".") > 1
- if hasinsideda != hasoutsideda {
- extrefstr := fmt.Sprintf("IED=%s,addr=%s/%s%s%s.%s", extref.IedName, extref.LdInst, extref.Prefix, extref.LnClass, extref.LnInst, extref.DoName)
- if extref.DaName != "" {
- extrefstr = extrefstr + "." + extref.DaName
- }
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)中LD(%s)的关联内(%s)外部虚端子(%s)类型不一致", iedObj.Name, ap.Name, ap.Desc, ld.Inst, extref.IntAddr, extrefstr)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": extref.Lineno, "ruleid": c.getRuleIdByName("连线两端数据不匹配"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- has1, cdc1 := c.IedFcdaExist(extref.IedName, extref.LdInst, extref.LnClass, extref.LnInst, extref.Prefix, extref.DoName, extref.DaName)
- if has1 == nil {
- extrefstr := fmt.Sprintf("IED=%s,addr=%s/%s%s%s.%s", extref.IedName, extref.LdInst, extref.Prefix, extref.LnClass, extref.LnInst, extref.DoName)
- if extref.DaName != "" {
- extrefstr = extrefstr + "." + extref.DaName
- }
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)中LD(%s)的关联外部虚端子(%s)不存在", iedObj.Name, ap.Name, ap.Desc, ld.Inst, extrefstr)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": extref.Lineno, "ruleid": c.getRuleIdByName("连线外部虚端子合法性"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- //内部地址对应的定义是否存在校验
- /*
- has2 := c.iedIntAddrExist(iedObj.Name, extref.IntAddr)
- if has2 == nil {
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)中LD(%s)的虚回路关联内部虚端子(%s)不存在", iedObj.Name, ap.Name, ap.Desc, ld.Inst, extref.IntAddr)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": extref.Lineno, "ruleid": c.getRuleIdByName("连线内部参引对应数据不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- */
- //da或do实例化校验
- has2, cdc2 := c.iedIntAddrDoiOrDaiExist(iedObj.Name, extref.IntAddr)
- if has2 == nil {
- //parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)中LD(%s)的虚回路关联内部虚端子(%s)属性值与实例化不匹配", iedObj.Name, ap.Name, ap.Desc, ld.Inst, extref.IntAddr)
- //r := map[string]interface{}{"scdid": c.ScdID, "lineno": extref.Lineno, "ruleid": c.getRuleIdByName("连线内部参引对应数据不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- //c.AppendPaseResult(r, iedObj)
- }
- //连接2端端子数据类型匹配检查。即DO数据模板的cdc属性值以及Da的bType
- if has1 != nil && has2 != nil && cdc1 != cdc2 {
- tmpTypeName := "CDC"
- if extref.DaName != "" {
- tmpTypeName = "bType"
- }
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": extref.Lineno, "ruleid": c.getRuleIdByName("连线两端数据不匹配"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- }
- }
- //GOOSE控制块校验
- gooseitemMap := map[string]int{}
- if iedObj.Services.GOOSE != nil {
- max, _ := strconv.Atoi(iedObj.Services.GOOSE.Max)
- if len(ld.LN0.GSEControl) > max {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedObj.Services.GOOSE.Lineno, "ruleid": c.getRuleIdByName("GOOSE控制块的个数超出声明的最大值"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- }
- for _, gooseitem := range ld.LN0.GSEControl {
- if gooseitemMap[gooseitem.Name] == 1 {
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)GOOSE控制块(%s)name属性值在LN内重复配置", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE控制块的name属性值在LN内重复配置"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- continue
- }
- gooseitemMap[gooseitem.Name] = 1
- if datsetList[gooseitem.DatSet] == nil {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE控制块引用的数据集不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- if gooseitem.AppID == "" {
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)GOOSE控制块(%s)appID属性配置错误", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE控制块的appID属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- } else {
- if tmpIED, h := gooseAppidMap.Load(gooseitem.AppID); h {
- iedPointer := tmpIED.(*node_attr.NIED)
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE控制块的appID唯一性"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- //格式校验
- newGooseAppid := fmt.Sprintf("%s%s/LLN0.%s", iedObj.Name, ld.Inst, gooseitem.Name)
- if gooseitem.AppID != newGooseAppid {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE控制块appID格式校验"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- gooseAppidMap.Store(gooseitem.AppID, iedObj)
- if gooseitem.ConfRev == "" {
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)GOOSE控制块(%s)的confRev属性配置错误", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE控制块的confRev属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- //是否配置网络参数
- gseNetFound := false
- for _, net := range c.scdXmlObject.Communication.SubNetwork {
- if net.Type != gooseitem.Type && net.Type != "IECGOOSE" {
- continue
- }
- for _, connAp := range net.ConnectedAP {
- if connAp.IedName == iedObj.Name {
- for _, gseNet := range connAp.GSE {
- if gseNet.CbName == gooseitem.Name && gseNet.LdInst == ld.Inst {
- gseNetFound = true
- }
- }
- }
- }
- }
- if !gseNetFound {
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)GOOSE控制块(%s)未配置网络参数", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE控制块未配置网络参数"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- }
- }
- //SV控制块
- smvitemMap := map[string]int{}
- for _, gooseitem := range ld.LN0.SampledValueControl {
- if smvitemMap[gooseitem.Name] == 1 {
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)SV控制块(%s)name属性值在LN内重复配置", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("SV控制块的name属性值在LN内重复配置"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- continue
- }
- smvitemMap[gooseitem.Name] = 1
- if datsetList[gooseitem.DatSet] == nil {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("SV控制块引用的数据集不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- if gooseitem.SmvID == "" {
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)SV控制块(%s)smvID属性配置错误", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("SV控制块的smvID属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- } else {
- if tmpIED, h := smvAppidMap.Load(gooseitem.SmvID); h {
- iedPointer := tmpIED.(*node_attr.NIED)
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("SV控制块的smvID唯一性"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- //格式校验
- newGooseAppid := fmt.Sprintf("%s%s/LLN0.%s", iedObj.Name, ld.Inst, gooseitem.Name)
- if gooseitem.SmvID != newGooseAppid {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("SV控制块appID格式校验"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- smvAppidMap.Store(gooseitem.SmvID, iedObj)
- if gooseitem.ConfRev == "" {
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)SV控制块(%s)的confRev属性配置错误", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("SV控制块的confRev属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- if gooseitem.SmpRate == "" {
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)SV控制块(%s)的smpRate属性配置错误", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("SV控制块的smpRate属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- if gooseitem.NofASDU == "" {
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)SV控制块(%s)的nofASDU属性配置错误", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("SV控制块的nofASDU属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- //是否配置网络参数
- gseNetFound := false
- for _, net := range c.scdXmlObject.Communication.SubNetwork {
- if net.Type != "SMV" {
- continue
- }
- for _, connAp := range net.ConnectedAP {
- if connAp.IedName == iedObj.Name {
- for _, gseNet := range connAp.SMV {
- if gseNet.CbName == gooseitem.Name && gseNet.LdInst == ld.Inst {
- gseNetFound = true
- }
- }
- }
- }
- }
- if !gseNetFound {
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)SV控制块(%s)未配置网络参数", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("SV控制块未配置网络参数"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- }
- }
- //日志控制块校验
- logNameMap := map[string]int{}
- for _, logItem := range ld.LN0.LogControl {
- if logItem.DatSet == "" {
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)日志控制块(%s)datSet属性配置错误(缺失、值为空)", iedObj.Name, ap.Name, ap.Desc, ld.Inst, logItem.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": logItem.Lineno, "ruleid": c.getRuleIdByName("日志控制块的datSet属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- } else {
- logDatsetFound := false
- for _, dsitem := range ld.LN0.DataSet {
- if dsitem.Name == logItem.DatSet {
- logDatsetFound = true
- break
- }
- }
- if !logDatsetFound {
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)日志控制块(%s)引用的数据集(%s)不存在", iedObj.Name, ap.Name, ap.Desc, ld.Inst, logItem.Name, logItem.DatSet)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": logItem.Lineno, "ruleid": c.getRuleIdByName("日志控制块引用的数据集不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- }
- if logItem.IntgPd == "" {
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)日志控制块(%s)intgPd属性配置错误(缺失、值为空)", iedObj.Name, ap.Name, ap.Desc, ld.Inst, logItem.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": logItem.Lineno, "ruleid": c.getRuleIdByName("日志控制块的intgPd属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- logLdnameFound := false
- for _, logLd := range ap.Server.LDevice {
- if logLd.Inst == logItem.LogName {
- logLdnameFound = true
- break
- }
- }
- if !logLdnameFound {
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)日志控制块(%s)对应的日志名(%s)不存在", iedObj.Name, ap.Name, ap.Desc, ld.Inst, logItem.Name, logItem.LogName)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": logItem.Lineno, "ruleid": c.getRuleIdByName("日志控制块对应的日志名不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- if _, h := logNameMap[logItem.Name]; h {
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)日志控制块的name(%s)属性在LN下配置重复", iedObj.Name, ap.Name, ap.Desc, ld.Inst, logItem.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": logItem.Lineno, "ruleid": c.getRuleIdByName("日志控制块的name属性在LN下配置重复"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- logNameMap[logItem.Name] = 1
- }
- //报告控制块校验
- reportNameMap := map[string]int{}
- for _, reportItem := range ld.LN0.ReportControl {
- if reportItem.DatSet != "" {
- datsetFound := false
- for _, dsitem := range ld.LN0.DataSet {
- if dsitem.Name == reportItem.DatSet {
- datsetFound = true
- break
- }
- }
- if !datsetFound {
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)报告控制块(%s)引用的数据集(%s)不存在", iedObj.Name, ap.Name, ap.Desc, ld.Inst, reportItem.Name, reportItem.DatSet)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": reportItem.Lineno, "ruleid": c.getRuleIdByName("报告控制块引用的数据集不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- }
- if reportItem.RptID == "" {
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)报告控制块(%s)中的rptID属性配置错误(缺失、值为空)", iedObj.Name, ap.Name, ap.Desc, ld.Inst, reportItem.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": reportItem.Lineno, "ruleid": c.getRuleIdByName("报告控制块的rptID属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- } else {
- if v, h := reportRptIDMap.Load(iedObj.Name + reportItem.RptID); h {
- v1 := v.(map[string]interface{})
- 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"]))
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": reportItem.Lineno, "ruleid": c.getRuleIdByName("报告控制块的rptID重复"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- reportRptIDMap.Store(iedObj.Name+reportItem.RptID, map[string]interface{}{"iedname": iedObj.Name, "reportcontrol": reportItem.Name})
- }
- if reportItem.ConfRev == "" {
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)报告控制块(%s)中的confRev属性配置错误(缺失、值为空)", iedObj.Name, ap.Name, ap.Desc, ld.Inst, reportItem.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": reportItem.Lineno, "ruleid": c.getRuleIdByName("报告控制块的confRev属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- if _, h := reportNameMap[iedObj.Name+reportItem.Name]; h {
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)报告控制块的name(%s)属性在LN下配置重复", iedObj.Name, ap.Name, ap.Desc, ld.Inst, reportItem.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": reportItem.Lineno, "ruleid": c.getRuleIdByName("报告控制块的name属性在LN下配置重复"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- reportNameMap[iedObj.Name+reportItem.Name] = 1
- if len(reportItem.Name) >= 4 && (reportItem.Name[0:4] == "brcb" || reportItem.Name[0:4] == "urcb") {
- //名称符合规范
- } else {
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)报告控制块的name(%s)属性未按规范命名", iedObj.Name, ap.Name, ap.Desc, ld.Inst, reportItem.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": reportItem.Lineno, "ruleid": c.getRuleIdByName("报告控制块属性正确性及规范性检查"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- }
- //定值控制块校验
- if ld.LN0.SettingControl != nil {
- if ld.LN0.SettingControl.ActSG == "" {
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)定值控制块actSG属性配置值不正确", iedObj.Name, ap.Name, ap.Desc, ld.Inst)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": ld.LN0.SettingControl.Lineno, "ruleid": c.getRuleIdByName("定值控制块的actSG属性配置错误(值不正确)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- if ld.LN0.SettingControl.NumOfSGs == "" {
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)定值控制块numOfSGs属性配置值不正确", iedObj.Name, ap.Name, ap.Desc, ld.Inst)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": ld.LN0.SettingControl.Lineno, "ruleid": c.getRuleIdByName("定值控制块的numOfSGs属性配置错误(值不正确)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- }
- }
- lphdFound := false
- otherLnFound := false
- for _, lns := range ld.LN {
- if _, h := c.lnodeTypeMap.Load(lns.LnType); !h {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": lns.Lineno, "ruleid": c.getRuleIdByName("LN引用LNodeType不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- if lns.LnClass == "LPHD" {
- lphdFound = true
- } else {
- otherLnFound = true
- }
- }
- if !lphdFound {
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)中LD(%s)的缺失对象LPHD", iedObj.Name, ap.Name, ap.Desc, ld.Inst)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": ld.Lineno, "ruleid": c.getRuleIdByName("逻辑设备建模正确性"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- if !otherLnFound {
- parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)中LD(%s)的缺失非LPHD外其他LN", iedObj.Name, ap.Name, ap.Desc, ld.Inst)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": ld.Lineno, "ruleid": c.getRuleIdByName("逻辑设备建模正确性"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- }
- }
- }
- }
- //校验IED crc一致性
- func (c *ScdNodeRule) CheckFunc_crc() {
- defer func() {
- c.isRun = 2 //校验完成标识
- c.Flush() //将校验结果写数据库
- }()
- logger.Logger.Debug(fmt.Sprintf("校验SCD %d的IED Crc", c.ScdID))
- if c.scdXmlObject == nil {
- return
- }
- checkcnt := 1
- timeoutTotal := len(c.scdXmlObject.IED) * 3
- for {
- //检查crc提取是否完成
- if v, h := global.IedCrcMakeState.Load(fmt.Sprintf("crc_%d", c.ScdID)); h {
- v1 := tools.IsEmpty(v)
- if v1 == "0" || v1 == "2" {
- //提取失败0或者已完成2
- break
- }
- }
- time.Sleep(500 * time.Millisecond)
- checkcnt = checkcnt + 1
- if checkcnt > timeoutTotal {
- //crc提取超时
- logger.Logger.Error(errors.New(fmt.Sprintf("SCD %d的IED Crc提取超时", c.ScdID)))
- break
- }
- }
- crclist, _ := global.CachedScdCrc.Load(fmt.Sprintf("crc_%d", c.ScdID))
- if crclist == nil {
- logger.Logger.Debug(fmt.Sprintf("未找到SCD %d的IED Crc提取结果数据", c.ScdID))
- return
- }
- crcmap := crclist.(map[string]string)
- for _, iedObj := range c.scdXmlObject.IED {
- crc := ""
- p := new(node_attr.NPrivate)
- for _, p = range iedObj.Priavate {
- if p.Type == "IED virtual terminal conection CRC" {
- crc = p.InnerText
- break
- }
- }
- iedcrc2 := crcmap[iedObj.Name]
- if crc != "" && iedcrc2 != crc {
- parse_result := fmt.Sprintf("IED(%s)中存储的CCD校验码(%s)与实际校验码(%s)不一致", iedObj.Name, crc, iedcrc2)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": p.Lineno, "ruleid": c.getRuleIdByName("CCD校验码校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- }
- }
- func (c *ScdNodeRule) check_ln_doidai(iedObj *node_attr.NIED, dATypeMap map[string]*node_attr.NDAType, ld *node_attr.NLDevice) {
- if c.daMap == nil {
- c.daMap = &sync.Map{}
- }
- if c.doiMap == nil {
- c.doiMap = &sync.Map{}
- }
- if ld.LN0 != nil {
- vlnnode, _ := c.lnodeTypeMap.Load(ld.LN0.LnType)
- if vlnnode == nil {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": ld.LN0.Lineno, "ruleid": c.getRuleIdByName("LN引用LNodeType不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- } else {
- lnnode := vlnnode.(*node_attr.NLNodeType)
- lnchilderdoi := map[string]string{}
- v_lnchilderdoi, _ := c.doiMap.Load(ld.LN0.LnType)
- if v_lnchilderdoi == nil {
- for _, do := range lnnode.DO {
- lnchilderdoi[do.Name] = do.Type
- }
- c.doiMap.Store(ld.LN0.LnType, lnchilderdoi)
- } else {
- lnchilderdoi = v_lnchilderdoi.(map[string]string)
- }
- for _, doi := range ld.LN0.DOI {
- if lnchilderdoi[doi.Name] == "" {
- //fmt.Println(fmt.Sprintf("ied:%s LN0.LnType:%s doi.Name:%s %+v", iedObj.Name, ld.LN0.LnType, doi.Name, lnchilderdoi))
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": doi.Lineno, "ruleid": c.getRuleIdByName("DOI/SDI引用模板不一致"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- }
- }
- }
- for _, ln := range ld.LN {
- vlnnode, _ := c.lnodeTypeMap.Load(ln.LnType)
- if vlnnode == nil {
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": ln.Lineno, "ruleid": c.getRuleIdByName("LN引用LNodeType不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- } else {
- lnnode := vlnnode.(*node_attr.NLNodeType)
- lnchilderdoi := map[string]string{}
- v_lnchilderdoi, _ := c.doiMap.Load(ln.LnType)
- if v_lnchilderdoi == nil {
- for _, do := range lnnode.DO {
- lnchilderdoi[do.Name] = do.Type
- }
- c.doiMap.Store(ln.LnType, lnchilderdoi)
- } else {
- lnchilderdoi = v_lnchilderdoi.(map[string]string)
- }
- for _, doi := range ln.DOI {
- if lnchilderdoi[doi.Name] == "" {
- //fmt.Println(fmt.Sprintf("ied:%s LN.LnType:%s doi.Name:%s %+v", iedObj.Name, ln.LnType, doi.Name, lnchilderdoi))
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": doi.Lineno, "ruleid": c.getRuleIdByName("DOI/SDI引用模板不一致"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- continue
- }
- dotype := lnchilderdoi[doi.Name]
- dalist := map[string]string{}
- v_dalist, _ := c.daMap.Load(dotype)
- if v_dalist == nil {
- v, _ := c.doTypeMap.Load(dotype)
- if v == nil {
- //do模板不存在
- continue
- }
- for _, daitem := range v.(*node_attr.NDOType).DA {
- dalist[daitem.Name] = "1"
- }
- c.daMap.Store(dotype, dalist)
- } else {
- dalist = v_dalist.(map[string]string)
- }
- for _, da := range doi.DAI {
- if dalist[da.Name] == "" {
- //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]))
- 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)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": da.Lineno, "ruleid": c.getRuleIdByName("DAI引用模板不一致"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r, iedObj)
- }
- }
- }
- }
- }
- }
- //DataTypeTemplates校验
- //数据实例引用模板正确性检查
- //数据类型模板引用正确性检查
- //模板重复定义校验
- //冗余模板校验
- func (c *ScdNodeRule) CheckFunc_datatypetemplates(para orm.Params) (a3 map[string]*node_attr.NDAType) {
- logger.Logger.Debug(fmt.Sprintf("校验SCD %d的数据模板节点", c.ScdID))
- if c.scdXmlObject == nil {
- return
- }
- usedLNodeTypeMap := map[string]int{}
- for _, iedObj := range c.scdXmlObject.IED {
- for _, acc := range iedObj.AccessPoint {
- if acc.Server == nil {
- continue
- }
- for _, ld := range acc.Server.LDevice {
- usedLNodeTypeMap[ld.LN0.LnType] = 1
- for _, ln := range ld.LN {
- usedLNodeTypeMap[ln.LnType] = 1
- }
- }
- }
- }
- usedDoTypeMap := map[string]int{}
- daTypeMap := map[string]*node_attr.NDAType{}
- usedDaTypeMap := map[string]int{}
- enumTypeMap := map[string]*node_attr.NEnumType{}
- usedEnumTypeMap := map[string]int{}
- for _, enumtype := range c.scdXmlObject.DataTypeTemplates.EnumType {
- if enumTypeMap[enumtype.Id] != nil {
- parse_result := fmt.Sprintf("EnumType(%s)定义重复", enumtype.Id)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": enumtype.Lineno, "ruleid": c.getRuleIdByName("模板重复定义校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- continue
- }
- enumTypeMap[enumtype.Id] = enumtype
- }
- for _, datype := range c.scdXmlObject.DataTypeTemplates.DAType {
- if daTypeMap[datype.Id] != nil {
- parse_result := fmt.Sprintf("DAType(%s)定义重复", datype.Id)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": datype.Lineno, "ruleid": c.getRuleIdByName("模板重复定义校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- continue
- }
- daTypeMap[datype.Id] = datype
- c.daTypeMap.Store(datype.Id, datype)
- for _, enum := range datype.BDA {
- if enum.Type == "" {
- continue
- }
- if enum.BType == "Enum" {
- usedEnumTypeMap[enum.Type] = 1 //使用的模板
- if enumTypeMap[enum.Type] == nil {
- parse_result := fmt.Sprintf("DAType(%s)中引用的EnumType(%s)不存在", datype.Id, enum.Type)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": enum.Lineno, "ruleid": c.getRuleIdByName("EnumType模板引用合法性校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- }
- }
- }
- for _, dotype := range c.scdXmlObject.DataTypeTemplates.DOType {
- if v, _ := c.doTypeMap.Load(dotype.Id); v != nil {
- parse_result := fmt.Sprintf("DOType(%s)定义重复", dotype.Id)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": dotype.Lineno, "ruleid": c.getRuleIdByName("模板重复定义校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- continue
- }
- c.doTypeMap.Store(dotype.Id, dotype)
- for _, da := range dotype.DA {
- if da.Type == "" {
- continue
- }
- if da.BType == "Enum" {
- usedEnumTypeMap[da.Type] = 1 //使用的模板
- if enumTypeMap[da.Type] == nil {
- parse_result := fmt.Sprintf("DOType(%s)中引用的btype为Enum的DAType(%s)不存在", dotype.Id, da.Type)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": da.Lineno, "ruleid": c.getRuleIdByName("EnumType模板引用合法性校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- } else {
- usedDaTypeMap[da.Type] = 1
- if daTypeMap[da.Type] == nil {
- parse_result := fmt.Sprintf("DOType(%s)中引用的DAType(%s)不存在", dotype.Id, da.Type)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": da.Lineno, "ruleid": c.getRuleIdByName("DaType模板引用合法性校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- }
- }
- }
- //查找未被引用的enum模板
- for enumtype, obj := range enumTypeMap {
- if _, h := usedEnumTypeMap[enumtype]; !h {
- parse_result := fmt.Sprintf("EnumType(%s)未被引用", enumtype)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": obj.Lineno, "ruleid": c.getRuleIdByName("冗余模板校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- }
- //查找未被引用的da模板
- //fmt.Println(fmt.Sprintf("%+v", daTypeMap))
- for datype, obj := range daTypeMap {
- if _, h := usedDaTypeMap[datype]; !h {
- parse_result := fmt.Sprintf("DAType(%s)未被引用", datype)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": obj.Lineno, "ruleid": c.getRuleIdByName("冗余模板校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- }
- for _, lntype := range c.scdXmlObject.DataTypeTemplates.LNodeType {
- if v, _ := c.lnodeTypeMap.Load(lntype.Id); v != nil {
- parse_result := fmt.Sprintf("LNodeType(%s)定义重复", lntype.Id)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": lntype.Lineno, "ruleid": c.getRuleIdByName("模板重复定义校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- continue
- }
- //查找未被引用的LNodeType模板
- if _, h := usedLNodeTypeMap[lntype.Id]; !h {
- parse_result := fmt.Sprintf("LNodeType(%s)未被引用", lntype.Id)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": lntype.Lineno, "ruleid": c.getRuleIdByName("冗余模板校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- continue
- }
- c.lnodeTypeMap.Store(lntype.Id, lntype)
- for _, do := range lntype.DO {
- if do.Type == "" {
- continue
- }
- usedDoTypeMap[do.Type] = 1
- if v, _ := c.doTypeMap.Load(do.Type); v == nil {
- parse_result := fmt.Sprintf("LNodeType(%s)中引用的DoType(%s)不存在", lntype.Id, do.Type)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": do.Lineno, "ruleid": c.getRuleIdByName("DoType模板引用合法性校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- }
- }
- //查找未被引用的DOtype模板
- c.doTypeMap.Range(func(k, v any) bool {
- dotype := tools.IsEmpty(k)
- if _, h := usedDoTypeMap[dotype]; !h {
- parse_result := fmt.Sprintf("DOType(%s)未被引用", dotype)
- 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}
- c.AppendPaseResult(r)
- }
- return true
- })
- return daTypeMap
- }
- //发送端虚端子检查
- //存在性检查
- //cdc检查
- //
- func (c *ScdNodeRule) IedFcdaExist(iedname, ldinst, lnclass, lninst, prefix, doname, daname string) (obj interface{}, cdc string) {
- if c.scdXmlObject == nil {
- return nil, ""
- }
- donames := strings.Split(doname, ".") //检查是否是sdi定义
- doname = donames[0]
- sdiname := ""
- if len(donames) > 1 {
- sdiname = donames[1]
- }
- for _, iedObj := range c.scdXmlObject.IED {
- if iedObj.Name != iedname {
- continue
- }
- for _, ap := range iedObj.AccessPoint {
- if ap.Server == nil {
- continue
- }
- for _, ld := range ap.Server.LDevice {
- if ld.Inst != ldinst {
- continue
- }
- if ld.LN0 != nil && lnclass == ld.LN0.LnClass && lninst == ld.LN0.Inst && prefix == ld.LN0.Prefix {
- for _, doi := range ld.LN0.DOI {
- if doi.Name == doname {
- if sdiname != "" {
- foundsdi := false
- for _, sdi := range doi.SDI {
- if sdi.Name == sdiname {
- foundsdi = true
- }
- }
- if !foundsdi {
- return nil, ""
- }
- }
- cdc := c.getDoICdc(ld.LN0.LnType, doname, daname)
- return doi, cdc
- }
- }
- }
- for _, ln := range ld.LN {
- if lnclass == ln.LnClass && lninst == ln.Inst && prefix == ln.Prefix {
- for _, doi := range ln.DOI {
- if doi.Name == doname {
- if sdiname != "" {
- foundsdi := false
- for _, sdi := range doi.SDI {
- if sdi.Name == sdiname {
- foundsdi = true
- }
- }
- if !foundsdi {
- return nil, ""
- }
- }
- cdc := c.getDoICdc(ln.LnType, doname, daname)
- return doi, cdc
- }
- }
- }
- }
- }
- }
- }
- return nil, ""
- }
- func (c *ScdNodeRule) IedIntAddrExist(iedname, intAddr string) (obj interface{}) {
- if c.scdXmlObject == nil {
- return nil
- }
- //intaddr格式:2-B:PIGO1/GOINGGIO1.SPCSO8.stVal
- addrs := strings.Split(intAddr, ":")
- if len(addrs) == 2 {
- intAddr = addrs[1]
- }
- intAddrs := strings.Split(intAddr, "/")
- if len(intAddrs) == 1 {
- logger.Logger.Error(errors.New(fmt.Sprintf("装置%s发现无效的intAddr:%s", iedname, intAddr)))
- return nil
- }
- ldinst := intAddrs[0]
- lnstr := intAddrs[1]
- v_tmpAry := strings.Split(lnstr, ".")
- if len(v_tmpAry) < 2 {
- logger.Logger.Error(errors.New(fmt.Sprintf("装置%s发现无效的intAddr:%s", iedname, intAddr)))
- return nil
- }
- doda := v_tmpAry[1:]
- doname := ""
- //daname := ""
- if len(doda) == 1 {
- //只有do
- doname = doda[0]
- } else {
- doname = doda[0]
- //daname = strings.Join(doda[1:], ".") //还原da
- }
- for _, iedObj := range c.scdXmlObject.IED {
- if iedObj.Name != iedname {
- continue
- }
- for _, ap := range iedObj.AccessPoint {
- if ap.Server != nil {
- for _, ld := range ap.Server.LDevice {
- if ld.Inst == ldinst {
- if ld.LN0 != nil {
- if strings.HasPrefix(lnstr, fmt.Sprintf("%s%s%s", ld.LN0.Prefix, ld.LN0.LnClass, ld.LN0.Inst)) {
- for _, item := range ld.LN0.DOI {
- if item.Name == doname {
- return item
- }
- }
- }
- }
- for _, item := range ld.LN {
- if strings.HasPrefix(lnstr, fmt.Sprintf("%s%s%s", item.Prefix, item.LnClass, item.Inst)) {
- for _, item := range item.DOI {
- if item.Name == doname {
- return item
- }
- }
- }
- }
- }
- }
- }
- }
- }
- return nil
- }
- //校验内部端子的DO或DA实例是否存在
- func (c *ScdNodeRule) iedIntAddrDoiOrDaiExist(iedname, intAddr string) (obj interface{}, cdc string) {
- if c.scdXmlObject == nil {
- return nil, ""
- }
- //intaddr格式:2-B:PIGO1/GOINGGIO1.SPCSO8.stVal
- addrs := strings.Split(intAddr, ":")
- if len(addrs) == 2 {
- intAddr = addrs[1]
- }
- intAddrs := strings.Split(intAddr, "/")
- if len(intAddrs) == 1 {
- logger.Logger.Error(errors.New(fmt.Sprintf("装置%s发现无效的intAddr:%s", iedname, intAddr)))
- return nil, ""
- }
- ldinst := intAddrs[0]
- lnstr := intAddrs[1]
- for _, iedObj := range c.scdXmlObject.IED {
- if iedObj.Name != iedname {
- continue
- }
- for _, ap := range iedObj.AccessPoint {
- if ap.Server != nil {
- for _, ld := range ap.Server.LDevice {
- if ld.Inst == ldinst {
- for _, ln := range ld.LN {
- str := fmt.Sprintf("%s%s%s", ln.Prefix, ln.LnClass, ln.Inst)
- v_tmpAry := strings.Split(lnstr, ".")
- if v_tmpAry[0] == str {
- doda := v_tmpAry[1:]
- doname := ""
- daname := ""
- if len(doda) == 1 {
- //只有do
- doname = doda[0]
- } else {
- doname = doda[0]
- daname = strings.Join(doda[1:], ".") //还原da
- }
- for _, doi := range ln.DOI {
- if doi.Name == doname {
- cdc := c.getDoICdc(ln.LnType, doi.Name, daname)
- if daname == "" {
- return doi, cdc
- }
- for _, dai := range doi.DAI {
- if dai.Name == daname {
- return dai, cdc
- }
- }
- das := strings.Split(daname, ".")
- if len(das) > 1 {
- for _, sdi := range doi.SDI {
- if sdi.Name == das[0] {
- for _, dai := range sdi.DAI {
- if dai.Name == das[1] {
- return dai, cdc
- }
- }
- for _, sdi2 := range sdi.SDI {
- for _, dai := range sdi2.DAI {
- if dai.Name == das[1] {
- return dai, cdc
- }
- }
- }
- return nil, cdc
- }
- }
- }
- return nil, cdc
- }
- }
- return nil, ""
- }
- }
- return nil, ""
- }
- }
- }
- }
- }
- return nil, ""
- }
- //根据LNtype和doi名称返回其cdc属性值
- func (c *ScdNodeRule) getDoICdc(lntype, doiname, daname string) string {
- if c.lnodeTypeMap == nil {
- return ""
- }
- v, _ := c.lnodeTypeMap.Load(lntype)
- if v == nil {
- return ""
- }
- for _, do := range v.(*node_attr.NLNodeType).DO {
- if do.Name == doiname {
- if do.Type == "" {
- return ""
- }
- d1, _ := c.doTypeMap.Load(do.Type)
- if d1 == nil {
- return ""
- }
- if daname == "" {
- return d1.(*node_attr.NDOType).Cdc
- }
- das := strings.Split(daname, ".") //多层da
- for _, daitem := range d1.(*node_attr.NDOType).DA {
- if daitem.Name == das[0] {
- if len(das) == 1 {
- return daitem.BType
- } else {
- bdatype := daitem.Type
- da1, _ := c.daTypeMap.Load(bdatype)
- if da1 == nil {
- return ""
- }
- for _, dbaitem := range da1.(*node_attr.NDAType).BDA {
- if dbaitem.Name == das[1] {
- return dbaitem.BType
- }
- }
- }
- return ""
- }
- }
- }
- }
- return ""
- }
- //---------------------------------------------------------
- func (c *ScdNodeRule) AppendPaseResult(r map[string]interface{}, ied ...*node_attr.NIED) {
- var iedobj *node_attr.NIED
- if len(ied) > 0 && ied[0] != nil {
- iedobj = ied[0]
- r["ied_name"] = iedobj.Name
- r["ied_desc"] = iedobj.Desc
- }
- c.checkFailListLock.Lock()
- c.CheckFailList = append(c.CheckFailList, r)
- c.checkFailListLock.Unlock()
- //logger.Logger.Info(fmt.Sprintf("========校验结果:%v", r))
- //实时将结果通过mqtt发送解析结果
- //结果处理客户端需要订阅/jujutong/scd_check_tools/ruleparse/{scdid}
- //go mqtt.PublishMessage("/jujutong/scd_check_tools/ruleparse/"+fmt.Sprintf("%d", c.ScdID), r["parse_result"].(string))
- }
- //添加端子检查结果
- //需要数据:ied_name,ied_desc,fcda_desc,fcda_addr,out_ied_name,out_ied_desc,out_fcda_desc,out_fcda_addr,error_type
- //其中error_type值为以下之一:1 多余端子 2 错误端子 3 缺失
- func (c *ScdNodeRule) AppendFcdaCheckResult(r map[string]interface{}) {
- r["check_type"] = "fcda"
- c.checkFailListLock.Lock()
- c.CheckFailList = append(c.CheckFailList, r)
- c.checkFailListLock.Unlock()
- }
- func (c *ScdNodeRule) CheckFinish() {
- c.isRun = 2
- }
- //节点规则验证完成
- func (c *ScdNodeRule) Flush() {
- //判断等待验证队列中的数据是否已处理完,没有处理完则一直等待
- if c.isRun != 2 {
- for {
- time.Sleep(100 * time.Millisecond)
- if c.isRun == 2 {
- break
- }
- }
- }
- logger.Logger.Debug(fmt.Sprintln("规则校验结果,共%d条!", len(c.CheckFailList)))
- c.writeNodeDB()
- }
- //根据规则名称获取规则ID.返回为""时表示还未定义该规则名称
- func (c *ScdNodeRule) getRuleIdByName(name string) string {
- row := c.NodeRuleList[name]
- if row == nil {
- return "0"
- }
- return tools.IsEmpty(row["id"])
- }
- //将验证结果写入数据库。仅写入验证不通过的结果
- //每5000条写入一次
- func (c *ScdNodeRule) writeNodeDB() {
- if len(c.CheckFailList) == 0 {
- return
- }
- db := orm.NewOrm()
- s1 := time.Now().Unix()
- nodeCols := "(scd_id,node_id,line_no,rule_target,rule_id,parse_result,ied_name,ied_desc)"
- fcdaCols := "(scd_id,ied_name,ied_desc,fcda_desc,fcda_addr,out_ied_name,out_ied_desc,out_fcda_desc,out_fcda_addr,rule_id,parse_result,error_type)"
- loadedRec := 0
- nodeSqlValuesAry := []string{}
- fcdaSqlValuesAry := []string{}
- for _, m := range c.CheckFailList {
- check_type := tools.IsEmpty(m["check_type"]) // fcda检查结果写入t_scd_fcda_check_result
- if check_type == "fcda" {
- fcdaSqlValuesAry = append(fcdaSqlValuesAry, "("+tools.IsEmpty(m["scdid"])+",'"+tools.IsEmpty(m["ied_name"])+"','"+tools.IsEmpty(m["ied_desc"])+"','"+tools.IsEmpty(m["fcda_desc"])+"','"+tools.IsEmpty(m["fcda_addr"])+"','"+tools.IsEmpty(m["out_ied_name"])+"','"+tools.IsEmpty(m["out_ied_desc"])+"','"+tools.IsEmpty(m["out_fcda_desc"])+"','"+tools.IsEmpty(m["out_fcda_addr"])+"',"+tools.IsEmpty(m["ruleid"], "0")+",'"+tools.IsEmpty(m["parse_result"])+"',"+tools.IsEmpty(m["error_type"], "0")+")")
- } else {
- 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"])+"')")
- }
- if len(nodeSqlValuesAry) == 1000 {
- sql := "insert into t_scd_node_rule_parse" + nodeCols + "values" + strings.Join(nodeSqlValuesAry, ",")
- _, err := db.Raw(sql).Exec()
- if err != nil {
- log.Println(err)
- }
- loadedRec = loadedRec + 1000
- nodeSqlValuesAry = nil
- nodeSqlValuesAry = []string{}
- }
- if len(fcdaSqlValuesAry) == 1000 {
- sql := "insert into t_scd_fcda_check_result" + fcdaCols + "values" + strings.Join(fcdaSqlValuesAry, ",")
- _, err := db.Raw(sql).Exec()
- if err != nil {
- log.Println(err)
- }
- loadedRec = loadedRec + 1000
- fcdaSqlValuesAry = nil
- fcdaSqlValuesAry = []string{}
- }
- }
- if len(nodeSqlValuesAry) > 0 {
- sql := "insert into t_scd_node_rule_parse" + nodeCols + "values" + strings.Join(nodeSqlValuesAry, ",")
- _, err := db.Raw(sql).Exec()
- if err != nil {
- log.Println(err)
- }
- nodeSqlValuesAry = nil
- }
- if len(fcdaSqlValuesAry) > 0 {
- sql := "insert into t_scd_fcda_check_result" + fcdaCols + "values" + strings.Join(fcdaSqlValuesAry, ",")
- _, err := db.Raw(sql).Exec()
- if err != nil {
- log.Println(err)
- }
- fcdaSqlValuesAry = nil
- }
- c.CheckFailList = nil
- runtime.GC()
- s2 := time.Now().Unix()
- fmt.Println(fmt.Sprintf("===================Flush NodeAttrParse 完成!。耗时:%d秒", s2-s1))
- fmt.Println("===========节点属性验证完成")
- mqtt.PublishMessage(fmt.Sprintf("%s/%d", checktopic, c.ScdID), `{"code":1,"scdid":"`+tools.IsEmpty(c.ScdID)+`","state":1,"msg":"该SCD校验完成"}`)
- global.CheckingScd.Delete(c.ScdID)
- }
|