dsl2014 2019-01-03 15:58
浏览 50

带有串行通信的io.Reader中缺少字节

I'm setting up a Serial communication with Golang. I'm using the a https://github.com/jacobsa/go-serial library for this. The Golang code is a master setup. So, it has to write to the serialport and listen to the reply. This works great when everything is working like expected. So writing to the serialport is successful, and the reply is successfully retrieved.

However, when the reply went wrong 1 time, or the slave doesn't respond, the Golang io.Reader can't restore itself. Then every single message is wrong, because it misses some bytes. I've used a scope to try and see what's going wrong, but the request from the master and reply from the slave are correct.

I'm using a RS485 communication with an Arduino-based PCB. Nothing wrong with the communication, only with the Golang code.

The communication structure is as follows:

STX | DESTINATION | SOURCE | Number of Bytes | Data | CRC16

The STX is always 0x02, so that indicates the start of a message. The destination and source is 32 bits, number of bytes is 16 bits, data depends on the number of bytes and the CRC is 16 bits. Like I said, this data is transmitted successfully.

I've made some software in Golang that opens the port, and uses a "for" loop to write data and wait for new data. This is added below. I've used the "Peek" function below, just for an example. But I've also tried ReadByte and UnreadByte, and even ReadByte and that the ReadMessage function doesn't wait for the 0x02. And I've tried it without the bufio reader, but without any result.

I've added the code to reproduce it and probably notice my mistakes:

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")
    }
}

The expected result is that every time a message is sent to the Master that begins with 0x02, it's going to read the whole message. Whenever that message is complete, it has to print the whole message. Or print an error. When no byte is received after the write, it has to print "TIMEOUT" after 200ms.

The actual result is that at the start, when the Slave is plugged in to the Master, I get all the nice replies from the slave. However, when I unplug the Slave for even the slightest bit of time and plug it back in, I only get timeouts, because the Golang code never sees the 0x02 again. So all messages are completely ignored.

The same happens when I add another Slave ID, that isn't connected, so it tries to talk to 2 slaves after each other. (First slave 1, then slave 2, then slave 1 again etc.), but the same happens as before.

I've tried everything I know, even used another Master PC and another connection shield, but the hardware checks out. The scope tells me everything is fine. I'm really out of ideas, any help would be really appreciated.

  • 写回答

0条回答 默认 最新

    报告相同问题?

    悬赏问题

    • ¥15 划分vlan后,链路不通了?
    • ¥20 求各位懂行的人,注册表能不能看到usb使用得具体信息,干了什么,传输了什么数据
    • ¥15 个人网站被恶意大量访问,怎么办
    • ¥15 Vue3 大型图片数据拖动排序
    • ¥15 Centos / PETGEM
    • ¥15 划分vlan后不通了
    • ¥20 用雷电模拟器安装百达屋apk一直闪退
    • ¥15 算能科技20240506咨询(拒绝大模型回答)
    • ¥15 自适应 AR 模型 参数估计Matlab程序
    • ¥100 角动量包络面如何用MATLAB绘制