12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705 |
- package bo
- import (
- "errors"
- "fmt"
- "log"
- "os"
- "runtime"
- "scd_check_tools/global"
- "scd_check_tools/logger"
- "scd_check_tools/models/enum"
- "scd_check_tools/models/node_attr"
- "scd_check_tools/mqtt"
- "scd_check_tools/tools"
- "strconv"
- "strings"
- "sync"
- "time"
- "github.com/astaxie/beego/orm"
- )
- //节点规则解析管理
- //单独启用专用解析进程,与节点入库操作为异步关系。该进程在没有新scd入库时为睡眠状态,当有新scd需要解析时,需要外部将其唤醒
- //进程被唤醒后,定时查询节点表中未被解析的节点进行规则有效性验证,如果验证不通过,则将结果写入规则解析结果表
- //每个节点状态都将按以下状态进行切换:0 未解析->1 解析中-> 2已解析
- type ScdNodeRule struct {
- ScdID int64
- ScdName string
- DeviceBaseModel
- doiMap *sync.Map
- daMap *sync.Map
- lnodeTypeMap *sync.Map // map[string]*node_attr.NLNodeType{}
- doTypeMap *sync.Map // map[string]*node_attr.NDOType{}
- daTypeMap *sync.Map // map[string]*node_attr.NDOType{}
- //当前未通过验证的节点列表
- CheckFailList []map[string]interface{}
- //等待解析的队列
- NodeRuleList map[string]orm.Params
- //
- NodeRuleFunctionList []orm.Params
- //是否正在解析节点。默认为0
- isRun int
- parseLock sync.RWMutex
- checkFailListLock sync.RWMutex
- scdXmlObject *node_attr.SCL
- }
- type t_scd_node_rule_parse struct {
- Id int64 `orm:"pk"`
- ScdId int64
- NodeId int64
- RuleId int64
- ParseResult string
- CreatedBy int
- CreatedTime string
- }
- //语法语义规则模型
- type t_scd_scl_check struct {
- Id int64 `orm:"pk"`
- CheckName string
- CheckType string
- HintText string
- ApplyStandard string
- ApplyStandardNo string
- ObjectType string
- ObjectName string
- FuncName string
- CheckDesc string
- CheckArea string
- AlertLevel string
- NodePath string
- IsExists string
- IsRef string
- IsNotnull string
- DataType string
- MinLen string
- MaxLen string
- MinValue string
- MaxValue string
- IsuniqueByParent string
- IsuniqueByGlobal string
- ConstValue string
- EmunValue string
- RegexpValue string
- Enable string
- CreatedBy int
- CreatedTime string
- }
- //逻辑规则模型.(已不使用)
- type t_scd_node_check struct {
- Id int64 `orm:"pk"`
- CheckObject string
- CheckDesc string
- CheckArea string
- AlertLevel string
- IsExists string
- IsRef string
- IsUnique string
- HintText string
- Enable string
- CreatedBy int
- CreatedTime string
- }
- func init() {
- orm.RegisterModel(new(t_scd_node_rule_parse))
- orm.RegisterModel(new(t_scd_node_check))
- orm.RegisterModel(new(t_scd_scl_check))
- }
- var checktopic = "/jujutong/scd_check_tools/ruleparse"
- func (c *ScdNodeRule) SetScdXmlObject(obj *node_attr.SCL) {
- c.scdXmlObject = obj
- }
- func (c *ScdNodeRule) TestCheckRule() {
- c.scdXmlObject, _ = new(ScdParse).GetScdXmlObjectBySCDID(tools.IsEmpty(c.ScdID))
- if c.scdXmlObject == nil {
- logger.Logger.Error(errors.New("无效的SCD"))
- mqtt.PublishMessage(fmt.Sprintf("%s/%d", checktopic, c.ScdID), `{"code":0,"scdid":"`+tools.IsEmpty(c.ScdID)+`","state":0,"msg":"无效的SCD"}`)
- return
- }
- if _, h := global.CheckingScd.Load(c.ScdID); h {
- logger.Logger.Debug(fmt.Sprintf("%d文件正在校验中", c.ScdID))
- mqtt.PublishMessage(fmt.Sprintf("%s/%d", checktopic, c.ScdID), `{"code":0,"scdid":"`+tools.IsEmpty(c.ScdID)+`","state":0,"msg":"该SCD正在校验中"}`)
- return
- }
- c.doiMap = &sync.Map{}
- c.daMap = &sync.Map{}
- c.lnodeTypeMap = &sync.Map{}
- c.doTypeMap = &sync.Map{}
- c.daTypeMap = &sync.Map{}
- c.NodeRuleList = map[string]orm.Params{}
- c.NodeRuleFunctionList = []orm.Params{}
- db := orm.NewOrm()
- lst := []orm.Params{}
- db.Raw("select * from t_scd_scl_check where enable=1").Values(&lst)
- for _, r := range lst {
- //object_name := r["object_name"].(string)
- //object_type := r["object_type"].(string)
- checkname := tools.IsEmpty(r["check_name"])
- if checkname != "" {
- c.NodeRuleList[checkname] = r
- }
- }
- mqtt.PublishMessage(fmt.Sprintf("%s/%d", checktopic, c.ScdID), `{"code":1,"scdid":"`+tools.IsEmpty(c.ScdID)+`","state":0,"msg":"SCD正在校验中"}`)
- global.CheckingScd.Store(c.ScdID, "1")
- c.StartFunctionNodeParse()
- }
- //查询规则定义列表
- func (c *ScdNodeRule) GetDefList(param map[string]interface{}, pageno, pagesize int) ([]orm.Params, int, error) {
- db := orm.NewOrm()
- rule_type := param["rule_type"]
- sqlParams := []interface{}{}
- sql := "select t.*,ifnull(c.name,'其它') check_type_name from t_scd_scl_check t left join global_const_code c on t.check_type=c.id and c.parentcode='checkrule_type' where 1=1"
- if v1, ok := param["rule_id"]; ok {
- v := tools.IsEmpty(v1)
- if v != "" {
- sql = sql + " and t.id=?"
- sqlParams = append(sqlParams, v)
- }
- }
- if v1, ok := param["check_type"]; ok {
- v := tools.IsEmpty(v1)
- if v != "" {
- sql = sql + " and t.check_type=?"
- sqlParams = append(sqlParams, v)
- }
- }
- if v1, ok := param["check_name"]; ok {
- v := tools.IsEmpty(v1)
- if v != "" {
- sql = sql + " and t.check_name like ?"
- sqlParams = append(sqlParams, "%"+v+"%")
- }
- }
- if v1, ok := param["enable"]; ok {
- v := tools.IsEmpty(v1)
- if v != "" {
- sql = sql + " and t.enable=?"
- sqlParams = append(sqlParams, v)
- }
- }
- if v1, ok := param["object_type"]; ok {
- v := tools.IsEmpty(v1)
- if v != "" {
- sql = sql + " and t.object_type=?"
- sqlParams = append(sqlParams, v)
- }
- }
- if v1, ok := param["object_name"]; ok {
- v := tools.IsEmpty(v1)
- if v != "" {
- if rule_type == "logic" {
- sql = sql + " and t.check_object like ?"
- sqlParams = append(sqlParams, v+"%")
- } else {
- sql = sql + " and t.object_name like ?"
- sqlParams = append(sqlParams, v+"%")
- }
- }
- }
- if v1, ok := param["apply_standard"]; ok {
- v := tools.IsEmpty(v1)
- if v != "" {
- sql = sql + " and t.apply_standard like ?"
- sqlParams = append(sqlParams, "%"+v+"%")
- }
- }
- if v1, ok := param["alert_level"]; ok {
- v := tools.IsEmpty(v1)
- if v != "" {
- sql = sql + " and t.alert_level=?"
- sqlParams = append(sqlParams, v)
- }
- }
- limit := fmt.Sprintf(" order by t.check_type desc,t.id limit %d,%d", (pageno-1)*pagesize, pagesize)
- rowset := []orm.Params{}
- _, err := db.Raw(sql+limit, sqlParams).Values(&rowset)
- if err != nil {
- logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql+limit, sqlParams))
- return nil, 0, err
- }
- totalSql := "select count(1) cnt " + sql[strings.Index(sql, "from "):]
- tmpRowset := []orm.Params{}
- _, err = db.Raw(totalSql, sqlParams).Values(&tmpRowset)
- if err != nil {
- logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", totalSql, sqlParams))
- return nil, 0, err
- }
- totalCnt, _ := strconv.Atoi(tools.IsEmpty(tmpRowset[0]["cnt"]))
- return rowset, totalCnt, err
- }
- //删除指定的规则定义
- func (c *ScdNodeRule) DeleteRuleDef(id, rule_type string) error {
- db := orm.NewOrm()
- sql := ""
- sql2 := ""
- if rule_type == "logic" {
- //逻辑规则
- sql = "delete from t_scd_node_check t where id=?"
- sql2 = "delete from t_scd_node_rule_parse where rule_target='node' and rule_id=?"
- } else {
- //语法规则
- sql = "delete from t_scd_scl_check t where id=?"
- sql2 = "delete from t_scd_node_rule_parse where rule_target='attr' and rule_id=?"
- }
- dblog := new(SystemLog)
- dblog.SetUserInfo(c.GetUserInfo())
- dblog.Audittype = enum.AuditType_admin_rule
- dblog.Logtype = enum.LogType_Delete
- dblog.Eventtype = enum.OptEventType_Bus
- dblog.Eventlevel = enum.OptEventLevel_Hight
- _, err := db.Raw(sql, id).Exec()
- if err != nil {
- logger.Logger.Error(err)
- dblog.Description = fmt.Sprintf("删除scd校验规则(id=%s)失败:%s", id, err.Error())
- dblog.Fail2()
- return err
- }
- _, err = db.Raw(sql2, id).Exec()
- if err != nil {
- logger.Logger.Error(err)
- dblog.Description = fmt.Sprintf("删除scd校验规则(id=%s)失败:%s", id, err.Error())
- dblog.Fail2()
- return err
- }
- dblog.Description = fmt.Sprintf("删除scd校验规则(id=%s)成功", id)
- dblog.Success2()
- return nil
- }
- //添加新的规则定义
- func (c *ScdNodeRule) AddRuleDef(param map[string]string, rule_type string) error {
- db := orm.NewOrm()
- id, _ := strconv.Atoi(param["id"])
- dblog := new(SystemLog)
- dblog.SetUserInfo(c.GetUserInfo())
- dblog.Audittype = enum.AuditType_admin_rule
- dblog.Logtype = enum.LogType_Insert
- dblog.Eventtype = enum.OptEventType_Bus
- dblog.Eventlevel = enum.OptEventLevel_Hight
- if rule_type == "logic" {
- //逻辑规则
- mo := t_scd_node_check{}
- mo.CreatedBy, _ = strconv.Atoi(c.GetUserId())
- mo.CreatedTime = tools.NowTime()
- mo.Enable = param["enable"]
- mo.AlertLevel = param["alert_level"]
- mo.CheckArea = param["check_area"]
- mo.CheckDesc = param["check_desc"]
- mo.CheckObject = param["check_object"]
- mo.HintText = param["hint_text"]
- mo.IsExists = param["is_exists"]
- mo.IsRef = param["is_ref"]
- mo.IsUnique = param["is_unique"]
- if id != 0 {
- mo.Id = int64(id)
- _, err := db.Update(&mo)
- if err != nil {
- dblog.Description = fmt.Sprintf("编辑scd逻辑校验规则(id=%d)失败:%s", id, err.Error())
- dblog.Fail2()
- return err
- }
- dblog.Description = fmt.Sprintf("编辑scd逻辑校验规则(id=%d)成功", id)
- dblog.Success2()
- return nil
- } else {
- _, err := db.Insert(&mo)
- if err != nil {
- dblog.Description = fmt.Sprintf("新增scd逻辑校验规则(id=%d)失败:%s", id, err.Error())
- dblog.Fail2()
- return err
- }
- dblog.Description = fmt.Sprintf("新增scd逻辑校验规则(id=%d)成功", id)
- dblog.Success2()
- return nil
- }
- } else {
- //语法规则
- mo := t_scd_scl_check{}
- mo.FuncName = param["func_name"]
- mo.CheckType = tools.IsEmpty(param["check_type"], "0")
- mo.CheckName = param["check_name"]
- mo.CheckArea = param["check_area"]
- mo.CheckDesc = param["check_desc"]
- mo.HintText = param["hint_text"]
- mo.ApplyStandard = tools.IsEmpty(param["apply_standard"], "")
- mo.ApplyStandardNo = tools.IsEmpty(param["apply_standard_no"], "")
- mo.IsExists = tools.IsEmpty(param["is_exists"], "0")
- mo.IsRef = tools.IsEmpty(param["is_ref"], "0")
- mo.AlertLevel = param["alert_level"]
- mo.ConstValue = param["const_value"]
- mo.CreatedBy, _ = strconv.Atoi(c.GetUserId())
- mo.CreatedTime = tools.NowTime()
- mo.DataType = param["data_type"]
- mo.EmunValue = param["emun_value"]
- mo.Enable = param["enable"]
- mo.IsNotnull = tools.IsEmpty(param["is_notnull"], "0")
- mo.IsuniqueByGlobal = tools.IsEmpty(param["isunique_by_global"], "0")
- mo.IsuniqueByParent = tools.IsEmpty(param["isunique_by_parent"], "0")
- mo.MaxLen = tools.IsEmpty(param["max_len"], "0")
- mo.MinLen = tools.IsEmpty(param["min_len"], "0")
- mo.MaxValue = tools.IsEmpty(param["max_value"], "")
- mo.MinValue = tools.IsEmpty(param["min_value"], "")
- mo.NodePath = param["node_path"]
- mo.ObjectName = param["object_name"]
- mo.ObjectType = param["object_type"]
- mo.RegexpValue = param["regexp_value"]
- syslog := new(SystemLog)
- syslog.SetUserInfo(c.GetUserInfo())
- mo.CreatedBy, _ = strconv.Atoi(c.GetUserId())
- mo.CreatedTime = tools.NowTime()
- if id != 0 {
- mo.Id = int64(id)
- _, err := db.Update(&mo)
- if err != nil {
- dblog.Description = fmt.Sprintf("编辑scd语法语义校验规则(id=%d)失败:%s", id, err.Error())
- dblog.Fail2()
- //syslog.Fail("规则管理", fmt.Sprintf("编辑scd语法语义校验规则(id=%d)失败:%s", id, err.Error()))
- //SaveSyslog(fmt.Sprintf("编辑scd语法语义校验规则(id=%d)失败:%s", id, err.Error()), "规则管理", false, tools.IsEmpty(c.UserInfo["name"]))
- return err
- }
- dblog.Description = fmt.Sprintf("编辑scd语法语义校验规则(id=%d)成功", id)
- dblog.Fail2()
- return nil
- } else {
- _, err := db.Insert(&mo)
- if err != nil {
- dblog.Description = fmt.Sprintf("新增scd语法语义校验规则(id=%d)失败:%s", id, err.Error())
- dblog.Fail2()
- return err
- }
- dblog.Description = fmt.Sprintf("新增scd语法语义校验规则(id=%d)成功", id)
- dblog.Success2()
- return nil
- }
- }
- }
- //按校验等级统计数量
- func (c *ScdNodeRule) ResultStatByLevel(scdname, scdpath, ied_name, node_name, node_id string) ([]orm.Params, error) {
- if c.ScdID == 0 {
- fline := string(os.PathSeparator)
- fileFirstChar := scdpath[0:1]
- if fileFirstChar != "." {
- if fileFirstChar == fline {
- scdpath = "." + scdpath
- } else {
- scdpath = "." + fline + scdpath
- }
- }
- if scdname == "" && scdpath == "" {
- return nil, errors.New("scd名称和路径不能为空")
- }
- db := orm.NewOrm()
- sql := "select id from t_scd_scl where scd_name=? and path=? limit 0,1"
- tmpRowset := []orm.Params{}
- db.Raw(sql, scdname, scdpath).Values(&tmpRowset)
- if len(tmpRowset) == 0 {
- return nil, errors.New("无效的scd名称和路径")
- }
- cScdID, _ := strconv.Atoi(tools.IsEmpty(tmpRowset[0]["id"]))
- c.ScdID = int64(cScdID)
- }
- where := ""
- param := []interface{}{}
- param = append(param, c.ScdID)
- if ied_name != "" {
- where += " and t.ied_name=?"
- param = append(param, ied_name)
- }
- if node_name != "" {
- if node_name == "area" {
- //间隔
- where += " and EXISTS(select 1 from t_area_ied_relation a where a.ied_name=t.ied_name and a.area_id=? )"
- param = append(param, node_id)
- } else if node_name == "voltage_level" {
- //电压等级
- where += " and EXISTS(select 1 from t_substation_area v1, t_area_ied_relation v2 where v1.id=v2.area_id and v2.ied_name=t.ied_name and v1.voltage_level=? and v1.scd_id=? )"
- param = append(param, node_id)
- param = append(param, c.ScdID)
- } else if node_name == "Communication" {
- //通讯类
- where += " and t1.object_name=?"
- param = append(param, "Communication")
- } else if node_name == "DataTypeTemplates" {
- //通讯类
- where += " and t1.object_name=?"
- param = append(param, "DataTypeTemplates")
- } else if node_name == "SCLSyntax" {
- //语法类
- where += " and t1.object_name=?"
- param = append(param, "SCLSyntax")
- }
- }
- db := orm.NewOrm()
- sql := `select t1.alert_level, count(0) cnt from t_scd_scl_check t1 ,t_scd_node_rule_parse t where t.scd_id=? ` + where + ` and t.rule_id=t1.id GROUP BY alert_level`
- rowset := []orm.Params{}
- _, err := db.Raw(sql, param).Values(&rowset)
- if err != nil {
- logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql, c.ScdID))
- }
- return rowset, err
- }
- //汇总统计校验结果数量
- func (c *ScdNodeRule) SumCheckResult() ([]orm.Params, error) {
- db := orm.NewOrm()
- sql := `SELECT t1.object_name, t1.alert_level ,a.ied_name from t_scd_node_rule_parse a ,t_scd_scl_check t1 where a.rule_id=t1.id and a.scd_id=? GROUP BY t1.object_name,a.ied_name ,t1.alert_level`
- rowset := []orm.Params{}
- _, err := db.Raw(sql, c.ScdID).Values(&rowset)
- if err != nil {
- logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql, []interface{}{c.ScdID, c.ScdID, c.ScdID}))
- return rowset, err
- }
- return rowset, nil
- }
- //统计指定站当前scd的正确率
- func (c *ScdNodeRule) RightRateStat(stationid string) (orm.Params, error) {
- db := orm.NewOrm()
- sql := `select a.* from ( select t1.node_cnt nodetotal, max(t2.id) station_id,max(t2.AREA_NAME) station_name,max(t1.id) scd_id, count(t.id) cnt
- from t_scd_node_rule_parse t,t_scd_scl t1,t_data_area t2
- where t.scd_id=t1.id and t1.station_id=t2.id and t1.station_id=? and t1.version like '在运版%') a `
- rowset := []orm.Params{}
- _, err := db.Raw(sql, stationid).Values(&rowset)
- if err != nil {
- logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql, stationid))
- return nil, err
- }
- if len(rowset) == 0 {
- return nil, nil
- }
- return rowset[0], nil
- }
- func (c *ScdNodeRule) ExportData(level, ied_name string) ([]orm.Params, error) {
- sql := "select t.*,g.alert_level,g.apply_standard,g.apply_standard_no from t_scd_node_rule_parse t inner join t_scd_scl_check g on t.rule_id=g.id where t.scd_id=? and t.rule_target='attr' "
- param := []interface{}{}
- param = append(param, c.ScdID)
- if level != "" {
- sql += " and g.alert_level=? "
- param = append(param, level)
- }
- if ied_name != "" {
- sql += " and t.ied_name=?"
- param = append(param, ied_name)
- }
- limit := fmt.Sprintf(" order by id ")
- rowset := []orm.Params{}
- db := orm.NewOrm()
- _, err := db.Raw(sql+limit, param).Values(&rowset)
- if err != nil {
- logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql+limit, param))
- }
- return rowset, err
- }
- //查询校验规则列表
- //level 规则检查结果级别 为空时查询所有的结果
- func (c *ScdNodeRule) ResultList(scdname, scdpath string, level, ied_name, node_name, node_id string, pageno, pagesize int) ([]orm.Params, int, error) {
- if c.ScdID == 0 {
- fline := string(os.PathSeparator)
- fileFirstChar := scdpath[0:1]
- if fileFirstChar != "." {
- if fileFirstChar == fline {
- scdpath = "." + scdpath
- } else {
- scdpath = "." + fline + scdpath
- }
- }
- if scdname == "" && scdpath == "" {
- return nil, 0, errors.New("scd名称和路径不能为空")
- }
- db := orm.NewOrm()
- sql := "select id from t_scd_scl where scd_name=? and path=? limit 0,1"
- tmpRowset := []orm.Params{}
- db.Raw(sql, scdname, scdpath).Values(&tmpRowset)
- if len(tmpRowset) == 0 {
- return nil, 0, errors.New("无效的scd名称和路径")
- }
- cScdID, _ := strconv.Atoi(tools.IsEmpty(tmpRowset[0]["id"]))
- c.ScdID = int64(cScdID)
- }
- sql := "select t.*,g.alert_level,g.apply_standard,g.apply_standard_no from t_scd_node_rule_parse t inner join t_scd_scl_check g on t.rule_id=g.id where t.scd_id=? "
- where := ""
- param := []interface{}{}
- param = append(param, c.ScdID)
- if level != "" {
- where += " and g.alert_level=? "
- param = append(param, level)
- }
- if ied_name != "" {
- where += " and t.ied_name=?"
- param = append(param, ied_name)
- }
- if node_name != "" {
- if node_name == "area" {
- //间隔
- where += " and EXISTS(select 1 from t_area_ied_relation a where a.ied_name=t.ied_name and a.area_id=? )"
- param = append(param, node_id)
- } else if node_name == "voltage_level" {
- //电压等级
- where += " and EXISTS(select 1 from t_substation_area v1, t_area_ied_relation v2 where v1.id=v2.area_id and v2.ied_name=t.ied_name and v1.voltage_level=? and v1.scd_id=? )"
- param = append(param, node_id)
- param = append(param, c.ScdID)
- } else if node_name == "Communication" {
- //通讯类
- where += " and g.object_name=?"
- param = append(param, "Communication")
- } else if node_name == "DataTypeTemplates" {
- //通讯类
- where += " and g.object_name=?"
- param = append(param, "DataTypeTemplates")
- } else if node_name == "SCLSyntax" {
- //语法类
- where += " and g.object_name=?"
- param = append(param, "SCLSyntax")
- }
- }
- sql += where
- limit := fmt.Sprintf(" order by g.alert_level limit %d,%d", (pageno-1)*pagesize, pagesize)
- rowset := []orm.Params{}
- db := orm.NewOrm()
- _, err := db.Raw(sql+limit, param).Values(&rowset)
- if err != nil {
- logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql+limit, param))
- return rowset, 0, err
- }
- totalNum := 0
- if err == nil {
- tmpRowset := []orm.Params{}
- _, err = db.Raw(strings.ReplaceAll(sql, "t.*,g.alert_level", "count(1) cnt"), param).Values(&tmpRowset)
- if err != nil {
- logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql, param))
- } else if len(tmpRowset) > 0 {
- for _, r1 := range tmpRowset {
- totalNumi, _ := strconv.Atoi(tools.IsEmpty(r1["cnt"]))
- totalNum += totalNumi
- }
- }
- }
- return rowset, totalNum, err
- }
- //启动自定义校验
- func (c *ScdNodeRule) StartFunctionNodeParse() {
- new(TaskMgr).SetStep(tools.IsEmpty(c.ScdID), enum.TaskStep_SCD_rule_parse.Code(), 1)
- c.CheckFunc_header_number(nil)
- c.CheckFunc_header_name_structure(nil)
- c.CheckFunc_header_toolid(nil)
- c.CheckFunc_header_complete(nil)
- c.CheckFunc_header_version(nil)
- c.CheckFunc_header_hitem_complete(nil)
- c.CheckFunc_substation_number(nil)
- c.CheckFunc_substation_name(nil)
- c.CheckFunc_voltagelevel_complete(nil)
- c.CheckFunc_communication_connectedap(nil)
- dATypeMap := c.CheckFunc_datatypetemplates(nil)
- c.CheckFunc_ied(dATypeMap)
- new(TaskMgr).SetStep(tools.IsEmpty(c.ScdID), enum.TaskStep_SCD_rule_parse.Code(), 2)
- //在crc校验完成后将所有校验结果写入数据库
- go c.CheckFunc_crc()
- c.doiMap = nil
- c.daMap = nil
- }
- //----------------------自定义的规则校验方法------------------
- func (c *ScdNodeRule) CheckFunc_header_number(para orm.Params) {
- ruleid := c.getRuleIdByName("Header元素完备性校验")
- if ruleid != "" {
- if c.scdXmlObject.Header == nil {
- parse_result := fmt.Sprintf("Header元素缺失")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- }
- }
- func (c *ScdNodeRule) CheckFunc_header_name_structure(para orm.Params) {
- ruleid := c.getRuleIdByName("Header元素完备性校验")
- if ruleid != "" {
- if c.scdXmlObject.Header != nil && c.scdXmlObject.Header.NameStructure != "IEDName" {
- parse_result := fmt.Sprintf("Header元素中的属性nameStructure值不正确,其值只能为IEDName")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Header.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Header.NodeId, "parse_result": parse_result}
- //唯一性检查未通过
- c.AppendPaseResult(r)
- }
- }
- }
- func (c *ScdNodeRule) CheckFunc_header_toolid(para orm.Params) {
- ruleid := c.getRuleIdByName("toolID属性检查")
- if ruleid != "" {
- if c.scdXmlObject.Header != nil && c.scdXmlObject.Header.ToolID == "" {
- parse_result := fmt.Sprintf("Header元素中的属性toolID配置不规范,其值为空")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Header.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Header.NodeId, "parse_result": parse_result}
- //唯一性检查未通过
- c.AppendPaseResult(r)
- }
- if c.scdXmlObject.Header != nil && c.scdXmlObject.Header.ToolID != "" {
- ary := strings.Split(c.scdXmlObject.Header.ToolID, "_")
- if len(ary) != 3 {
- parse_result := fmt.Sprintf("Header元素属性toolID配置不规范,格式应为:厂商编码_配置工具名称_工具软件版本")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Header.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Header.NodeId, "parse_result": parse_result}
- //唯一性检查未通过
- c.AppendPaseResult(r)
- }
- }
- }
- }
- //完整性校验
- func (c *ScdNodeRule) CheckFunc_header_complete(para orm.Params) {
- if c.scdXmlObject.Header == nil {
- return
- }
- ruleid := c.getRuleIdByName("Header元素完备性校验")
- if ruleid != "" {
- if c.scdXmlObject.Header.Id == "" {
- //验证不通过
- parse_result := fmt.Sprintf("Header元素中id属性缺失")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Header.NodeId, "parse_result": parse_result}
- //唯一性检查未通过
- c.AppendPaseResult(r)
- }
- if c.scdXmlObject.Header.Version == "" {
- //验证不通过
- parse_result := fmt.Sprintf("Header元素中version属性缺失")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Header.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Header.NodeId, "parse_result": parse_result}
- //唯一性检查未通过
- c.AppendPaseResult(r)
- }
- if c.scdXmlObject.Header.Revision == "" {
- //验证不通过
- parse_result := fmt.Sprintf("Header元素中revision属性缺失")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Header.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Header.NodeId, "parse_result": parse_result}
- //唯一性检查未通过
- c.AppendPaseResult(r)
- }
- }
- }
- func (c *ScdNodeRule) CheckFunc_header_version(para orm.Params) {
- if c.scdXmlObject.Header == nil {
- return
- }
- ruleid := c.getRuleIdByName("Header版本一致性")
- if ruleid != "" {
- ver := c.scdXmlObject.Header.Version
- rever := c.scdXmlObject.Header.Revision
- if c.scdXmlObject.Header.History != nil {
- hitems := c.scdXmlObject.Header.History.Hitem
- if len(hitems) > 0 {
- lastHitem := hitems[len(hitems)-1]
- if ver != lastHitem.Version && rever != lastHitem.Revision {
- //验证不通过
- parse_result := fmt.Sprintf("Header中的version=%s、revision=%s与History中的最后一个Item不一致", ver, rever)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": lastHitem.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Header.NodeId, "parse_result": parse_result}
- //唯一性检查未通过
- c.AppendPaseResult(r)
- }
- }
- }
- }
- }
- func (c *ScdNodeRule) CheckFunc_header_hitem_complete(para orm.Params) {
- if c.scdXmlObject.Header == nil {
- return
- }
- if c.scdXmlObject.Header.History != nil {
- hitems := c.scdXmlObject.Header.History.Hitem
- if len(hitems) > 0 {
- ver := ""
- rever := ""
- hitemruleid1 := c.getRuleIdByName("Hitem元素完备性校验")
- hitemruleid2 := c.getRuleIdByName("History版本连续性")
- for _, hitem := range hitems {
- if hitemruleid1 != "" {
- errattr := []string{}
- if hitem.Version == "" {
- errattr = append(errattr, "version")
- }
- if hitem.Revision == "" {
- errattr = append(errattr, "revision")
- }
- if hitem.When == "" {
- errattr = append(errattr, "when")
- }
- if len(errattr) > 0 {
- //验证不通过
- parse_result := fmt.Sprintf("Hitem元素中%s属性缺失", strings.Join(errattr, ","))
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": hitem.Lineno, "ruleid": hitemruleid1, "nodeid": hitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- }
- if hitemruleid2 != "" {
- //连续性判断
- if ver == "" {
- ver = hitem.Version
- rever = hitem.Revision
- } else {
- v1, _ := strconv.Atoi(hitem.Version)
- v2, _ := strconv.Atoi(hitem.Revision)
- v3, _ := strconv.Atoi(ver)
- v4, _ := strconv.Atoi(rever)
- if v1 == v3 && int(float64(v2)-float64(v4)-0.1) != 0 {
- //验证不通过
- parse_result := fmt.Sprintf("History版本元素中版本信息不连续:version=%s,revison=%s->version=%s,revison=%s", ver, rever, hitem.Version, hitem.Revision)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": hitem.Lineno, "ruleid": hitemruleid2, "nodeid": hitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- if v1 != v3 && hitem.Revision != "1.0" {
- //验证不通过
- parse_result := fmt.Sprintf("History版本元素中版本信息不规范:文件版本增加时,文件修订版本应置为1.0")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": hitem.Lineno, "ruleid": hitemruleid2, "nodeid": hitem.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- ver = hitem.Version
- rever = hitem.Revision
- }
- }
- }
- }
- }
- }
- func (c *ScdNodeRule) CheckFunc_substation_number(para orm.Params) {
- ruleid := c.getRuleIdByName("Substation完备性校验")
- if ruleid != "" {
- if c.scdXmlObject.Substation == nil {
- //验证不通过
- parse_result := fmt.Sprintf("Substation元素缺失")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- return
- }
- }
- ruleid = c.getRuleIdByName("Substation对象缺失CIME-dtype元素")
- ruleid2 := c.getRuleIdByName("Substation对象缺失CIME-area元素")
- if ruleid != "" || ruleid2 != "" {
- if len(c.scdXmlObject.Substation.Private) == 0 {
- parse_result := fmt.Sprintf("Substation对象缺失CIME-dtype元素")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Substation.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- return
- }
- isFound := false
- isFoundCIMEArea := false
- for _, pr := range c.scdXmlObject.Substation.Private {
- if pr.Type == "CIME-dtype" {
- isFound = true
- ruleid3 := c.getRuleIdByName("Substation对象对应CIME-dtype中属性缺失")
- if ruleid3 != "" && (pr.Desc == "") {
- parse_result := fmt.Sprintf("Substation对象对应CIME-dtype中属性(desc)缺失")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": pr.Lineno, "ruleid": ruleid3, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- }
- if pr.Type == "CIME-area" {
- isFoundCIMEArea = true
- ruleid3 := c.getRuleIdByName("Substation对象对应CIME-area中属性缺失")
- if ruleid3 != "" && (pr.Name == "" || pr.Desc == "") {
- parse_result := fmt.Sprintf("Substation对象对应CIME-area中属性(name或desc)缺失")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": pr.Lineno, "ruleid": ruleid3, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- }
- }
- if !isFound {
- parse_result := fmt.Sprintf("Substation对象缺失CIME-dtype元素")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Substation.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- if !isFoundCIMEArea {
- parse_result := fmt.Sprintf("Substation对象缺失CIME-area元素")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Substation.Lineno, "ruleid": ruleid2, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- }
- }
- func (c *ScdNodeRule) CheckFunc_substation_name(para orm.Params) {
- if c.scdXmlObject.Substation == nil {
- return
- }
- ruleid := c.getRuleIdByName("变电站名称一致性")
- if ruleid != "" {
- if c.scdXmlObject.Substation.Name != c.scdXmlObject.Header.Id {
- //验证不通过
- parse_result := fmt.Sprintf("Substation的name(%s)与Header中的id(%s)不一致", c.scdXmlObject.Substation.Name, c.scdXmlObject.Header.Id)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Substation.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- }
- }
- //VoltageLevel 对象的命名 name 应按“‘额定电压’ kV”形式命名,如“ 1000kV”“110kV”等,并且全站唯一。 desc 描述参照 name 命名方式
- func (c *ScdNodeRule) CheckFunc_voltagelevel_complete(para orm.Params) {
- if c.scdXmlObject.Substation == nil {
- return
- }
- ruleid1 := c.getRuleIdByName("VoltageLevel命名错误")
- ruleid2 := c.getRuleIdByName("VoltageLevel下Voltage缺失")
- ruleid3 := c.getRuleIdByName("Voltage对象的取值/属性错误")
- ruleid4 := c.getRuleIdByName("SSD关联关系错误")
- if len(c.scdXmlObject.Substation.VoltageLevel) == 0 {
- parse_result := fmt.Sprintf("Substation中存在层级关系错误:未定义VoltageLevel")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Substation.Lineno, "ruleid": ruleid4, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- return
- }
- priMap := map[string]string{}
- for _, item := range c.scdXmlObject.Substation.VoltageLevel {
- name := item.Name
- //desc := item.Desc
- if ruleid1 != "" {
- if _, h := priMap[name]; h {
- //验证不通过
- parse_result := fmt.Sprintf("VoltageLevel命名错误:name应该全站唯一")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": item.Lineno, "ruleid": ruleid1, "nodeid": item.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- continue
- }
- priMap[name] = ""
- if name == "" || len(name) < 3 || !strings.HasSuffix(name, "kV") {
- //验证不通过
- parse_result := fmt.Sprintf("VoltageLevel命名错误:name应按“‘额定电压’ kV”形式命名,如“1000kV”“110kV”等,并且全站唯一")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": item.Lineno, "ruleid": ruleid1, "nodeid": item.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- }
- if ruleid2 != "" {
- if item.Voltage == nil {
- //验证不通过
- parse_result := fmt.Sprintf("VoltageLevel(%s)下缺失Voltage对象", item.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": item.Lineno, "ruleid": ruleid2, "nodeid": item.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- }
- if ruleid3 != "" && item.Voltage != nil {
- if item.Voltage.InnerText != item.Name[0:len(item.Name)-2] {
- //验证不通过
- parse_result := fmt.Sprintf("VoltageLevel(%s)下属Voltage对象的取值错误", item.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": item.Voltage.Lineno, "ruleid": ruleid3, "nodeid": item.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- if item.Voltage.Multiplier != "k" {
- //验证不通过
- parse_result := fmt.Sprintf("VoltageLevel(%s)下属Voltage对象属性(%s=%s)错误", item.Name, "multiplier", item.Voltage.Multiplier)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": item.Voltage.Lineno, "ruleid": ruleid3, "nodeid": item.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- if item.Voltage.Unit != "V" {
- //验证不通过
- parse_result := fmt.Sprintf("VoltageLevel(%s)下属Voltage对象属性(%s=%s)错误", item.Name, "unit", item.Voltage.Unit)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": item.Voltage.Lineno, "ruleid": ruleid3, "nodeid": item.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- }
- //Bay校验
- if len(item.Bay) > 0 {
- ruleid5 := c.getRuleIdByName("Bay对象缺失CIME-dtype元素")
- ruleid6 := c.getRuleIdByName("Bay对象对应CIME-dtype中desc属性值错误")
- if ruleid5 != "" {
- for _, bayrow := range item.Bay {
- if bayrow.Private == nil {
- parse_result := fmt.Sprintf("Bay对象缺失CIME-dtype元素")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": bayrow.Lineno, "ruleid": ruleid5, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- } else {
- if ruleid6 != "" && bayrow.Private.Desc == "" {
- parse_result := fmt.Sprintf("Bay对象对应CIME-dtype中desc属性值错误")
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": bayrow.Lineno, "ruleid": ruleid6, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- }
- bayRule1 := c.getRuleIdByName("间隔关联逻辑节点不存在")
- if len(bayrow.PowerTransformer) > 0 {
- ruleid7 := c.getRuleIdByName("PowerTransformer对象命名错误")
- ruleid8 := c.getRuleIdByName("PowerTransformer对象type错误")
- for _, tmpr := range bayrow.PowerTransformer {
- if ruleid7 != "" && (tmpr.Name == "" || !strings.HasPrefix(tmpr.Name, "PTR")) {
- parse_result := fmt.Sprintf("PowerTransformer对象命名(%s)错误", tmpr.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpr.Lineno, "ruleid": ruleid7, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- if ruleid8 != "" && tmpr.Type != "PTR" {
- parse_result := fmt.Sprintf("PowerTransformer对象(%s)type(%s)不为PTR", tmpr.Name, tmpr.Type)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpr.Lineno, "ruleid": ruleid8, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- if len(tmpr.TransformerWinding) > 0 {
- ruleid9 := c.getRuleIdByName("TransformerWinding对象缺失:CIME-voltageLevel")
- ruleid10 := c.getRuleIdByName("TransformerWinding对象中CIME-voltageLevel属性错误或缺失")
- for _, rw := range tmpr.TransformerWinding {
- if ruleid9 != "" && (rw.Private == nil || rw.Private.Type != "CIME-voltageLevel") {
- parse_result := fmt.Sprintf("TransformerWinding对象(%s)缺失:CIME-voltageLevel", rw.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": rw.Lineno, "ruleid": ruleid9, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- if ruleid10 != "" && rw.Private != nil && rw.Private.Desc == "" {
- parse_result := fmt.Sprintf("TransformerWinding对象(%s)中的CIME-voltageLevel的desc属性缺失", rw.Desc)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": rw.Lineno, "ruleid": ruleid10, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- if ruleid10 != "" && rw.Private != nil && rw.Private.Name == "" {
- parse_result := fmt.Sprintf("TransformerWinding对象(%s)中的CIME-voltageLevel的name属性缺失", rw.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": rw.Lineno, "ruleid": ruleid10, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- if ruleid10 != "" && rw.Private != nil && rw.Private.Name != item.Name {
- parse_result := fmt.Sprintf("TransformerWinding对象(%s)中的CIME-voltageLevel的name属性(%s)与已有电压等级(%s)不一致", rw.Name, rw.Private.Name, item.Name)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": rw.Lineno, "ruleid": ruleid10, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- }
- }
- if bayRule1 != "" && len(tmpr.LNode) > 0 {
- scdnode := new(ScdNode)
- for _, i1 := range tmpr.LNode {
- if scdnode.GetIed(c.scdXmlObject, tools.IsEmpty(c.ScdID), i1.IedName) == nil {
- parse_result := fmt.Sprintf("间隔(%s)关联逻辑节点(%s)不存在", bayrow.Name, i1.IedName)
- r := map[string]interface{}{"scdid": c.ScdID, "lineno": i1.Lineno, "ruleid": bayRule1, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(r)
- }
- }
- }
- }
- }
- if len(bayrow.ConductingEquipment) > 0 {
- ruleid7 := c.getRuleIdByName("ConductingEquipment命名错误")
- condmap := map[string]int{}
- for _, r := range bayrow.ConductingEquipment {
- if ruleid7 != "" {
- if r.Name == "" {
- parse_result := fmt.Sprintf("ConductingEquipment命名错误:name不能为空")
- rt := map[string]interface{}{"scdid": c.ScdID, "lineno": r.Lineno, "ruleid": ruleid7, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(rt)
- continue
- }
- if condmap[r.Name] == 1 {
- parse_result := fmt.Sprintf("在同一Bay内不应有两个同名的ConductingEquipment(%s)元素", r.Name)
- rt := map[string]interface{}{"scdid": c.ScdID, "lineno": r.Lineno, "ruleid": ruleid7, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
- c.AppendPaseResult(rt)
- continue
- }
- condmap[r.Name] = 1
- }
- ruleid8 := c.getRuleIdByName("ConductingEquipment对象缺失CIME-dtype元素")
- if ruleid8 != "" && (r.Private == nil || r.Private.Type != "CIME-dtype") {
- parse_result := fmt.Sprintf("ConductingEquipment对象(%s)缺失CIME-dtype元素", r.Name)
- rt := map[string]interface{}{"scdid": c.ScdID, "lineno": r.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
- }
- lnstr = v_tmpAry[0]
- 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 lnstr == fmt.Sprintf("%s%s%s", ld.LN0.Prefix, ld.LN0.LnClass, ld.LN0.Inst) {
- for _, item := range ld.LN0.DOI {
- if item.Name == doname {
- return item
- }
- }
- }
- }
- for _, item := range ld.LN {
- if lnstr == fmt.Sprintf("%s%s%s", item.Prefix, item.LnClass, item.Inst) {
- for _, item2 := range item.DOI {
- if item2.Name == doname {
- return item2
- }
- }
- }
- }
- }
- }
- }
- }
- }
- return nil
- }
- //校验内部端子的DO或DA实例是否存在
- func (c *ScdNodeRule) iedIntAddrDoiOrDaiExist(iedname, intAddr string) (obj interface{}, cdc string) {
- if c.scdXmlObject == nil {
- return nil, ""
- }
- //intaddr格式:2-B:PIGO1/GOINGGIO1.SPCSO8.stVal
- addrs := strings.Split(intAddr, ":")
- if len(addrs) == 2 {
- intAddr = addrs[1]
- }
- intAddrs := strings.Split(intAddr, "/")
- if len(intAddrs) == 1 {
- logger.Logger.Error(errors.New(fmt.Sprintf("装置%s发现无效的intAddr:%s", iedname, intAddr)))
- return nil, ""
- }
- ldinst := intAddrs[0]
- lnstr := intAddrs[1]
- for _, iedObj := range c.scdXmlObject.IED {
- if iedObj.Name != iedname {
- continue
- }
- for _, ap := range iedObj.AccessPoint {
- if ap.Server != nil {
- for _, ld := range ap.Server.LDevice {
- if ld.Inst == ldinst {
- for _, ln := range ld.LN {
- str := fmt.Sprintf("%s%s%s", ln.Prefix, ln.LnClass, ln.Inst)
- v_tmpAry := strings.Split(lnstr, ".")
- if v_tmpAry[0] == str {
- doda := v_tmpAry[1:]
- doname := ""
- daname := ""
- if len(doda) == 1 {
- //只有do
- doname = doda[0]
- } else {
- doname = doda[0]
- daname = strings.Join(doda[1:], ".") //还原da
- }
- for _, doi := range ln.DOI {
- if doi.Name == doname {
- cdc := c.getDoICdc(ln.LnType, doi.Name, daname)
- if daname == "" {
- return doi, cdc
- }
- for _, dai := range doi.DAI {
- if dai.Name == daname {
- return dai, cdc
- }
- }
- das := strings.Split(daname, ".")
- if len(das) > 1 {
- for _, sdi := range doi.SDI {
- if sdi.Name == das[0] {
- for _, dai := range sdi.DAI {
- if dai.Name == das[1] {
- return dai, cdc
- }
- }
- for _, sdi2 := range sdi.SDI {
- for _, dai := range sdi2.DAI {
- if dai.Name == das[1] {
- return dai, cdc
- }
- }
- }
- return nil, cdc
- }
- }
- }
- return nil, cdc
- }
- }
- return nil, ""
- }
- }
- return nil, ""
- }
- }
- }
- }
- }
- return nil, ""
- }
- //根据LNtype和doi名称返回其cdc属性值
- func (c *ScdNodeRule) getDoICdc(lntype, doiname, daname string) string {
- if c.lnodeTypeMap == nil {
- return ""
- }
- v, _ := c.lnodeTypeMap.Load(lntype)
- if v == nil {
- return ""
- }
- for _, do := range v.(*node_attr.NLNodeType).DO {
- if do.Name == doiname {
- if do.Type == "" {
- return ""
- }
- d1, _ := c.doTypeMap.Load(do.Type)
- if d1 == nil {
- return ""
- }
- if daname == "" {
- return d1.(*node_attr.NDOType).Cdc
- }
- das := strings.Split(daname, ".") //多层da
- for _, daitem := range d1.(*node_attr.NDOType).DA {
- if daitem.Name == das[0] {
- if len(das) == 1 {
- return daitem.BType
- } else {
- bdatype := daitem.Type
- da1, _ := c.daTypeMap.Load(bdatype)
- if da1 == nil {
- return ""
- }
- for _, dbaitem := range da1.(*node_attr.NDAType).BDA {
- if dbaitem.Name == das[1] {
- return dbaitem.BType
- }
- }
- }
- return ""
- }
- }
- }
- }
- return ""
- }
- //---------------------------------------------------------
- func (c *ScdNodeRule) AppendPaseResult(r map[string]interface{}, ied ...*node_attr.NIED) {
- var iedobj *node_attr.NIED
- if len(ied) > 0 && ied[0] != nil {
- iedobj = ied[0]
- r["ied_name"] = iedobj.Name
- r["ied_desc"] = iedobj.Desc
- }
- c.checkFailListLock.Lock()
- c.CheckFailList = append(c.CheckFailList, r)
- c.checkFailListLock.Unlock()
- //logger.Logger.Info(fmt.Sprintf("========校验结果:%v", r))
- //实时将结果通过mqtt发送解析结果
- //结果处理客户端需要订阅/jujutong/scd_check_tools/ruleparse/{scdid}
- //go mqtt.PublishMessage("/jujutong/scd_check_tools/ruleparse/"+fmt.Sprintf("%d", c.ScdID), r["parse_result"].(string))
- }
- //添加端子检查结果
- //需要数据:ied_name,ied_desc,fcda_desc,fcda_addr,out_ied_name,out_ied_desc,out_fcda_desc,out_fcda_addr,error_type
- //其中error_type值为以下之一:1 多余端子 2 错误端子 3 缺失
- func (c *ScdNodeRule) AppendFcdaCheckResult(r map[string]interface{}) {
- r["check_type"] = "fcda"
- c.checkFailListLock.Lock()
- c.CheckFailList = append(c.CheckFailList, r)
- c.checkFailListLock.Unlock()
- }
- func (c *ScdNodeRule) CheckFinish() {
- c.isRun = 2
- }
- //节点规则验证完成
- func (c *ScdNodeRule) Flush() {
- //判断等待验证队列中的数据是否已处理完,没有处理完则一直等待
- if c.isRun != 2 {
- for {
- time.Sleep(100 * time.Millisecond)
- if c.isRun == 2 {
- break
- }
- }
- }
- logger.Logger.Debug(fmt.Sprintln("规则校验结果,共%d条!", len(c.CheckFailList)))
- c.writeNodeDB()
- }
- //根据规则名称获取规则ID.返回为""时表示还未定义该规则名称
- func (c *ScdNodeRule) getRuleIdByName(name string) string {
- row := c.NodeRuleList[name]
- if row == nil {
- return "0"
- }
- return tools.IsEmpty(row["id"])
- }
- //将验证结果写入数据库。仅写入验证不通过的结果
- //每5000条写入一次
- func (c *ScdNodeRule) writeNodeDB() {
- if len(c.CheckFailList) == 0 {
- return
- }
- db := orm.NewOrm()
- s1 := time.Now().Unix()
- nodeCols := "(scd_id,node_id,line_no,rule_target,rule_id,parse_result,ied_name,ied_desc)"
- fcdaCols := "(scd_id,ied_name,ied_desc,fcda_desc,fcda_addr,out_ied_name,out_ied_desc,out_fcda_desc,out_fcda_addr,rule_id,parse_result,error_type)"
- loadedRec := 0
- nodeSqlValuesAry := []string{}
- fcdaSqlValuesAry := []string{}
- for _, m := range c.CheckFailList {
- check_type := tools.IsEmpty(m["check_type"]) // fcda检查结果写入t_scd_fcda_check_result
- if check_type == "fcda" {
- fcdaSqlValuesAry = append(fcdaSqlValuesAry, "("+tools.IsEmpty(m["scdid"])+",'"+tools.IsEmpty(m["ied_name"])+"','"+tools.IsEmpty(m["ied_desc"])+"','"+tools.IsEmpty(m["fcda_desc"])+"','"+tools.IsEmpty(m["fcda_addr"])+"','"+tools.IsEmpty(m["out_ied_name"])+"','"+tools.IsEmpty(m["out_ied_desc"])+"','"+tools.IsEmpty(m["out_fcda_desc"])+"','"+tools.IsEmpty(m["out_fcda_addr"])+"',"+tools.IsEmpty(m["ruleid"], "0")+",'"+tools.IsEmpty(m["parse_result"])+"',"+tools.IsEmpty(m["error_type"], "0")+")")
- } else {
- nodeSqlValuesAry = append(nodeSqlValuesAry, "("+tools.IsEmpty(m["scdid"])+","+tools.IsEmpty(m["nodeid"], "0")+","+tools.IsEmpty(m["lineno"], "0")+",'"+tools.IsEmpty(m["rule_target"])+"',"+tools.IsEmpty(m["ruleid"], "0")+",'"+tools.IsEmpty(m["parse_result"])+"','"+tools.IsEmpty(m["ied_name"])+"','"+tools.IsEmpty(m["ied_desc"])+"')")
- }
- if len(nodeSqlValuesAry) == 1000 {
- sql := "insert into t_scd_node_rule_parse" + nodeCols + "values" + strings.Join(nodeSqlValuesAry, ",")
- _, err := db.Raw(sql).Exec()
- if err != nil {
- log.Println(err)
- }
- loadedRec = loadedRec + 1000
- nodeSqlValuesAry = nil
- nodeSqlValuesAry = []string{}
- }
- if len(fcdaSqlValuesAry) == 1000 {
- sql := "insert into t_scd_fcda_check_result" + fcdaCols + "values" + strings.Join(fcdaSqlValuesAry, ",")
- _, err := db.Raw(sql).Exec()
- if err != nil {
- log.Println(err)
- }
- loadedRec = loadedRec + 1000
- fcdaSqlValuesAry = nil
- fcdaSqlValuesAry = []string{}
- }
- }
- if len(nodeSqlValuesAry) > 0 {
- sql := "insert into t_scd_node_rule_parse" + nodeCols + "values" + strings.Join(nodeSqlValuesAry, ",")
- _, err := db.Raw(sql).Exec()
- if err != nil {
- log.Println(err)
- }
- nodeSqlValuesAry = nil
- }
- if len(fcdaSqlValuesAry) > 0 {
- sql := "insert into t_scd_fcda_check_result" + fcdaCols + "values" + strings.Join(fcdaSqlValuesAry, ",")
- _, err := db.Raw(sql).Exec()
- if err != nil {
- log.Println(err)
- }
- fcdaSqlValuesAry = nil
- }
- c.CheckFailList = nil
- runtime.GC()
- s2 := time.Now().Unix()
- fmt.Println(fmt.Sprintf("===================Flush NodeAttrParse 完成!。耗时:%d秒", s2-s1))
- fmt.Println("===========节点属性验证完成")
- mqtt.PublishMessage(fmt.Sprintf("%s/%d", checktopic, c.ScdID), `{"code":1,"scdid":"`+tools.IsEmpty(c.ScdID)+`","state":1,"msg":"该SCD校验完成"}`)
- global.CheckingScd.Delete(c.ScdID)
- }
|