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;
}
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
add a comment |
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
"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
add a comment |
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
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
go serial-port
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
add a comment |
"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
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
"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