Недостающие байты в io.Reader с последовательной связью - PullRequest
0 голосов
/ 03 января 2019

Я устанавливаю последовательную связь с Голангом.Я использую библиотеку https://github.com/jacobsa/go-serial для этого.Код Голанга является основной установкой.Итак, он должен написать в последовательный порт и прослушать ответ.Это прекрасно работает, когда все работает, как ожидалось.Таким образом, запись в последовательный порт выполнена успешно, и ответ успешно получен.

Однако, если ответ ошибся 1 раз или ведомое устройство не отвечает, Golang io.Reader не может восстановить себя.Тогда каждое сообщение ошибочно, потому что оно пропускает несколько байтов.Я использовал прицел, чтобы попытаться увидеть, что идет не так, но запрос от мастера и ответ от ведомого устройства верны.

Я использую связь RS485 с платой на базе Arduino.Ничего плохого в связи, только с кодом Голанга.

Структура связи следующая:

STX |НАЗНАЧЕНИЕ |ИСТОЧНИК |Количество байтов |Данные |CRC16

STX всегда 0x02, что указывает на начало сообщения.Назначение и источник - 32 бита, количество байтов - 16 бит, данные зависят от количества байтов, а CRC - 16 бит.Как я уже сказал, эти данные успешно передаются.

Я создал на Голанге некоторое программное обеспечение, которое открывает порт и использует цикл «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, оно будет читать все сообщение целиком.Всякий раз, когда это сообщение завершено, оно должно распечатать все сообщение.Или напечатайте ошибку.Если после записи не получен ни один байт, он должен напечатать «TIMEOUT» через 200 мс.

Фактический результат заключается в том, что в начале, когда подчиненное устройство подключено к мастеру, я получаю все хорошие ответы.от рабаОднако, когда я отключаю Slave даже на малейшее время и снова подключаю его, я получаю только тайм-ауты, потому что код Golang никогда не видит 0x02 снова.Таким образом, все сообщения полностью игнорируются.

То же самое происходит, когда я добавляю еще один идентификатор ведомого, который не подключен, поэтому он пытается общаться с двумя подчиненными.(Сначала подчиненный 1, затем подчиненный 2, затем снова подчиненный 1 и т. Д.), Но происходит то же самое, что и раньше.

Я перепробовал все, что знаю, даже использовал другой мастер-ПК и другой экран подключения, нопроверка оборудованияОбъем говорит мне, что все в порядке.У меня действительно нет идей, любая помощь будет очень признательна.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...