Add partial vt100 emulation to shell (#39)
This commit is contained in:
parent
00652eff8e
commit
5cc32ea9cc
|
@ -33,8 +33,11 @@ StringBuffer = $0200
|
||||||
PrintChar = $fded
|
PrintChar = $fded
|
||||||
Keyboard = $c000
|
Keyboard = $c000
|
||||||
ClearKeyboard = $c010
|
ClearKeyboard = $c010
|
||||||
|
Home = $fc58
|
||||||
Wait = $fca8
|
Wait = $fca8
|
||||||
PromptChar = $33
|
PromptChar = $33
|
||||||
|
htab = $24
|
||||||
|
vtab = $25
|
||||||
|
|
||||||
ESC = $9b
|
ESC = $9b
|
||||||
|
|
||||||
|
@ -116,39 +119,53 @@ sendNullTerminator:
|
||||||
|
|
||||||
DumpOutput:
|
DumpOutput:
|
||||||
jsr GetByte
|
jsr GetByte
|
||||||
bcs skipOutput
|
bcs checkInput
|
||||||
cmp #$00
|
cmp #$00
|
||||||
beq endOutput
|
beq endOutput
|
||||||
cmp #ESC
|
cmp #'H'
|
||||||
beq escapeSequence
|
beq setColumn
|
||||||
|
cmp #'V'
|
||||||
|
beq setRow
|
||||||
|
cmp #'C'
|
||||||
|
beq clearScreen
|
||||||
|
cmp #'T'
|
||||||
|
beq setTop
|
||||||
|
cmp #'B'
|
||||||
|
beq setBottom
|
||||||
jsr PrintChar
|
jsr PrintChar
|
||||||
skipOutput:
|
jmp DumpOutput
|
||||||
|
checkInput:
|
||||||
bit Keyboard ;check for keypress
|
bit Keyboard ;check for keypress
|
||||||
bpl DumpOutput ;keep dumping output if no keypress
|
bpl DumpOutput ;keep dumping output if no keypress
|
||||||
lda Keyboard ;send keypress to RPi
|
lda Keyboard ;send keypress to RPi
|
||||||
;jsr PrintChar
|
|
||||||
and #$7f
|
and #$7f
|
||||||
jsr SendByte
|
jsr SendByte
|
||||||
bit ClearKeyboard
|
bit ClearKeyboard
|
||||||
clc
|
jmp DumpOutput
|
||||||
bcc DumpOutput
|
|
||||||
endOutput:
|
endOutput:
|
||||||
rts
|
rts
|
||||||
escapeSequence:
|
clearScreen:
|
||||||
jsr ParseEscape
|
jsr Home
|
||||||
clc
|
jmp DumpOutput
|
||||||
bcc DumpOutput
|
setColumn:
|
||||||
|
jsr GetByte
|
||||||
ParseEscape:
|
sta htab
|
||||||
jsr GetByte ; expect first byte after ESC to be '['
|
sta $057B
|
||||||
cmp #'['|$80
|
jmp DumpOutput
|
||||||
beq endParse
|
setRow:
|
||||||
checkLetter:
|
jsr GetByte
|
||||||
jsr GetByte ; loop until there is a letter
|
sta vtab
|
||||||
cmp #$C1
|
jsr $fbc1 ; bascalc
|
||||||
bcc checkLetter
|
sta $28 ;basl
|
||||||
endParse:
|
jmp DumpOutput
|
||||||
rts
|
setTop:
|
||||||
|
jsr GetByte
|
||||||
|
sta $22
|
||||||
|
jmp DumpOutput
|
||||||
|
setBottom:
|
||||||
|
jsr GetByte
|
||||||
|
sta $23
|
||||||
|
jmp DumpOutput
|
||||||
|
|
||||||
SendByte:
|
SendByte:
|
||||||
pha
|
pha
|
||||||
|
@ -202,4 +219,4 @@ HelpCommand:
|
||||||
PromptCommand:
|
PromptCommand:
|
||||||
.byte "a2prompt",$00
|
.byte "a2prompt",$00
|
||||||
OldPromptChar:
|
OldPromptChar:
|
||||||
.byte "]"
|
.byte "]"
|
||||||
|
|
BIN
Apple2/Shell.bin
BIN
Apple2/Shell.bin
Binary file not shown.
223
Apple2/Shell.lst
223
Apple2/Shell.lst
|
@ -37,47 +37,50 @@ Current file: Shell.asm
|
||||||
000000r 1 PrintChar = $fded
|
000000r 1 PrintChar = $fded
|
||||||
000000r 1 Keyboard = $c000
|
000000r 1 Keyboard = $c000
|
||||||
000000r 1 ClearKeyboard = $c010
|
000000r 1 ClearKeyboard = $c010
|
||||||
|
000000r 1 Home = $fc58
|
||||||
000000r 1 Wait = $fca8
|
000000r 1 Wait = $fca8
|
||||||
000000r 1 PromptChar = $33
|
000000r 1 PromptChar = $33
|
||||||
|
000000r 1 htab = $24
|
||||||
|
000000r 1 vtab = $25
|
||||||
000000r 1
|
000000r 1
|
||||||
000000r 1 ESC = $9b
|
000000r 1 ESC = $9b
|
||||||
000000r 1
|
000000r 1
|
||||||
000000r 1 .org $2000
|
000000r 1 .org $2000
|
||||||
002000 1 Start:
|
002000 1 Start:
|
||||||
002000 1 A5 33 lda PromptChar
|
002000 1 A5 33 lda PromptChar
|
||||||
002002 1 8D 20 21 sta OldPromptChar
|
002002 1 8D 4C 21 sta OldPromptChar
|
||||||
002005 1 A9 A4 lda #'$'|$80
|
002005 1 A9 A4 lda #'$'|$80
|
||||||
002007 1 85 33 sta PromptChar
|
002007 1 85 33 sta PromptChar
|
||||||
002009 1 A9 05 lda #ExecCommand
|
002009 1 A9 05 lda #ExecCommand
|
||||||
00200B 1 20 C9 20 jsr SendByte
|
00200B 1 20 F5 20 jsr SendByte
|
||||||
00200E 1 A2 00 ldx #$00
|
00200E 1 A2 00 ldx #$00
|
||||||
002010 1 sendHelpCommand:
|
002010 1 sendHelpCommand:
|
||||||
002010 1 BD 10 21 lda HelpCommand,x
|
002010 1 BD 3C 21 lda HelpCommand,x
|
||||||
002013 1 C9 00 cmp #$00
|
002013 1 C9 00 cmp #$00
|
||||||
002015 1 F0 06 beq sendHelpCommandEnd
|
002015 1 F0 06 beq sendHelpCommandEnd
|
||||||
002017 1 20 C9 20 jsr SendByte
|
002017 1 20 F5 20 jsr SendByte
|
||||||
00201A 1 E8 inx
|
00201A 1 E8 inx
|
||||||
00201B 1 10 F3 bpl sendHelpCommand
|
00201B 1 10 F3 bpl sendHelpCommand
|
||||||
00201D 1 sendHelpCommandEnd:
|
00201D 1 sendHelpCommandEnd:
|
||||||
00201D 1 A9 00 lda #$00
|
00201D 1 A9 00 lda #$00
|
||||||
00201F 1 20 C9 20 jsr SendByte
|
00201F 1 20 F5 20 jsr SendByte
|
||||||
002022 1 2C 10 C0 bit ClearKeyboard
|
002022 1 2C 10 C0 bit ClearKeyboard
|
||||||
002025 1 20 90 20 jsr DumpOutput
|
002025 1 20 90 20 jsr DumpOutput
|
||||||
002028 1
|
002028 1
|
||||||
002028 1 Prompt:
|
002028 1 Prompt:
|
||||||
002028 1 A9 05 lda #ExecCommand
|
002028 1 A9 05 lda #ExecCommand
|
||||||
00202A 1 20 C9 20 jsr SendByte
|
00202A 1 20 F5 20 jsr SendByte
|
||||||
00202D 1 A2 00 ldx #$00
|
00202D 1 A2 00 ldx #$00
|
||||||
00202F 1 sendPromptCommand:
|
00202F 1 sendPromptCommand:
|
||||||
00202F 1 BD 17 21 lda PromptCommand,x
|
00202F 1 BD 43 21 lda PromptCommand,x
|
||||||
002032 1 C9 00 cmp #$00
|
002032 1 C9 00 cmp #$00
|
||||||
002034 1 F0 06 beq sendPromptCommandEnd
|
002034 1 F0 06 beq sendPromptCommandEnd
|
||||||
002036 1 20 C9 20 jsr SendByte
|
002036 1 20 F5 20 jsr SendByte
|
||||||
002039 1 E8 inx
|
002039 1 E8 inx
|
||||||
00203A 1 10 F3 bpl sendPromptCommand
|
00203A 1 10 F3 bpl sendPromptCommand
|
||||||
00203C 1 sendPromptCommandEnd:
|
00203C 1 sendPromptCommandEnd:
|
||||||
00203C 1 A9 00 lda #$00
|
00203C 1 A9 00 lda #$00
|
||||||
00203E 1 20 C9 20 jsr SendByte
|
00203E 1 20 F5 20 jsr SendByte
|
||||||
002041 1 2C 10 C0 bit ClearKeyboard
|
002041 1 2C 10 C0 bit ClearKeyboard
|
||||||
002044 1 20 90 20 jsr DumpOutput
|
002044 1 20 90 20 jsr DumpOutput
|
||||||
002047 1
|
002047 1
|
||||||
|
@ -96,118 +99,132 @@ Current file: Shell.asm
|
||||||
00205F 1 AD 03 02 lda StringBuffer+3
|
00205F 1 AD 03 02 lda StringBuffer+3
|
||||||
002062 1 C9 F4 cmp #'t'|$80
|
002062 1 C9 F4 cmp #'t'|$80
|
||||||
002064 1 D0 06 bne Execute
|
002064 1 D0 06 bne Execute
|
||||||
002066 1 AD 20 21 lda OldPromptChar
|
002066 1 AD 4C 21 lda OldPromptChar
|
||||||
002069 1 85 33 sta PromptChar
|
002069 1 85 33 sta PromptChar
|
||||||
00206B 1 60 rts
|
00206B 1 60 rts
|
||||||
00206C 1 Execute:
|
00206C 1 Execute:
|
||||||
00206C 1 2C 10 C0 bit ClearKeyboard
|
00206C 1 2C 10 C0 bit ClearKeyboard
|
||||||
00206F 1 A9 05 lda #ExecCommand
|
00206F 1 A9 05 lda #ExecCommand
|
||||||
002071 1 20 C9 20 jsr SendByte
|
002071 1 20 F5 20 jsr SendByte
|
||||||
002074 1 A0 00 ldy #$00
|
002074 1 A0 00 ldy #$00
|
||||||
002076 1 sendInput:
|
002076 1 sendInput:
|
||||||
002076 1 B9 00 02 lda $0200,y
|
002076 1 B9 00 02 lda $0200,y
|
||||||
002079 1 C9 8D cmp #$8d
|
002079 1 C9 8D cmp #$8d
|
||||||
00207B 1 F0 08 beq sendNullTerminator
|
00207B 1 F0 08 beq sendNullTerminator
|
||||||
00207D 1 29 7F and #$7f
|
00207D 1 29 7F and #$7f
|
||||||
00207F 1 20 C9 20 jsr SendByte
|
00207F 1 20 F5 20 jsr SendByte
|
||||||
002082 1 C8 iny
|
002082 1 C8 iny
|
||||||
002083 1 D0 F1 bne sendInput
|
002083 1 D0 F1 bne sendInput
|
||||||
002085 1 sendNullTerminator:
|
002085 1 sendNullTerminator:
|
||||||
002085 1 A9 00 lda #$00
|
002085 1 A9 00 lda #$00
|
||||||
002087 1 20 C9 20 jsr SendByte
|
002087 1 20 F5 20 jsr SendByte
|
||||||
00208A 1 20 90 20 jsr DumpOutput
|
00208A 1 20 90 20 jsr DumpOutput
|
||||||
00208D 1 4C 28 20 jmp Prompt
|
00208D 1 4C 28 20 jmp Prompt
|
||||||
002090 1
|
002090 1
|
||||||
002090 1 DumpOutput:
|
002090 1 DumpOutput:
|
||||||
002090 1 20 E7 20 jsr GetByte
|
002090 1 20 13 21 jsr GetByte
|
||||||
002093 1 B0 0B bcs skipOutput
|
002093 1 B0 1E bcs checkInput
|
||||||
002095 1 C9 00 cmp #$00
|
002095 1 C9 00 cmp #$00
|
||||||
002097 1 F0 1A beq endOutput
|
002097 1 F0 2D beq endOutput
|
||||||
002099 1 C9 9B cmp #ESC
|
002099 1 C9 48 cmp #'H'
|
||||||
00209B 1 F0 17 beq escapeSequence
|
00209B 1 F0 30 beq setColumn
|
||||||
00209D 1 20 ED FD jsr PrintChar
|
00209D 1 C9 56 cmp #'V'
|
||||||
0020A0 1 skipOutput:
|
00209F 1 F0 37 beq setRow
|
||||||
0020A0 1 2C 00 C0 bit Keyboard ;check for keypress
|
0020A1 1 C9 43 cmp #'C'
|
||||||
0020A3 1 10 EB bpl DumpOutput ;keep dumping output if no keypress
|
0020A3 1 F0 22 beq clearScreen
|
||||||
0020A5 1 AD 00 C0 lda Keyboard ;send keypress to RPi
|
0020A5 1 C9 54 cmp #'T'
|
||||||
0020A8 1 ;jsr PrintChar
|
0020A7 1 F0 3C beq setTop
|
||||||
0020A8 1 29 7F and #$7f
|
0020A9 1 C9 42 cmp #'B'
|
||||||
0020AA 1 20 C9 20 jsr SendByte
|
0020AB 1 F0 40 beq setBottom
|
||||||
0020AD 1 2C 10 C0 bit ClearKeyboard
|
0020AD 1 20 ED FD jsr PrintChar
|
||||||
0020B0 1 18 clc
|
0020B0 1 4C 90 20 jmp DumpOutput
|
||||||
0020B1 1 90 DD bcc DumpOutput
|
0020B3 1 checkInput:
|
||||||
0020B3 1 endOutput:
|
0020B3 1 2C 00 C0 bit Keyboard ;check for keypress
|
||||||
0020B3 1 60 rts
|
0020B6 1 10 D8 bpl DumpOutput ;keep dumping output if no keypress
|
||||||
0020B4 1 escapeSequence:
|
0020B8 1 AD 00 C0 lda Keyboard ;send keypress to RPi
|
||||||
0020B4 1 20 BA 20 jsr ParseEscape
|
0020BB 1 29 7F and #$7f
|
||||||
0020B7 1 18 clc
|
0020BD 1 20 F5 20 jsr SendByte
|
||||||
0020B8 1 90 D6 bcc DumpOutput
|
0020C0 1 2C 10 C0 bit ClearKeyboard
|
||||||
0020BA 1
|
0020C3 1 4C 90 20 jmp DumpOutput
|
||||||
0020BA 1 ParseEscape:
|
0020C6 1 endOutput:
|
||||||
0020BA 1 20 E7 20 jsr GetByte ; expect first byte after ESC to be '['
|
0020C6 1 60 rts
|
||||||
0020BD 1 C9 DB cmp #'['|$80
|
0020C7 1 clearScreen:
|
||||||
0020BF 1 F0 07 beq endParse
|
0020C7 1 20 58 FC jsr Home
|
||||||
0020C1 1 checkLetter:
|
0020CA 1 4C 90 20 jmp DumpOutput
|
||||||
0020C1 1 20 E7 20 jsr GetByte ; loop until there is a letter
|
0020CD 1 setColumn:
|
||||||
0020C4 1 C9 C1 cmp #$C1
|
0020CD 1 20 13 21 jsr GetByte
|
||||||
0020C6 1 90 F9 bcc checkLetter
|
0020D0 1 85 24 sta htab
|
||||||
0020C8 1 endParse:
|
0020D2 1 8D 7B 05 sta $057B
|
||||||
0020C8 1 60 rts
|
0020D5 1 4C 90 20 jmp DumpOutput
|
||||||
0020C9 1
|
0020D8 1 setRow:
|
||||||
0020C9 1 SendByte:
|
0020D8 1 20 13 21 jsr GetByte
|
||||||
0020C9 1 48 pha
|
0020DB 1 85 25 sta vtab
|
||||||
0020CA 1 waitWrite:
|
0020DD 1 20 C1 FB jsr $fbc1 ; bascalc
|
||||||
0020CA 1 AD FB C0 lda InputFlags
|
0020E0 1 85 28 sta $28 ;basl
|
||||||
0020CD 1 2A rol
|
0020E2 1 4C 90 20 jmp DumpOutput
|
||||||
0020CE 1 2A rol
|
0020E5 1 setTop:
|
||||||
0020CF 1 B0 F9 bcs waitWrite
|
0020E5 1 20 13 21 jsr GetByte
|
||||||
0020D1 1 68 pla
|
0020E8 1 85 22 sta $22
|
||||||
0020D2 1 8D FD C0 sta OutputByte
|
0020EA 1 4C 90 20 jmp DumpOutput
|
||||||
0020D5 1 A9 1E lda #$1e ; set bit 0 low to indicate write started
|
0020ED 1 setBottom:
|
||||||
0020D7 1 8D F7 C0 sta OutputFlags
|
0020ED 1 20 13 21 jsr GetByte
|
||||||
0020DA 1 finishWrite:
|
0020F0 1 85 23 sta $23
|
||||||
0020DA 1 AD FB C0 lda InputFlags
|
0020F2 1 4C 90 20 jmp DumpOutput
|
||||||
0020DD 1 2A rol
|
0020F5 1
|
||||||
0020DE 1 2A rol
|
0020F5 1 SendByte:
|
||||||
0020DF 1 90 F9 bcc finishWrite
|
0020F5 1 48 pha
|
||||||
0020E1 1 A9 1F lda #$1f
|
0020F6 1 waitWrite:
|
||||||
0020E3 1 8D F7 C0 sta OutputFlags
|
0020F6 1 AD FB C0 lda InputFlags
|
||||||
0020E6 1 60 rts
|
0020F9 1 2A rol
|
||||||
0020E7 1
|
0020FA 1 2A rol
|
||||||
0020E7 1 GetByte:
|
0020FB 1 B0 F9 bcs waitWrite
|
||||||
0020E7 1 A9 1D lda #$1d ;set read flag low
|
0020FD 1 68 pla
|
||||||
0020E9 1 8D F7 C0 sta OutputFlags
|
0020FE 1 8D FD C0 sta OutputByte
|
||||||
0020EC 1 waitRead:
|
002101 1 A9 1E lda #$1e ; set bit 0 low to indicate write started
|
||||||
0020EC 1 AD FB C0 lda InputFlags
|
002103 1 8D F7 C0 sta OutputFlags
|
||||||
0020EF 1 2A rol
|
002106 1 finishWrite:
|
||||||
0020F0 1 90 0C bcc readByte
|
002106 1 AD FB C0 lda InputFlags
|
||||||
0020F2 1 2C 00 C0 bit Keyboard ;keypress will abort waiting to read
|
002109 1 2A rol
|
||||||
0020F5 1 10 F5 bpl waitRead
|
|
||||||
0020F7 1 A9 1F lda #$1f ;set all flags high and exit
|
|
||||||
0020F9 1 8D F7 C0 sta OutputFlags
|
|
||||||
0020FC 1 38 sec ;failure
|
|
||||||
0020FD 1 60 rts
|
|
||||||
0020FE 1 readByte:
|
|
||||||
0020FE 1 AD FE C0 lda InputByte
|
|
||||||
002101 1 48 pha
|
|
||||||
002102 1 A9 1F lda #$1f ;set all flags high
|
|
||||||
002104 1 8D F7 C0 sta OutputFlags
|
|
||||||
002107 1 finishRead:
|
|
||||||
002107 1 AD FB C0 lda InputFlags
|
|
||||||
00210A 1 2A rol
|
00210A 1 2A rol
|
||||||
00210B 1 90 FA bcc finishRead
|
00210B 1 90 F9 bcc finishWrite
|
||||||
00210D 1 68 pla
|
00210D 1 A9 1F lda #$1f
|
||||||
00210E 1 18 clc ;success
|
00210F 1 8D F7 C0 sta OutputFlags
|
||||||
00210F 1 end:
|
002112 1 60 rts
|
||||||
00210F 1 60 rts
|
002113 1
|
||||||
002110 1
|
002113 1 GetByte:
|
||||||
002110 1 HelpCommand:
|
002113 1 A9 1D lda #$1d ;set read flag low
|
||||||
002110 1 61 32 68 65 .byte "a2help",$00
|
002115 1 8D F7 C0 sta OutputFlags
|
||||||
002114 1 6C 70 00
|
002118 1 waitRead:
|
||||||
002117 1 PromptCommand:
|
002118 1 AD FB C0 lda InputFlags
|
||||||
002117 1 61 32 70 72 .byte "a2prompt",$00
|
00211B 1 2A rol
|
||||||
00211B 1 6F 6D 70 74
|
00211C 1 90 0C bcc readByte
|
||||||
00211F 1 00
|
00211E 1 2C 00 C0 bit Keyboard ;keypress will abort waiting to read
|
||||||
002120 1 OldPromptChar:
|
002121 1 10 F5 bpl waitRead
|
||||||
002120 1 5D .byte "]"
|
002123 1 A9 1F lda #$1f ;set all flags high and exit
|
||||||
002121 1
|
002125 1 8D F7 C0 sta OutputFlags
|
||||||
|
002128 1 38 sec ;failure
|
||||||
|
002129 1 60 rts
|
||||||
|
00212A 1 readByte:
|
||||||
|
00212A 1 AD FE C0 lda InputByte
|
||||||
|
00212D 1 48 pha
|
||||||
|
00212E 1 A9 1F lda #$1f ;set all flags high
|
||||||
|
002130 1 8D F7 C0 sta OutputFlags
|
||||||
|
002133 1 finishRead:
|
||||||
|
002133 1 AD FB C0 lda InputFlags
|
||||||
|
002136 1 2A rol
|
||||||
|
002137 1 90 FA bcc finishRead
|
||||||
|
002139 1 68 pla
|
||||||
|
00213A 1 18 clc ;success
|
||||||
|
00213B 1 end:
|
||||||
|
00213B 1 60 rts
|
||||||
|
00213C 1
|
||||||
|
00213C 1 HelpCommand:
|
||||||
|
00213C 1 61 32 68 65 .byte "a2help",$00
|
||||||
|
002140 1 6C 70 00
|
||||||
|
002143 1 PromptCommand:
|
||||||
|
002143 1 61 32 70 72 .byte "a2prompt",$00
|
||||||
|
002147 1 6F 6D 70 74
|
||||||
|
00214B 1 00
|
||||||
|
00214C 1 OldPromptChar:
|
||||||
|
00214C 1 5D .byte "]"
|
||||||
|
00214D 1
|
||||||
|
|
Binary file not shown.
|
@ -18,4 +18,5 @@ type A2Io interface {
|
||||||
ReadByte() (byte, error)
|
ReadByte() (byte, error)
|
||||||
ReadString() (string, error)
|
ReadString() (string, error)
|
||||||
ReadBlock(buffer []byte) error
|
ReadBlock(buffer []byte) error
|
||||||
|
SendCharacter(character byte)
|
||||||
}
|
}
|
||||||
|
|
|
@ -313,3 +313,8 @@ func (a2 A2Gpio) WriteBuffer(buffer []byte) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SendCharacter is a pass-through to vt100 implementation
|
||||||
|
func (a2 A2Gpio) SendCharacter(character byte) {
|
||||||
|
sendCharacter(a2, character)
|
||||||
|
}
|
||||||
|
|
|
@ -100,3 +100,8 @@ func (mockIo MockIo) ReadBlock(buffer []byte) error {
|
||||||
}
|
}
|
||||||
return mockIo.Data.ErrorToThrow
|
return mockIo.Data.ErrorToThrow
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SendCharacter is a pass-through to vt100 implementation
|
||||||
|
func (mockIo MockIo) SendCharacter(character byte) {
|
||||||
|
sendCharacter(mockIo, character)
|
||||||
|
}
|
||||||
|
|
|
@ -77,3 +77,8 @@ func (userIo UserIo) ReadBlock(buffer []byte) error {
|
||||||
fmt.Printf("ReadBlock: (Not supported)")
|
fmt.Printf("ReadBlock: (Not supported)")
|
||||||
return errors.New("ReadBlock not supported")
|
return errors.New("ReadBlock not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SendCharacter is a pass-through to vt100 implementation
|
||||||
|
func (userIo UserIo) SendCharacter(character byte) {
|
||||||
|
sendCharacter(userIo, character)
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,182 @@
|
||||||
|
// Copyright Terence J. Boldt (c)2021
|
||||||
|
// Use of this source code is governed by an MIT
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// This file is contains VT100 terminal emulation
|
||||||
|
|
||||||
|
package a2io
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var escapeSequence string
|
||||||
|
var htab, vtab, savedHtab, savedVtab int
|
||||||
|
var applicationMode bool
|
||||||
|
var windowTop int
|
||||||
|
var windowBottom = 22
|
||||||
|
|
||||||
|
func sendCharacter(comm A2Io, b byte) {
|
||||||
|
if b == 0x1b {
|
||||||
|
escapeSequence = "^["
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(escapeSequence) > 0 {
|
||||||
|
escapeSequence += string(b)
|
||||||
|
// save cursor
|
||||||
|
if escapeSequence == "^[7" {
|
||||||
|
savedHtab = htab
|
||||||
|
savedVtab = vtab
|
||||||
|
escapeSequence = ""
|
||||||
|
}
|
||||||
|
// restore cursor
|
||||||
|
if escapeSequence == "^[8" {
|
||||||
|
htab = savedHtab
|
||||||
|
vtab = savedVtab
|
||||||
|
comm.WriteByte('H')
|
||||||
|
comm.WriteByte(byte(htab))
|
||||||
|
comm.WriteByte('V')
|
||||||
|
comm.WriteByte(byte(vtab))
|
||||||
|
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 = ""
|
||||||
|
case 'r':
|
||||||
|
fmt.Sscanf(escapeSequence, "^[[%d;%dr", &windowTop, &windowBottom)
|
||||||
|
windowTop--
|
||||||
|
//windowBottom--
|
||||||
|
comm.WriteByte('T')
|
||||||
|
comm.WriteByte(byte(windowTop))
|
||||||
|
comm.WriteByte('B')
|
||||||
|
comm.WriteByte(byte(windowBottom))
|
||||||
|
escapeSequence = ""
|
||||||
|
case 'C':
|
||||||
|
var right int
|
||||||
|
fmt.Sscanf(escapeSequence, "^[[%dC", &right)
|
||||||
|
htab -= right
|
||||||
|
for i := 0; i < right; i++ {
|
||||||
|
comm.WriteByte(0x08)
|
||||||
|
}
|
||||||
|
escapeSequence = ""
|
||||||
|
}
|
||||||
|
switch escapeSequence {
|
||||||
|
// Set/clear application mode for cursor
|
||||||
|
case "^[[?1h":
|
||||||
|
applicationMode = true
|
||||||
|
comm.WriteByte(0x0c) // ^L clears the screen
|
||||||
|
escapeSequence = ""
|
||||||
|
case "^[[?1l":
|
||||||
|
applicationMode = false
|
||||||
|
comm.WriteByte('T')
|
||||||
|
comm.WriteByte(0x00)
|
||||||
|
comm.WriteByte('B')
|
||||||
|
comm.WriteByte(0x18)
|
||||||
|
comm.WriteByte(0x0c) // ^L clears the screen
|
||||||
|
escapeSequence = ""
|
||||||
|
// Tab to home position
|
||||||
|
case "^[[H", "^[[;H", "^[[f", "^[[;f":
|
||||||
|
htab = 0
|
||||||
|
vtab = 0
|
||||||
|
comm.WriteByte(0x19) // ^Y moves to home position
|
||||||
|
escapeSequence = ""
|
||||||
|
// Clear screen
|
||||||
|
case "^[[2J", "^[[c":
|
||||||
|
htab = 0
|
||||||
|
vtab = 0
|
||||||
|
comm.WriteByte(0x0c) // ^L clears the screen
|
||||||
|
escapeSequence = ""
|
||||||
|
// Move down one line
|
||||||
|
case "^[E":
|
||||||
|
comm.WriteByte(0x0A) // ^J moves cursor down
|
||||||
|
escapeSequence = ""
|
||||||
|
case "^[D":
|
||||||
|
comm.WriteByte(0x17) // ^W scrolls up
|
||||||
|
escapeSequence = ""
|
||||||
|
// Clear line to the right
|
||||||
|
case "^[[K", "^[[0K":
|
||||||
|
comm.WriteByte(0x1d) // ^] clears to end of line
|
||||||
|
escapeSequence = ""
|
||||||
|
case "^[M":
|
||||||
|
comm.WriteByte(0x16) // ^V scrolls down
|
||||||
|
escapeSequence = ""
|
||||||
|
// Clear screen below cursor
|
||||||
|
case "^[[J":
|
||||||
|
comm.WriteByte(0x0b) // ^K clears to end of screen
|
||||||
|
escapeSequence = ""
|
||||||
|
case "^[[7m":
|
||||||
|
comm.WriteByte(0x0f) // ^O inverse video
|
||||||
|
escapeSequence = ""
|
||||||
|
case "^[[m", "^[[0m":
|
||||||
|
comm.WriteByte(0x0e) // ^N normal video
|
||||||
|
escapeSequence = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(escapeSequence) > 0 {
|
||||||
|
fmt.Printf("\nUnhandled escape sequence: %s\n", escapeSequence)
|
||||||
|
}
|
||||||
|
escapeSequence = ""
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Print(string(b))
|
||||||
|
htabIncrement := 0
|
||||||
|
switch b {
|
||||||
|
// convert LF to CR for Apple II compatiblity
|
||||||
|
case 10:
|
||||||
|
b = 13
|
||||||
|
vtab++
|
||||||
|
htab = 0
|
||||||
|
htabIncrement = 0
|
||||||
|
case 13:
|
||||||
|
htab = 0
|
||||||
|
htabIncrement = 0
|
||||||
|
return
|
||||||
|
// convert TAB to spaces
|
||||||
|
case 9:
|
||||||
|
b = ' '
|
||||||
|
b |= 0x80
|
||||||
|
err := comm.WriteByte(b)
|
||||||
|
if err != nil {
|
||||||
|
// try again because could have been cancelled by input
|
||||||
|
time.Sleep(time.Millisecond * 10)
|
||||||
|
comm.WriteByte(b)
|
||||||
|
}
|
||||||
|
htabIncrement = 2
|
||||||
|
default:
|
||||||
|
htabIncrement = 1
|
||||||
|
}
|
||||||
|
if !applicationMode || htab < 78 {
|
||||||
|
updateTabs(comm)
|
||||||
|
b |= 0x80
|
||||||
|
htab += htabIncrement
|
||||||
|
err := comm.WriteByte(b)
|
||||||
|
if err != nil {
|
||||||
|
// try again because could have been cancelled by input
|
||||||
|
time.Sleep(time.Millisecond * 10)
|
||||||
|
comm.WriteByte(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateTabs(comm A2Io) {
|
||||||
|
if htab >= 80 {
|
||||||
|
htab = 0
|
||||||
|
vtab++
|
||||||
|
}
|
||||||
|
if vtab > windowBottom {
|
||||||
|
vtab = windowBottom
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/tjboldt/Apple2-IO-RPi/RaspberryPi/apple2driver/a2io"
|
"github.com/tjboldt/Apple2-IO-RPi/RaspberryPi/apple2driver/a2io"
|
||||||
"github.com/tjboldt/Apple2-IO-RPi/RaspberryPi/apple2driver/handlers"
|
"github.com/tjboldt/Apple2-IO-RPi/RaspberryPi/apple2driver/handlers"
|
||||||
|
@ -36,9 +37,12 @@ func main() {
|
||||||
handlers.SetCommunication(comm)
|
handlers.SetCommunication(comm)
|
||||||
comm.Init()
|
comm.Init()
|
||||||
|
|
||||||
|
lastCommandTime := time.Now()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
command, err := comm.ReadByte()
|
command, err := comm.ReadByte()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
lastCommandTime = time.Now()
|
||||||
switch command {
|
switch command {
|
||||||
case readBlockCommand:
|
case readBlockCommand:
|
||||||
handlers.ReadBlockCommand(drive1, drive2)
|
handlers.ReadBlockCommand(drive1, drive2)
|
||||||
|
@ -53,6 +57,9 @@ func main() {
|
||||||
case menuCommand:
|
case menuCommand:
|
||||||
handlers.MenuCommand()
|
handlers.MenuCommand()
|
||||||
}
|
}
|
||||||
|
// temporary workaround for busy wait loop heating up the RPi
|
||||||
|
} else if time.Since(lastCommandTime) > time.Millisecond*100 {
|
||||||
|
time.Sleep(time.Millisecond * 100)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,6 +75,11 @@ func execCommand(linuxCommand string, workingDirectory string) {
|
||||||
linuxCommand += " 2>&1"
|
linuxCommand += " 2>&1"
|
||||||
cmd := exec.Command("bash", "-c", linuxCommand)
|
cmd := exec.Command("bash", "-c", linuxCommand)
|
||||||
cmd.Dir = workingDirectory
|
cmd.Dir = workingDirectory
|
||||||
|
cmd.Env = append(os.Environ(),
|
||||||
|
"TERM=vt100",
|
||||||
|
"LINES=24",
|
||||||
|
"COLUMNS=80",
|
||||||
|
)
|
||||||
stdout, err := cmd.StdoutPipe()
|
stdout, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Failed to set stdout\n")
|
fmt.Printf("Failed to set stdout\n")
|
||||||
|
@ -100,11 +105,6 @@ func execCommand(linuxCommand string, workingDirectory string) {
|
||||||
inputComplete := make(chan bool)
|
inputComplete := make(chan bool)
|
||||||
userCancelled := make(chan bool)
|
userCancelled := make(chan bool)
|
||||||
|
|
||||||
if linuxCommand == "openssl" {
|
|
||||||
fmt.Printf("\nSending help command...\n")
|
|
||||||
io.WriteString(stdin, "help\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
go getStdin(stdin, outputComplete, inputComplete, userCancelled)
|
go getStdin(stdin, outputComplete, inputComplete, userCancelled)
|
||||||
go getStdout(stdout, outputComplete, userCancelled)
|
go getStdout(stdout, outputComplete, userCancelled)
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ func getStdout(stdout io.ReadCloser, outputComplete chan bool, userCancelled cha
|
||||||
}
|
}
|
||||||
if n > 0 {
|
if n > 0 {
|
||||||
b := bb[0]
|
b := bb[0]
|
||||||
sendCharacter(b)
|
comm.SendCharacter(b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -160,14 +160,18 @@ func getStdin(stdin io.WriteCloser, done chan bool, inputComplete chan bool, use
|
||||||
default:
|
default:
|
||||||
b, err := comm.ReadByte()
|
b, err := comm.ReadByte()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if b == 3 {
|
if b == 0x03 {
|
||||||
stdin.Close()
|
stdin.Close()
|
||||||
userCancelled <- true
|
userCancelled <- true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if b == 13 {
|
if b == 0x0d {
|
||||||
b = 10
|
b = 0x0a
|
||||||
}
|
}
|
||||||
|
if b == 0x0b {
|
||||||
|
b = 'k'
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Printf("%c", b)
|
fmt.Printf("%c", b)
|
||||||
io.WriteString(stdin, string(b))
|
io.WriteString(stdin, string(b))
|
||||||
}
|
}
|
||||||
|
@ -220,17 +224,3 @@ func a2wifiSelect(linuxCommand string) (string, error) {
|
||||||
"sudo wpa_cli -i wlan0 reconfigure"
|
"sudo wpa_cli -i wlan0 reconfigure"
|
||||||
return linuxCommand, nil
|
return linuxCommand, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendCharacter(b byte) {
|
|
||||||
fmt.Print(string(b))
|
|
||||||
if b == 10 { // convert LF to CR for Apple II compatiblity
|
|
||||||
b = 13
|
|
||||||
}
|
|
||||||
if b == 9 { // convert TAB to spaces
|
|
||||||
b = ' '
|
|
||||||
b += 128
|
|
||||||
comm.WriteByte(b)
|
|
||||||
}
|
|
||||||
b |= 128
|
|
||||||
comm.WriteByte(b)
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue