串行通讯的io.Reader中缺少字节

时间:2019-01-03 15:58:10

标签: go serial-port

我正在与Golang建立串行通讯。我为此使用了https://github.com/jacobsa/go-serial库。 Golang代码是主设置。因此,它必须写入串行端口并收听回复。当一切都按预期方式工作时,这非常有用。因此,成功写入串行端口,并成功检索到答复。

但是,当回复错误1次,或者从属服务器没有响应时,Golang io.Reader无法恢复自身。然后,每条消息都是错误的,因为它会丢失一些字节。我已经使用了示波器来尝试找出问题所在,但是来自主服务器的请求和来自从服务器的答复都是正确的。

我正在使用基于Arduino的PCB的RS485通讯。交流没有错,只有Golang代码。

通信结构如下:

STX |目的地|来源字节数数据CRC16

STX始终为0x02,因此指示消息的开始。目的和源是32位,字节数是16位,数据取决于字节数,CRC是16位。就像我说的那样,该数据已成功传输。

我已经在Golang中制作了一些软件,该软件可以打开端口,并使用“ for”循环写入数据并等待新数据。这在下面添加。我仅在以下示例中使用了“ Peek”功能。但是我还尝试了ReadByte和UnreadByte,甚至ReadByte,并且ReadMessage函数不会等待0x02。而且我已经在没有bufio阅读器的情况下进行了尝试,但是没有任何结果。

我添加了代码以重现它,并且可能注意到了我的错误:

package main

import (
    "bufio"
    "encoding/binary"
    "errors"
    "fmt"
    "log"
    "time"

    "github.com/jacobsa/go-serial/serial"
)

func main() {
    options := serial.OpenOptions{
        PortName:        "/dev/ttyAMA0",
        BaudRate:        57600,
        DataBits:        8,
        StopBits:        1,
        ParityMode:      0,
        MinimumReadSize: 1,
    }

    port, err := serial.Open(options)
    if err != nil {
        log.Fatalf("serial.Open: %v", err)
    }

    defer port.Close()

    writeBytes := []byte{0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x09, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB7, 0x92}
    b := bufio.NewReader(port)

    for {

        _, err = port.Write(writeBytes)
        if err != nil {
            log.Fatalf("port.Write: %v", err)
        }

        recievedSTX := make(chan bool, 1)
        go func(buf *bufio.Reader) {
            gotSTX := false

            for {
                n, err := b.Peek(1)
                if err != nil {
                    // Got error while peeking
                    break
                }

                // Check if peek output is STX
                // This goes wrong very often when communication didn't go as expected once
                if n[0] == 0x02 {
                    gotSTX = true
                    break
                }

            }

            recievedSTX <- gotSTX

        }(b)

        select {
        case stx := <-recievedSTX:
            if stx == true {

                // Function to read whole message
                message, err := ReadMessage(b)
                if err != nil {
                    // Error while reading whole message
                    // When 0x02 is read before, and communication didn't go as expected once, this is always going wrong
                    fmt.Println(err)
                } else {
                    // Message Successful!
                    fmt.Println(message)
                }
            } else {
                // STX not found, so just sleep like the timeout did
                time.Sleep(time.Duration(500) * time.Millisecond)
            }
        case <-time.After(time.Duration(500) * time.Millisecond):
            // Timeout while reading, so stopping. 500Ms for testing purposes
            fmt.Println("TIMEOUT")
        }

    }

}

func ReadMessage(b *bufio.Reader) ([]byte, error) {
    var message []byte
    var getNumberOfBytes int
    var countOfBytes int

    messageComplete := make(chan error, 1)
    go func() {

        STX := make([]byte, 1)
        getNumberOfBytes = len(STX)
        countOfBytes = 0
        for countOfBytes < getNumberOfBytes {
            n, err := b.ReadByte()
            if err != nil {
                messageComplete <- err
            }

            if n == 0x02 {
                STX[countOfBytes] = n
                message = append(message, n)
                break
            } else {
                fmt.Println("STX BYTE", n)
                messageComplete <- errors.New("First byte is not a STX byte (0x02)")
            }
        }

        Destination := make([]byte, 4)
        getNumberOfBytes = len(Destination)
        countOfBytes = 0
        for countOfBytes < getNumberOfBytes {
            n, err := b.ReadByte()
            if err != nil {
                messageComplete <- err
            }

            Destination[countOfBytes] = n
            message = append(message, n)
            countOfBytes++
        }

        Source := make([]byte, 4)
        getNumberOfBytes = len(Source)
        countOfBytes = 0
        for countOfBytes < getNumberOfBytes {
            n, err := b.ReadByte()
            if err != nil {
                messageComplete <- err
            }

            Source[countOfBytes] = n
            message = append(message, n)
            countOfBytes++
        }

        Length := make([]byte, 2)
        getNumberOfBytes = len(Length)
        countOfBytes = 0
        for countOfBytes < getNumberOfBytes {
            n, err := b.ReadByte()
            if err != nil {
                messageComplete <- err
            }

            Length[countOfBytes] = n
            message = append(message, n)
            countOfBytes++
        }
        NumberOfBytes := binary.LittleEndian.Uint16(Length)

        getNumberOfBytes = int(NumberOfBytes)
        countOfBytes = 0
        for countOfBytes < getNumberOfBytes {
            n, err := b.ReadByte()
            if err != nil {
                messageComplete <- err
            }

            message = append(message, n)
            countOfBytes++
        }

        CRC := make([]byte, 2)
        getNumberOfBytes = 2
        countOfBytes = 0
        for countOfBytes < getNumberOfBytes {
            n, err := b.ReadByte()
            if err != nil {
                messageComplete <- err
            }

            CRC[countOfBytes] = n
            message = append(message, n)
            countOfBytes++
        }

        messageComplete <- nil

    }()

    select {
    case mComplete := <-messageComplete:
        if mComplete != nil {
            return message, mComplete
        }

        return message, nil
    case <-time.After(time.Duration(200) * time.Millisecond):
        return message, errors.New("TIMEOUT: Could not read any more bytes")
    }
}

预期结果是,每当一条消息发送到以0x02开头的主服务器时,它将读取整个消息。每当该消息完成时,它都必须打印整个消息。或打印错误。如果写后未收到任何字节,则必须在200ms之后打印“ TIMEOUT”。

实际结果是,一开始,当从站插入主站时,我会收到从站的所有回复。但是,当我从最短的时间拔下Slave并重新插入时,我只会超时,因为Golang代码再也看不到0x02了。因此所有消息都将被完全忽略。

当我添加另一个未连接的从站ID时,也会发生同样的情况,因此它尝试与两个从站进行通信。 (首先是从站1,然后是从站2,然后又是从站1,依此类推),但与以前一样。

我已经尝试了所有已知的知识,甚至使用了另一台Master PC和另一个连接护罩,但是硬件签出了。示波器告诉我一切都很好。我真的没有主意,任何帮助将不胜感激。

0 个答案:

没有答案