210 lines
3.9 KiB
Go
210 lines
3.9 KiB
Go
package communication
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"io"
|
|
|
|
helper "esdi/helpers"
|
|
"esdi/peripheral/communication/constvar"
|
|
"esdi/peripheral/communication/packets"
|
|
"esdi/peripheral/types"
|
|
|
|
"github.com/tarm/serial"
|
|
)
|
|
|
|
type WalkieTalkie struct {
|
|
Serial *serial.Port
|
|
Cfg *serial.Config
|
|
}
|
|
|
|
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.Fprintf(os.Stderr, "dev read: %s\n", err.Error())
|
|
return err
|
|
}
|
|
|
|
if b[0] == constvar.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
|
|
}
|
|
|
|
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) RequestIdentification() (int, error) {
|
|
return wt.Serial.Write([]byte{uint8(CmdRequestID)})
|
|
}
|
|
|
|
func (wt *WalkieTalkie) AknowledgeIdentification() (int, error) {
|
|
return wt.Serial.Write([]byte{uint8(CmdAckID)})
|
|
}
|
|
|
|
type header struct {
|
|
StartByte uint8
|
|
CMD types.Command
|
|
EndByte uint8
|
|
}
|
|
|
|
type CMDDataPacket struct {
|
|
StartMarker uint8
|
|
CMD types.Command
|
|
Len uint16
|
|
Payload []byte
|
|
CRC uint8
|
|
EndMarker uint8
|
|
}
|
|
|
|
func (cmdp *CMDDataPacket) Serialize() []byte {
|
|
buf := make([]byte, 0, 1+1+2+len(cmdp.Payload)+1+1)
|
|
|
|
buf = append(buf, cmdp.StartMarker)
|
|
buf = append(buf, byte(cmdp.CMD))
|
|
buf = append(buf, byte(cmdp.Len), byte(cmdp.Len>>8))
|
|
buf = append(buf, cmdp.Payload...)
|
|
buf = append(buf, cmdp.CRC)
|
|
buf = append(buf, cmdp.EndMarker)
|
|
|
|
return buf
|
|
}
|
|
|
|
func (wt *WalkieTalkie) sendPacket(cmd types.Command, data any) error {
|
|
// Prepare the payload
|
|
payload, err := helper.StructToBytes(data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
packet := CMDDataPacket{
|
|
StartMarker: constvar.StartOfText,
|
|
CMD: cmd,
|
|
Len: uint16(len(payload)),
|
|
Payload: payload,
|
|
CRC: CRC8(payload),
|
|
EndMarker: constvar.EndOfText,
|
|
}
|
|
|
|
// Send the payload
|
|
serializedPacket := packet.Serialize()
|
|
// fmt.Fprintf(os.Stderr, "%+v", serializedPacket)
|
|
|
|
_, err = wt.Serial.Write(serializedPacket)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (wt *WalkieTalkie) readPacket(resp packets.Packet) error {
|
|
size := binary.Size(resp)
|
|
if size < 0 {
|
|
return fmt.Errorf("invalid packet size")
|
|
}
|
|
|
|
err := wt.ReadFramedData(size, resp)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !resp.Validate() {
|
|
return fmt.Errorf("badly formatted response")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// func (wt *WalkieTalkie) sendHeader(h *header) error {
|
|
// err := wt.sendPacket(h)
|
|
// if err != nil {
|
|
// return err
|
|
// }
|
|
//
|
|
// // var ack packets.AckPacket
|
|
// // err = wt.readPacket(&ack)
|
|
// // if err != nil {
|
|
// // return err
|
|
// // }
|
|
//
|
|
// return nil
|
|
// }
|
|
|
|
// func (wt *WalkieTalkie) sendBody(payload any, resp packets.Packet) error {
|
|
// err := wt.sendPacket(payload)
|
|
// if err != nil {
|
|
// return err
|
|
// }
|
|
//
|
|
// // err = wt.readPacket(resp)
|
|
// // if err != nil {
|
|
// // return err
|
|
// // }
|
|
//
|
|
// return nil
|
|
// }
|
|
|
|
func (wt *WalkieTalkie) SendCommand(cmd types.Command, payload any,
|
|
responseBody packets.Packet) error {
|
|
// Prepare the header
|
|
// header := header{
|
|
// StartByte: constvar.StartOfText,
|
|
// CMD: cmd,
|
|
// EndByte: constvar.EndOfText,
|
|
// }
|
|
|
|
// Send the header
|
|
// err := wt.sendHeader(&header)
|
|
// if err != nil {
|
|
// return err
|
|
// }
|
|
|
|
// Send the body
|
|
err := wt.sendPacket(cmd, payload)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// if the responseBody != nil, then we also read and populate it???
|
|
if responseBody != nil {
|
|
err = wt.readPacket(responseBody)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|