| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- package main
- import (
- "encoding/binary"
- "errors"
- "io"
- "sync"
- "time"
- "github.com/goburrow/serial"
- "lc/edge/ipole/modbus"
- "lc/edge/ipole/ym485"
- "lc/edge/ipole/zigbee"
- )
- const (
- // SerialDefaultTimeout Serial Default timeout
- SerialDefaultTimeout = 2000 * time.Millisecond
- // SerialDefaultAutoReconnect Serial Default auto reconnect count
- SerialDefaultAutoReconnect = 6
- SerialReadMaxLength = 40
- FlagModbusRtu = 0
- FlagChZigbee = 1
- FlagYm485 = 2
- )
- var ErrClosedConnection = errors.New("use of closed connection")
- // serialPort has configuration and I/O controller.
- type serialPort struct {
- // Serial port configuration.
- serial.Config
- mu sync.Mutex
- port io.ReadWriteCloser
- // if > 0, when disconnected,it will try to reconnect the remote
- // but if we activate close self,it will not to reconnect
- // if == 0 auto reconnect not active
- autoReconnect byte
- }
- // Connect try to connect the remote server
- func (sf *serialPort) Connect() (err error) {
- sf.mu.Lock()
- err = sf.connect()
- sf.mu.Unlock()
- return
- }
- // Caller must hold the mutex before calling this method.
- func (sf *serialPort) connect() error {
- port, err := serial.Open(&sf.Config)
- if err != nil {
- return err
- }
- sf.port = port
- return nil
- }
- // IsConnected returns a bool signifying whether the client is connected or not.
- func (sf *serialPort) IsConnected() (b bool) {
- sf.mu.Lock()
- b = sf.isConnected()
- sf.mu.Unlock()
- return b
- }
- // Caller must hold the mutex before calling this method.
- func (sf *serialPort) isConnected() bool {
- return sf.port != nil
- }
- // SetAutoReconnect set auto reconnect count
- // if cnt == 0, disable auto reconnect
- // if cnt > 0 ,enable auto reconnect,but max 6
- func (sf *serialPort) SetAutoReconnect(cnt byte) {
- sf.mu.Lock()
- sf.autoReconnect = cnt
- if sf.autoReconnect > 6 {
- sf.autoReconnect = 6
- }
- sf.mu.Unlock()
- }
- // setSerialConfig set serial config
- func (sf *serialPort) setSerialConfig(config serial.Config) {
- sf.Config = config
- }
- // Close current connection.
- func (sf *serialPort) Close() (err error) {
- sf.mu.Lock()
- if sf.port != nil {
- err = sf.port.Close()
- sf.port = nil
- }
- sf.mu.Unlock()
- return
- }
- func (sf *serialPort) send(aduRequest []byte) error {
- var err error
- var tryCnt byte
- for {
- if _, err = sf.port.Write(aduRequest); err == nil {
- break
- }
- if sf.autoReconnect == 0 {
- break
- }
- for {
- if err = sf.connect(); err == nil {
- break
- }
- if tryCnt++; tryCnt <= sf.autoReconnect {
- return err //超过最大重试次数则退出
- }
- time.Sleep(1 * time.Second) //1秒后重试
- }
- }
- return err
- }
- func (sf *serialPort) recv(flag uint8) ([]byte, error) {
- var n int
- var aduResponse []byte
- var err error
- data := make([]byte, SerialReadMaxLength, SerialReadMaxLength)
- for {
- if n, err = sf.port.Read(data); err != nil {
- if VerifyCrc16(aduResponse, flag) {
- err = nil //读取完整
- break
- }
- break
- }
- if n > 0 {
- aduResponse = append(aduResponse, data[:n]...)
- if n <= SerialReadMaxLength { //读取少于等于SerialReadMaxLength字节,可能已经读完,判断CRC16确认
- if VerifyCrc16(aduResponse, flag) {
- break //读取完整
- }
- }
- } else if n == 0 {
- break
- }
- }
- return aduResponse, err
- }
- func (sf *serialPort) waitSendRecv(aduRequest []byte, flag uint8, wait uint) {
- var bytesToRead = 0
- if flag == 0 { //标准modbusRTU协议
- bytesToRead = modbus.CalculateResponseLength(aduRequest)
- } else if flag == 1 { //长和单灯控制器,zigbee协议
- bytesToRead = zigbee.CalculateChddjkZigbeeResponselength(aduRequest)
- }
- time.Sleep(sf.calculateDelay(len(aduRequest) + bytesToRead))
- if wait > 0 {
- time.Sleep(time.Duration(wait) * time.Millisecond)
- }
- }
- // SendRecvData 发送和接收
- func (sf *serialPort) SendRecvData(aduRequest []byte, flag uint8, wait uint) (aduResponse []byte, err error) {
- sf.mu.Lock()
- defer sf.mu.Unlock()
- //连接检查
- if !sf.isConnected() {
- //重试一次
- if err := sf.connect(); err != nil {
- return nil, ErrClosedConnection
- }
- }
- //发送请求
- if err := sf.send(aduRequest); err != nil {
- return nil, err
- }
- //等待发完和从机处理返回
- sf.waitSendRecv(aduRequest, flag, wait)
- //接收响应
- return sf.recv(flag)
- }
- // SendData 仅发送,用于广播
- func (sf *serialPort) SendData(aduRequest []byte, flag uint8, wait uint) error {
- sf.mu.Lock()
- defer sf.mu.Unlock()
- //连接检查
- if !sf.isConnected() {
- //重试一次
- if err := sf.connect(); err != nil {
- return ErrClosedConnection
- }
- }
- err := sf.send(aduRequest)
- if err == nil {
- sf.waitSendRecv(aduRequest, flag, wait) //等待发完
- }
- return err
- }
- func (sf *serialPort) calculateDelay(chars int) time.Duration {
- var characterDelay, frameDelay int // us
- if sf.BaudRate <= 0 || sf.BaudRate > 19200 {
- characterDelay = 750
- frameDelay = 1750
- } else {
- characterDelay = 15000000 / sf.BaudRate
- frameDelay = 35000000 / sf.BaudRate
- }
- return time.Duration(characterDelay*chars+frameDelay) * time.Microsecond
- }
- // VerifyCrc16 标准Modbus-RTU,末尾2字节是crc16,大端
- // 长和单灯控制器zigbee协议,末尾2字节是crc16
- func VerifyCrc16(data []byte, flag uint8) bool {
- if flag == FlagYm485 {
- return ym485.VerifySum(data)
- }
- datalen := len(data)
- if datalen > 4 {
- var crc_ uint16
- crc := modbus.CRC16(data[:datalen-2])
- if flag == FlagModbusRtu {
- crc_ = binary.LittleEndian.Uint16(data[datalen-2 : datalen])
- } else if flag == FlagChZigbee {
- crc_ = binary.BigEndian.Uint16(data[datalen-2 : datalen])
- } else {
- crc_ = binary.LittleEndian.Uint16(data[datalen-2 : datalen])
- }
- if crc == crc_ {
- return true
- }
- }
- return false
- }
|