diff --git a/Apple2/AT28C64B.bin b/Apple2/AT28C64B.bin index 00bf3da..26928c7 100644 Binary files a/Apple2/AT28C64B.bin and b/Apple2/AT28C64B.bin differ diff --git a/Apple2/CommandFirmware.asm b/Apple2/CommandFirmware.asm index 18dd4d2..fd3c0ed 100644 --- a/Apple2/CommandFirmware.asm +++ b/Apple2/CommandFirmware.asm @@ -27,6 +27,9 @@ MenuCommand = $08 InputString = $fd67 PrintChar = $fded +Keyboard = $c000 +ClearKeyboard = $c010 +Wait = $fca8 .org SLOT*$100 + $C000 ;ID bytes for booting and drive detection @@ -79,6 +82,7 @@ GetCommand: bcc GetCommand SendCommand: + bit ClearKeyboard lda #$05 ;send command 5 = exec jsr SendByte ldy #$00 @@ -98,6 +102,12 @@ DumpOutput: cmp #$00 beq endOutput jsr PrintChar + bit Keyboard ;check for keypress + bpl DumpOutput ;keep dumping output if no keypress + lda Keyboard ;send keypress to RPi + and #$7f + jsr SendByte + bit ClearKeyboard clc bcc DumpOutput endOutput: @@ -132,7 +142,14 @@ GetByte: waitRead: lda InputFlags rol - bcs waitRead + bcc readByte + bit Keyboard ;keypress will abort waiting to read + bpl waitRead + lda #$1f ;set all flags high and exit + sta OutputFlags + lda #$ff + rts +readByte: lda InputByte pha lda #$1f ;set all flags high diff --git a/Apple2/CommandFirmware.lst b/Apple2/CommandFirmware.lst index dcf61eb..d4e2b7b 100644 --- a/Apple2/CommandFirmware.lst +++ b/Apple2/CommandFirmware.lst @@ -31,6 +31,9 @@ Current file: CommandFirmware.asm 000000r 1 000000r 1 InputString = $fd67 000000r 1 PrintChar = $fded +000000r 1 Keyboard = $c000 +000000r 1 ClearKeyboard = $c010 +000000r 1 Wait = $fca8 000000r 1 000000r 1 .org SLOT*$100 + $C000 00C700 1 ;ID bytes for booting and drive detection @@ -56,18 +59,18 @@ Current file: CommandFirmware.asm 00C719 1 Start: 00C719 1 20 00 C3 jsr $c300 ;enable 80 columns 00C71C 1 A9 05 lda #$05 ;execute command -00C71E 1 20 7D C7 jsr SendByte +00C71E 1 20 90 C7 jsr SendByte 00C721 1 A0 00 ldy #$00 00C723 1 sendHelp: -00C723 1 B9 76 C7 lda HelpCommand,y +00C723 1 B9 89 C7 lda HelpCommand,y 00C726 1 F0 06 beq endSendHelp -00C728 1 20 7D C7 jsr SendByte +00C728 1 20 90 C7 jsr SendByte 00C72B 1 C8 iny 00C72C 1 D0 F5 bne sendHelp 00C72E 1 endSendHelp: 00C72E 1 A9 00 lda #$00 -00C730 1 20 7D C7 jsr SendByte -00C733 1 20 68 C7 jsr DumpOutput +00C730 1 20 90 C7 jsr SendByte +00C733 1 20 6B C7 jsr DumpOutput 00C736 1 00C736 1 A5 33 lda $33 00C738 1 48 pha @@ -83,82 +86,88 @@ Current file: CommandFirmware.asm 00C74B 1 90 F0 bcc GetCommand 00C74D 1 00C74D 1 SendCommand: -00C74D 1 A9 05 lda #$05 ;send command 5 = exec -00C74F 1 20 7D C7 jsr SendByte -00C752 1 A0 00 ldy #$00 -00C754 1 getInput: -00C754 1 B9 00 02 lda $0200,y -00C757 1 C9 8D cmp #$8d -00C759 1 F0 08 beq sendNullTerminator -00C75B 1 29 7F and #$7f -00C75D 1 20 7D C7 jsr SendByte -00C760 1 C8 iny -00C761 1 D0 F1 bne getInput -00C763 1 sendNullTerminator: -00C763 1 A9 00 lda #$00 -00C765 1 20 7D C7 jsr SendByte -00C768 1 DumpOutput: -00C768 1 20 9B C7 jsr GetByte -00C76B 1 C9 00 cmp #$00 -00C76D 1 F0 06 beq endOutput -00C76F 1 20 ED FD jsr PrintChar -00C772 1 18 clc -00C773 1 90 F3 bcc DumpOutput -00C775 1 endOutput: -00C775 1 60 rts -00C776 1 -00C776 1 HelpCommand: -00C776 1 61 32 68 65 .byte "a2help",$00 -00C77A 1 6C 70 00 -00C77D 1 -00C77D 1 SendByte: -00C77D 1 48 pha -00C77E 1 waitWrite: -00C77E 1 AD FB C0 lda InputFlags -00C781 1 2A rol -00C782 1 2A rol -00C783 1 B0 F9 bcs waitWrite -00C785 1 68 pla -00C786 1 8D FD C0 sta OutputByte -00C789 1 A9 1E lda #$1e ; set bit 0 low to indicate write started -00C78B 1 8D F7 C0 sta OutputFlags -00C78E 1 finishWrite: -00C78E 1 AD FB C0 lda InputFlags -00C791 1 2A rol -00C792 1 2A rol -00C793 1 90 F9 bcc finishWrite -00C795 1 A9 1F lda #$1f -00C797 1 8D F7 C0 sta OutputFlags -00C79A 1 60 rts -00C79B 1 -00C79B 1 GetByte: -00C79B 1 A9 1D lda #$1d ;set read flag low -00C79D 1 8D F7 C0 sta OutputFlags -00C7A0 1 waitRead: -00C7A0 1 AD FB C0 lda InputFlags -00C7A3 1 2A rol -00C7A4 1 B0 FA bcs waitRead -00C7A6 1 AD FE C0 lda InputByte -00C7A9 1 48 pha -00C7AA 1 A9 1F lda #$1f ;set all flags high -00C7AC 1 8D F7 C0 sta OutputFlags -00C7AF 1 finishRead: -00C7AF 1 AD FB C0 lda InputFlags -00C7B2 1 2A rol -00C7B3 1 90 FA bcc finishRead -00C7B5 1 68 pla -00C7B6 1 end: -00C7B6 1 60 rts -00C7B7 1 -00C7B7 1 00 00 00 00 .repeat 251- /tmp/wpa_supplicant.conf; " + - "sudo mv /tmp/wpa_supplicant.conf /etc/wpa_supplicant/; " + - "sudo wpa_cli -i wlan0 reconfigure" + linuxCommand, err = a2wifiSelect(linuxCommand) } + if err == nil { + execCommand(linuxCommand, workingDirectory) + } +} + +func execCommand(linuxCommand string, workingDirectory string) { cmd := exec.Command("bash", "-c", linuxCommand) cmd.Dir = workingDirectory stdout, err := cmd.StdoutPipe() + stdin, err := cmd.StdinPipe() + if err != nil { fmt.Printf("Failed to set stdout\n") a2io.WriteString("Failed to set stdout\r") @@ -96,26 +78,127 @@ func ExecCommand() { return } - reader := bufio.NewReader(stdout) + outputComplete := make(chan bool) + inputComplete := make(chan bool) + userCancelled := make(chan bool) - for err == nil { - var b byte - b, err = reader.ReadByte() - if err == nil { + if linuxCommand == "openssl" { + fmt.Printf("\nSending help command...\n") + io.WriteString(stdin, "help\n") + } + + go getStdin(stdin, outputComplete, inputComplete, userCancelled) + go getStdout(stdout, outputComplete, userCancelled) + + for { + select { + case <-outputComplete: + outputComplete <- true + case <-userCancelled: + a2io.WriteString("^C\r") + cmd.Process.Kill() + return + case <-inputComplete: + cmd.Wait() + a2io.WriteByte(0) + return + default: + } + } +} + +func getStdout(stdout io.ReadCloser, done chan bool, userCancelled chan bool) { + for { + select { + case <-userCancelled: + stdout.Close() + return + default: + bb := make([]byte, 1) + n, err := stdout.Read(bb) + if err != nil || n == 0 { + stdout.Close() + done <- true + return + } + b := bb[0] fmt.Print(string(b)) if b == 10 { // convert LF to CR for Apple II compatiblity b = 13 } b |= 128 - err = a2io.WriteByte(b) - if err != nil { - fmt.Printf("\nFailed to write byte\n") - cmd.Process.Kill() - return + a2io.WriteByte(b) + } + } +} + +func getStdin(stdin io.WriteCloser, done chan bool, inputComplete chan bool, userCancelled chan bool) { + for { + select { + case <-done: + stdin.Close() + inputComplete <- true + return + default: + b, err := a2io.ReadByte() + if err == nil { + if b == 3 { + stdin.Close() + userCancelled <- true + return + } else { + if b == 13 { + b = 10 + } + fmt.Printf("%c", b) + io.WriteString(stdin, string(b)) + } } } } - - cmd.Wait() - a2io.WriteByte(0) +} + +func a2help() { + a2io.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" + + "Built-in commands:\r" + + "a2help - display this message\r" + + "a2wifi - set up wifi\r" + + "A2LOWER - force lowercase for II+\r" + + "\r") +} + +func a2lower() { + forceLowercase = true + a2io.WriteString("All commands will be converted to lowercase\r") +} + +func a2wifi() { + a2io.WriteString("\r" + + "Usage: a2wifi list\r" + + " a2wifi select SSID PASSWORD\r" + + "\r") +} + +func a2wifiList() string { + return "sudo iwlist wlan0 scanning | grep ESSID | sed s/.*ESSID://g | sed s/\\\"//g" +} + +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") + return "", errors.New("Incorrect number of parameters. Usage: a2wifi select SSID PASSWORD") + } + ssid := params[2] + psk := params[3] + linuxCommand = "printf \"country=ca\\nupdate_config=1\\nctrl_interface=/var/run/wpa_supplicant\\n\\nnetwork={\\n scan_ssid=1\\n ssid=\\\"%s\\\"\n psk=\\\"%s\\\"\\n}\\n\" " + + ssid + " " + + psk + " " + + " > /tmp/wpa_supplicant.conf; " + + "sudo mv /tmp/wpa_supplicant.conf /etc/wpa_supplicant/; " + + "sudo wpa_cli -i wlan0 reconfigure" + return linuxCommand, nil }