| | |
| | | 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 |
| | | //} |