Trying to get a nice architecture to work with this
This commit is contained in:
@@ -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
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user