zhangqian
2023-10-26 2df84cdc7faf29cc8a2512b627a36a3881276b9f
pkg/plc/com.go
@@ -1,235 +1,236 @@
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
}
//
//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
//}