// Copyright Terence J. Boldt (c)2020-2022 // Use of this source code is governed by an MIT // license that can be found in the LICENSE file. // This file is used for communicating with the Apple II data bus via the // GPIO ports on the Raspberry Pi package a2io import ( "bytes" "errors" "fmt" "strings" "time" "go.bug.st/serial" "go.bug.st/serial/enumerator" ) var port serial.Port // CDCio is a live implementation of A2Io interface type CDCio struct { } // Init initializes the CDC driver on the Raspberry Pi func (a2 CDCio) Init() { name := "" for { portInfos, err := enumerator.GetDetailedPortsList() if err == nil { for _, portInfo := range portInfos { if portInfo.IsUSB && strings.ToUpper(portInfo.VID) == "2E8A" && strings.ToUpper(portInfo.PID) == "000A" { name = portInfo.Name fmt.Printf("Found CDC port %s\n", name) break } } if name != "" { break } } time.Sleep(time.Millisecond) } for { var err error port, err = serial.Open(name, &serial.Mode{}) if err == nil { break } var portErr *serial.PortError if !errors.As(err, &portErr) || portErr.Code() != serial.PortNotFound && portErr.Code() != serial.PermissionDenied { panic(err) } time.Sleep(time.Millisecond) } err := port.SetReadTimeout(time.Second) if err != nil { panic(err) } } // ReadByte reads a byte from the Apple II via Raspberry Pi's CDC driver func (a2 CDCio) ReadByte(noDelay ...bool) (byte, error) { var data [1]byte n, err := port.Read(data[:]) if err != nil { return 0, err } if n == 0 { return 0, errors.New("timed out reading byte") } return data[0], nil } // WriteByte writes a byte to the Apple II via Raspberry Pi's CDC driver func (a2 CDCio) WriteByte(data byte) error { _, err := port.Write([]byte{data}) return err } // ReadString reads a string from the Apple II via Raspberry Pi's CDC driver func (a2 CDCio) ReadString() (string, error) { var inBytes bytes.Buffer for { inByte, err := a2.ReadByte() if err != nil { return "", err } if inByte == 0 { break } inBytes.WriteByte(inByte) } return inBytes.String(), nil } // WriteString writes a string to the Apple II via Raspberry Pi's CDC driver func (a2 CDCio) WriteString(outString string) error { for _, character := range outString { err := a2.WriteByte(byte(character) | 128) if err != nil { fmt.Printf("Failed to write string\n") return err } } a2.WriteByte(0) return nil } // WriteBlock writes 512 bytes to the Apple II via Raspberry Pi's CDC driver func (a2 CDCio) WriteBlock(buffer []byte) error { _, err := port.Write(buffer) return err } // ReadBlock reads 512 bytes from the Apple II via Raspberry Pi's CDC driver func (a2 CDCio) ReadBlock(buffer []byte) error { var err error for i := 0; i < 512; i++ { buffer[i], err = a2.ReadByte() if err != nil { return err } } return nil } // WriteBuffer writes a buffer of bytes to the Apple II via Raspberry Pi's CDC driver func (a2 CDCio) WriteBuffer(buffer []byte) error { _, err := port.Write(buffer) return err } // SendCharacter is a pass-through to vt100 implementation func (a2 CDCio) SendCharacter(character byte) { sendCharacter(a2, character) } // ReadCharacter is a pass-through to vt100 implementation func (a2 CDCio) ReadCharacter() (string, error) { return readCharacter(a2) }