Skip to content

Commit

Permalink
CSP Protocol Update (#13)
Browse files Browse the repository at this point in the history
* device: set player number

* CSP protocol update

* CSP fixes

* Assorted CSP fixes
  • Loading branch information
ysoldak authored Jul 7, 2024
1 parent 176ef82 commit fdd0596
Show file tree
Hide file tree
Showing 8 changed files with 348 additions and 203 deletions.
142 changes: 142 additions & 0 deletions src/csp/adapter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package csp

import (
"errors"
"fmt"
"machine"
"time"
)

const DEBUG = false

var ErrNoData = errors.New("No data available")
var ErrWrongChecksum = errors.New("Wrong checksum")
var ErrWrite = errors.New("Write failed")
var ErrWriteLength = errors.New("Write failed to send all bytes")

// States
const (
STATE_IDLE byte = iota
STATE_HEADER
STATE_LENGTH
STATE_COMMAND
STATE_PAYLOAD
STATE_CHECKSUM
)

type Adapter struct {
uart *machine.UART

state byte
Message Message
}

func NewAdapter(uart *machine.UART) *Adapter {
return &Adapter{
uart: uart,
}
}

// Send a message.
func (a *Adapter) Send(m *Message) error {
bytes := m.Bytes()
if DEBUG {
fmt.Printf("%s SEND ", time.Now().Format("15:04:05.000"))
for _, b := range bytes {
fmt.Printf(" %02X", b)
}
fmt.Println()
}
n, err := a.uart.Write(bytes)
if err != nil {
return ErrWrite
}
if n != len(bytes) {
return ErrWriteLength
}
return nil
}

// Receive a message; returns nil if no message is available (yet).
func (a *Adapter) Receive() (*Message, error) {
for {
b, err := a.uart.ReadByte()
if err != nil {
return nil, ErrNoData
}
switch a.state {
case STATE_IDLE:
if b == '$' {
if DEBUG {
fmt.Printf("%s IDLE %02X\n", time.Now().Format("15:04:05.000"), b)
}
a.Message.Header[0] = b
a.state = STATE_HEADER
}
case STATE_HEADER:
if b == 'C' {
if DEBUG {
fmt.Printf("%s HEADER %02X\n", time.Now().Format("15:04:05.000"), b)
}
a.Message.Header[1] = b
a.state = STATE_LENGTH
} else {
a.state = STATE_IDLE
}
case STATE_LENGTH:
if DEBUG {
fmt.Printf("%s LENGTH %02X\n", time.Now().Format("15:04:05.000"), b)
}
if b > MAX_PAYLOAD {
a.state = STATE_IDLE
continue
}
a.Message.Length = b
a.Message.Payload = []byte{}
a.Message.Checksum = b
a.state = STATE_COMMAND
case STATE_COMMAND:
if DEBUG {
fmt.Printf("%s COMMAND %02X\n", time.Now().Format("15:04:05.000"), b)
}
a.Message.Command = b
a.Message.Checksum ^= b
a.state = STATE_PAYLOAD
case STATE_PAYLOAD:
a.Message.Payload = append(a.Message.Payload, b)
a.Message.Checksum ^= b
if len(a.Message.Payload) == int(a.Message.Length) {
a.state = STATE_CHECKSUM
}
case STATE_CHECKSUM:
if DEBUG {
fmt.Printf("%s PAYLOAD ", time.Now().Format("15:04:05.000"))
for _, bb := range a.Message.Bytes() {
fmt.Printf(" %02X", bb)
}
fmt.Println()
fmt.Printf("%s CHECKSUM expected %02X ?= %02X actual\n", time.Now().Format("15:04:05.000"), a.Message.Checksum, b)
}
m := a.Message
a.Message = Message{}
a.state = STATE_IDLE
if m.Checksum == b {
return &m, nil
} else {
return nil, ErrWrongChecksum
}
}
}
}

// Reset the state machine and clear the message buffer.
func (a *Adapter) Reset() {
a.state = STATE_IDLE
a.Message = Message{}
for {
_, err := a.uart.ReadByte()
if err != nil {
return
}
}
}
49 changes: 49 additions & 0 deletions src/csp/message.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package csp

const MAX_PAYLOAD = 1 + 1 + 110 // CFG SET requests: ID, Offset, Data

// Commands
const (
COMMAND_BEACON byte = 0x71 // ID[1], Name[10], Description[20]

COMMAND_CFG_GET_REQ byte = 0x72 // ID[1], Offset[1], Length[1]
COMMAND_CFG_GET_RSP byte = 0x73 // ID[1], Offset[1], Data[<=110]
COMMAND_CFG_SET_REQ byte = 0x74 // ID[1], Offset[1], Data[<=110] <-- data length = message payload length - 2
COMMAND_CFG_SET_RSP byte = 0x75 // ID[1], Offset[1], Data[<=110] <-- ID[1] can be new if team or player changed

COMMAND_HIT byte = 0x82 // ID[1], Lives[1]
COMMAND_CLAIM byte = 0x84 // ID[1], Power[1]
)

type Message struct {
Header [2]byte // '$' + 'C'
Length byte // Length of the payload
Command byte // 0x82 = Claim, 0x83 = Hit, etc
Payload []byte // Data
Checksum byte // XOR of all bytes from length to the end of payload
}

func NewMessage(command byte, data []byte) *Message {
checksum := byte(len(data)) ^ command
for _, b := range data {
checksum ^= b
}
return &Message{
Header: [2]byte{'$', 'C'},
Length: byte(len(data)),
Command: command,
Payload: data,
Checksum: checksum,
}
}

func (m *Message) Bytes() []byte {
b := make([]byte, 4+len(m.Payload)+1)
b[0] = m.Header[0]
b[1] = m.Header[1]
b[2] = m.Length
b[3] = m.Command
copy(b[4:], m.Payload)
b[len(b)-1] = m.Checksum
return b
}
7 changes: 5 additions & 2 deletions src/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"fmt"
"fpvc-gadget/src/csp"
"machine"
"time"
)
Expand All @@ -10,16 +11,18 @@ var Version string

var battery *Battery
var display *Display
var serial *Serial

var encoder *Encoder
var network *csp.Adapter

func main() {

battery = NewBattery()
battery.Configure()

serial = NewSerial(machine.UART0, machine.D7, machine.D6)
serial := NewSerial(machine.UART0, machine.D7, machine.D6)
serial.Configure()
network = csp.NewAdapter(serial.uart)

display = &Display{}
display.Configure()
Expand Down
7 changes: 6 additions & 1 deletion src/page_device.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ func (pd *PageDevice) Enter() {
display.Show()

// Do fetch
display.Print(120, 60, "*")
display.Show()
err := settings.Fetch(pd.id)
display.Erase(120, 60, "*")
display.Show()
if err != nil {
display.Fill(10, 24+10, 128, 20, BLACK)
display.Print(10, 24+20, err.Error())
Expand All @@ -61,11 +65,12 @@ func (pd *PageDevice) ItemsFromSettings() []Item {
items := []Item{}
items = append(items, NewItemSimple("- BATTLE ---------"))
items = append(items, NewItemByte("Team", 72, 0x0A, 0x0E, 1).WithDrawer(&TeamNameDrawer{}))
items = append(items, NewItemByte("Player", 73, 1, 9, 1))
items = append(items, NewItemByte("Life", 70, 1, 255, 1))
items = append(items, NewItemByte("Ammo", 71, 1, 255, 1))
items = append(items, NewItemByte("Shoot Power", 75, 1, 10-settings.Get(76)-settings.Get(77), 1))
items = append(items, NewItemByte("Shoot Rate", 76, 1, 10-settings.Get(75)-settings.Get(77), 1))
items = append(items, NewItemByte("Defense", 77, 1, 10-settings.Get(75)-settings.Get(76), 1))
items = append(items, NewItemByte("Armor", 77, 1, 10-settings.Get(75)-settings.Get(76), 1))
items = append(items, NewItemSimple("- DISPLAY --------"))
items = append(items, NewItemString("Name", 100, 10))
items = append(items, NewItemByte("Canvas", 95, 0, 4, 1).WithDrawer(NewNamesDrawer("30x16", "50x18", "30x16C", "60x22", "53x20")).WithValuer(&BitsValuer{0b00011100}))
Expand Down
64 changes: 34 additions & 30 deletions src/page_device_byte.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,58 +43,62 @@ func NewItemByte(title string, address, min, max, inc byte) *ItemByte {
}
}

func (si *ItemByte) WithDrawer(drawer ItemDrawer) *ItemByte {
si.ItemDrawer = drawer
return si
func (ib *ItemByte) WithDrawer(drawer ItemDrawer) *ItemByte {
ib.ItemDrawer = drawer
return ib
}

func (si *ItemByte) WithValuer(valuer ItemValuer) *ItemByte {
si.ItemValuer = valuer
return si
func (ib *ItemByte) WithValuer(valuer ItemValuer) *ItemByte {
ib.ItemValuer = valuer
return ib
}

func (si *ItemByte) Draw(row int) {
si.row = row
func (ib *ItemByte) Draw(row int) {
ib.row = row
display.Fill(20, pageBodyOffset+int16(row)*pageRowHeight-8, 100, 10, BLACK)
si.ItemDrawer.Draw(row, si)
ib.ItemDrawer.Draw(row, ib)
}

func (si *ItemByte) Enter() {
si.editing = true
encoder.SetClickHandler(si.HandleClick)
encoder.SetChangeHandler(si.HandleChange, int(si.getValue(si.address)))
display.Print(120, pageBodyOffset+int16(si.row)*pageRowHeight, "<")
func (ib *ItemByte) Enter() {
ib.editing = true
encoder.SetClickHandler(ib.HandleClick)
encoder.SetChangeHandler(ib.HandleChange, int(ib.getValue(ib.address)))
display.Print(120, pageBodyOffset+int16(ib.row)*pageRowHeight, "<")
display.Show()
for si.editing {
if si.changed {
si.changed = false
si.Draw(si.row)
for ib.editing {
if ib.changed {
ib.changed = false
ib.Draw(ib.row)
display.Show()
}
time.Sleep(10 * time.Millisecond)
}
err := settings.Commit()
display.Print(120, 60, "*")
display.Show()
err := settings.Commit(ib.address, 1)
display.Erase(120, 60, "*")
display.Show()
if err != nil {
println(err.Error())
}
}

func (si *ItemByte) HandleClick() {
si.editing = false
func (ib *ItemByte) HandleClick() {
ib.editing = false
}

func (si *ItemByte) HandleChange(value int) int {
eValue := si.ItemValuer.getValue(si.address)
diff := (value - int(eValue)) * int(si.inc)
func (ib *ItemByte) HandleChange(value int) int {
eValue := ib.ItemValuer.getValue(ib.address)
diff := (value - int(eValue)) * int(ib.inc)
value = int(eValue) + diff
if value < int(si.min) {
value = int(si.max)
if value < int(ib.min) {
value = int(ib.max)
}
if value > int(si.max) {
value = int(si.min)
if value > int(ib.max) {
value = int(ib.min)
}
si.ItemValuer.setValue(si.address, byte(value))
si.changed = eValue != byte(value)
ib.ItemValuer.setValue(ib.address, byte(value))
ib.changed = eValue != byte(value)
return value
}

Expand Down
6 changes: 5 additions & 1 deletion src/page_device_string.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,11 @@ func (is *ItemString) Enter() {
}
time.Sleep(10 * time.Millisecond)
}
err := settings.Commit()
display.Print(120, 60, "*")
display.Show()
err := settings.Commit(is.address, is.length)
display.Erase(120, 60, "*")
display.Show()
if err != nil {
println(err.Error())
}
Expand Down
Loading

0 comments on commit fdd0596

Please sign in to comment.