123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697 |
- 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) 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%s", ld.Inst, 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%s", ld.Inst, 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 {
- 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"])+")")
- } 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) == 5000 {
- 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 + 5000
- nodeSqlValuesAry = nil
- nodeSqlValuesAry = []string{}
- }
- if len(fcdaSqlValuesAry) == 5000 {
- sql := "insert into t_scd_fcda_check_result" + fcdaCols + "values" + strings.Join(nodeSqlValuesAry, ",")
- _, err := db.Raw(sql).Exec()
- if err != nil {
- log.Println(err)
- }
- loadedRec = loadedRec + 5000
- 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(nodeSqlValuesAry, ",")
- _, 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)
- }
|