package serial import ( "errors" "sync" "time" "go.bug.st/serial" ) const portDev = "/dev/ttyUSB0" const maxAddr = 1 << 17 type Serial struct { portMu sync.Mutex port serial.Port } func Open() (*Serial, error) { mode := &serial.Mode{ BaudRate: 115_200, } port, err := serial.Open(portDev, mode) if err != nil { return nil, err } return &Serial{port: port}, nil } func (d *Serial) Close() error { d.portMu.Lock() defer d.portMu.Unlock() 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 *Serial) ReadAt(bs []byte, off int64) (int, error) { d.portMu.Lock() defer d.portMu.Unlock() if off+int64(len(bs)) >= maxAddr { return 0, errors.New("OOB read") } for i := range bs { packet := encode(int(off)+i, false, 0) if _, err := d.port.Write(packet[:]); err != nil { return i, err } d.port.SetReadTimeout(2 * time.Second) n, err := d.port.Read(packet[:1]) if err != nil { return i, err } else if n == 0 { return i, errors.New("short read") } bs[i] = packet[0] } return len(bs), nil } func (d *Serial) WriteAt(bs []byte, off int64) (int, error) { d.portMu.Lock() defer d.portMu.Unlock() if off+int64(len(bs)) >= maxAddr { return 0, errors.New("OOB write") } for i, v := range bs { packet := encode(int(off)+i, true, v) if _, err := d.port.Write(packet[:]); err != nil { return i, err } } return len(bs), nil }