Skip to content

Commit

Permalink
Add support for IEC104 server
Browse files Browse the repository at this point in the history
  • Loading branch information
wendy512 committed Oct 21, 2024
1 parent fe407c9 commit 8340d9f
Show file tree
Hide file tree
Showing 10 changed files with 322 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,15 @@ jobs:
${{ runner.os }}-go-
- name: Install Dependencies
run: go mod download
run: go mod tidy

- name: Run Go Vet
run: go vet ./...
- name: Build
run: go build -v ./...

- name: Run tests
run: go test -v ./...

- name: Run lint
run: |
go install golang.org/x/lint/golint@latest
golint ./...
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ The library support the following IEC 104 protocol features:
go get -u github.com/wendy512/iec104
```

- [Client reads and writes values](tests/clien_test.go)
- [Server and client test examples](tests/iec104_test.go)

## License
iec104 is based on the [Apache License 2.0](./LICENSE) agreement.
Expand Down
2 changes: 1 addition & 1 deletion README_zh_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ IEC 104 是在电力系统和工业自动化领域广泛使用的协议,旨在
go get -u github.com/wendy512/iec104
```

- [客户端读和写入值](tests/clien_test.go)
- [服务端和客户端测试示例](tests/iec104_test.go)

## 开源许可
iec104 基于 [Apache License 2.0](./LICENSE) 协议。
Expand Down
2 changes: 1 addition & 1 deletion client/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ type ASDUCall interface {
OnResetProcess(*asdu.ASDU) error
// OnDelayAcquisition 延迟获取回复
OnDelayAcquisition(*asdu.ASDU) error
// OnASDU 数据正体
// OnASDU 数据回复或控制回复
OnASDU(*asdu.ASDU) error
}
73 changes: 73 additions & 0 deletions server/core.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package server

import (
"github.com/wendy512/go-iecp5/asdu"
"github.com/wendy512/go-iecp5/clog"
"github.com/wendy512/go-iecp5/cs104"
"strconv"
)

// Settings 连接配置
type Settings struct {
Host string
Port int
Cfg104 *cs104.Config //104协议规范配置
Params *asdu.Params //ASDU相关特定参数
LogCfg *LogCfg
}

type LogCfg struct {
Enable bool //是否开启log
LogProvider clog.LogProvider
}

type Server struct {
settings *Settings
cs104Server *cs104.Server
}

func NewSettings() *Settings {
cfg104 := cs104.DefaultConfig()
return &Settings{
Host: "localhost",
Port: 2404,
Cfg104: &cfg104,
Params: asdu.ParamsWide,
}
}

func New(settings *Settings, handler CommandHandler) *Server {
cs104Server := cs104.NewServer(&serverHandler{h: handler})
cs104Server.SetConfig(*settings.Cfg104)
cs104Server.SetParams(settings.Params)

logCfg := settings.LogCfg
if logCfg != nil {
cs104Server.LogMode(logCfg.Enable)
cs104Server.SetLogProvider(logCfg.LogProvider)
}

return &Server{
settings: settings,
cs104Server: cs104Server,
}
}

func (s *Server) Start() {
addr := s.settings.Host + ":" + strconv.Itoa(s.settings.Port)
go s.cs104Server.ListenAndServer(addr)
}

func (s *Server) Stop() {
_ = s.cs104Server.Close()
}

// SetOnConnectionHandler set on connect handler
func (s *Server) SetOnConnectionHandler(f func(asdu.Connect)) {
s.SetOnConnectionHandler(f)
}

// SetConnectionLostHandler set connect lost handler
func (s *Server) SetConnectionLostHandler(f func(asdu.Connect)) {
s.SetConnectionLostHandler(f)
}
38 changes: 38 additions & 0 deletions server/handle.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package server

import (
"github.com/wendy512/go-iecp5/asdu"
"time"
)

type serverHandler struct {
h CommandHandler
}

func (s *serverHandler) InterrogationHandler(conn asdu.Connect, pack *asdu.ASDU, quality asdu.QualifierOfInterrogation) error {
return s.h.OnInterrogation(conn, pack, quality)
}

func (s *serverHandler) CounterInterrogationHandler(conn asdu.Connect, pack *asdu.ASDU, quality asdu.QualifierCountCall) error {
return s.h.OnCounterInterrogation(conn, pack, quality)
}

func (s *serverHandler) ReadHandler(conn asdu.Connect, pack *asdu.ASDU, addr asdu.InfoObjAddr) error {
return s.h.OnRead(conn, pack, addr)
}

func (s *serverHandler) ClockSyncHandler(conn asdu.Connect, pack *asdu.ASDU, time time.Time) error {
return s.h.OnClockSync(conn, pack, time)
}

func (s *serverHandler) ResetProcessHandler(conn asdu.Connect, pack *asdu.ASDU, quality asdu.QualifierOfResetProcessCmd) error {
return s.h.OnResetProcess(conn, pack, quality)
}

func (s *serverHandler) DelayAcquisitionHandler(conn asdu.Connect, pack *asdu.ASDU, msec uint16) error {
return s.h.OnDelayAcquisition(conn, pack, msec)
}

func (s *serverHandler) ASDUHandler(conn asdu.Connect, pack *asdu.ASDU) error {
return s.h.OnASDU(conn, pack)
}
23 changes: 23 additions & 0 deletions server/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package server

import (
"github.com/wendy512/go-iecp5/asdu"
"time"
)

type CommandHandler interface {
// OnInterrogation 总召唤请求
OnInterrogation(asdu.Connect, *asdu.ASDU, asdu.QualifierOfInterrogation) error
// OnCounterInterrogation 总计数器请求
OnCounterInterrogation(asdu.Connect, *asdu.ASDU, asdu.QualifierCountCall) error
// OnRead 读定值请求
OnRead(asdu.Connect, *asdu.ASDU, asdu.InfoObjAddr) error
// OnClockSync 时钟同步请求
OnClockSync(asdu.Connect, *asdu.ASDU, time.Time) error
// OnResetProcess 进程重置请求
OnResetProcess(asdu.Connect, *asdu.ASDU, asdu.QualifierOfResetProcessCmd) error
// OnDelayAcquisition 延迟获取请求
OnDelayAcquisition(asdu.Connect, *asdu.ASDU, uint16) error
// OnASDU 控制命令请求
OnASDU(asdu.Connect, *asdu.ASDU) error
}
76 changes: 0 additions & 76 deletions tests/clien_test.go → tests/client_handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,84 +4,8 @@ import (
"fmt"
"github.com/wendy512/go-iecp5/asdu"
"github.com/wendy512/iec104/client"
"sync"
"testing"
"time"
)

const (
commonAddr = 1
)

func TestClient(t *testing.T) {
settings := client.NewSettings()
settings.Host = "192.168.33.12"
settings.LogCfg = &client.LogCfg{Enable: true}
c := client.New(settings, &clientCall{})

wg := sync.WaitGroup{}
wg.Add(1)
c.SetOnConnectHandler(func(c *client.Client) {
// 连接成功以后做的操作
fmt.Printf("connected %s iec104 server\n", settings.Host)
})

// server active确认后回调
c.SetServerActiveHandler(func(c *client.Client) {
// 发送总召唤
if err := c.SendInterrogationCmd(commonAddr); err != nil {
t.Errorf("send interrogation cmd error %v\n", err)
t.FailNow()
}

// 累积量召唤
if err := c.SendCounterInterrogationCmd(commonAddr); err != nil {
t.Errorf("send counter interrogation cmd error %v\n", err)
t.FailNow()
}

// read cmd
if err := c.SendReadCmd(commonAddr, 400); err != nil {
t.Errorf("send counter interrogation cmd error %v\n", err)
t.FailNow()
}

// 时钟同步
if err := c.SendClockSynchronizationCmd(commonAddr, time.Now()); err != nil {
t.Errorf("send clock sync cmd error %v\n", err)
t.FailNow()
}

// test cmd
if err := c.SendTestCmd(commonAddr); err != nil {
t.Errorf("send test cmd error %v\n", err)
t.FailNow()
}

// 单点控制
if err := c.SendCmd(commonAddr, asdu.C_SC_NA_1, asdu.InfoObjAddr(1000), true); err != nil {
t.Errorf("send single cmd error %v\n", err)
t.FailNow()
}

// 测试等待回复,不能结束太快
time.Sleep(time.Second * 10)
wg.Done()
})

// Connect后会发送server active
if err := c.Connect(); err != nil {
t.Errorf("client connect error %v\n", err)
t.FailNow()
}
wg.Wait()

if err := c.Close(); err != nil {
t.Errorf("close error %v\n", err)
t.FailNow()
}
}

type clientCall struct {
}

Expand Down
87 changes: 87 additions & 0 deletions tests/iec104_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package tests

import (
"fmt"
"github.com/wendy512/go-iecp5/asdu"
"github.com/wendy512/iec104/client"
"github.com/wendy512/iec104/server"
"sync"
"testing"
"time"
)

func TestClient(t *testing.T) {
srv := startServer()
settings := client.NewSettings()
settings.LogCfg = &client.LogCfg{Enable: true}
c := client.New(settings, &clientCall{})

wg := sync.WaitGroup{}
wg.Add(1)
c.SetOnConnectHandler(func(c *client.Client) {
// 连接成功以后做的操作
fmt.Printf("connected %s iec104 server\n", settings.Host)
})

// server active确认后回调
c.SetServerActiveHandler(func(c *client.Client) {
//// 发送总召唤
if err := c.SendInterrogationCmd(commonAddr); err != nil {
t.Errorf("send interrogation cmd error %v\n", err)
t.FailNow()
}

// 累积量召唤
if err := c.SendCounterInterrogationCmd(commonAddr); err != nil {
t.Errorf("send counter interrogation cmd error %v\n", err)
t.FailNow()
}

// read cmd
if err := c.SendReadCmd(commonAddr, 100); err != nil {
t.Errorf("send counter interrogation cmd error %v\n", err)
t.FailNow()
}

// 时钟同步
if err := c.SendClockSynchronizationCmd(commonAddr, time.Now()); err != nil {
t.Errorf("send clock sync cmd error %v\n", err)
t.FailNow()
}

// test cmd
if err := c.SendTestCmd(commonAddr); err != nil {
t.Errorf("send test cmd error %v\n", err)
t.FailNow()
}

// 单点控制
if err := c.SendCmd(commonAddr, asdu.C_SC_NA_1, asdu.InfoObjAddr(1000), false); err != nil {
t.Errorf("send single cmd error %v\n", err)
t.FailNow()
}

// 测试等待回复,不能结束太快
time.Sleep(time.Second * 10)
wg.Done()
})

// Connect后会发送server active
if err := c.Connect(); err != nil {
t.Errorf("client connect error %v\n", err)
t.FailNow()
}
wg.Wait()

if err := c.Close(); err != nil {
t.Errorf("close error %v\n", err)
t.FailNow()
}
srv.Stop()
}

func startServer() *server.Server {
s := server.New(server.NewSettings(), &myServerHandler{})
s.Start()
return s
}
Loading

0 comments on commit 8340d9f

Please sign in to comment.