Julian Strobl 8db682d994
feat(lint): replace deprecated exportloopref (#467)
with `copyloopvar`, which needs Go 1.22.

* chore(ci): bump go version to v1.22
* fix(ci): pin release pipeline to go v1.22

Signed-off-by: Julian Strobl <jmastr@mailbox.org>
2024-11-12 15:59:09 +01:00

140 lines
3.0 KiB
Go

package trustwallet
import (
"errors"
"fmt"
"io"
"time"
"go.bug.st/serial"
)
const (
SlipEnd = 0xC0
SlipEsc = 0xDB
SlipEscEnd = 0xDC
SlipEscEsc = 0xDD
nsPerUs = 1000
nsPerMs = 8000 * nsPerUs
)
// occDo performs the operations to send and receive data over serial port.
func occDo(data []byte, bufferDelayMs int, portName string, outBuffer []byte) (int, error) {
// Initialize unencoded and encoded payloads
payloadUnencoded := make([]byte, 0, len(data))
payloadSlipEncoded := make([]byte, 0, len(data)*2)
// Copy data to payloadUnencoded
payloadUnencoded = append(payloadUnencoded, data...)
// Open serial port
mode := &serial.Mode{BaudRate: 115200}
s, err := serial.Open(portName, mode)
if err != nil {
return 0, fmt.Errorf("unable to open serial port: %w", err)
}
defer s.Close()
// Encode payload using SLIP
encodeSLIP(payloadUnencoded, &payloadSlipEncoded)
// Send encoded payload over serial
if _, err := s.Write(payloadSlipEncoded); err != nil {
return 0, fmt.Errorf("unable to write to serial port: %w", err)
}
time.Sleep(time.Duration(bufferDelayMs) * time.Millisecond)
// Read response from serial
readBuffer := make([]byte, 1)
encodedResponse := make([]byte, 0)
slipMsgFramer := 0
for {
n, err := s.Read(readBuffer)
if err != nil && !errors.Is(err, io.EOF) {
time.Sleep(10 * time.Millisecond)
continue
}
if n == 0 {
break
}
encodedResponse = append(encodedResponse, readBuffer[0])
if readBuffer[0] == SlipEnd {
if slipMsgFramer == 1 {
break
}
slipMsgFramer++
}
time.Sleep(1 * time.Millisecond)
}
// Decode SLIP response
decodedResponse, err := decodeSLIP(encodedResponse)
if err != nil {
return 0, fmt.Errorf("unable to decode SLIP: %w", err)
}
// Copy decoded response to outBuffer
copyLength := min(len(decodedResponse), len(outBuffer))
copy(outBuffer, decodedResponse[:copyLength])
return copyLength, nil
}
// encodeSLIP encodes data using SLIP protocol.
func encodeSLIP(data []byte, encoded *[]byte) {
*encoded = append(*encoded, SlipEnd)
for _, b := range data {
switch b {
case SlipEnd:
*encoded = append(*encoded, SlipEsc, SlipEscEnd)
case SlipEsc:
*encoded = append(*encoded, SlipEsc, SlipEscEsc)
default:
*encoded = append(*encoded, b)
}
}
*encoded = append(*encoded, SlipEnd)
}
// decodeSLIP decodes SLIP-encoded data.
func decodeSLIP(encoded []byte) ([]byte, error) {
// Check for empty input
if len(encoded) == 0 {
return nil, errors.New("encoded data is empty")
}
// Remove first and last SLIP_END bytes
if encoded[0] == SlipEnd {
encoded = encoded[1:]
}
if encoded[len(encoded)-1] == SlipEnd {
encoded = encoded[:len(encoded)-1]
}
decoded := make([]byte, 0, len(encoded))
esc := false
for _, b := range encoded {
switch {
case b == SlipEsc && !esc:
esc = true
case b == SlipEscEnd && esc:
decoded = append(decoded, SlipEnd)
esc = false
case b == SlipEscEsc && esc:
decoded = append(decoded, SlipEsc)
esc = false
default:
decoded = append(decoded, b)
esc = false
}
}
return decoded, nil
}