diff --git a/RaspberryPi/apple2driver/a2io/communication.go b/RaspberryPi/apple2driver/a2io/communication.go index 2e6abd6..bfb3118 100644 --- a/RaspberryPi/apple2driver/a2io/communication.go +++ b/RaspberryPi/apple2driver/a2io/communication.go @@ -1,292 +1,16 @@ package a2io -import ( - "bytes" - "errors" - "fmt" - "time" - - "periph.io/x/periph/conn/gpio" - "periph.io/x/periph/conn/gpio/gpioreg" - "periph.io/x/periph/host" -) - -var edgeTimeout time.Duration - -var out_write gpio.PinIO -var out_read gpio.PinIO -var out_reserved2 gpio.PinIO -var out_reserved1 gpio.PinIO -var out_bit7 gpio.PinIO -var out_bit6 gpio.PinIO -var out_bit5 gpio.PinIO -var out_bit4 gpio.PinIO -var out_bit3 gpio.PinIO -var out_bit2 gpio.PinIO -var out_bit1 gpio.PinIO -var out_bit0 gpio.PinIO -var in_write gpio.PinIO -var in_read gpio.PinIO -var in_reserved2 gpio.PinIO -var in_reserved1 gpio.PinIO -var in_bit7 gpio.PinIO -var in_bit6 gpio.PinIO -var in_bit5 gpio.PinIO -var in_bit4 gpio.PinIO -var in_bit3 gpio.PinIO -var in_bit2 gpio.PinIO -var in_bit1 gpio.PinIO -var in_bit0 gpio.PinIO - -func InitGpio() { - host.Init() - - out_write = gpioreg.ByName("GPIO24") - out_read = gpioreg.ByName("GPIO25") - out_reserved2 = gpioreg.ByName("GPIO7") //note GPIO7 and CPIO8 require extra effort to use - out_reserved1 = gpioreg.ByName("GPIO8") - out_bit7 = gpioreg.ByName("GPIO5") - out_bit6 = gpioreg.ByName("GPIO11") - out_bit5 = gpioreg.ByName("GPIO9") - out_bit4 = gpioreg.ByName("GPIO10") - out_bit3 = gpioreg.ByName("GPIO22") - out_bit2 = gpioreg.ByName("GPIO27") - out_bit1 = gpioreg.ByName("GPIO17") - out_bit0 = gpioreg.ByName("GPIO4") - in_write = gpioreg.ByName("GPIO23") - in_read = gpioreg.ByName("GPIO18") - in_reserved2 = gpioreg.ByName("GPIO14") - in_reserved1 = gpioreg.ByName("GPIO15") - in_bit7 = gpioreg.ByName("GPIO12") - in_bit6 = gpioreg.ByName("GPIO16") - in_bit5 = gpioreg.ByName("GPIO20") - in_bit4 = gpioreg.ByName("GPIO21") - in_bit3 = gpioreg.ByName("GPIO26") - in_bit2 = gpioreg.ByName("GPIO19") - in_bit1 = gpioreg.ByName("GPIO13") - in_bit0 = gpioreg.ByName("GPIO6") - - in_write.In(gpio.PullDown, gpio.BothEdges) - in_read.In(gpio.PullDown, gpio.BothEdges) - out_reserved1.Out(gpio.High) - out_reserved2.Out(gpio.High) - out_read.Out(gpio.High) - out_write.Out(gpio.High) - out_bit7.Out(gpio.Low) - out_bit6.Out(gpio.Low) - out_bit5.Out(gpio.Low) - out_bit4.Out(gpio.Low) - out_bit3.Out(gpio.Low) - out_bit2.Out(gpio.Low) - out_bit1.Out(gpio.Low) - out_bit0.Out(gpio.Low) - - edgeTimeout = time.Second +type A2Io interface { + Init() + WriteByte(data byte) error + WriteString(outString string) error + WriteBlock(buffer []byte) error + WriteBuffer(buffer []byte) error + ReadByte() (byte, error) + ReadString() (string, error) + ReadBlock(buffer []byte) error } -func ReadString() (string, error) { - var inBytes bytes.Buffer - for { - inByte, err := ReadByte() - if err != nil { - return "", err - } - if inByte == 0 { - break - } - inBytes.WriteByte(inByte) - } - return string(inBytes.Bytes()), nil -} - -func WriteString(outString string) error { - for _, character := range outString { - err := WriteByte(byte(character) | 128) - if err != nil { - fmt.Printf("Failed to write string\n") - return err - } - } - WriteByte(0) - return nil -} - -func ReadByte() (byte, error) { - // let the Apple II know we are ready to read - out_read.Out(gpio.Low) - - // wait for the Apple II to write - for in_write.Read() == gpio.High { - if !in_write.WaitForEdge(edgeTimeout) { - out_read.Out(gpio.High) - return 0, errors.New("Timed out reading byte -- write stuck high\n") - } - } - - // get a nibble of data - var data byte - data = 0 - bit7 := in_bit7.Read() - bit6 := in_bit6.Read() - bit5 := in_bit5.Read() - bit4 := in_bit4.Read() - bit3 := in_bit3.Read() - bit2 := in_bit2.Read() - bit1 := in_bit1.Read() - bit0 := in_bit0.Read() - - if bit7 == gpio.High { - data += 128 - } - if bit6 == gpio.High { - data += 64 - } - if bit5 == gpio.High { - data += 32 - } - if bit4 == gpio.High { - data += 16 - } - if bit3 == gpio.High { - data += 8 - } - if bit2 == gpio.High { - data += 4 - } - if bit1 == gpio.High { - data += 2 - } - if bit0 == gpio.High { - data += 1 - } - - // let the Apple II know we are done reading - //fmt.Printf("let the Apple II know we are done reading\n") - out_read.Out(gpio.High) - - // wait for the Apple II to finish writing - //fmt.Printf("wait for the Apple II to finish writing\n") - for in_write.Read() == gpio.Low { - if !in_write.WaitForEdge(edgeTimeout) { - return 0, errors.New("Timed out reading byte -- write stuck low") - } - } - - return data, nil -} - -func WriteByte(data byte) error { - // check if the Apple II wants to send a byte to us first - if in_write.Read() == gpio.Low { - out_write.Out(gpio.High) - return errors.New("Can't write byte while byte is incoming") - } - - // wait for the Apple II to be ready to read - for in_read.Read() == gpio.High { - if !in_read.WaitForEdge(edgeTimeout) { - out_write.Out(gpio.High) - return errors.New("Timed out writing byte -- read stuck high") - } - } - - bit7 := gpio.Low - bit6 := gpio.Low - bit5 := gpio.Low - bit4 := gpio.Low - bit3 := gpio.Low - bit2 := gpio.Low - bit1 := gpio.Low - bit0 := gpio.Low - - if ((data & 128) >> 7) == 1 { - bit7 = gpio.High - } - out_bit7.Out(bit7) - - if ((data & 64) >> 6) == 1 { - bit6 = gpio.High - } - out_bit6.Out(bit6) - - if ((data & 32) >> 5) == 1 { - bit5 = gpio.High - } - out_bit5.Out(bit5) - - if ((data & 16) >> 4) == 1 { - bit4 = gpio.High - } - out_bit4.Out(bit4) - - if ((data & 8) >> 3) == 1 { - bit3 = gpio.High - } - out_bit3.Out(bit3) - - if ((data & 4) >> 2) == 1 { - bit2 = gpio.High - } - out_bit2.Out(bit2) - - if ((data & 2) >> 1) == 1 { - bit1 = gpio.High - } - out_bit1.Out(bit1) - - if (data & 1) == 1 { - bit0 = gpio.High - } - out_bit0.Out(bit0) - - // let Apple II know we're writing - out_write.Out(gpio.Low) - - // wait for the Apple II to finsih reading - //fmt.Printf("wait for the Apple II to finsih reading\n") - for in_read.Read() == gpio.Low { - if !in_read.WaitForEdge(edgeTimeout) { - out_write.Out(gpio.High) - return errors.New("Timed out writing byte -- read stuck low") - } - } - - // let the Apple II know we are done writing - out_write.Out(gpio.High) - return nil -} - -func WriteBlock(buffer []byte) error { - for i := 0; i < 512; i++ { - err := WriteByte(buffer[i]) - if err != nil { - return err - } - } - - return nil -} - -func ReadBlock(buffer []byte) error { - var err error - for i := 0; i < 512; i++ { - buffer[i], err = ReadByte() - if err != nil { - return err - } - } - - return nil -} - -func WriteBuffer(buffer []byte) error { - bufferSize := len(buffer) - for i := 0; i < bufferSize; i++ { - err := WriteByte(buffer[i]) - if err != nil { - return err - } - } - - return nil +type A2Comm struct { + A2Io A2Io } diff --git a/RaspberryPi/apple2driver/a2io/gpio.go b/RaspberryPi/apple2driver/a2io/gpio.go new file mode 100644 index 0000000..d0fed12 --- /dev/null +++ b/RaspberryPi/apple2driver/a2io/gpio.go @@ -0,0 +1,295 @@ +package a2io + +import ( + "bytes" + "errors" + "fmt" + "time" + + "periph.io/x/periph/conn/gpio" + "periph.io/x/periph/conn/gpio/gpioreg" + "periph.io/x/periph/host" +) + +var edgeTimeout time.Duration + +var out_write gpio.PinIO +var out_read gpio.PinIO +var out_reserved2 gpio.PinIO +var out_reserved1 gpio.PinIO +var out_bit7 gpio.PinIO +var out_bit6 gpio.PinIO +var out_bit5 gpio.PinIO +var out_bit4 gpio.PinIO +var out_bit3 gpio.PinIO +var out_bit2 gpio.PinIO +var out_bit1 gpio.PinIO +var out_bit0 gpio.PinIO +var in_write gpio.PinIO +var in_read gpio.PinIO +var in_reserved2 gpio.PinIO +var in_reserved1 gpio.PinIO +var in_bit7 gpio.PinIO +var in_bit6 gpio.PinIO +var in_bit5 gpio.PinIO +var in_bit4 gpio.PinIO +var in_bit3 gpio.PinIO +var in_bit2 gpio.PinIO +var in_bit1 gpio.PinIO +var in_bit0 gpio.PinIO + +type A2Gpio struct { +} + +func (a2 A2Gpio) Init() { + host.Init() + + out_write = gpioreg.ByName("GPIO24") + out_read = gpioreg.ByName("GPIO25") + out_reserved2 = gpioreg.ByName("GPIO7") //note GPIO7 and CPIO8 require extra effort to use + out_reserved1 = gpioreg.ByName("GPIO8") + out_bit7 = gpioreg.ByName("GPIO5") + out_bit6 = gpioreg.ByName("GPIO11") + out_bit5 = gpioreg.ByName("GPIO9") + out_bit4 = gpioreg.ByName("GPIO10") + out_bit3 = gpioreg.ByName("GPIO22") + out_bit2 = gpioreg.ByName("GPIO27") + out_bit1 = gpioreg.ByName("GPIO17") + out_bit0 = gpioreg.ByName("GPIO4") + in_write = gpioreg.ByName("GPIO23") + in_read = gpioreg.ByName("GPIO18") + in_reserved2 = gpioreg.ByName("GPIO14") + in_reserved1 = gpioreg.ByName("GPIO15") + in_bit7 = gpioreg.ByName("GPIO12") + in_bit6 = gpioreg.ByName("GPIO16") + in_bit5 = gpioreg.ByName("GPIO20") + in_bit4 = gpioreg.ByName("GPIO21") + in_bit3 = gpioreg.ByName("GPIO26") + in_bit2 = gpioreg.ByName("GPIO19") + in_bit1 = gpioreg.ByName("GPIO13") + in_bit0 = gpioreg.ByName("GPIO6") + + in_write.In(gpio.PullDown, gpio.BothEdges) + in_read.In(gpio.PullDown, gpio.BothEdges) + out_reserved1.Out(gpio.High) + out_reserved2.Out(gpio.High) + out_read.Out(gpio.High) + out_write.Out(gpio.High) + out_bit7.Out(gpio.Low) + out_bit6.Out(gpio.Low) + out_bit5.Out(gpio.Low) + out_bit4.Out(gpio.Low) + out_bit3.Out(gpio.Low) + out_bit2.Out(gpio.Low) + out_bit1.Out(gpio.Low) + out_bit0.Out(gpio.Low) + + edgeTimeout = time.Second +} + +func (a2 A2Gpio) 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 string(inBytes.Bytes()), nil +} + +func (a2 A2Gpio) 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 +} + +func (a2 A2Gpio) ReadByte() (byte, error) { + // let the Apple II know we are ready to read + out_read.Out(gpio.Low) + + // wait for the Apple II to write + for in_write.Read() == gpio.High { + if !in_write.WaitForEdge(edgeTimeout) { + out_read.Out(gpio.High) + return 0, errors.New("Timed out reading byte -- write stuck high\n") + } + } + + // get a nibble of data + var data byte + data = 0 + bit7 := in_bit7.Read() + bit6 := in_bit6.Read() + bit5 := in_bit5.Read() + bit4 := in_bit4.Read() + bit3 := in_bit3.Read() + bit2 := in_bit2.Read() + bit1 := in_bit1.Read() + bit0 := in_bit0.Read() + + if bit7 == gpio.High { + data += 128 + } + if bit6 == gpio.High { + data += 64 + } + if bit5 == gpio.High { + data += 32 + } + if bit4 == gpio.High { + data += 16 + } + if bit3 == gpio.High { + data += 8 + } + if bit2 == gpio.High { + data += 4 + } + if bit1 == gpio.High { + data += 2 + } + if bit0 == gpio.High { + data += 1 + } + + // let the Apple II know we are done reading + //fmt.Printf("let the Apple II know we are done reading\n") + out_read.Out(gpio.High) + + // wait for the Apple II to finish writing + //fmt.Printf("wait for the Apple II to finish writing\n") + for in_write.Read() == gpio.Low { + if !in_write.WaitForEdge(edgeTimeout) { + return 0, errors.New("Timed out reading byte -- write stuck low") + } + } + + return data, nil +} + +func (a2 A2Gpio) WriteByte(data byte) error { + // check if the Apple II wants to send a byte to us first + if in_write.Read() == gpio.Low { + out_write.Out(gpio.High) + return errors.New("Can't write byte while byte is incoming") + } + + // wait for the Apple II to be ready to read + for in_read.Read() == gpio.High { + if !in_read.WaitForEdge(edgeTimeout) { + out_write.Out(gpio.High) + return errors.New("Timed out writing byte -- read stuck high") + } + } + + bit7 := gpio.Low + bit6 := gpio.Low + bit5 := gpio.Low + bit4 := gpio.Low + bit3 := gpio.Low + bit2 := gpio.Low + bit1 := gpio.Low + bit0 := gpio.Low + + if ((data & 128) >> 7) == 1 { + bit7 = gpio.High + } + out_bit7.Out(bit7) + + if ((data & 64) >> 6) == 1 { + bit6 = gpio.High + } + out_bit6.Out(bit6) + + if ((data & 32) >> 5) == 1 { + bit5 = gpio.High + } + out_bit5.Out(bit5) + + if ((data & 16) >> 4) == 1 { + bit4 = gpio.High + } + out_bit4.Out(bit4) + + if ((data & 8) >> 3) == 1 { + bit3 = gpio.High + } + out_bit3.Out(bit3) + + if ((data & 4) >> 2) == 1 { + bit2 = gpio.High + } + out_bit2.Out(bit2) + + if ((data & 2) >> 1) == 1 { + bit1 = gpio.High + } + out_bit1.Out(bit1) + + if (data & 1) == 1 { + bit0 = gpio.High + } + out_bit0.Out(bit0) + + // let Apple II know we're writing + out_write.Out(gpio.Low) + + // wait for the Apple II to finsih reading + //fmt.Printf("wait for the Apple II to finsih reading\n") + for in_read.Read() == gpio.Low { + if !in_read.WaitForEdge(edgeTimeout) { + out_write.Out(gpio.High) + return errors.New("Timed out writing byte -- read stuck low") + } + } + + // let the Apple II know we are done writing + out_write.Out(gpio.High) + return nil +} + +func (a2 A2Gpio) WriteBlock(buffer []byte) error { + for i := 0; i < 512; i++ { + err := a2.WriteByte(buffer[i]) + if err != nil { + return err + } + } + + return nil +} + +func (a2 A2Gpio) 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 +} + +func (a2 A2Gpio) WriteBuffer(buffer []byte) error { + bufferSize := len(buffer) + for i := 0; i < bufferSize; i++ { + err := a2.WriteByte(buffer[i]) + if err != nil { + return err + } + } + + return nil +} diff --git a/RaspberryPi/apple2driver/a2io/mockio.go b/RaspberryPi/apple2driver/a2io/mockio.go new file mode 100644 index 0000000..0b93ee4 --- /dev/null +++ b/RaspberryPi/apple2driver/a2io/mockio.go @@ -0,0 +1,85 @@ +package a2io + +import ( + "errors" + "strings" +) + +type MockIoData struct { + BytesToRead []byte + BytesWritten []byte + byteRead int + byteWritten int + ErrorToThrow error +} + +type MockIo struct { + Data *MockIoData +} + +func (mockIo MockIo) Init() { + +} + +func (mockIo MockIo) WriteByte(data byte) error { + mockIo.Data.BytesWritten[mockIo.Data.byteWritten] = data + mockIo.Data.byteWritten++ + return mockIo.Data.ErrorToThrow +} + +func (mockIo MockIo) WriteString(outString string) error { + for i, b := range outString { + mockIo.Data.BytesWritten[i+mockIo.Data.byteWritten] = byte(b) + } + mockIo.Data.byteWritten += len(outString) + return mockIo.Data.ErrorToThrow +} + +func (mockIo MockIo) WriteBlock(buffer []byte) error { + for i, b := range buffer { + mockIo.Data.BytesWritten[i+mockIo.Data.byteWritten] = b + } + mockIo.Data.byteWritten += len(buffer) + return mockIo.Data.ErrorToThrow +} + +func (mockIo MockIo) WriteBuffer(buffer []byte) error { + for i, b := range buffer { + mockIo.Data.BytesWritten[i+mockIo.Data.byteWritten] = b + } + mockIo.Data.byteWritten += len(buffer) + return mockIo.Data.ErrorToThrow +} + +func (mockIo MockIo) ReadByte() (byte, error) { + b := mockIo.Data.BytesToRead[mockIo.Data.byteRead] + mockIo.Data.byteRead++ + return b, mockIo.Data.ErrorToThrow +} + +func (mockIo MockIo) ReadString() (string, error) { + builder := strings.Builder{} + for { + if mockIo.Data.byteRead > len(mockIo.Data.BytesToRead) { + return "", errors.New("Read more data than available") + } + builder.WriteByte(mockIo.Data.BytesToRead[mockIo.Data.byteRead]) + mockIo.Data.byteRead++ + if mockIo.Data.BytesToRead[mockIo.Data.byteRead] == 0 { + mockIo.Data.byteRead++ + break + } + } + return builder.String(), mockIo.Data.ErrorToThrow +} + +func (mockIo MockIo) ReadBlock(buffer []byte) error { + if mockIo.Data.byteRead+512 > len(mockIo.Data.BytesToRead) { + return errors.New("Read more data than available") + } + for i := 0; i < 512; i++ { + buffer[i] = mockIo.Data.BytesToRead[mockIo.Data.byteRead] + mockIo.Data.byteRead++ + } + return mockIo.Data.ErrorToThrow +} diff --git a/RaspberryPi/apple2driver/driver.go b/RaspberryPi/apple2driver/driver.go index 2137888..beac08c 100644 --- a/RaspberryPi/apple2driver/driver.go +++ b/RaspberryPi/apple2driver/driver.go @@ -24,10 +24,13 @@ func main() { fmt.Printf("Starting Apple II RPi...\n") - a2io.InitGpio() + comm := a2io.A2Gpio{} + + handlers.SetCommunication(comm) + comm.Init() for { - command, err := a2io.ReadByte() + command, err := comm.ReadByte() if err == nil { switch command { case ReadBlockCommand: diff --git a/RaspberryPi/apple2driver/handlers/block.go b/RaspberryPi/apple2driver/handlers/block.go new file mode 100644 index 0000000..77d2c5d --- /dev/null +++ b/RaspberryPi/apple2driver/handlers/block.go @@ -0,0 +1,78 @@ +package handlers + +import ( + "fmt" + "os" + + "github.com/tjboldt/ProDOS-Utilities/prodos" +) + +var oldFirmware = false + +func ReadBlockCommand(drive1 *os.File, drive2 *os.File) { + blockLow, _ := comm.ReadByte() + blockHigh, _ := comm.ReadByte() + var driveUnit byte = 0 + var err error + + if !oldFirmware { + driveUnit, err = comm.ReadByte() + fmt.Printf("Drive unit: %0X\n", driveUnit) + + if err != nil { + fmt.Printf("Drive unit not sent, assuming older firmware") + oldFirmware = true + } + } + + file := drive1 + + if driveUnit >= 128 { + file = drive2 + } + + block := int(blockHigh)*256 + int(blockLow) + + fmt.Printf("Read block %d\n", block) + + buffer := prodos.ReadBlock(file, block) + + err = comm.WriteBlock(buffer) + if err == nil { + fmt.Printf("Read block completed\n") + } else { + fmt.Printf("Failed to read block\n") + } +} + +func WriteBlockCommand(drive1 *os.File, drive2 *os.File) { + blockLow, _ := comm.ReadByte() + blockHigh, _ := comm.ReadByte() + + var driveUnit byte = 0 + var err error + + if !oldFirmware { + driveUnit, err = comm.ReadByte() + if err != nil { + fmt.Printf("Drive unit not sent, assuming older firmware") + oldFirmware = true + } + } + + file := drive1 + + if driveUnit >= 128 { + file = drive2 + } + + buffer := make([]byte, 512) + + block := int(blockHigh)*256 + int(blockLow) + + fmt.Printf("Write block %d\n", block) + + comm.ReadBlock(buffer) + prodos.WriteBlock(file, block, buffer) + fmt.Printf("Write block completed\n") +} diff --git a/RaspberryPi/apple2driver/handlers/communication.go b/RaspberryPi/apple2driver/handlers/communication.go new file mode 100644 index 0000000..f19b248 --- /dev/null +++ b/RaspberryPi/apple2driver/handlers/communication.go @@ -0,0 +1,11 @@ +package handlers + +import ( + "github.com/tjboldt/Apple2-IO-RPi/RaspberryPi/apple2driver/a2io" +) + +var comm a2io.A2Io + +func SetCommunication(commIO a2io.A2Io) { + comm = commIO +} diff --git a/RaspberryPi/apple2driver/handlers/exec.go b/RaspberryPi/apple2driver/handlers/exec.go index 67c6862..9a8a997 100644 --- a/RaspberryPi/apple2driver/handlers/exec.go +++ b/RaspberryPi/apple2driver/handlers/exec.go @@ -7,8 +7,6 @@ import ( "os" "os/exec" "strings" - - "github.com/tjboldt/Apple2-IO-RPi/RaspberryPi/apple2driver/a2io" ) var forceLowercase = false @@ -17,11 +15,11 @@ func ExecCommand() { workingDirectory, err := os.Getwd() if err != nil { workingDirectory = "/home" - a2io.WriteString("Failed to get current working directory, setting to /home\r") + comm.WriteString("Failed to get current working directory, setting to /home\r") } fmt.Printf("Reading command to execute...\n") - linuxCommand, err := a2io.ReadString() + linuxCommand, err := comm.ReadString() if forceLowercase { linuxCommand = strings.ToLower(linuxCommand) } @@ -30,10 +28,10 @@ func ExecCommand() { workingDirectory = strings.Replace(linuxCommand, "cd ", "", 1) err = os.Chdir(workingDirectory) if err != nil { - a2io.WriteString("Failed to set working directory\r") + comm.WriteString("Failed to set working directory\r") return } - a2io.WriteString("Working directory set\r") + comm.WriteString("Working directory set\r") return } if linuxCommand == "a2help" { @@ -68,14 +66,14 @@ func execCommand(linuxCommand string, workingDirectory string) { if err != nil { fmt.Printf("Failed to set stdout\n") - a2io.WriteString("Failed to set stdout\r") + comm.WriteString("Failed to set stdout\r") return } fmt.Printf("Command output:\n") err = cmd.Start() if err != nil { fmt.Printf("Failed to start command\n") - a2io.WriteString("Failed to start command\r") + comm.WriteString("Failed to start command\r") return } @@ -98,12 +96,12 @@ func execCommand(linuxCommand string, workingDirectory string) { case <-outputComplete: outputComplete <- true case <-userCancelled: - a2io.WriteString("^C\r") + comm.WriteString("^C\r") cmd.Process.Kill() return case <-inputComplete: cmd.Wait() - a2io.WriteByte(0) + comm.WriteByte(0) return default: } @@ -173,7 +171,7 @@ func getStdin(stdin io.WriteCloser, done chan bool, inputComplete chan bool, use inputComplete <- true return default: - b, err := a2io.ReadByte() + b, err := comm.ReadByte() if err == nil { if b == 3 { stdin.Close() @@ -192,7 +190,7 @@ func getStdin(stdin io.WriteCloser, done chan bool, inputComplete chan bool, use } func a2help() { - a2io.WriteString("\r" + + comm.WriteString("\r" + "This is a pseudo shell. Each command is executed as a process. The cd command\r" + "is intercepted and sets the working directory for the next command.\r" + "\r" + @@ -205,11 +203,11 @@ func a2help() { func a2lower() { forceLowercase = true - a2io.WriteString("All commands will be converted to lowercase\r") + comm.WriteString("All commands will be converted to lowercase\r") } func a2wifi() { - a2io.WriteString("\r" + + comm.WriteString("\r" + "Usage: a2wifi list\r" + " a2wifi select SSID PASSWORD\r" + "\r") @@ -222,7 +220,7 @@ func a2wifiList() string { func a2wifiSelect(linuxCommand string) (string, error) { params := strings.Fields(linuxCommand) if len(params) != 4 { - a2io.WriteString("\rIncorrect number of parameters. Usage: a2wifi select SSID PASSWORD\r\r") + comm.WriteString("\rIncorrect number of parameters. Usage: a2wifi select SSID PASSWORD\r\r") return "", errors.New("Incorrect number of parameters. Usage: a2wifi select SSID PASSWORD") } ssid := params[2] @@ -244,8 +242,8 @@ func sendCharacter(b byte) { if b == 9 { // convert TAB to spaces b = ' ' b += 128 - a2io.WriteByte(b) + comm.WriteByte(b) } b |= 128 - a2io.WriteByte(b) + comm.WriteByte(b) } diff --git a/RaspberryPi/apple2driver/handlers/getTime.go b/RaspberryPi/apple2driver/handlers/getTime.go index 004c5d2..bd62193 100644 --- a/RaspberryPi/apple2driver/handlers/getTime.go +++ b/RaspberryPi/apple2driver/handlers/getTime.go @@ -4,7 +4,6 @@ import ( "fmt" "time" - "github.com/tjboldt/Apple2-IO-RPi/RaspberryPi/apple2driver/a2io" "github.com/tjboldt/ProDOS-Utilities/prodos" ) @@ -13,7 +12,7 @@ func GetTimeCommand() { prodosTime := prodos.DateTimeToProDOS(time.Now()) for i := 0; i < len(prodosTime); i++ { - a2io.WriteByte(prodosTime[i]) + comm.WriteByte(prodosTime[i]) } fmt.Printf("Send time complete\n") diff --git a/RaspberryPi/apple2driver/handlers/loadFile.go b/RaspberryPi/apple2driver/handlers/loadFile.go index dd4e140..8686d41 100644 --- a/RaspberryPi/apple2driver/handlers/loadFile.go +++ b/RaspberryPi/apple2driver/handlers/loadFile.go @@ -3,18 +3,16 @@ package handlers import ( "fmt" "os" - - "github.com/tjboldt/Apple2-IO-RPi/RaspberryPi/apple2driver/a2io" ) func LoadFileCommand() { - fileName, _ := a2io.ReadString() + fileName, _ := comm.ReadString() file, err := os.OpenFile(fileName, os.O_RDWR, 0755) if err != nil { fmt.Printf("ERROR: %s\n", err.Error()) - a2io.WriteByte(0) - a2io.WriteByte(0) + comm.WriteByte(0) + comm.WriteByte(0) return } @@ -26,11 +24,11 @@ func LoadFileCommand() { fileSizeHigh := byte(fileSize >> 8) fileSizeLow := byte(fileSize & 255) - err = a2io.WriteByte(fileSizeLow) + err = comm.WriteByte(fileSizeLow) if err != nil { return } - err = a2io.WriteByte(fileSizeHigh) + err = comm.WriteByte(fileSizeHigh) if err != nil { return } @@ -41,5 +39,5 @@ func LoadFileCommand() { file.Read(buffer) - a2io.WriteBuffer(buffer) + comm.WriteBuffer(buffer) } diff --git a/RaspberryPi/apple2driver/handlers/loadFile_test.go b/RaspberryPi/apple2driver/handlers/loadFile_test.go new file mode 100644 index 0000000..5d8c435 --- /dev/null +++ b/RaspberryPi/apple2driver/handlers/loadFile_test.go @@ -0,0 +1,26 @@ +package handlers + +import ( + "testing" + + "github.com/tjboldt/Apple2-IO-RPi/RaspberryPi/apple2driver/a2io" +) + +func TestLoadFileCommandReturnZeroLengthOnFileNotFound(t *testing.T) { + mockIoData := a2io.MockIoData{ + BytesToRead: []byte("FILE_DOES_NOT_EXIST\x00"), + BytesWritten: make([]byte, 1000), + } + + mockIo := a2io.MockIo{Data: &mockIoData} + + SetCommunication(&mockIo) + + LoadFileCommand() + + got := mockIoData.BytesWritten + + if got[0] != 0 && got[1] != 0 { + t.Errorf("MenuCommand() sent = %s; want 00", got) + } +} diff --git a/RaspberryPi/apple2driver/handlers/menu.go b/RaspberryPi/apple2driver/handlers/menu.go index 8e4fca1..afe1262 100755 --- a/RaspberryPi/apple2driver/handlers/menu.go +++ b/RaspberryPi/apple2driver/handlers/menu.go @@ -2,13 +2,11 @@ package handlers import ( "fmt" - - "github.com/tjboldt/Apple2-IO-RPi/RaspberryPi/apple2driver/a2io" ) func MenuCommand() { fmt.Printf("Sending menu...\n") - a2io.WriteString("Apple2-IO-RPi\r" + + comm.WriteString("Apple2-IO-RPi\r" + "(c)2020-2021 Terence J. Boldt\r" + "\r" + "Select an option:\r" + diff --git a/RaspberryPi/apple2driver/handlers/menu_test.go b/RaspberryPi/apple2driver/handlers/menu_test.go new file mode 100644 index 0000000..a87b898 --- /dev/null +++ b/RaspberryPi/apple2driver/handlers/menu_test.go @@ -0,0 +1,28 @@ +package handlers + +import ( + "strings" + "testing" + + "github.com/tjboldt/Apple2-IO-RPi/RaspberryPi/apple2driver/a2io" +) + +func TestMenuCommand(t *testing.T) { + mockIoData := a2io.MockIoData{ + ErrorToThrow: nil, + BytesWritten: make([]byte, 1000), + } + + mockIo := a2io.MockIo{Data: &mockIoData} + + SetCommunication(&mockIo) + + MenuCommand() + + want := "Apple2-IO-RPi" + got := string(mockIoData.BytesWritten) + + if strings.Index(got, want) != 0 { + t.Errorf("MenuCommand() sent = %s; want startsWith %s", got, want) + } +} diff --git a/RaspberryPi/apple2driver/handlers/readBlock.go b/RaspberryPi/apple2driver/handlers/readBlock.go deleted file mode 100644 index ab84b8b..0000000 --- a/RaspberryPi/apple2driver/handlers/readBlock.go +++ /dev/null @@ -1,48 +0,0 @@ -package handlers - -import ( - "fmt" - "os" - - "github.com/tjboldt/Apple2-IO-RPi/RaspberryPi/apple2driver/a2io" - "github.com/tjboldt/ProDOS-Utilities/prodos" -) - -var oldFirmware = false - -func ReadBlockCommand(drive1 *os.File, drive2 *os.File) { - blockLow, _ := a2io.ReadByte() - blockHigh, _ := a2io.ReadByte() - var driveUnit byte = 0 - var err error - - if !oldFirmware { - driveUnit, err = a2io.ReadByte() - fmt.Printf("Drive unit: %0X\n", driveUnit) - - if err != nil { - fmt.Printf("Drive unit not sent, assuming older firmware") - oldFirmware = true - } - } - - file := drive1 - - if driveUnit >= 128 { - file = drive2 - } - - var block int - block = int(blockHigh)*256 + int(blockLow) - - fmt.Printf("Read block %d\n", block) - - buffer := prodos.ReadBlock(file, block) - - err = a2io.WriteBlock(buffer) - if err == nil { - fmt.Printf("Read block completed\n") - } else { - fmt.Printf("Failed to read block\n") - } -} diff --git a/RaspberryPi/apple2driver/handlers/writeBlock.go b/RaspberryPi/apple2driver/handlers/writeBlock.go deleted file mode 100644 index f5b92e7..0000000 --- a/RaspberryPi/apple2driver/handlers/writeBlock.go +++ /dev/null @@ -1,41 +0,0 @@ -package handlers - -import ( - "fmt" - "os" - - "github.com/tjboldt/Apple2-IO-RPi/RaspberryPi/apple2driver/a2io" - "github.com/tjboldt/ProDOS-Utilities/prodos" -) - -func WriteBlockCommand(drive1 *os.File, drive2 *os.File) { - blockLow, _ := a2io.ReadByte() - blockHigh, _ := a2io.ReadByte() - - var driveUnit byte = 0 - var err error - - if !oldFirmware { - driveUnit, err = a2io.ReadByte() - if err != nil { - fmt.Printf("Drive unit not sent, assuming older firmware") - oldFirmware = true - } - } - - file := drive1 - - if driveUnit >= 128 { - file = drive2 - } - - buffer := make([]byte, 512) - var block int - block = int(blockHigh)*256 + int(blockLow) - - fmt.Printf("Write block %d\n", block) - - a2io.ReadBlock(buffer) - prodos.WriteBlock(file, block, buffer) - fmt.Printf("Write block completed\n") -}