Skip to content

Commit 906c5f1

Browse files
committed
add GetLogicalDeviceList function to browse the data model of an unknown device.
1 parent 6ade905 commit 906c5f1

File tree

6 files changed

+234
-1
lines changed

6 files changed

+234
-1
lines changed

cgo_util.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package iec61850
2+
3+
import "C"
4+
import sc "golang.org/x/text/encoding/simplifiedchinese"
5+
6+
func C2GoStr(str *C.char) string {
7+
utf8str, _ := sc.GB18030.NewDecoder().String(C.GoString(str))
8+
return utf8str
9+
}
10+
11+
func Go2CStr(str string) *C.char {
12+
gbstr, _ := sc.GB18030.NewEncoder().String(str)
13+
return C.CString(gbstr)
14+
}
15+
16+
func C2GoBool(i C.int) bool {
17+
if i == 1 {
18+
return true
19+
}
20+
return false
21+
}
22+
23+
func Go2CBool(b bool) C.int {
24+
if b {
25+
return 1
26+
}
27+
return 0
28+
}

client.go

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package iec61850
33
// #include <iec61850_client.h>
44
import "C"
55
import (
6+
"fmt"
67
"sync/atomic"
78
"unsafe"
89
)
@@ -162,6 +163,135 @@ func (c *Client) Read(objectRef string, fc FC) (interface{}, error) {
162163
return c.toGoValue(mmsValue, mmsType), nil
163164
}
164165

166+
func (c *Client) GetLogicalDeviceList() DataModel {
167+
var clientError C.IedClientError
168+
deviceList := C.IedConnection_getLogicalDeviceList(c.conn, &clientError)
169+
170+
var dataModel DataModel
171+
172+
device := deviceList.next
173+
for device != nil {
174+
175+
var ld LD
176+
ld.Data = C2GoStr((*C.char)(device.data))
177+
178+
logicalNodes := C.IedConnection_getLogicalDeviceDirectory(c.conn, &clientError, (*C.char)(device.data))
179+
logicalNode := logicalNodes.next
180+
181+
for logicalNode != nil {
182+
var ln LN
183+
ln.Data = C2GoStr((*C.char)(logicalNode.data))
184+
185+
lnRef := fmt.Sprintf("%s/%s", ld.Data, C2GoStr((*C.char)(logicalNode.data)))
186+
187+
cRef := Go2CStr(lnRef)
188+
dataObjects := C.IedConnection_getLogicalNodeDirectory(c.conn, &clientError, cRef, C.ACSI_CLASS_DATA_OBJECT)
189+
dataObject := dataObjects.next
190+
for dataObject != nil {
191+
var do DO
192+
do.Data = C2GoStr((*C.char)(dataObject.data))
193+
194+
dataObject = dataObject.next
195+
doRef := fmt.Sprintf("%s/%s.%s", C2GoStr((*C.char)(device.data)), C2GoStr((*C.char)(logicalNode.data)), do.Data)
196+
197+
var das []DA
198+
c.GetDAs(doRef, das)
199+
200+
do.DAs = das
201+
ln.DOs = append(ln.DOs, do)
202+
}
203+
204+
C.LinkedList_destroy(dataObjects)
205+
206+
dataSets := C.IedConnection_getLogicalNodeDirectory(c.conn, &clientError, Go2CStr(lnRef), C.ACSI_CLASS_DATA_SET)
207+
dataSet := dataSets.next
208+
for dataSet != nil {
209+
var ds DS
210+
ds.Data = C2GoStr((*C.char)(dataSet.data))
211+
212+
var isDeletable C.bool
213+
dataSetRef := fmt.Sprintf("%s.%s", lnRef, ds.Data)
214+
dataSetMembers := C.IedConnection_getDataSetDirectory(c.conn, &clientError, Go2CStr(dataSetRef), &isDeletable)
215+
216+
if isDeletable {
217+
fmt.Println(fmt.Sprintf(" Data set: %s (deletable)", ds.Data))
218+
} else {
219+
fmt.Println(fmt.Sprintf(" Data set: %s (not deletable)", ds.Data))
220+
}
221+
222+
dataSetMemberRef := dataSetMembers.next
223+
for dataSetMemberRef != nil {
224+
var dsRef DSRef
225+
dsRef.Data = C2GoStr((*C.char)(dataSetMemberRef.data))
226+
ds.DSRefs = append(ds.DSRefs, dsRef)
227+
228+
dataSetMemberRef = dataSetMemberRef.next
229+
}
230+
C.LinkedList_destroy(dataSetMembers)
231+
dataSet = dataSet.next
232+
ln.DSs = append(ln.DSs, ds)
233+
}
234+
235+
C.LinkedList_destroy(dataSets)
236+
237+
reports := C.IedConnection_getLogicalNodeDirectory(c.conn, &clientError, Go2CStr(lnRef), C.ACSI_CLASS_URCB)
238+
report := reports.next
239+
for report != nil {
240+
var r URReport
241+
r.Data = C2GoStr((*C.char)(report.data))
242+
ln.URReports = append(ln.URReports, r)
243+
244+
report = report.next
245+
}
246+
C.LinkedList_destroy(reports)
247+
248+
reports = C.IedConnection_getLogicalNodeDirectory(c.conn, &clientError, Go2CStr(lnRef), C.ACSI_CLASS_BRCB)
249+
report = reports.next
250+
for report != nil {
251+
var r BRReport
252+
r.Data = C2GoStr((*C.char)(report.data))
253+
ln.BRReports = append(ln.BRReports, r)
254+
255+
report = report.next
256+
}
257+
258+
C.LinkedList_destroy(reports)
259+
260+
ld.LNs = append(ld.LNs, ln)
261+
262+
logicalNode = logicalNode.next
263+
}
264+
C.LinkedList_destroy(logicalNodes)
265+
266+
dataModel.LDs = append(dataModel.LDs, ld)
267+
268+
device = device.next
269+
}
270+
C.LinkedList_destroy(deviceList)
271+
return dataModel
272+
}
273+
274+
func (c *Client) GetDAs(doRef string, das []DA) {
275+
276+
var clientError C.IedClientError
277+
dataAttributes := C.IedConnection_getDataDirectory(c.conn, &clientError, Go2CStr(doRef))
278+
defer C.LinkedList_destroy(dataAttributes)
279+
if dataAttributes != nil {
280+
dataAttribute := dataAttributes.next
281+
282+
for dataAttribute != nil {
283+
var da DA
284+
da.Data = C2GoStr((*C.char)(dataAttribute.data))
285+
das = append(das, da)
286+
287+
dataAttribute = dataAttribute.next
288+
daRef := fmt.Sprintf("%s.%s", doRef, da.Data)
289+
c.GetDAs(daRef, das)
290+
}
291+
}
292+
293+
}
294+
165295
// ReadDataSet 读取DataSet
166296
func (c *Client) ReadDataSet(objectRef string) ([]*MmsValue, error) {
167297
cObjectRef := C.CString(objectRef)

data_model.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package iec61850
2+
3+
type DataModel struct {
4+
LDs []LD
5+
}
6+
7+
type LD struct {
8+
Data string
9+
LNs []LN
10+
}
11+
12+
type LN struct {
13+
Data string
14+
DOs []DO
15+
DSs []DS
16+
URReports []URReport
17+
BRReports []BRReport
18+
}
19+
20+
type URReport struct {
21+
Data string
22+
}
23+
24+
type BRReport struct {
25+
Data string
26+
}
27+
28+
type DS struct {
29+
Data string
30+
DSRefs []DSRef
31+
}
32+
33+
type DSRef struct {
34+
Data string
35+
}
36+
37+
type DO struct {
38+
Data string
39+
DAs []DA
40+
}
41+
42+
type DA struct {
43+
Data string
44+
DAs []DA
45+
}

go.mod

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,7 @@ module github.com/wendy512/iec61850
22

33
go 1.19
44

5-
require github.com/spf13/cast v1.6.0 // indirect
5+
require (
6+
github.com/spf13/cast v1.6.0
7+
golang.org/x/text v0.14.0
8+
)

go.sum

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,9 @@
1+
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
2+
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
3+
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
4+
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
5+
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
16
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
27
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
8+
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
9+
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=

test/client_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package test
22

33
import (
4+
"encoding/json"
5+
"fmt"
46
"github.com/wendy512/iec61850"
57
"testing"
68
)
@@ -57,3 +59,21 @@ func doRead(t *testing.T, client *iec61850.Client, objectRef string, fc iec61850
5759
}
5860
t.Logf("read %s value -> %v", objectRef, value)
5961
}
62+
63+
func TestGetLogicalDeviceList(t *testing.T) {
64+
client, err := iec61850.NewClient(&iec61850.Settings{
65+
Host: "127.0.0.1",
66+
Port: 10086,
67+
ConnectTimeout: 10000,
68+
RequestTimeout: 10000,
69+
})
70+
if err != nil {
71+
panic(err)
72+
}
73+
deviceList := client.GetLogicalDeviceList()
74+
marshal, err := json.Marshal(deviceList)
75+
if err != nil {
76+
panic(err)
77+
}
78+
fmt.Println(string(marshal))
79+
}

0 commit comments

Comments
 (0)