From c23441908fb9dec2339aaef3229e940108e8931a Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Sat, 6 Dec 2025 22:26:03 +0000 Subject: [PATCH] Adding multi device support --- cmd/repl.go | 46 +++++++++++++++++++++++++++++ helpers/helper.go | 8 +++++ peripheral/device.go | 2 ++ peripheral/devices/cdash_display.go | 35 ++++++++++++++++++++++ peripheral/devices/devices.go | 46 +++++++++++++++++++++++++++++ peripheral/devices/esbtn_box.go | 9 ++++++ peripheral/peripheral.go | 38 +++++++++++++++++++++--- peripheral/types/types.go | 4 +++ repl/repl.go | 4 +++ 9 files changed, 188 insertions(+), 4 deletions(-) create mode 100644 helpers/helper.go create mode 100644 peripheral/devices/cdash_display.go create mode 100644 peripheral/devices/devices.go create mode 100644 peripheral/devices/esbtn_box.go create mode 100644 peripheral/types/types.go diff --git a/cmd/repl.go b/cmd/repl.go index ff453e6..b6e5a2b 100644 --- a/cmd/repl.go +++ b/cmd/repl.go @@ -3,6 +3,8 @@ package cmd import ( "esdi/peripheral" "esdi/repl" + "fmt" + "strconv" "github.com/spf13/cobra" ) @@ -37,8 +39,52 @@ func replCmdAction(cmd *cobra.Command, args []string) { }, } + listDeviceAPIREPLCmd := repl.Command{ + Name: "v-api", + Usage: "shows API of a device - pass its ID", + Action: func(r *repl.REPL, args []string) error { + // We should add this to the REPL instead + if len(args) < 1 { + return fmt.Errorf("requires at least on argument") + } + + // First and only argument should be the ID of the device we want to use + targetID, err := strconv.ParseInt(args[0], 10, 0) + if err != nil { + return err + } + + err = perClerk.ListDeviceAPI(uint8(targetID)) + if err != nil { + fmt.Println("failed to view device API: ", err.Error()) + } + + return nil + }, + } + // selectDeviceREPLCmd := repl.Command{ + // Name: "select", + // Usage: "Selects a given device - pass its ID", + // Action: func(r *repl.REPL, args []string) error { + // // We should add this to the REPL instead + // if len(args) < 1 { + // return fmt.Errorf("requires at least on argument") + // } + // + // // First and only argument should be the ID of the device we want to use + // targetID, err := strconv.ParseInt(args[0], 10, 0) + // if err != nil { + // return err + // } + // + // return nil + // }, + // } + r.RegisterCMD(discoverDevicesREPLCmd) r.RegisterCMD(listDevicesREPLCmd) + // r.RegisterCMD(selectDeviceREPLCmd) + r.RegisterCMD(listDeviceAPIREPLCmd) r.Start() r.Close() diff --git a/helpers/helper.go b/helpers/helper.go new file mode 100644 index 0000000..f943198 --- /dev/null +++ b/helpers/helper.go @@ -0,0 +1,8 @@ +// Package helper +package helper + +func B32(s string) [32]byte { + var b [32]byte + copy(b[:], s) + return b +} diff --git a/peripheral/device.go b/peripheral/device.go index 3b8c28c..e3b2183 100644 --- a/peripheral/device.go +++ b/peripheral/device.go @@ -1,6 +1,7 @@ package peripheral import ( + "esdi/peripheral/devices" "time" "github.com/tarm/serial" @@ -39,6 +40,7 @@ type PeripheralDevice struct { ID uint8 Name string WT *WalkieTalkie + DeviceAPI *devices.Device } func NewPeripheralDevice(port string) *PeripheralDevice { diff --git a/peripheral/devices/cdash_display.go b/peripheral/devices/cdash_display.go new file mode 100644 index 0000000..8f6d3b7 --- /dev/null +++ b/peripheral/devices/cdash_display.go @@ -0,0 +1,35 @@ +package devices + +import helper "esdi/helpers" + +const ( + newWindowCMDID = iota + destroyWindowCMDID +) + +var CDashDisplay = Device{ + ID: CDashDisplayDevID, + Name: helper.B32("ESLabs CDashDisplay"), + API: map[string]DeviceCMD{ + "new-window": { + Identifier: newWindowCMDID, + Name: "new-window", + Desc: "Creates a new window - pass the window name and dimensions", + Fn: createWindow, + }, + "destroy-window": { + Identifier: destroyWindowCMDID, + Name: "destroy-window", + Desc: "Destroys a window by its ID", + Fn: destroyWindow, + }, + }, +} + +func createWindow(data []byte) { + // Parse the command +} + +func destroyWindow(data []byte) { + // Parse the command +} diff --git a/peripheral/devices/devices.go b/peripheral/devices/devices.go new file mode 100644 index 0000000..38b3aba --- /dev/null +++ b/peripheral/devices/devices.go @@ -0,0 +1,46 @@ +// Package devices will define the available devices we can communicate with +package devices + +import "esdi/peripheral/types" + +// IDs for our devices. They need to be correctly mapped on the devices +// themselves so we can discover them +const ( + CDashDisplayDevID = 0x01 + ESBtnBoxDevID = 0x02 +) + +// DeviceMap maps the implemented devices +// When adding a new device we append it here too +var DeviceMap = map[int]Device{ + CDashDisplayDevID: CDashDisplay, + ESBtnBoxDevID: ESBtnBox, +} + +type Device struct { + ID uint8 + Name [32]byte + API map[string]DeviceCMD +} + +type DeviceCMDHeader struct { + Payload [64]byte +} + +type DeviceCMDPayload struct { + Payload [64]byte +} + +// DeviceCMDFn defines the basic type for the functions the devices can have +// The function will receive a []byte that should be the arguments the user +// types in the REPL - or however this will be used +type DeviceCMDFn func(data []byte) + +type DeviceCMD struct { + Identifier types.CommandID + Name string + Desc string + Header DeviceCMDHeader + Data DeviceCMDPayload + Fn DeviceCMDFn +} diff --git a/peripheral/devices/esbtn_box.go b/peripheral/devices/esbtn_box.go new file mode 100644 index 0000000..1365b66 --- /dev/null +++ b/peripheral/devices/esbtn_box.go @@ -0,0 +1,9 @@ +package devices + +import helper "esdi/helpers" + +var ESBtnBox = Device{ + ID: ESBtnBoxDevID, + Name: helper.B32("ESLabs Button Box"), + API: map[string]DeviceCMD{}, +} diff --git a/peripheral/peripheral.go b/peripheral/peripheral.go index 5fd29ee..bf6cace 100644 --- a/peripheral/peripheral.go +++ b/peripheral/peripheral.go @@ -2,6 +2,7 @@ package peripheral import ( + "esdi/peripheral/devices" "fmt" "path/filepath" ) @@ -14,12 +15,12 @@ const ( type PeripheralDeviceClerk struct { // mu sync.RWMutex - Devices map[string]*PeripheralDevice + Devices map[uint8]*PeripheralDevice } func NewPeripheralDeviceClerk() *PeripheralDeviceClerk { return &PeripheralDeviceClerk{ - Devices: make(map[string]*PeripheralDevice), + Devices: make(map[uint8]*PeripheralDevice), } } @@ -33,7 +34,17 @@ func (clerk *PeripheralDeviceClerk) listPorts() ([]string, error) { } func (clerk *PeripheralDeviceClerk) addDevice(dev *PeripheralDevice) { - clerk.Devices[string(dev.Name[:])] = dev + clerk.Devices[dev.ID] = dev +} + +func (clerk *PeripheralDeviceClerk) FindDeviceAPI(ID uint8) *devices.Device { + for _, d := range devices.DeviceMap { + if d.ID == ID { + return &d + } + } + + return nil } func (clerk *PeripheralDeviceClerk) FindDevices() error { @@ -51,6 +62,13 @@ func (clerk *PeripheralDeviceClerk) FindDevices() error { continue } + // Look for the device on our device list - we need its API + newDevice.DeviceAPI = clerk.FindDeviceAPI(newDevice.ID) + if newDevice.DeviceAPI == nil { + fmt.Printf("Failed to acquire API for device: [%2d] %s\n", + newDevice.ID, newDevice.Name) + } + clerk.addDevice(newDevice) fmt.Println(p, string(newDevice.Name[:])) } @@ -62,7 +80,19 @@ func (clerk *PeripheralDeviceClerk) FindDevices() error { func (clerk *PeripheralDeviceClerk) ListDevices() error { for _, d := range clerk.Devices { - fmt.Printf("[%d] %s\n", d.ID, d.Name) + fmt.Printf("[%2d] %s\n", d.ID, d.Name) + } + + return nil +} + +func (clerk *PeripheralDeviceClerk) ListDeviceAPI(ID uint8) error { + if _, ok := clerk.Devices[ID]; !ok { + return fmt.Errorf("device with ID %d not found", ID) + } + + for _, f := range clerk.Devices[ID].DeviceAPI.API { + fmt.Printf("%s\t%s\n", f.Name, f.Desc) } return nil diff --git a/peripheral/types/types.go b/peripheral/types/types.go new file mode 100644 index 0000000..83b5c42 --- /dev/null +++ b/peripheral/types/types.go @@ -0,0 +1,4 @@ +// Package types defines the types necessary to handle peripherals +package types + +type CommandID uint8 diff --git a/repl/repl.go b/repl/repl.go index aeca455..91384b1 100644 --- a/repl/repl.go +++ b/repl/repl.go @@ -47,6 +47,10 @@ func (r *REPL) printPrompt() { _, _ = os.Stdout.Write([]byte(r.Cfg.PS1)) } +func (r *REPL) SetPS1(s string) { + r.Cfg.PS1 = s +} + func (r *REPL) mainLoop() { reader := bufio.NewReader(os.Stdin) for {