Skip to content

Commit

Permalink
Merge pull request #5 from buhuang28/dev
Browse files Browse the repository at this point in the history
add GetLogicalDeviceList function to browse the data model of an unknown device.
  • Loading branch information
wendy512 authored May 7, 2024
2 parents 57ffa5c + 906c5f1 commit 5a8477f
Show file tree
Hide file tree
Showing 7 changed files with 235 additions and 1 deletion.
28 changes: 28 additions & 0 deletions cgo_util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package iec61850

import "C"
import sc "golang.org/x/text/encoding/simplifiedchinese"

func C2GoStr(str *C.char) string {
utf8str, _ := sc.GB18030.NewDecoder().String(C.GoString(str))
return utf8str
}

func Go2CStr(str string) *C.char {
gbstr, _ := sc.GB18030.NewEncoder().String(str)
return C.CString(gbstr)
}

func C2GoBool(i C.int) bool {
if i == 1 {
return true
}
return false
}

func Go2CBool(b bool) C.int {
if b {
return 1
}
return 0
}
130 changes: 130 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package iec61850
// #include <iec61850_client.h>
import "C"
import (
"fmt"
"sync/atomic"
"unsafe"
)
Expand Down Expand Up @@ -162,6 +163,135 @@ func (c *Client) Read(objectRef string, fc FC) (interface{}, error) {
return c.toGoValue(mmsValue, mmsType), nil
}

func (c *Client) GetLogicalDeviceList() DataModel {
var clientError C.IedClientError
deviceList := C.IedConnection_getLogicalDeviceList(c.conn, &clientError)

var dataModel DataModel

device := deviceList.next
for device != nil {

var ld LD
ld.Data = C2GoStr((*C.char)(device.data))

logicalNodes := C.IedConnection_getLogicalDeviceDirectory(c.conn, &clientError, (*C.char)(device.data))
logicalNode := logicalNodes.next

for logicalNode != nil {
var ln LN
ln.Data = C2GoStr((*C.char)(logicalNode.data))

lnRef := fmt.Sprintf("%s/%s", ld.Data, C2GoStr((*C.char)(logicalNode.data)))

cRef := Go2CStr(lnRef)
dataObjects := C.IedConnection_getLogicalNodeDirectory(c.conn, &clientError, cRef, C.ACSI_CLASS_DATA_OBJECT)
dataObject := dataObjects.next
for dataObject != nil {
var do DO
do.Data = C2GoStr((*C.char)(dataObject.data))

dataObject = dataObject.next
doRef := fmt.Sprintf("%s/%s.%s", C2GoStr((*C.char)(device.data)), C2GoStr((*C.char)(logicalNode.data)), do.Data)

var das []DA
c.GetDAs(doRef, das)

do.DAs = das
ln.DOs = append(ln.DOs, do)
}

C.LinkedList_destroy(dataObjects)

dataSets := C.IedConnection_getLogicalNodeDirectory(c.conn, &clientError, Go2CStr(lnRef), C.ACSI_CLASS_DATA_SET)
dataSet := dataSets.next
for dataSet != nil {
var ds DS
ds.Data = C2GoStr((*C.char)(dataSet.data))

var isDeletable C.bool
dataSetRef := fmt.Sprintf("%s.%s", lnRef, ds.Data)
dataSetMembers := C.IedConnection_getDataSetDirectory(c.conn, &clientError, Go2CStr(dataSetRef), &isDeletable)

if isDeletable {
fmt.Println(fmt.Sprintf(" Data set: %s (deletable)", ds.Data))
} else {
fmt.Println(fmt.Sprintf(" Data set: %s (not deletable)", ds.Data))
}

dataSetMemberRef := dataSetMembers.next
for dataSetMemberRef != nil {
var dsRef DSRef
dsRef.Data = C2GoStr((*C.char)(dataSetMemberRef.data))
ds.DSRefs = append(ds.DSRefs, dsRef)

dataSetMemberRef = dataSetMemberRef.next
}
C.LinkedList_destroy(dataSetMembers)
dataSet = dataSet.next
ln.DSs = append(ln.DSs, ds)
}

C.LinkedList_destroy(dataSets)

reports := C.IedConnection_getLogicalNodeDirectory(c.conn, &clientError, Go2CStr(lnRef), C.ACSI_CLASS_URCB)
report := reports.next
for report != nil {
var r URReport
r.Data = C2GoStr((*C.char)(report.data))
ln.URReports = append(ln.URReports, r)

report = report.next
}
C.LinkedList_destroy(reports)

reports = C.IedConnection_getLogicalNodeDirectory(c.conn, &clientError, Go2CStr(lnRef), C.ACSI_CLASS_BRCB)
report = reports.next
for report != nil {
var r BRReport
r.Data = C2GoStr((*C.char)(report.data))
ln.BRReports = append(ln.BRReports, r)

report = report.next
}

C.LinkedList_destroy(reports)

ld.LNs = append(ld.LNs, ln)

logicalNode = logicalNode.next
}
C.LinkedList_destroy(logicalNodes)

dataModel.LDs = append(dataModel.LDs, ld)

device = device.next
}
C.LinkedList_destroy(deviceList)
return dataModel
}

func (c *Client) GetDAs(doRef string, das []DA) {

var clientError C.IedClientError
dataAttributes := C.IedConnection_getDataDirectory(c.conn, &clientError, Go2CStr(doRef))
defer C.LinkedList_destroy(dataAttributes)
if dataAttributes != nil {
dataAttribute := dataAttributes.next

for dataAttribute != nil {
var da DA
da.Data = C2GoStr((*C.char)(dataAttribute.data))
das = append(das, da)

dataAttribute = dataAttribute.next
daRef := fmt.Sprintf("%s.%s", doRef, da.Data)
c.GetDAs(daRef, das)
}
}

}

// ReadDataSet 读取DataSet
func (c *Client) ReadDataSet(objectRef string) ([]*MmsValue, error) {
cObjectRef := C.CString(objectRef)
Expand Down
45 changes: 45 additions & 0 deletions data_model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package iec61850

type DataModel struct {
LDs []LD
}

type LD struct {
Data string
LNs []LN
}

type LN struct {
Data string
DOs []DO
DSs []DS
URReports []URReport
BRReports []BRReport
}

type URReport struct {
Data string
}

type BRReport struct {
Data string
}

type DS struct {
Data string
DSRefs []DSRef
}

type DSRef struct {
Data string
}

type DO struct {
Data string
DAs []DA
}

type DA struct {
Data string
DAs []DA
}
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@ module github.com/wendy512/iec61850

go 1.19

require github.com/spf13/cast v1.6.0 // indirect
require (
github.com/spf13/cast v1.6.0
golang.org/x/text v0.14.0
)
7 changes: 7 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,2 +1,9 @@
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
1 change: 1 addition & 0 deletions scl_xml/scl.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ type LN0 struct {
LnType string `xml:"lnType,attr"`
LnClass string `xml:"lnClass,attr"`
DataSets []DataSet `xml:"DataSet"`
DOI []DOI `xml:"DOI"`
}

type LN struct {
Expand Down
20 changes: 20 additions & 0 deletions test/client_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package test

import (
"encoding/json"
"fmt"
"github.com/wendy512/iec61850"
"testing"
)
Expand Down Expand Up @@ -57,3 +59,21 @@ func doRead(t *testing.T, client *iec61850.Client, objectRef string, fc iec61850
}
t.Logf("read %s value -> %v", objectRef, value)
}

func TestGetLogicalDeviceList(t *testing.T) {
client, err := iec61850.NewClient(&iec61850.Settings{
Host: "127.0.0.1",
Port: 10086,
ConnectTimeout: 10000,
RequestTimeout: 10000,
})
if err != nil {
panic(err)
}
deviceList := client.GetLogicalDeviceList()
marshal, err := json.Marshal(deviceList)
if err != nil {
panic(err)
}
fmt.Println(string(marshal))
}

0 comments on commit 5a8477f

Please sign in to comment.