mirror of
https://github.com/planetmint/planetmint-go.git
synced 2025-03-30 15:08:28 +00:00

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>
140 lines
3.0 KiB
Go
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
|
|
}
|