grim/gousb2snes

Initial import, lots of hard coding
draft
2019-02-27, Gary Kramlich
32c861e0f399
Parents
Children c3cd4e43b5a9
Initial import, lots of hard coding
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore Wed Feb 27 00:21:12 2019 -0600
@@ -0,0 +1,3 @@
+syntax: glob
+gousb2snes
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/commands/byteslice.go Wed Feb 27 00:21:12 2019 -0600
@@ -0,0 +1,23 @@
+package commands
+
+// overwrite will overwrite the a with the entire run of b
+func overwrite(a, b []byte) {
+ for i, v := range b {
+ a[i] = v
+ }
+}
+
+// equal checks if byte slice a starts with b
+func equal(a, b []byte) bool {
+ if len(a) < len(b) {
+ return false
+ }
+
+ for i, v := range b {
+ if a[i] != v {
+ return false
+ }
+ }
+
+ return true
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/commands/commands.go Wed Feb 27 00:21:12 2019 -0600
@@ -0,0 +1,49 @@
+package commands
+
+import (
+ "errors"
+ "io"
+
+ "bitbucket.org/rw_grim/gousb2snes/protocol"
+)
+
+type Command interface {
+ Send(rwc io.ReadWriteCloser) error
+}
+
+func sync(rwc io.ReadWriteCloser, opcode protocol.OpCode, ns protocol.Namespace, flags protocol.Flag) ([]byte, error) {
+ req := make([]byte, 512)
+ header := []byte{'U', 'S', 'B', 'A', byte(opcode), byte(ns), byte(flags)}
+
+ overwrite(req, header)
+
+ n, err := rwc.Write(req)
+ if err != nil {
+ return nil, err
+ }
+
+ if n == 0 {
+ return nil, errors.New("failed to write!")
+ }
+
+ resp := make([]byte, 512)
+ total := 0
+ for total < 512 {
+ n, err = rwc.Read(resp[total:])
+ total += n
+
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ if !equal(resp, []byte{'U', 'S', 'B', 'A', byte(protocol.OpCodeResponse)}) {
+ return nil, errors.New("Bad response")
+ }
+
+ if resp[5] == 1 {
+ return nil, errors.New("Bad response")
+ }
+
+ return resp, nil
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/commands/info.go Wed Feb 27 00:21:12 2019 -0600
@@ -0,0 +1,86 @@
+package commands
+
+import (
+ "encoding/binary"
+ "fmt"
+ "io"
+ "strings"
+
+ "bitbucket.org/rw_grim/gousb2snes/protocol"
+)
+
+type Info struct {
+ version string
+ fwver string
+ features InfoFeature
+ rom string
+}
+
+type InfoFeature byte
+
+const (
+ InfoFeatureDSPX InfoFeature = 1 << iota
+ InfoFeatureST0010
+ InfoFeatureSRTC
+ InfoFeatureMSU1
+ InfoFeature213F
+ InfoFeatureCmdUnlock
+ InfoFeatureUSB1
+ InfoFeatureDMA1
+)
+
+func (f InfoFeature) String() string {
+ r := []string{}
+
+ if f&InfoFeatureDSPX != 0 {
+ r = append(r, "FEAT_DSPX")
+ }
+ if f&InfoFeatureST0010 != 0 {
+ r = append(r, "FEAT_ST0010")
+ }
+ if f&InfoFeatureSRTC != 0 {
+ r = append(r, "FEAT_SRTC")
+ }
+ if f&InfoFeatureMSU1 != 0 {
+ r = append(r, "FEAT_MSU1")
+ }
+ if f&InfoFeature213F != 0 {
+ r = append(r, "FEAT_213F")
+ }
+ if f&InfoFeatureCmdUnlock != 0 {
+ r = append(r, "FEAT_CMD_UNLOCK")
+ }
+ if f&InfoFeatureUSB1 != 0 {
+ r = append(r, "FEAT_USB1")
+ }
+ if f&InfoFeatureDMA1 != 0 {
+ r = append(r, "FEAT_DMA1")
+ }
+ return strings.Join(r, "|")
+}
+
+func (i *Info) Send(rwc io.ReadWriteCloser) error {
+ resp, err := sync(rwc, protocol.OpCodeInfo, protocol.NamespaceSNES, protocol.FlagNone)
+ if err != nil {
+ return err
+ }
+
+ fwver := binary.BigEndian.Uint32(resp[256:])
+ i.fwver = fmt.Sprintf("%08x", fwver)
+
+ i.version = nullTerminated(resp[260:])
+ i.features = InfoFeature(resp[6])
+ i.rom = nullTerminated(resp[16:])
+
+ return nil
+}
+
+func (i *Info) String() string {
+ return fmt.Sprintf(
+ "version: %s\nfwver: %s\nfeatures: %s\nrom: %s",
+ i.version,
+ i.fwver,
+ i.features,
+ i.rom,
+ )
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/commands/string.go Wed Feb 27 00:21:12 2019 -0600
@@ -0,0 +1,15 @@
+package commands
+
+func nullTerminated(buffer []byte) string {
+ r := ""
+
+ for _, b := range buffer {
+ if b == 0x0 {
+ break
+ }
+
+ r += string(b)
+ }
+
+ return r
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main.go Wed Feb 27 00:21:12 2019 -0600
@@ -0,0 +1,37 @@
+package main
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/jacobsa/go-serial/serial"
+
+ "bitbucket.org/rw_grim/gousb2snes/commands"
+)
+
+func main() {
+ opts := serial.OpenOptions{
+ PortName: "/dev/ttyACM0",
+ BaudRate: 9600,
+ DataBits: 8,
+ StopBits: 1,
+ MinimumReadSize: 4,
+ }
+
+ sock, err := serial.Open(opts)
+ if err != nil {
+ fmt.Printf("failed to open serial device : %v\n", err)
+ os.Exit(1)
+ }
+
+ defer sock.Close()
+
+ info := &commands.Info{}
+ err = info.Send(sock)
+ if err != nil {
+ fmt.Printf("error: %v\n", err)
+ return
+ }
+
+ fmt.Printf("-----\n%s\n", info)
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/protocol/consts.go Wed Feb 27 00:21:12 2019 -0600
@@ -0,0 +1,45 @@
+package protocol
+
+type OpCode byte
+
+const (
+ OpCodeGet OpCode = iota
+ OpCodePut
+ OpCodeVGet
+ OpCodeVPut
+ OpCodeLs
+ OpCodeMkdir
+ OpCodeRm
+ OpCodeMv
+ OpCodeReset
+ OpCodeBoot
+ OpCodePowerCycle
+ OpCodeInfo
+ OpCodeMenuReset
+ OpCodeStream
+ OpCodeTime
+ OpCodeResponse
+)
+
+type Flag byte
+
+const (
+ FlagNone Flag = 1 << iota
+ FlagSkiPreset
+ FlagOnlyReset
+ FlagClrX
+ FlagSetX
+ FlagStreamBurst
+ FlagNoResponse
+ FlagData64B
+)
+
+type Namespace byte
+
+const (
+ NamespaceFile Namespace = iota
+ NamespaceSNES
+ NamespaceMSU
+ NamespaceCommand
+ NamespaceConfig
+)