;VT100/ANSI-Funktionen für ATmega auf (Hyper)Terminal
;Benötigt:
; getchar() Zeichen lesen (blockierend) - Ergebnis in UART_InChar
; putchar(r16) Zeichen schreiben (blockierend)
; UART_InChar Register >R16
;Wenn Symbol COLOR_CACHED definiert:
; CurrentColor Register >R0
;Bietet (diverses):
; div10b(r16) Division Byte durch 10, lausig wie 8051...
; div10(r17:r16) Division Word durch 10
; SendByte(r16) Ausgabe 1 Byte dezimal
; SendSpace() Leerzeichen senden
; SendCSI() CSI (ESC"[") senden
; SendVisible(r16)`if (r16==0x7F || r16<' ') r16='_';´ und ausgeben
;Bietet (Terminal-Hilfe):
; GetKey() Tastenkode lesen mit VT100-Umrechnung der Kursortasten
; GotoXY(x,y) Gehe zur Position
; SendColor(r17) Farbe setzen (mit oder ohne Cache-Funktion je nach COLOR_CACHED)
#ifndef VT100_I90
#define VT100_I90
;##############################
;## Zahlen und Zeichenketten ##
;##############################
div10b:
clr r17
div10:
;Division 16bit/10 = 8 bit Rest 8 bit
;PE: R17:R16=Dividend
;PA: R16=Quotient, R17=Rest
;VR: R16-R17
push r18
clr r17
ldi r18,8 ;Schleifenzähler
div1: lsl r16
rol r17
cpi r17,10
brcs div2
subi r17,10
inc r16 ;LSB im Divisionsergebnis setzen
div2: dec r18
brne div1
pop r18
ret
SendByte: ;Byte R16 dezimal ausgeben
;VR: R16-R17
push r18
ldi r18,1
sb1: cpi r16,10
brlo sb3 ;Letzte Division vermeiden
rcall div10b
;Fertig mit Division, aus Rest ASCII-Zeichen machen
push r17
inc r18 ;PUSH mitzählen
rjmp sb1
sb2: pop r16
sb3: ori r16,'0'
rcall putchar
dec r18
brne sb2
pop r18
ret
;#########################
;## VT100/ANSI-Routinen ##
;#########################
GetKey:
;Tastenabfrage mit Konvertierung von Kursortasten u.ä., blockierend
;VR: R16
rcall getchar
dontknow:
cpi UART_InChar,0x00;Müll von HyperTerminal
breq GetKey
cpi UART_InChar,0x1B;ESC
breq handle_esc
ret
handle_esc: ;Idee: Nur ESC nach einemm TimeOut erzeugt ^C!
rcall getchar ;Folgezeichen
cpi UART_InChar,'['
breq handle_esc
cpi UART_InChar,'O'
breq handle_esc
;Steuertasten
cpi UART_InChar,0x1B;ESC (2x)
ldi r16, 0x03 ;^C
breq chr_r16
cpi UART_InChar,'H' ;Pos1
ldi r16, 0x01 ;^A
breq chr_r16
cpi UART_InChar,'K' ;Ende
ldi r16, 0x05 ;^E
breq chr_r16
;Cursortasten
cpi UART_InChar,'A' ;Pfeil hoch
ldi r16, 0x10 ;^P
breq chr_r16
cpi UART_InChar,'B' ;Pfeil runter
ldi r16, 0x0E ;^N
breq chr_r16
cpi UART_InChar,'C' ;Pfeil rechts
ldi r16, 0x06 ;^F
breq chr_r16
cpi UART_InChar,'D' ;Pfeil links
ldi r16, 0x02 ;^B
;Funktionstasten
breq chr_r16
cpi UART_InChar,'P' ;F1..F4
brlo dontknow
cpi UART_InChar,'S'+1
brsh dontknow
subi UART_InChar,'P'+0x1C ;µC-interne Kodes
ret
chr_r16:
mov UART_InChar,r16
ret
SendSemi: ;Semikolon ausgeben
ldi r16,';'
rjmp putchar
SendCSI: ;CSI (ESC'[') ausgeben
ldi r16,0x1B
rcall putchar
ldi r16,'['
rjmp putchar
SendSpace:
ldi r16,' '
rjmp putchar
SendVisible:
cpi r16,0x7F
breq sv1
cpi r16,' '
brsh sv2
sv1: ldi r16,'_' ;Alle "unangenehmen" Zeichen ersetzen!
sv2: rjmp putchar
GotoXY: ;Setze Kursor auf Position
;PE: R16 = X-Position (0 = erste Spalte links)
; R17 = Y-Position (0 = erste Zeile oben)
;VR: R16-R17
push r16
rcall SendCSI
mov r16,r17
inc r16
rcall SendByte
rcall SendSemi
pop r16
inc r16
rcall SendByte
ldi r16,'H'
rjmp putchar
putchar0: ;Ausgabe von '0' bis '7' (für ANSI-Farben)
andi r16,0x07
ori r16,'0'
rjmp putchar
#ifdef COLOR_CACHED
SendSemiCheck:
brtc ssc1 ;Semikolon ausgeben, wenn T-Flag gesetzt
rcall SendSemi
ssc1: set ;Beim nächsten Mal immer ein Semikolon ausgeben
sce: ret
SendColor: ;Setze Farbe für folgende Ausgaben, kürzestmögliche Sequenz mit Cache
;Besonders für langsame serielle Verbindungen oder häufigen Farbwechseln gut
;PE: R17 = Farbkode
; Bit3:0 = Vordergrund (Bit 3 = Intensitätsbit)
; Bit6:4 = Hintergrund
; Bit7 = Blinken
; CurrentColor = momentane Farbe (>R0)
;VR: R16, T-Flag, CurrentColor=R17
;Farb-Bitzuordnung anders als in DOS!! Bit 0=rot, Bit 1=grün, Bit2=blau
;Unterstreichung wird hier nicht gehandhabt.
clt
cp CurrentColor,r17
breq sce ;Nichts zu tun!
rcall SendCSI
;Das "Rücksetzen von Attributen" ist nur notwendig, wenn ein Intensitäts-
;oder ein Blinkbit verschwindet - oder kurzerhand wenn grau-auf-weiß gewünscht
cpi r17,0x07 ;Standard?
breq sc0 ;Nur CSI"0m" ausgeben
mov r16,r17
com r16 ;Null-Bits zu 1
and r16,CurrentColor
andi r16,0x88 ;Intensität oder Blinken Übergang 1->0?
breq sc1 ;Kein derartiger Fall: Null überspringen
sc0: ldi r16,'0'
rcall putchar
set
ldi_ CurrentColor,0x07;Jetzt ist's grau auf schwarz
sc1:
sbrc r17,7 ;Immer überspringen, wenn Blink-Bit zu löschen
sbrc CurrentColor,7 ;RJMP überspringen, wenn Blink-Bit gelöscht war
rjmp sc2 ;Heißer Kode!!
rcall SendSemiCheck
ldi r16,'5'
rcall putchar ;wenn Blink-Bit hinzukommt
sc2:
mov r16,r17
eor r16,CurrentColor
andi r16,0x70 ;Hintergrundfarbe
breq sc3 ;unverändert
rcall SendSemiCheck
ldi r16,'4' ;Hintergrundfarbe
rcall putchar
mov r16,r17
swap r16
rcall putchar0 ;wenn Hintergrundfarbe sich ändert
sc3:
sbrc r17,3
sbrc CurrentColor,3
rjmp sc4
rcall SendSemiCheck
ldi r16,'1'
rcall putchar ;wenn Intensitäts-Bit hinzukommt
sc4:
mov r16,r17
eor r16,CurrentColor
andi r16,0x07 ;Textfarbe
breq sc5 ;unverändert
rcall SendSemiCheck
ldi r16,'3' ;Textfarbe
rcall putchar
mov r16,r17
rcall putchar0 ;wenn Textfarbe sich ändert
sc5:
mov CurrentColor,r17
ldi r16,'m'
rjmp putchar
#else
SendColor: ;Setze Farbe für folgende Ausgaben, ohne Cache
;PE: R17 = Farbkode
; Bit3:0 = Vordergrund
; Bit6:4 = Hintergrund
; Bit7 = Blinken
;VR: R16
;Farb-Bitzuordnung anders als in DOS!! Bit 0=rot, Bit 1=grün, Bit2=blau
;Unschön: Verschwindet das Blinken, wenn man "intensiv" eingeschaltet hat?
rcall SendCSI
ldi r16,'0'
sbrc r17,3 ;Intensitäts-Bit
inc r16
rcall putchar
rcall SendSemi
ldi r16,'3' ;Textfarbe
rcall putchar
mov r16,r17 ;Vordergrundfarbe
rcall putchar0
rcall SendSemi
ldi r16,'4' ;Hintergrundfarbe
rcall putchar
mov r16,r17
swap r16
andi r16,0x07 ;Hintergrundfarbe
subi r16,-'0'
rcall putchar
sbrs r17,7 ;Blink-Bit
rjmp sc1
rcall SendSemi
ldi r16,'5'
rcall putchar
sc1: ldi r16,'m'
rjmp putchar
#endif
#endif//VT100_H
Detected encoding: UTF-8 | 0
|