package plc
|
|
import (
|
"encoding/hex"
|
"errors"
|
"fmt"
|
"io"
|
"strings"
|
"time"
|
|
"github.com/jacobsa/go-serial/serial"
|
)
|
|
/*
|
定义串口客户端
|
*/
|
|
type SerialClient struct {
|
readWriter io.ReadWriteCloser
|
OutBuffer chan string
|
PortName string
|
baudRate uint
|
}
|
|
func NewSerialClient(portName string, baudRate uint) (*SerialClient, error) {
|
c := &SerialClient{
|
readWriter: nil,
|
OutBuffer: make(chan string, 1024),
|
PortName: portName,
|
baudRate: baudRate,
|
}
|
r, err := c.open(portName, baudRate)
|
if err != nil {
|
return nil, err
|
}
|
|
c.readWriter = r
|
return c, nil
|
}
|
|
func (c *SerialClient) Start() {
|
for {
|
buf := make([]byte, 1024)
|
n, err := c.readWriter.Read(buf)
|
if err != nil {
|
if err != io.EOF {
|
//尝试重新打开
|
r, err := c.open(c.PortName, c.baudRate)
|
if err != nil {
|
time.Sleep(2 * time.Second)
|
continue
|
}
|
c.readWriter = r
|
}
|
continue
|
}
|
|
buf = buf[:n]
|
res := hex.EncodeToString(buf)
|
if strings.TrimSpace(res) == "" {
|
continue
|
}
|
fmt.Printf("Rx: %s\n", res)
|
c.OutBuffer <- res
|
}
|
}
|
|
func (c *SerialClient) open(portName string, baudRate uint) (io.ReadWriteCloser, error) {
|
options := serial.OpenOptions{
|
PortName: portName,
|
BaudRate: baudRate,
|
DataBits: 7,
|
StopBits: 1,
|
MinimumReadSize: 4,
|
ParityMode: serial.PARITY_EVEN,
|
}
|
|
r, err := serial.Open(options)
|
if err != nil {
|
return nil, err
|
}
|
|
c.readWriter = r
|
|
return r, err
|
}
|
|
func (c *SerialClient) Close() {
|
if c.readWriter != nil {
|
c.readWriter.Close()
|
}
|
}
|
|
func (c *SerialClient) SendMsg(data string) (int, error) {
|
if c.readWriter == nil {
|
return 0, errors.New("serial port is closed")
|
}
|
|
bytes, err := hex.DecodeString(data)
|
if err != nil {
|
return 0, err
|
}
|
|
return c.readWriter.Write(bytes)
|
}
|
|
func (c *SerialClient) ReadHoldRegister(addr string) (int, error) {
|
if c.readWriter == nil {
|
return 0, errors.New("serial port is closed")
|
}
|
|
// 三菱fn系列串口协议
|
// 02 表示开始 + 30 表示读数据 + 4位地址位 + 02 数据长度 + 03 停止 + 偶校验
|
|
// 先组装数据
|
// 读取的地址
|
dataBytes := append([]byte{0x30}, []byte(addr)...)
|
|
// 读取的长度
|
dataBytes = append(dataBytes, []byte("02")...)
|
|
// 停止
|
dataBytes = append(dataBytes, []byte{0x03}...)
|
|
// 计算校验码, 30 + 地址编码 + 数据长度 + 03 , 十六进制结果取后两位.
|
var sum uint8
|
for _, d := range dataBytes {
|
sum += d
|
}
|
|
sumStr := fmt.Sprintf("%x", sum)
|
|
fmt.Printf("sumStr: %s\n", sumStr)
|
|
var checkCode string
|
if len(sumStr) < 2 {
|
checkCode = "0" + sumStr
|
} else {
|
checkCode = sumStr[len(sumStr)-2:]
|
}
|
|
var bytes = []byte{0x02}
|
// 添加数据
|
bytes = append(bytes, dataBytes...)
|
// 添加校验
|
bytes = append(bytes, []byte(checkCode)...)
|
|
fmt.Printf("Tx: %X \n", bytes)
|
|
// 写
|
if n, err := c.readWriter.Write(bytes); err != nil {
|
return n, err
|
} else {
|
fmt.Printf("Tx:len:%d\n", n)
|
}
|
|
// 读
|
buf := make([]byte, 1024)
|
n, err := c.readWriter.Read(buf)
|
if err != nil {
|
return n, err
|
}
|
|
buf = buf[:n]
|
|
fmt.Printf("Rx: %X\nRx len:%d", buf, n)
|
fmt.Printf("value: %d\n", buf[2:6])
|
|
return n, nil
|
}
|
|
func (c *SerialClient) WriteHoldRegister(addr string) (int, error) {
|
if c.readWriter == nil {
|
return 0, errors.New("serial port is closed")
|
}
|
|
// 三菱fn系列串口协议
|
// 02 表示开始 + 31 表示写数据 + 4位地址位 + 02 数据长度 + 03 停止 + 偶校验
|
|
// 先组装数据
|
// 读取的地址
|
dataBytes := append([]byte{0x31}, []byte(addr)...)
|
|
// 读取的长度
|
dataBytes = append(dataBytes, []byte("02")...)
|
|
// 停止
|
dataBytes = append(dataBytes, []byte{0x03}...)
|
|
// 计算校验码, 30 + 地址编码 + 数据长度 + 03 , 十六进制结果取后两位.
|
var sum uint8
|
for _, d := range dataBytes {
|
sum += d
|
}
|
|
sumStr := fmt.Sprintf("%x", sum)
|
|
fmt.Printf("sumStr: %s\n", sumStr)
|
|
var checkCode string
|
if len(sumStr) < 2 {
|
checkCode = "0" + sumStr
|
} else {
|
checkCode = sumStr[len(sumStr)-2:]
|
}
|
|
var bytes = []byte{0x02}
|
// 添加数据
|
bytes = append(bytes, dataBytes...)
|
// 添加校验
|
bytes = append(bytes, []byte(checkCode)...)
|
|
fmt.Printf("Tx: %X \n", bytes)
|
|
// 写
|
if n, err := c.readWriter.Write(bytes); err != nil {
|
return n, err
|
} else {
|
fmt.Printf("Tx:len:%d\n", n)
|
}
|
|
// 读
|
buf := make([]byte, 1024)
|
n, err := c.readWriter.Read(buf)
|
if err != nil {
|
return n, err
|
}
|
|
buf = buf[:n]
|
|
fmt.Printf("Rx: %X\nRx len:%d", buf, n)
|
fmt.Printf("value: %d\n", buf[2:6])
|
|
return n, nil
|
}
|