package main import ( "errors" "fmt" "log" "sync" "time" "go.bug.st/serial" ) const portDev = "/dev/ttyUSB0" func main() { dbg, err := Open() if err != nil { log.Fatalf("connecting to debugger: %v", err) } defer dbg.Close() fmt.Println("Writing...") if err := dbg.Write(0x42, 123); err != nil { log.Fatalf("writing to memory: %v", err) } v, err := dbg.Read(0x42) if err != nil { log.Fatalf("reading from memory: %v", err) } fmt.Printf("addr 0: %02x\n", v) } type Debugger struct { port serial.Port mu sync.Mutex } func Open() (*Debugger, error) { mode := &serial.Mode{ BaudRate: 115_200, } port, err := serial.Open(portDev, mode) if err != nil { return nil, err } return &Debugger{port: port}, nil } func (d *Debugger) Close() error { d.mu.Lock() // note, deliberately no unlocking, to poison. return d.port.Close() } func encode(addr int, write bool, data byte) [4]byte { writeVal := uint8(0) if write { writeVal = 1 } var ret [4]byte ret[3] = data ret[2] = byte(addr<<1) | writeVal ret[1] = byte(addr >> 7) ret[0] = byte(addr >> 15) return ret } func (d *Debugger) Read(addr int) (byte, error) { d.mu.Lock() defer d.mu.Unlock() if addr >= 2<<17 { return 0, fmt.Errorf("read %d out of bounds", addr) } packet := encode(addr, false, 0) fmt.Printf("Writing: %02x %02x %02x %02x\n", packet[0], packet[1], packet[2], packet[3]) if _, err := d.port.Write(packet[:]); err != nil { return 0, err } d.port.SetReadTimeout(2 * time.Second) n, err := d.port.Read(packet[:1]) if err != nil { return 0, err } else if n == 0 { return 0, errors.New("no read") } return packet[0], nil } func (d *Debugger) Write(addr int, val byte) error { d.mu.Lock() defer d.mu.Unlock() if addr >= 2<<17 { return fmt.Errorf("write %d out of bounds", addr) } packet := encode(addr, true, val) fmt.Printf("Writing: %02x %02x %02x %02x\n", packet[0], packet[1], packet[2], packet[3]) if _, err := d.port.Write(packet[:]); err != nil { return err } return nil }