From 5910d66fa211dcc467d292707f09b28f6d95fe6e Mon Sep 17 00:00:00 2001 From: Terence Boldt Date: Thu, 25 Nov 2021 18:45:56 -0500 Subject: [PATCH] Auto boot with recovery and improved VT100 support (#45) * Improve vt100 support to make vim work * Fix home and add line clear * Auto boot with recovery --- Apple2/AT28C64B.bin | Bin 8192 -> 8192 bytes Apple2/MenuFirmware.asm | 55 ++-- Apple2/MenuFirmware.lst | 177 ++++++------ Apple2/Shell.asm | 48 +++- Apple2/Shell.bin | Bin 204 -> 266 bytes Apple2/Shell.lst | 252 ++++++++++-------- RaspberryPi/Apple2-IO-RPi.hdv | Bin 33553920 -> 33553920 bytes .../apple2driver/a2io/communication.go | 1 + RaspberryPi/apple2driver/a2io/gpio.go | 5 + RaspberryPi/apple2driver/a2io/mockio.go | 5 + RaspberryPi/apple2driver/a2io/userio.go | 5 + RaspberryPi/apple2driver/a2io/vt100.go | 172 ++++++++++-- RaspberryPi/apple2driver/driver.go | 6 + RaspberryPi/apple2driver/handlers/exec.go | 17 +- RaspberryPi/apple2driver/handlers/reset.go | 18 ++ RaspberryPi/apple2driver/handlers/shell.go | 9 +- 16 files changed, 513 insertions(+), 257 deletions(-) create mode 100755 RaspberryPi/apple2driver/handlers/reset.go diff --git a/Apple2/AT28C64B.bin b/Apple2/AT28C64B.bin index 6b17c9686b111a03eb601c8bf780a87b82a2d3a3..41aaea0a8d695a1edd41f4445e6ad6507c35a74a 100644 GIT binary patch delta 543 zcmZY1Eeb+G6oz5JU^UMDA3>|tdV?6mZRjFQw+I%~EpB0oxB$caPcXOyS0LC$@SHLp znDX-Rg{Nz~_BvrBF+R+=`t(!A=L;#G{Ph(BzL(;N>jL3t`5tc8Qk?L4VD6ZH$5#D~ zZU00Dgo=csghE24Lo5pgs6e=k?@r8Ncfbffv5@501+Y)C=rkdDbWDImOuW_ B9n}B; delta 447 zcmZ|GEeZlr6oz3zkWmcAJO4+M-C~>|uE7mhT!4AviNallO}k-!@8D7<2!hoC5BSyd zrnfwKmS?x68Pnlw*M?S`LhkC(sUR+%qxXbfgSmWYK5YB@Oq$xW+1uV**oQg(nJ=sa zD~U^m`CvX+Agltbh%1E!U;$VttOl!zYlVeiAy_1=0c(gGg+*WySS+jsYl&Nh#b7a5 ZBFup~VyCbKECEY}bzmKFr?3>v?0)2Vuu=d3 diff --git a/Apple2/MenuFirmware.asm b/Apple2/MenuFirmware.asm index c9fd19b..3ea237c 100644 --- a/Apple2/MenuFirmware.asm +++ b/Apple2/MenuFirmware.asm @@ -16,6 +16,7 @@ OutputByte = $c08d+SLOT*$10 InputFlags = $c08b+SLOT*$10 OutputFlags = $c087+SLOT*$10 +ResetCommand = $00 ReadBlockCommand = $01 WriteBlockCommand = $02 GetTimeCommand = $03 @@ -29,6 +30,11 @@ Wait = $fca8 PrintChar = $fded Home = $fc58 ReadChar = $fd0c +BasCalc = $fbc1 +htab = $24 +vtab = $25 +BasL = $28 +htab80 = $057b .org SLOT*$100 + $C000 ;ID bytes for booting and drive detection @@ -57,7 +63,10 @@ Start: sta $36 lda #$fd sta $37 - jsr Home ;clear screen and show menu options + ;jsr Home ;clear screen and show menu options + lda #$10 + sta vtab + jsr BasCalc ldy #$00 PrintString: lda Text,y @@ -70,36 +79,36 @@ PrintString: WaitForRPi: lda InputFlags rol - bcs OK + bcs Reset lda #$ff jsr Wait lda #'.'+$80 jsr PrintChar jmp WaitForRPi -OK: - jsr Home ;clear screen - - lda #MenuCommand ;request menu text from RPi - jsr SendByte - -DumpOutput: - jsr GetByte - cmp #$00 - beq GetChar +Reset: + lda #'_'|$80 jsr PrintChar - clc - bcc DumpOutput + lda #ResetCommand + jsr SendByte + lda #$88 + jsr PrintChar + lda #'.'|$80 + jsr PrintChar + jsr GetByte + beq Ok + jmp Reset -GetChar: - jsr ReadChar - sec ;subtract ascii "1" to get 0 - 3 from "1" to "4" - sbc #$b1 - asl ;put in top nibble as EPROM page - asl - asl - asl - ora #$0f ;set all flags high +Ok: + lda #$8D + jsr PrintChar + lda #'O'|$80 + jsr PrintChar + lda #'K'|$80 + jsr PrintChar + +Boot: + lda #$0f jmp PageJump SendByte: diff --git a/Apple2/MenuFirmware.lst b/Apple2/MenuFirmware.lst index db8acab..77276fa 100644 --- a/Apple2/MenuFirmware.lst +++ b/Apple2/MenuFirmware.lst @@ -20,6 +20,7 @@ Current file: MenuFirmware.asm 000000r 1 InputFlags = $c08b+SLOT*$10 000000r 1 OutputFlags = $c087+SLOT*$10 000000r 1 +000000r 1 ResetCommand = $00 000000r 1 ReadBlockCommand = $01 000000r 1 WriteBlockCommand = $02 000000r 1 GetTimeCommand = $03 @@ -33,6 +34,11 @@ Current file: MenuFirmware.asm 000000r 1 PrintChar = $fded 000000r 1 Home = $fc58 000000r 1 ReadChar = $fd0c +000000r 1 BasCalc = $fbc1 +000000r 1 htab = $24 +000000r 1 vtab = $25 +000000r 1 BasL = $28 +000000r 1 htab80 = $057b 000000r 1 000000r 1 .org SLOT*$100 + $C000 00C700 1 ;ID bytes for booting and drive detection @@ -61,95 +67,94 @@ Current file: MenuFirmware.asm 00C71B 1 85 36 sta $36 00C71D 1 A9 FD lda #$fd 00C71F 1 85 37 sta $37 -00C721 1 20 58 FC jsr Home ;clear screen and show menu options -00C724 1 A0 00 ldy #$00 -00C726 1 PrintString: -00C726 1 B9 BC C7 lda Text,y -00C729 1 F0 08 beq WaitForRPi -00C72B 1 09 80 ora #$80 -00C72D 1 20 ED FD jsr PrintChar -00C730 1 C8 iny -00C731 1 D0 F3 bne PrintString -00C733 1 -00C733 1 WaitForRPi: -00C733 1 AD FB C0 lda InputFlags -00C736 1 2A rol -00C737 1 B0 0D bcs OK -00C739 1 A9 FF lda #$ff -00C73B 1 20 A8 FC jsr Wait -00C73E 1 A9 AE lda #'.'+$80 -00C740 1 20 ED FD jsr PrintChar -00C743 1 4C 33 C7 jmp WaitForRPi -00C746 1 -00C746 1 OK: -00C746 1 20 58 FC jsr Home ;clear screen -00C749 1 -00C749 1 A9 08 lda #MenuCommand ;request menu text from RPi -00C74B 1 20 6A C7 jsr SendByte -00C74E 1 -00C74E 1 DumpOutput: -00C74E 1 20 88 C7 jsr GetByte -00C751 1 C9 00 cmp #$00 -00C753 1 F0 06 beq GetChar -00C755 1 20 ED FD jsr PrintChar -00C758 1 18 clc -00C759 1 90 F3 bcc DumpOutput -00C75B 1 -00C75B 1 GetChar: -00C75B 1 20 0C FD jsr ReadChar -00C75E 1 38 sec ;subtract ascii "1" to get 0 - 3 from "1" to "4" -00C75F 1 E9 B1 sbc #$b1 -00C761 1 0A asl ;put in top nibble as EPROM page -00C762 1 0A asl -00C763 1 0A asl -00C764 1 0A asl -00C765 1 09 0F ora #$0f ;set all flags high -00C767 1 4C 0E C7 jmp PageJump -00C76A 1 -00C76A 1 SendByte: -00C76A 1 48 pha -00C76B 1 waitWrite: -00C76B 1 AD FB C0 lda InputFlags -00C76E 1 2A rol -00C76F 1 2A rol -00C770 1 B0 F9 bcs waitWrite -00C772 1 68 pla -00C773 1 8D FD C0 sta OutputByte -00C776 1 A9 3E lda #$3e ; set bit 0 low to indicate write started -00C778 1 8D F7 C0 sta OutputFlags -00C77B 1 finishWrite: +00C721 1 ;jsr Home ;clear screen and show menu options +00C721 1 A9 10 lda #$10 +00C723 1 85 25 sta vtab +00C725 1 20 C1 FB jsr BasCalc +00C728 1 A0 00 ldy #$00 +00C72A 1 PrintString: +00C72A 1 B9 BC C7 lda Text,y +00C72D 1 F0 08 beq WaitForRPi +00C72F 1 09 80 ora #$80 +00C731 1 20 ED FD jsr PrintChar +00C734 1 C8 iny +00C735 1 D0 F3 bne PrintString +00C737 1 +00C737 1 WaitForRPi: +00C737 1 AD FB C0 lda InputFlags +00C73A 1 2A rol +00C73B 1 B0 0D bcs Reset +00C73D 1 A9 FF lda #$ff +00C73F 1 20 A8 FC jsr Wait +00C742 1 A9 AE lda #'.'+$80 +00C744 1 20 ED FD jsr PrintChar +00C747 1 4C 37 C7 jmp WaitForRPi +00C74A 1 +00C74A 1 Reset: +00C74A 1 A9 DF lda #'_'|$80 +00C74C 1 20 ED FD jsr PrintChar +00C74F 1 A9 00 lda #ResetCommand +00C751 1 20 7A C7 jsr SendByte +00C754 1 A9 88 lda #$88 +00C756 1 20 ED FD jsr PrintChar +00C759 1 A9 AE lda #'.'|$80 +00C75B 1 20 ED FD jsr PrintChar +00C75E 1 20 98 C7 jsr GetByte +00C761 1 F0 03 beq Ok +00C763 1 4C 4A C7 jmp Reset +00C766 1 +00C766 1 Ok: +00C766 1 A9 8D lda #$8D +00C768 1 20 ED FD jsr PrintChar +00C76B 1 A9 CF lda #'O'|$80 +00C76D 1 20 ED FD jsr PrintChar +00C770 1 A9 CB lda #'K'|$80 +00C772 1 20 ED FD jsr PrintChar +00C775 1 +00C775 1 Boot: +00C775 1 A9 0F lda #$0f +00C777 1 4C 0E C7 jmp PageJump +00C77A 1 +00C77A 1 SendByte: +00C77A 1 48 pha +00C77B 1 waitWrite: 00C77B 1 AD FB C0 lda InputFlags 00C77E 1 2A rol 00C77F 1 2A rol -00C780 1 90 F9 bcc finishWrite -00C782 1 A9 3F lda #$3f -00C784 1 8D F7 C0 sta OutputFlags -00C787 1 60 rts -00C788 1 -00C788 1 GetByte: -00C788 1 A9 3D lda #$3d ;set read flag low -00C78A 1 8D F7 C0 sta OutputFlags -00C78D 1 waitRead: -00C78D 1 AD FB C0 lda InputFlags -00C790 1 2A rol -00C791 1 B0 FA bcs waitRead -00C793 1 AD FE C0 lda InputByte -00C796 1 48 pha -00C797 1 A9 3F lda #$3f ;set all flags high -00C799 1 8D F7 C0 sta OutputFlags -00C79C 1 finishRead: -00C79C 1 AD FB C0 lda InputFlags -00C79F 1 2A rol -00C7A0 1 90 FA bcc finishRead -00C7A2 1 68 pla -00C7A3 1 end: -00C7A3 1 60 rts -00C7A4 1 -00C7A4 1 00 00 00 00 .repeat 187-7npYA>*XS2dk4|A6!m4f6zP` z^1WypfH~ z;oxrsPYKAB0O|m#Q-%m1Q(X#GGqKQ1b8R)N*NU~F2PQDD4LPt;!?R(c29S}EXq1tf SQ^1gDR8W+kTTsFf+W-I;DovpP delta 153 zcmeBTI>T76z;IYc;J`{wg%Sk?euV^uNeUa}PBMJZJ?Zhm;AGeb^OMdWlum|xusP}U z!9n5eUmt!29fkt}H`X#7(5wgQ0qO+`B`8Gv0a8HCtt!3MtWc(^!olCI8c>cBlvW1P l9&3Le(9+uQGo$zK#HBWZiAEWzIRy-fMg>LrxdkN*u>eBFIIsW! diff --git a/Apple2/Shell.lst b/Apple2/Shell.lst index ea8c832..427d069 100644 --- a/Apple2/Shell.lst +++ b/Apple2/Shell.lst @@ -41,8 +41,15 @@ Current file: Shell.asm 000000r 1 Home = $fc58 000000r 1 Wait = $fca8 000000r 1 PromptChar = $33 +000000r 1 Read80Col = $c01f +000000r 1 TextPage1 = $c054 +000000r 1 TextPage2 = $c055 +000000r 1 000000r 1 htab = $24 000000r 1 vtab = $25 +000000r 1 BasL = $28 +000000r 1 htab80 = $057b +000000r 1 BasCalc = $fbc1 000000r 1 000000r 1 ESC = $9b 000000r 1 @@ -51,114 +58,147 @@ Current file: Shell.asm 002000 1 20 00 C3 jsr $c300 ; force 80 columns 002003 1 2C 10 C0 bit ClearKeyboard 002006 1 A9 09 lda #ShellCommand -002008 1 20 74 20 jsr SendByte +002008 1 20 9A 20 jsr SendByte 00200B 1 20 0F 20 jsr DumpOutput 00200E 1 60 rts 00200F 1 00200F 1 DumpOutput: -00200F 1 20 92 20 jsr GetByte -002012 1 B0 1E bcs checkInput +00200F 1 20 B8 20 jsr GetByte +002012 1 B0 2A bcs checkInput 002014 1 C9 00 cmp #$00 -002016 1 F0 2D beq endOutput -002018 1 C9 48 cmp #'H' -00201A 1 F0 30 beq setColumn -00201C 1 C9 56 cmp #'V' -00201E 1 F0 37 beq setRow -002020 1 C9 43 cmp #'C' -002022 1 F0 22 beq clearScreen -002024 1 C9 54 cmp #'T' -002026 1 F0 3C beq setTop -002028 1 C9 42 cmp #'B' -00202A 1 F0 40 beq setBottom -00202C 1 20 ED FD jsr PrintChar -00202F 1 4C 0F 20 jmp DumpOutput -002032 1 checkInput: -002032 1 2C 00 C0 bit Keyboard ;check for keypress -002035 1 10 D8 bpl DumpOutput ;keep dumping output if no keypress -002037 1 AD 00 C0 lda Keyboard ;send keypress to RPi -00203A 1 29 7F and #$7f -00203C 1 20 74 20 jsr SendByte -00203F 1 2C 10 C0 bit ClearKeyboard -002042 1 4C 0F 20 jmp DumpOutput -002045 1 endOutput: -002045 1 60 rts -002046 1 clearScreen: -002046 1 20 58 FC jsr Home -002049 1 4C 0F 20 jmp DumpOutput -00204C 1 setColumn: -00204C 1 20 92 20 jsr GetByte -00204F 1 85 24 sta htab -002051 1 8D 7B 05 sta $057B -002054 1 4C 0F 20 jmp DumpOutput -002057 1 setRow: -002057 1 20 92 20 jsr GetByte -00205A 1 85 25 sta vtab -00205C 1 20 C1 FB jsr $fbc1 ; bascalc -00205F 1 85 28 sta $28 ;basl -002061 1 4C 0F 20 jmp DumpOutput -002064 1 setTop: -002064 1 20 92 20 jsr GetByte -002067 1 85 22 sta $22 -002069 1 4C 0F 20 jmp DumpOutput -00206C 1 setBottom: -00206C 1 20 92 20 jsr GetByte -00206F 1 85 23 sta $23 -002071 1 4C 0F 20 jmp DumpOutput -002074 1 -002074 1 SendByte: -002074 1 48 pha -002075 1 waitWrite: -002075 1 AD FB C0 lda InputFlags -002078 1 2A rol -002079 1 2A rol -00207A 1 B0 F9 bcs waitWrite -00207C 1 68 pla -00207D 1 8D FD C0 sta OutputByte -002080 1 A9 1E lda #$1e ; set bit 0 low to indicate write started -002082 1 8D F7 C0 sta OutputFlags -002085 1 finishWrite: -002085 1 AD FB C0 lda InputFlags -002088 1 2A rol -002089 1 2A rol -00208A 1 90 F9 bcc finishWrite -00208C 1 A9 1F lda #$1f -00208E 1 8D F7 C0 sta OutputFlags -002091 1 60 rts -002092 1 -002092 1 GetByte: -002092 1 A9 1D lda #$1d ;set read flag low -002094 1 8D F7 C0 sta OutputFlags -002097 1 waitRead: -002097 1 AD FB C0 lda InputFlags -00209A 1 2A rol -00209B 1 90 0C bcc readByte -00209D 1 2C 00 C0 bit Keyboard ;keypress will abort waiting to read -0020A0 1 10 F5 bpl waitRead -0020A2 1 A9 1F lda #$1f ;set all flags high and exit -0020A4 1 8D F7 C0 sta OutputFlags -0020A7 1 38 sec ;failure -0020A8 1 60 rts -0020A9 1 readByte: -0020A9 1 AD FE C0 lda InputByte -0020AC 1 48 pha -0020AD 1 A9 1F lda #$1f ;set all flags high -0020AF 1 8D F7 C0 sta OutputFlags -0020B2 1 finishRead: -0020B2 1 AD FB C0 lda InputFlags -0020B5 1 2A rol -0020B6 1 90 FA bcc finishRead -0020B8 1 68 pla -0020B9 1 18 clc ;success -0020BA 1 end: -0020BA 1 60 rts -0020BB 1 -0020BB 1 HelpCommand: -0020BB 1 61 32 68 65 .byte "a2help",$00 -0020BF 1 6C 70 00 -0020C2 1 PromptCommand: -0020C2 1 61 32 70 72 .byte "a2prompt",$00 -0020C6 1 6F 6D 70 74 -0020CA 1 00 -0020CB 1 OldPromptChar: -0020CB 1 5D .byte "]" -0020CC 1 +002016 1 F0 39 beq endOutput +002018 1 48 pha +002019 1 20 E1 20 jsr InvertChar +00201C 1 68 pla +00201D 1 C9 48 cmp #'H' +00201F 1 F0 3A beq setColumn +002021 1 C9 56 cmp #'V' +002023 1 F0 44 beq setRow +002025 1 C9 43 cmp #'C' +002027 1 F0 29 beq clearScreen +002029 1 C9 54 cmp #'T' +00202B 1 F0 4A beq setTop +00202D 1 C9 42 cmp #'B' +00202F 1 F0 51 beq setBottom +002031 1 C9 55 cmp #'U' +002033 1 F0 58 beq moveUp +002035 1 20 ED FD jsr PrintChar +002038 1 20 E1 20 jsr InvertChar +00203B 1 4C 0F 20 jmp DumpOutput +00203E 1 checkInput: +00203E 1 2C 00 C0 bit Keyboard ;check for keypress +002041 1 10 CC bpl DumpOutput ;keep dumping output if no keypress +002043 1 AD 00 C0 lda Keyboard ;send keypress to RPi +002046 1 29 7F and #$7f +002048 1 20 9A 20 jsr SendByte +00204B 1 2C 10 C0 bit ClearKeyboard +00204E 1 4C 0F 20 jmp DumpOutput +002051 1 endOutput: +002051 1 60 rts +002052 1 clearScreen: +002052 1 20 58 FC jsr Home +002055 1 20 E1 20 jsr InvertChar +002058 1 4C 0F 20 jmp DumpOutput +00205B 1 setColumn: +00205B 1 20 B8 20 jsr GetByte +00205E 1 85 24 sta htab +002060 1 8D 7B 05 sta htab80 +002063 1 20 E1 20 jsr InvertChar +002066 1 4C 0F 20 jmp DumpOutput +002069 1 setRow: +002069 1 20 B8 20 jsr GetByte +00206C 1 85 25 sta vtab +00206E 1 20 C1 FB jsr BasCalc +002071 1 20 E1 20 jsr InvertChar +002074 1 4C 0F 20 jmp DumpOutput +002077 1 setTop: +002077 1 20 B8 20 jsr GetByte +00207A 1 85 22 sta $22 +00207C 1 20 E1 20 jsr InvertChar +00207F 1 4C 0F 20 jmp DumpOutput +002082 1 setBottom: +002082 1 20 B8 20 jsr GetByte +002085 1 85 23 sta $23 +002087 1 20 E1 20 jsr InvertChar +00208A 1 4C 0F 20 jmp DumpOutput +00208D 1 moveUp: +00208D 1 C6 25 dec vtab +00208F 1 A5 25 lda vtab +002091 1 20 C1 FB jsr BasCalc +002094 1 20 E1 20 jsr InvertChar +002097 1 4C 0F 20 jmp DumpOutput +00209A 1 +00209A 1 SendByte: +00209A 1 48 pha +00209B 1 waitWrite: +00209B 1 AD FB C0 lda InputFlags +00209E 1 2A rol +00209F 1 2A rol +0020A0 1 B0 F9 bcs waitWrite +0020A2 1 68 pla +0020A3 1 8D FD C0 sta OutputByte +0020A6 1 A9 1E lda #$1e ; set bit 0 low to indicate write started +0020A8 1 8D F7 C0 sta OutputFlags +0020AB 1 finishWrite: +0020AB 1 AD FB C0 lda InputFlags +0020AE 1 2A rol +0020AF 1 2A rol +0020B0 1 90 F9 bcc finishWrite +0020B2 1 A9 1F lda #$1f +0020B4 1 8D F7 C0 sta OutputFlags +0020B7 1 60 rts +0020B8 1 +0020B8 1 GetByte: +0020B8 1 A9 1D lda #$1d ;set read flag low +0020BA 1 8D F7 C0 sta OutputFlags +0020BD 1 waitRead: +0020BD 1 AD FB C0 lda InputFlags +0020C0 1 2A rol +0020C1 1 90 0C bcc readByte +0020C3 1 2C 00 C0 bit Keyboard ;keypress will abort waiting to read +0020C6 1 10 F5 bpl waitRead +0020C8 1 A9 1F lda #$1f ;set all flags high and exit +0020CA 1 8D F7 C0 sta OutputFlags +0020CD 1 38 sec ;failure +0020CE 1 60 rts +0020CF 1 readByte: +0020CF 1 AD FE C0 lda InputByte +0020D2 1 48 pha +0020D3 1 A9 1F lda #$1f ;set all flags high +0020D5 1 8D F7 C0 sta OutputFlags +0020D8 1 finishRead: +0020D8 1 AD FB C0 lda InputFlags +0020DB 1 2A rol +0020DC 1 90 FA bcc finishRead +0020DE 1 68 pla +0020DF 1 18 clc ;success +0020E0 1 end: +0020E0 1 60 rts +0020E1 1 +0020E1 1 InvertChar: +0020E1 1 AD 7B 05 lda htab80 ;get horizontal location / 2 +0020E4 1 4A lsr +0020E5 1 A8 tay +0020E6 1 AD 55 C0 lda TextPage2 +0020E9 1 90 03 bcc invert +0020EB 1 AD 54 C0 lda TextPage1 +0020EE 1 invert: +0020EE 1 B1 28 lda (BasL),y +0020F0 1 49 80 eor #$80 +0020F2 1 91 28 sta (BasL),y +0020F4 1 AD 54 C0 lda TextPage1 +0020F7 1 screen40: +0020F7 1 60 rts +0020F8 1 +0020F8 1 HelpCommand: +0020F8 1 61 32 68 65 .byte "a2help",$00 +0020FC 1 6C 70 00 +0020FF 1 PromptCommand: +0020FF 1 61 32 70 72 .byte "a2prompt",$00 +002103 1 6F 6D 70 74 +002107 1 00 +002108 1 OldPromptChar: +002108 1 5D .byte "]" +002109 1 DrawCursor: +002109 1 80 .byte $80 +002109 1 diff --git a/RaspberryPi/Apple2-IO-RPi.hdv b/RaspberryPi/Apple2-IO-RPi.hdv index 0089e928f335ebf751489c526f3948aacb85294c..e1632f354238fdb108c83d8748fb0a5fa1e76bb1 100755 GIT binary patch delta 3126 zcmZY9d6boN0Eh8=%Ty9GB9ZM?6HQHF_Q{skX-r6qEHNV`l%~Z}p&=>KW}9To5)CG0 zD-7M)yNc{PNwyHzmZ7{Oo^1u^0bTu3nQ_n1^JP(IbKV%(HSsGo zuGBPM$#NwtekI$L+J=?d_?22$Y8$U)yOJHhlH*EU!%AKJN}VfpjaPD9$%$Xdb)~*x zr9OV8-j({sE4ksmD=Tut1DZ`+6ahI<>mz&gVE8vSoi4ASnp`BSW0wo zEI-;aHZVFQHq0;2#-JcENDW1j)|H1MDbs>QL26QjONGI(9sk~BYew>%sR_HE`HkHD zto`m|hahp+UR}o}|GlPke2;K`O8L};{H5hXBJ-P;500$p)W2jwCk};0X`@GuDGn8- z6;Bv9ws=x#c*)F`Cx_7lO|b_O&)iY4BUvBn1!2gGiKu!%)wmD!+b2jt+)-h;||=3QY^$>ScJQA5AMZ%xF3u0 z03O6cco<9Y2p+{!l;JTvjweu#Wq1w!wX*`2x@f=oS6`scnco7wN2`^(cBB(?a zs!@Yl)S(`05XCE4i*{5Fg=Ve1cE00iR(bKF20} zfiLkDzQ#A$jBoKBzQ-2)fFBXVPxu+X;8*;Ht@s_=@CW|HcI?1T{Dr?~^V^>X)5J72 zdzb{%%rrMG%$}yD*~_#tdz*bsqDeCQn$~7Nv%hI$4lr%af#x97&KztGF^8JN%;6?5 zN0|1egGn|W&5`CP)5)Zm&Zdh=HC;_NbF?|e9Ba}{y2&t^Cd*`-9FuFho8!#!<^*%1 zImz@eyWYf}o_d+yrjO}s`k6e_-{hN9Oo16-PBo{Q)6GD0h8biAn;~YXInxX?XPL9j zIp$n5+?;35H-)CiTwq3+3(ZI~%3Nedn~TjQ=2A1pj5U{;ai-XeHxtZ6Gs#?Tt}s`c ztIT9G#Y{CdCsgftIYG}1@oe*FfW;x&1w@dm8Qy6n;KJV>P)>^W1{92v(~ILubS7) zdh@z@!@OzUGH;uA%)912^S=4Od}uy0ADd6ir)Gos%xpBDn@#2m^QHO9d~Lolo6Wc8 vJM+ESVtz0`nwa^?{A_+Pznb67R`a{rX8tgLn(bzX*=ha?ujbz`ytU#V98@Nk delta 3032 zcmZ|Pdw7)t0LSrj%BGSwB|_zG65YR?d!t=4!a-VQjML>!f{C#p z5~~iylY?zFZ5D11n%CrQUD=FR)9AE}@Q~=zA>q{MnvC$c+G(cKlEkzmh?F!i&8(kh z)=jgVmL{g9L8P>SX;%F-t8SX@v@9_#3nFC=OtYEB`-fXZS7(RE*FJEL)AGc$JcyJx zFwLpIYfjx=bDdTsrWHY?qJe2{{WQ03n&-4KF|7SR;|tt4@;ggB?wZ2F~OpsxIKd&)dlgM)g$A%)dS;c)g$74st3gT@fR*k z3DQHc)Qu}bv92?MDM5N_j4zGhZX6iT?Nl^9DRJ64DA_Z&OX4CeaqP&kV8xzTw{FF| zCluAhmbWk38RI%Sd1$y*v~B-zudYGRszdGjEd2j8@jkT|X@#}NjvS+-hlY=w#|Dki z82caz$=DZ7&=k$EADUx-v_J|{aR6GP6%Ise9E5|>28ZBK9EP@NhxRxe0XiTJ9nlG$ zaRhv}F6fGG=#F&sz)?6FJ<$sp$V3*hk%L_1As@$}H~QdM9EZN>hyECVff$6r7=q(b zfD>>cPC_Au;$#fNDL56UVK_$Mbd1Cq7=<%&7S6_KoP%?59>!oS&c_9~5aVzW#$y65 z#zb6#OEC$T;c`sI6}S>tVG5>V8m`7QxE9x8I7vOh-G*P591L$ipTIcp1_k>j;HW6 zp1}${i|0^`m3SU6;6=QIm$3@3;8m=~YgmKV@dnl+h7y#b4CSamC93cys__=qVLdkB zZM=hb@gCmC2lx;l;bVM)jrbIw;d6X}P52UD;cI+@Z?PF$@EyL#5BL#V@e_W=FW81( z@f+g!9e-ducHmF^g`L=i-S``OuopG>2mj9Je}4f?Bh%RIW0Fj=+1E5NO-(bipJ{IP zH!VzxNi_$UmZp_C(6lxOnS)ImbBHf@`Q{kY+w?KVn&V7g)6e|>OB~?YKr_e;Hbczu zrofzFPBbT(LNnByY=)Ur%&F!yGu(_Yr<;-H3^U4{Y0ffdo6+VRbFMkhj4@-)`Q`$1 zp&4f`GULqzbFrCdE-{yyN#-(hxtVOPFjtzZ%oH=#Ofy%TYs|IgIy2o|Z*DL*ni*!M znPq01Ip!ua*W7I8nTWZ?+-l~V+f0$U-7GK*%^hZuxzpTb7Mmp|YVJ1on0w8A=6>^l zS!y0M%gjUOVe^Q2)I4S$H&2)+&2saUdD=WrT`NC{6Uz)GX*XA4Zt=Vk0nD5N@<_Ghm*=l|=Kbv37HuJ0b&BV>`<`1*o f>@a_tzsydv%j`CPn>}W)sWJbA*YfEX-m>ODlcCq^ diff --git a/RaspberryPi/apple2driver/a2io/communication.go b/RaspberryPi/apple2driver/a2io/communication.go index 1aee7a7..e93f7b3 100644 --- a/RaspberryPi/apple2driver/a2io/communication.go +++ b/RaspberryPi/apple2driver/a2io/communication.go @@ -19,4 +19,5 @@ type A2Io interface { ReadString() (string, error) ReadBlock(buffer []byte) error SendCharacter(character byte) + ReadCharacter() (string, error) } diff --git a/RaspberryPi/apple2driver/a2io/gpio.go b/RaspberryPi/apple2driver/a2io/gpio.go index 04c7adb..715ce40 100644 --- a/RaspberryPi/apple2driver/a2io/gpio.go +++ b/RaspberryPi/apple2driver/a2io/gpio.go @@ -318,3 +318,8 @@ func (a2 A2Gpio) WriteBuffer(buffer []byte) error { func (a2 A2Gpio) SendCharacter(character byte) { sendCharacter(a2, character) } + +// ReadCharacter is a pass-through to vt100 implementation +func (a2 A2Gpio) ReadCharacter() (string, error) { + return readCharacter(a2) +} diff --git a/RaspberryPi/apple2driver/a2io/mockio.go b/RaspberryPi/apple2driver/a2io/mockio.go index 04036c1..d26ec54 100644 --- a/RaspberryPi/apple2driver/a2io/mockio.go +++ b/RaspberryPi/apple2driver/a2io/mockio.go @@ -105,3 +105,8 @@ func (mockIo MockIo) ReadBlock(buffer []byte) error { func (mockIo MockIo) SendCharacter(character byte) { sendCharacter(mockIo, character) } + +// ReadCharacter is a pass-through to vt100 implementation +func (mockIo MockIo) ReadCharacter() (string, error) { + return readCharacter(mockIo) +} diff --git a/RaspberryPi/apple2driver/a2io/userio.go b/RaspberryPi/apple2driver/a2io/userio.go index f208393..7ab8460 100644 --- a/RaspberryPi/apple2driver/a2io/userio.go +++ b/RaspberryPi/apple2driver/a2io/userio.go @@ -82,3 +82,8 @@ func (userIo UserIo) ReadBlock(buffer []byte) error { func (userIo UserIo) SendCharacter(character byte) { sendCharacter(userIo, character) } + +// ReadCharacter is a pass-through to vt100 implementation +func (userIo UserIo) ReadCharacter() (string, error) { + return readCharacter(userIo) +} diff --git a/RaspberryPi/apple2driver/a2io/vt100.go b/RaspberryPi/apple2driver/a2io/vt100.go index bb98a4e..d566461 100644 --- a/RaspberryPi/apple2driver/a2io/vt100.go +++ b/RaspberryPi/apple2driver/a2io/vt100.go @@ -12,22 +12,50 @@ import ( ) var escapeSequence string +var operatingSystemSequence bool var htab, vtab, savedHtab, savedVtab int var applicationMode bool var windowTop int -var windowBottom = 22 +var windowBottom = 23 func sendCharacter(comm A2Io, b byte) { if b == 0x1b { escapeSequence = "^[" return } + if b == 13 { + fmt.Printf("CR\n") + comm.WriteByte('H') + comm.WriteByte(0) + return + } + if b > 13 && b < 32 { + fmt.Printf("Control code: %02X\n", b) + return + } + if len(escapeSequence) == 0 { + fmt.Printf("%c", b) + } if len(escapeSequence) > 0 { escapeSequence += string(b) + if escapeSequence == "^[]" { + fmt.Printf("Start operating system sequence\n") + operatingSystemSequence = true + return + } + if operatingSystemSequence { + if b == 0x07 { + fmt.Printf("Operating system sequence: %s\n", escapeSequence) + operatingSystemSequence = false + escapeSequence = "" + } + return + } // save cursor if escapeSequence == "^[7" { savedHtab = htab savedVtab = vtab + fmt.Printf("Save Cursor (%d, %d): %s\n", htab, vtab, escapeSequence) escapeSequence = "" } // restore cursor @@ -38,21 +66,34 @@ func sendCharacter(comm A2Io, b byte) { comm.WriteByte(byte(htab)) comm.WriteByte('V') comm.WriteByte(byte(vtab)) + fmt.Printf("Restore Cursor (%d, %d): %s\n", htab, vtab, escapeSequence) escapeSequence = "" } if (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') { switch b { // Set cursor location case 'H', 'f': - var ignore string - fmt.Sscanf(escapeSequence, "^[[%d;%d%s", &vtab, &htab, &ignore) - htab-- - vtab-- - comm.WriteByte('H') - comm.WriteByte(byte(htab)) - comm.WriteByte('V') - comm.WriteByte(byte(vtab)) - escapeSequence = "" + if escapeSequence == "^[[H" || escapeSequence == "^[[;H" { + htab = 0 + vtab = 0 + comm.WriteByte(0x19) // ^Y moves to home position + fmt.Printf("Home: %s\n", escapeSequence) + escapeSequence = "" + } else { + var ignore string + fmt.Sscanf(escapeSequence, "^[[%d;%d%s", &vtab, &htab, &ignore) + htab-- + vtab-- + if htab < 0 { + htab = 0 + } + comm.WriteByte('H') + comm.WriteByte(byte(htab)) + comm.WriteByte('V') + comm.WriteByte(byte(vtab)) + fmt.Printf("Set Cursor (%d, %d): %s\n", htab, vtab, escapeSequence) + escapeSequence = "" + } case 'r': fmt.Sscanf(escapeSequence, "^[[%d;%dr", &windowTop, &windowBottom) windowTop-- @@ -61,13 +102,68 @@ func sendCharacter(comm A2Io, b byte) { comm.WriteByte(byte(windowTop)) comm.WriteByte('B') comm.WriteByte(byte(windowBottom)) + fmt.Printf("Set Window (%d, %d): %s\n", windowTop, windowBottom, escapeSequence) + escapeSequence = "" + case 'A': + if escapeSequence == "^[[A" || escapeSequence == "^[A" { + vtab-- + comm.WriteByte('U') + fmt.Printf("Up: %s\n", escapeSequence) + } else { + var up int + fmt.Sscanf(escapeSequence, "^[[%dA", &up) + vtab -= up + for i := 0; i < up; i++ { + comm.WriteByte('U') + } + fmt.Printf("Up (%d): %s\n", up, escapeSequence) + } + escapeSequence = "" + case 'B': + if escapeSequence == "^[(B" || escapeSequence == "^[)B" || escapeSequence == "^[B" { + escapeSequence = "" + } else if escapeSequence == "^[[B" { + vtab++ + comm.WriteByte(0x0a) + fmt.Printf("Down: %s\n", escapeSequence) + } else { + var down int + fmt.Sscanf(escapeSequence, "^[[%dB", &down) + vtab += down + for i := 0; i < down; i++ { + comm.WriteByte(0x0a) + } + fmt.Printf("Down (%d): %s\n", down, escapeSequence) + } escapeSequence = "" case 'C': - var right int - fmt.Sscanf(escapeSequence, "^[[%dC", &right) - htab -= right - for i := 0; i < right; i++ { + if escapeSequence == "^[[C" || escapeSequence == "^[C" { + htab++ + comm.WriteByte(0x1c) + fmt.Printf("Right: %s\n", escapeSequence) + } else { + var right int + fmt.Sscanf(escapeSequence, "^[[%dC", &right) + htab += right + for i := 0; i < right; i++ { + comm.WriteByte(0x1c) + } + fmt.Printf("Right (%d): %s\n", right, escapeSequence) + } + escapeSequence = "" + case 'D': + if escapeSequence == "^[[D" || escapeSequence == "^[D" { + htab-- comm.WriteByte(0x08) + fmt.Printf("Left: %s\n", escapeSequence) + } else { + var left int + fmt.Sscanf(escapeSequence, "^[[%dD", &left) + htab -= left + for i := 0; i < left; i++ { + comm.WriteByte(0x08) + } + fmt.Printf("Left (%d): %s\n", left, escapeSequence) } escapeSequence = "" } @@ -76,6 +172,7 @@ func sendCharacter(comm A2Io, b byte) { case "^[[?1h": applicationMode = true comm.WriteByte(0x0c) // ^L clears the screen + fmt.Printf("Start application mode: %s\n", escapeSequence) escapeSequence = "" case "^[[?1l": applicationMode = false @@ -84,54 +181,65 @@ func sendCharacter(comm A2Io, b byte) { comm.WriteByte('B') comm.WriteByte(0x18) comm.WriteByte(0x0c) // ^L clears the screen + fmt.Printf("End application mode: %s\n", escapeSequence) escapeSequence = "" // Tab to home position - case "^[[H", "^[[;H", "^[[f", "^[[;f": + case "^[[f", "^[[;f": htab = 0 vtab = 0 comm.WriteByte(0x19) // ^Y moves to home position + fmt.Printf("Home: %s\n", escapeSequence) escapeSequence = "" // Clear screen case "^[[2J", "^[[c": htab = 0 vtab = 0 comm.WriteByte(0x0c) // ^L clears the screen + fmt.Printf("Clear screen: %s\n", escapeSequence) escapeSequence = "" - // Move down one line case "^[E": comm.WriteByte(0x0A) // ^J moves cursor down + fmt.Printf("Move down: %s\n", escapeSequence) escapeSequence = "" case "^[D": comm.WriteByte(0x17) // ^W scrolls up + fmt.Printf("Scroll up: %s\n", escapeSequence) escapeSequence = "" - // Clear line to the right case "^[[K", "^[[0K": comm.WriteByte(0x1d) // ^] clears to end of line + fmt.Printf("Clear line right: %s\n", escapeSequence) + escapeSequence = "" + case "^[[2K": + comm.WriteByte(0x1a) // ^Z clears line + fmt.Printf("Clear line: %s\n", escapeSequence) escapeSequence = "" case "^[M": comm.WriteByte(0x16) // ^V scrolls down + fmt.Printf("Scroll down: %s\n", escapeSequence) escapeSequence = "" - // Clear screen below cursor case "^[[J": comm.WriteByte(0x0b) // ^K clears to end of screen + fmt.Printf("Clear below cursor: %s\n", escapeSequence) escapeSequence = "" case "^[[7m": comm.WriteByte(0x0f) // ^O inverse video + fmt.Printf("Inverse: %s\n", escapeSequence) escapeSequence = "" case "^[[m", "^[[0m": - comm.WriteByte(0x0e) // ^N normal video + //comm.WriteByte(0x0e) // ^N normal video + fmt.Printf("Normal: %s\n", escapeSequence) escapeSequence = "" } if len(escapeSequence) > 0 { - fmt.Printf("\nUnhandled escape sequence: %s\n", escapeSequence) + fmt.Printf("Unhandled escape sequence: %s\n", escapeSequence) } escapeSequence = "" return } return } - fmt.Print(string(b)) + //fmt.Print(string(b)) htabIncrement := 0 switch b { // convert LF to CR for Apple II compatiblity @@ -158,7 +266,7 @@ func sendCharacter(comm A2Io, b byte) { default: htabIncrement = 1 } - if !applicationMode || htab < 78 { + if !applicationMode || htab < 79 { updateTabs(comm) b |= 0x80 htab += htabIncrement @@ -171,6 +279,26 @@ func sendCharacter(comm A2Io, b byte) { } } +func readCharacter(comm A2Io) (string, error) { + b, err := comm.ReadByte() + var s = string(b) + if err == nil { + switch b { + case 0x0b: // up + s = "\033[A" + case 0x0a: // down + s = "\033[B" + case 0x15: // right + s = "\033[C" + case 0x08: // left + s = "\033[D" + case 0x0d: // return + s = string(byte(0x0a)) + } + } + return s, err +} + func updateTabs(comm A2Io) { if htab >= 80 { htab = 0 diff --git a/RaspberryPi/apple2driver/driver.go b/RaspberryPi/apple2driver/driver.go index f5b18af..e3011ff 100644 --- a/RaspberryPi/apple2driver/driver.go +++ b/RaspberryPi/apple2driver/driver.go @@ -18,6 +18,7 @@ import ( "github.com/tjboldt/Apple2-IO-RPi/RaspberryPi/apple2driver/handlers" ) +const resetCommand = 0 const readBlockCommand = 1 const writeBlockCommand = 2 const getTimeCommand = 3 @@ -40,11 +41,16 @@ func main() { lastCommandTime := time.Now() + // In case Apple II is waiting, send 0 byte to start + comm.WriteByte(0) + for { command, err := comm.ReadByte() if err == nil { lastCommandTime = time.Now() switch command { + case resetCommand: + handlers.ResetCommand() case readBlockCommand: handlers.ReadBlockCommand(drive1, drive2) case writeBlockCommand: diff --git a/RaspberryPi/apple2driver/handlers/exec.go b/RaspberryPi/apple2driver/handlers/exec.go index c9aa1ba..da8eb22 100644 --- a/RaspberryPi/apple2driver/handlers/exec.go +++ b/RaspberryPi/apple2driver/handlers/exec.go @@ -117,7 +117,6 @@ func execCommand(linuxCommand string, workingDirectory string) { return case <-userCancelled: userCancelled <- true - comm.WriteString("^C\r") cmd.Process.Kill() return case <-inputComplete: @@ -132,6 +131,7 @@ func getStdout(stdout io.ReadCloser, outputComplete chan bool, userCancelled cha for { select { case <-userCancelled: + fmt.Printf("User Cancelled stdout\n") stdout.Close() return default: @@ -158,22 +158,15 @@ func getStdin(stdin io.WriteCloser, done chan bool, inputComplete chan bool, use inputComplete <- true return default: - b, err := comm.ReadByte() + s, err := comm.ReadCharacter() if err == nil { - if b == 0x03 { + if s == string(byte(0x00)) { stdin.Close() userCancelled <- true + fmt.Printf("\nUser cancelled stdin\n") return } - if b == 0x0d { - b = 0x0a - } - if b == 0x0b { - b = 'k' - } - - fmt.Printf("%c", b) - io.WriteString(stdin, string(b)) + io.WriteString(stdin, string(s)) } } } diff --git a/RaspberryPi/apple2driver/handlers/reset.go b/RaspberryPi/apple2driver/handlers/reset.go new file mode 100755 index 0000000..dcfd190 --- /dev/null +++ b/RaspberryPi/apple2driver/handlers/reset.go @@ -0,0 +1,18 @@ +// Copyright Terence J. Boldt (c)2020-2021 +// Use of this source code is governed by an MIT +// license that can be found in the LICENSE file. + +// This file is contains the handler for displaying the menu of choices on +// the Apple II + +package handlers + +import ( + "fmt" +) + +// ResetCommand responds with zero +func ResetCommand() { + fmt.Printf("Reset request\n") + comm.WriteByte(0) +} diff --git a/RaspberryPi/apple2driver/handlers/shell.go b/RaspberryPi/apple2driver/handlers/shell.go index bc0f910..599b982 100755 --- a/RaspberryPi/apple2driver/handlers/shell.go +++ b/RaspberryPi/apple2driver/handlers/shell.go @@ -7,6 +7,7 @@ package handlers import ( + "fmt" "os" "os/exec" @@ -41,14 +42,14 @@ func ShellCommand() { for { select { case <-outputComplete: - outputComplete <- true - cmd.Wait() + ptmx.Close() comm.WriteByte(0) return case <-userCancelled: - userCancelled <- true - comm.WriteString("^C\r") + fmt.Printf("User cancelled, killing process\n") + ptmx.Close() cmd.Process.Kill() + comm.WriteByte(0) return case <-inputComplete: cmd.Wait()