Trying to get a nice architecture to work with this

This commit is contained in:
2025-10-29 22:04:18 +00:00
parent c5250377f3
commit a15d5a4c3c
5 changed files with 251 additions and 66 deletions
+101
View File
@@ -0,0 +1,101 @@
package peripheral
import (
"bytes"
"encoding/binary"
"fmt"
"io"
"github.com/tarm/serial"
)
const (
startOfText = 0x02
endOfText = 0x03
)
type CommState uint8
const (
CommIdle CommState = iota
CommOff
)
type Command uint8
const (
CmdRequestID Command = iota
CmdAckID
)
type DataReceiver interface {
Read(dev *serial.Port) error
Validate(data []byte) bool
}
func (wt *WalkieTalkie) ReadFramedData(size int, packet any) error {
buf := make([]byte, size)
for {
b := make([]byte, 1)
_, err := wt.Serial.Read(b)
if err != nil {
fmt.Println("dev read:", err.Error())
return err
}
if b[0] == startOfText {
buf[0] = b[0]
break
}
}
_, err := io.ReadFull(wt.Serial, buf[1:])
if err != nil {
return err
}
reader := bytes.NewReader(buf)
err = binary.Read(reader, binary.LittleEndian, packet)
if err != nil {
return err
}
return nil
}
type WalkieTalkie struct {
Serial *serial.Port
Cfg *serial.Config
}
func (wt *WalkieTalkie) TurnOn() error {
var err error
wt.Serial, err = serial.OpenPort(wt.Cfg)
if err != nil {
return err
}
return nil
}
func (wt *WalkieTalkie) TurnOff() error {
return wt.Serial.Close()
}
// func (wt *WalkieTalkie) SendCommand(cmd Command, payload []byte) (int, error) {
// switch cmd {
// case CmdRequestID:
// return wt.RequestIdentification(d * serial.Port)
// }
// }
func (wt *WalkieTalkie) RequestIdentification() (int, error) {
return wt.Serial.Write([]byte{uint8(CmdRequestID)})
}
func (wt *WalkieTalkie) AknowledgeIdentification() (int, error) {
return wt.Serial.Write([]byte{uint8(CmdAckID)})
}
+74 -60
View File
@@ -1,87 +1,101 @@
package peripheral
import (
"encoding/binary"
"fmt"
"time"
"github.com/tarm/serial"
)
type PeripheralDevice struct {
Port string
Name [32]byte
}
type PeripheralDeviceState int
const (
PACKET_MAGIC = 0xDEADBEEF
CMD_HELLO = 1
CMD_IDENTIFY = 2
CMD_ACK = 3
StateDiscoveredStr = "discovered"
StateConnectedStr = "connected"
StateUnknownStr = "unknown"
)
type FlarePacket struct {
Name [16]byte
const (
StateUnknown PeripheralDeviceState = iota
StateDiscovered
StateConnected
)
func (s PeripheralDeviceState) String() string {
switch s {
case StateDiscovered:
return StateDiscoveredStr
case StateConnected:
return StateConnectedStr
case StateUnknown:
fallthrough
default:
return StateUnknownStr
}
}
func parseFlare(buf []byte) *FlarePacket {
pkt := &FlarePacket{}
err := binary.Read(sliceReader(buf), binary.LittleEndian, pkt)
type PeripheralDevice struct {
State PeripheralDeviceState
CommState CommState
Name [32]byte
WT *WalkieTalkie
}
func NewPeripheralDevice(port string) *PeripheralDevice {
return &PeripheralDevice{
State: StateUnknown,
CommState: CommOff,
WT: &WalkieTalkie{
Cfg: &serial.Config{
Name: port,
Baud: 115200,
ReadTimeout: 500 * time.Millisecond,
},
},
}
}
func (p *PeripheralDevice) Probe() error {
err := p.WT.TurnOn()
if err != nil {
return nil
}
// if pkt.Magic != PACKET_MAGIC || pkt.Cmd != CMD_HELLO {
// return nil
// }
return pkt
}
func sliceReader(b []byte) *byteReader { return &byteReader{b: b} }
type byteReader struct{ b []byte }
func (r *byteReader) Read(p []byte) (int, error) {
n := copy(p, r.b)
r.b = r.b[n:]
if n == 0 {
time.Sleep(10 * time.Millisecond)
}
return n, nil
}
func (p *PeripheralDevice) Connect() error {
cfg := &serial.Config{
Name: p.Port,
Baud: 115200,
ReadTimeout: 500 * time.Millisecond,
}
s, err := serial.OpenPort(cfg)
// Papers, please!
_, err = p.WT.RequestIdentification()
if err != nil {
return err
}
buf := make([]byte, binary.Size(FlarePacket{}))
n, _ := s.Read(buf)
if n == len(buf) {
flare := parseFlare(buf)
if flare != nil {
s.Write([]byte{CMD_ACK})
return nil
}
// Verify the papers
var pkt IdentificationPacket
err = pkt.Read(p.WT)
if err != nil {
// Throw the man in the gulag!
return err
}
// if we received nothing
s.Write([]byte{CMD_IDENTIFY})
n, _ = s.Read(buf)
if n == len(buf) {
pkt := parseFlare(buf)
if pkt != nil {
s.Write([]byte{CMD_ACK})
return nil
}
// Acknowledge successful identification
_, err = p.WT.AknowledgeIdentification()
if err != nil {
return err
}
return fmt.Errorf("no valid device response")
// copy the data
p.Merge(&pkt)
p.ToConnectedIdling()
return nil
}
func (p *PeripheralDevice) ToConnectedIdling() {
p.State = StateConnected
p.CommState = CommIdle
}
func (p *PeripheralDevice) Merge(packet *IdentificationPacket) {
p.Name = packet.Name
}
func (p *PeripheralDevice) Disconnect() error {
return p.WT.TurnOff()
}
+44
View File
@@ -0,0 +1,44 @@
package peripheral
import (
"encoding/binary"
"fmt"
)
type IdentificationPacket struct {
StartMarker byte
PktType PacketType
Name [32]byte
EndMarker byte
}
func (pkt *IdentificationPacket) Read(wt *WalkieTalkie) error {
fmt.Println("Reading framed data")
err := wt.ReadFramedData(binary.Size(IdentificationPacket{}), pkt)
if err != nil {
return err
}
if !pkt.Validate() {
return fmt.Errorf("invalid packet")
}
return nil
}
func (pkt *IdentificationPacket) Validate() bool {
fmt.Println("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓")
fmt.Println(pkt.StartMarker)
fmt.Println(pkt.PktType.String())
fmt.Println(string(pkt.Name[:]))
fmt.Println(pkt.EndMarker)
fmt.Println("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑")
if pkt.StartMarker != startOfText ||
pkt.EndMarker != endOfText {
return false
}
return true
}
+21
View File
@@ -0,0 +1,21 @@
package peripheral
type PacketType uint8
const (
identificationPacket PacketType = iota
)
const (
identificationPacketStr = "identificationPacket"
unknownPacketStr = "unknownPacket"
)
func (p PacketType) String() string {
switch p {
case identificationPacket:
return identificationPacketStr
default:
return unknownPacketStr
}
}
+11 -6
View File
@@ -13,7 +13,7 @@ const (
)
type PeripheralDeviceClerk struct {
Devices map[string]PeripheralDevice
// Devices map[string]PeripheralDevice
}
func NewPeripheralDeviceClerk() *PeripheralDeviceClerk {
@@ -36,12 +36,17 @@ func (clerk *PeripheralDeviceClerk) FindDevices() error {
}
for _, p := range ports {
newDevice := PeripheralDevice{
Port: p,
}
err := newDevice.Connect()
newDevice := NewPeripheralDevice(p)
err := newDevice.Probe()
fmt.Println(p, err)
var msg string
if err == nil {
msg = string(newDevice.Name[:])
} else {
msg = err.Error()
}
fmt.Println(p, msg)
}
return nil