Missing bytes in io.Reader with Serial communication





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







0















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.










share|improve this question























  • "However, when I unplug the Slave..." -- Just because a message always starts with STX, that does not mean that encountering a 0x02 byte means that you have found the start of a message. The only way to determine if you have a real or false STX is to "read" the "message" and try to verify the CRC. If the CRC is not valid, then do not toss those bytes!!! You have to rescan those bytes for a 0x02 starting with the byte following that false STX byte. See stackoverflow.com/questions/16177947/… for related concept.

    – sawdust
    Jan 4 at 2:06













  • @sawdust thanks for the reply! I’ve read that question, but the difference is that he has a fixed package size. Mine is depending on the number of bytes. You’re right that 0x02 doesn’t always mean that a message is starting, but 9/10 times it does. And if the message loses data, it’s stuck in a timeout. The first read for the byte is just so that the timeout isn’t triggered, because the master sees a reply coming. At the end of ReadMessage, I have a CRC16 check over the message, but I see that I haven’t posted it. I’ll change that. But that doesn’t change the fact that I’m missing some bytes.

    – Bart Versluijs
    Jan 4 at 6:48











  • "... the difference is that he has a fixed package size. Mine is depending on the number of bytes" -- You're focusing on an irrelevant detail (fixed versus variable length messages) instead of the salient concept. You're "missing some bytes" because your program is not robust; it can only handle a pre-synchronized input. "but 9/10 times it does" -- You really don't know that, and it looks like that alleged 1 out of 10 can occur reliably to reveal your code's flaws. Your code does not validate the CRC, it does not rescan the bytes, and it unnecessarily performs sleeps.

    – sawdust
    Jan 7 at 0:17




















0















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.










share|improve this question























  • "However, when I unplug the Slave..." -- Just because a message always starts with STX, that does not mean that encountering a 0x02 byte means that you have found the start of a message. The only way to determine if you have a real or false STX is to "read" the "message" and try to verify the CRC. If the CRC is not valid, then do not toss those bytes!!! You have to rescan those bytes for a 0x02 starting with the byte following that false STX byte. See stackoverflow.com/questions/16177947/… for related concept.

    – sawdust
    Jan 4 at 2:06













  • @sawdust thanks for the reply! I’ve read that question, but the difference is that he has a fixed package size. Mine is depending on the number of bytes. You’re right that 0x02 doesn’t always mean that a message is starting, but 9/10 times it does. And if the message loses data, it’s stuck in a timeout. The first read for the byte is just so that the timeout isn’t triggered, because the master sees a reply coming. At the end of ReadMessage, I have a CRC16 check over the message, but I see that I haven’t posted it. I’ll change that. But that doesn’t change the fact that I’m missing some bytes.

    – Bart Versluijs
    Jan 4 at 6:48











  • "... the difference is that he has a fixed package size. Mine is depending on the number of bytes" -- You're focusing on an irrelevant detail (fixed versus variable length messages) instead of the salient concept. You're "missing some bytes" because your program is not robust; it can only handle a pre-synchronized input. "but 9/10 times it does" -- You really don't know that, and it looks like that alleged 1 out of 10 can occur reliably to reveal your code's flaws. Your code does not validate the CRC, it does not rescan the bytes, and it unnecessarily performs sleeps.

    – sawdust
    Jan 7 at 0:17
















0












0








0


1






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.










share|improve this question














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.







go serial-port






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Jan 3 at 15:58









Bart VersluijsBart Versluijs

12




12













  • "However, when I unplug the Slave..." -- Just because a message always starts with STX, that does not mean that encountering a 0x02 byte means that you have found the start of a message. The only way to determine if you have a real or false STX is to "read" the "message" and try to verify the CRC. If the CRC is not valid, then do not toss those bytes!!! You have to rescan those bytes for a 0x02 starting with the byte following that false STX byte. See stackoverflow.com/questions/16177947/… for related concept.

    – sawdust
    Jan 4 at 2:06













  • @sawdust thanks for the reply! I’ve read that question, but the difference is that he has a fixed package size. Mine is depending on the number of bytes. You’re right that 0x02 doesn’t always mean that a message is starting, but 9/10 times it does. And if the message loses data, it’s stuck in a timeout. The first read for the byte is just so that the timeout isn’t triggered, because the master sees a reply coming. At the end of ReadMessage, I have a CRC16 check over the message, but I see that I haven’t posted it. I’ll change that. But that doesn’t change the fact that I’m missing some bytes.

    – Bart Versluijs
    Jan 4 at 6:48











  • "... the difference is that he has a fixed package size. Mine is depending on the number of bytes" -- You're focusing on an irrelevant detail (fixed versus variable length messages) instead of the salient concept. You're "missing some bytes" because your program is not robust; it can only handle a pre-synchronized input. "but 9/10 times it does" -- You really don't know that, and it looks like that alleged 1 out of 10 can occur reliably to reveal your code's flaws. Your code does not validate the CRC, it does not rescan the bytes, and it unnecessarily performs sleeps.

    – sawdust
    Jan 7 at 0:17





















  • "However, when I unplug the Slave..." -- Just because a message always starts with STX, that does not mean that encountering a 0x02 byte means that you have found the start of a message. The only way to determine if you have a real or false STX is to "read" the "message" and try to verify the CRC. If the CRC is not valid, then do not toss those bytes!!! You have to rescan those bytes for a 0x02 starting with the byte following that false STX byte. See stackoverflow.com/questions/16177947/… for related concept.

    – sawdust
    Jan 4 at 2:06













  • @sawdust thanks for the reply! I’ve read that question, but the difference is that he has a fixed package size. Mine is depending on the number of bytes. You’re right that 0x02 doesn’t always mean that a message is starting, but 9/10 times it does. And if the message loses data, it’s stuck in a timeout. The first read for the byte is just so that the timeout isn’t triggered, because the master sees a reply coming. At the end of ReadMessage, I have a CRC16 check over the message, but I see that I haven’t posted it. I’ll change that. But that doesn’t change the fact that I’m missing some bytes.

    – Bart Versluijs
    Jan 4 at 6:48











  • "... the difference is that he has a fixed package size. Mine is depending on the number of bytes" -- You're focusing on an irrelevant detail (fixed versus variable length messages) instead of the salient concept. You're "missing some bytes" because your program is not robust; it can only handle a pre-synchronized input. "but 9/10 times it does" -- You really don't know that, and it looks like that alleged 1 out of 10 can occur reliably to reveal your code's flaws. Your code does not validate the CRC, it does not rescan the bytes, and it unnecessarily performs sleeps.

    – sawdust
    Jan 7 at 0:17



















"However, when I unplug the Slave..." -- Just because a message always starts with STX, that does not mean that encountering a 0x02 byte means that you have found the start of a message. The only way to determine if you have a real or false STX is to "read" the "message" and try to verify the CRC. If the CRC is not valid, then do not toss those bytes!!! You have to rescan those bytes for a 0x02 starting with the byte following that false STX byte. See stackoverflow.com/questions/16177947/… for related concept.

– sawdust
Jan 4 at 2:06







"However, when I unplug the Slave..." -- Just because a message always starts with STX, that does not mean that encountering a 0x02 byte means that you have found the start of a message. The only way to determine if you have a real or false STX is to "read" the "message" and try to verify the CRC. If the CRC is not valid, then do not toss those bytes!!! You have to rescan those bytes for a 0x02 starting with the byte following that false STX byte. See stackoverflow.com/questions/16177947/… for related concept.

– sawdust
Jan 4 at 2:06















@sawdust thanks for the reply! I’ve read that question, but the difference is that he has a fixed package size. Mine is depending on the number of bytes. You’re right that 0x02 doesn’t always mean that a message is starting, but 9/10 times it does. And if the message loses data, it’s stuck in a timeout. The first read for the byte is just so that the timeout isn’t triggered, because the master sees a reply coming. At the end of ReadMessage, I have a CRC16 check over the message, but I see that I haven’t posted it. I’ll change that. But that doesn’t change the fact that I’m missing some bytes.

– Bart Versluijs
Jan 4 at 6:48





@sawdust thanks for the reply! I’ve read that question, but the difference is that he has a fixed package size. Mine is depending on the number of bytes. You’re right that 0x02 doesn’t always mean that a message is starting, but 9/10 times it does. And if the message loses data, it’s stuck in a timeout. The first read for the byte is just so that the timeout isn’t triggered, because the master sees a reply coming. At the end of ReadMessage, I have a CRC16 check over the message, but I see that I haven’t posted it. I’ll change that. But that doesn’t change the fact that I’m missing some bytes.

– Bart Versluijs
Jan 4 at 6:48













"... the difference is that he has a fixed package size. Mine is depending on the number of bytes" -- You're focusing on an irrelevant detail (fixed versus variable length messages) instead of the salient concept. You're "missing some bytes" because your program is not robust; it can only handle a pre-synchronized input. "but 9/10 times it does" -- You really don't know that, and it looks like that alleged 1 out of 10 can occur reliably to reveal your code's flaws. Your code does not validate the CRC, it does not rescan the bytes, and it unnecessarily performs sleeps.

– sawdust
Jan 7 at 0:17







"... the difference is that he has a fixed package size. Mine is depending on the number of bytes" -- You're focusing on an irrelevant detail (fixed versus variable length messages) instead of the salient concept. You're "missing some bytes" because your program is not robust; it can only handle a pre-synchronized input. "but 9/10 times it does" -- You really don't know that, and it looks like that alleged 1 out of 10 can occur reliably to reveal your code's flaws. Your code does not validate the CRC, it does not rescan the bytes, and it unnecessarily performs sleeps.

– sawdust
Jan 7 at 0:17














0






active

oldest

votes












Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54025753%2fmissing-bytes-in-io-reader-with-serial-communication%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























0






active

oldest

votes








0






active

oldest

votes









active

oldest

votes






active

oldest

votes
















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54025753%2fmissing-bytes-in-io-reader-with-serial-communication%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

MongoDB - Not Authorized To Execute Command

How to fix TextFormField cause rebuild widget in Flutter

Npm cannot find a required file even through it is in the searched directory