831 lines
24 KiB
C
831 lines
24 KiB
C
// NOTE: disable a couple of defines if you get "IndexError: list index out of range"
|
|
//#define DEBUG // Indicate data on the LEDs as a counter
|
|
//#define TESTS // Run some test procedures instead of actual terminal, defined in helpers.h
|
|
//#define SLOW // Runs tests slower
|
|
|
|
#define COLORS // Enable terminal colors (costs extra memory)
|
|
//#define LEDS // Allow for usage of Gigatron LEDs within the application (costs extra memory)
|
|
#define FAST_START // Quick startup by disabling the screen during initialization
|
|
#define ANSI_BLOCK_CHARS // Allow ANSI block characters (costs extra memory)
|
|
//#define TERMINAL_MODES // Enable terminal modes (costs extra memory)
|
|
#define TINY_FONT // Enables small font (costs extra memory)
|
|
|
|
// Successful combinations (trial and error), leave out one of the following:
|
|
// COLORS
|
|
// LEDS and ANSI_BLOCK_CHARS
|
|
// LEDS and TERMINAL_MODES
|
|
// ANSI_BLOCK_CHARS and TERMINAL_MODES
|
|
|
|
// We can only define the port after including the helper file
|
|
#include "vtactionstates.h"
|
|
#include "helpers.h"
|
|
|
|
// Enable SPI hardware by assigning Slave Select pin (SS0 to SS3). Note that SS0 is reserved for an SD card.
|
|
// Comment out to do local loopback
|
|
#define IOPORT SS1
|
|
|
|
byte oldchar;
|
|
byte intermediate = 0;
|
|
|
|
int params[10] = {0};
|
|
byte paramCount = 0;
|
|
|
|
int savedCursor = 0;
|
|
|
|
char response[10] = {0};
|
|
byte responseIndex = 0;
|
|
|
|
#ifdef TESTS
|
|
void main(void)
|
|
{
|
|
test();
|
|
while( 1 );
|
|
}
|
|
#else
|
|
// Forward declaration
|
|
void vt_parse( byte _byte );
|
|
byte SPIExchangeKey( byte _key );
|
|
|
|
void main(void)
|
|
{
|
|
byte spiData;
|
|
|
|
ScreenPos = (int)screenMemory;
|
|
#ifndef TINY_FONT
|
|
ScreenPos |= 0x02;
|
|
#endif
|
|
|
|
if ( romType < romTypeValue_DEVROM )
|
|
{
|
|
//puts( "Terminal is only supported\non ROMv4 or higher." );
|
|
puts( "Terminal is only supported\non xopr's DEVROM." );
|
|
while(1);
|
|
}
|
|
|
|
#ifdef FAST_START
|
|
// Disable video to increase speed
|
|
sysFn = SYS_SetMode_v2_80;
|
|
vAC = 1975;
|
|
__syscall(230); // 270-80/2
|
|
#else
|
|
// Set lower video mode to increase speed
|
|
sysFn = SYS_SetMode_v2_80;
|
|
vAC = 3;
|
|
__syscall(230); // 270-80/2
|
|
#endif
|
|
|
|
EraseInDisplay( 2, ScreenPos );
|
|
drawCursor( 1 );
|
|
setCursor( 0, 0 );
|
|
|
|
#ifdef IOPORT
|
|
// Enable SPI port
|
|
sysFn = SYS_ExpanderControl_v4_40;
|
|
vAC = ~IOPORT & SPI_MASK | BANK0;
|
|
__syscall(250); // 270-40/2
|
|
|
|
// To disable
|
|
//vAC = IOPORT & SPI_MASK | BANK0;
|
|
#endif
|
|
|
|
#ifdef LEDS
|
|
// Disable LED sequencer and set 4th led
|
|
ledState = 1;
|
|
xoutMask = 8;
|
|
|
|
#endif
|
|
|
|
#ifdef FAST_START
|
|
// Set lower video mode to increase speed
|
|
sysFn = SYS_SetMode_v2_80;
|
|
vAC = 3;
|
|
__syscall(230); // 270-80/2
|
|
#endif
|
|
|
|
while ( 1 )
|
|
{
|
|
if ( response[ responseIndex ] )
|
|
{
|
|
spiData = response[ responseIndex ];
|
|
responseIndex++;
|
|
|
|
// End of string?
|
|
if ( !response[ responseIndex ] )
|
|
{
|
|
response[ 0 ] = 0;
|
|
responseIndex = 0;
|
|
}
|
|
#ifndef IOPORT
|
|
// Color output marking it dummy
|
|
Color = Red;
|
|
PutChar( spiData );
|
|
Color = White;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
spiData = serialRaw;
|
|
|
|
#ifndef IOPORT
|
|
if ( spiData == DEL )
|
|
spiData = BS;
|
|
#endif
|
|
|
|
if ( spiData == oldchar )
|
|
spiData = 0;
|
|
else
|
|
oldchar = spiData;
|
|
|
|
#if defined(DEBUG) && defined(LEDS)
|
|
// Blinky led on input to detect freezes
|
|
if ( spiData && spiData != 0xff )
|
|
xoutMask++;
|
|
#endif
|
|
|
|
#ifdef IOPORT
|
|
// Translate buttons to escape code
|
|
switch ( spiData )
|
|
{
|
|
case buttonUp: response[ 0 ] = 0x1B; response[ 1 ] = '['; response[ 2 ] = 'A'; response[ 3 ] = 0;break;
|
|
case buttonDown: response[ 0 ] = 0x1B; response[ 1 ] = '['; response[ 2 ] = 'B'; response[ 3 ] = 0;break;
|
|
case buttonRight: response[ 0 ] = 0x1B; response[ 1 ] = '['; response[ 2 ] = 'C'; response[ 3 ] = 0;break;
|
|
case buttonLeft: response[ 0 ] = 0x1B; response[ 1 ] = '['; response[ 2 ] = 'D'; response[ 3 ] = 0;break;
|
|
}
|
|
#else
|
|
// Translate buttons to local action
|
|
switch ( spiData )
|
|
{
|
|
case buttonUp: cursorUp( 1, 0 ); break;
|
|
case buttonDown: cursorDown( 1, 0 ); break;
|
|
case buttonRight: cursorRight( 1 ); break;
|
|
case buttonLeft: cursorLeft( 1 ); break;
|
|
}
|
|
vt_parse( spiData );
|
|
#endif
|
|
}
|
|
|
|
#ifdef IOPORT
|
|
// Send key to terminal server
|
|
spiData = SPIExchangeKey( spiData );
|
|
vt_parse( spiData );
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void vt_action_regular( byte _byte )
|
|
{
|
|
if ( _byte >= SP && _byte < DEL )
|
|
{
|
|
// Print character
|
|
PutChar( _byte );
|
|
drawCursor( 1 );
|
|
}
|
|
#ifdef ANSI_BLOCK_CHARS
|
|
else if ( _byte == 176 )
|
|
{
|
|
// Block light
|
|
PutGlyph( 0x280a );
|
|
drawCursor( 1 );
|
|
}
|
|
else if ( _byte == 177 )
|
|
{
|
|
// Block medium
|
|
PutGlyph( 0x5555 );
|
|
drawCursor( 1 );
|
|
}
|
|
else if ( _byte == 178 )
|
|
{
|
|
// Block dark
|
|
PutGlyph( 0x7d5f );
|
|
drawCursor( 1 );
|
|
}
|
|
else if ( _byte == 219 )
|
|
{
|
|
// Block
|
|
PutChar( 127 );
|
|
drawCursor( 1 );
|
|
}
|
|
else if ( _byte == 220 )
|
|
{
|
|
// Block bottom
|
|
PutGlyph( 0x6318 );
|
|
drawCursor( 1 );
|
|
}
|
|
else if ( _byte == 221 )
|
|
{
|
|
// Block left
|
|
PutGlyph( 0x03ff );
|
|
drawCursor( 1 );
|
|
}
|
|
else if ( _byte == 222 )
|
|
{
|
|
// Block right
|
|
PutGlyph( 0xec00 );
|
|
drawCursor( 1 );
|
|
}
|
|
else if ( _byte == 223 )
|
|
{
|
|
// Block top
|
|
PutGlyph( 0x1ce7 );
|
|
drawCursor( 1 );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void vt_action_control_sequence_execute( byte _byte )
|
|
{
|
|
switch ( _byte )
|
|
{
|
|
case 'A':
|
|
// ESC [ Pn A CUU -- Cursor Up -- Host to VT100 and VT100 to Host
|
|
if ( params[0] == 0 )
|
|
params[0] = 1;
|
|
cursorUp( params[0], 0 );
|
|
break;
|
|
|
|
case 'B':
|
|
// ESC [ Pn B CUD -- Cursor Down -- Host to VT100 and VT100 to Host
|
|
if ( params[0] == 0 )
|
|
params[0] = 1;
|
|
cursorDown( params[0], 0 );
|
|
break;
|
|
|
|
case 'C':
|
|
// ESC [ Pn C CUF -- Cursor Forward -- Host to VT100 and VT100 to Host
|
|
if ( params[0] == 0 )
|
|
params[0] = 1;
|
|
cursorRight( params[0] );
|
|
break;
|
|
|
|
case 'D':
|
|
// ESC [ Pn D CUB -- Cursor Backward -- Host to VT100 and VT100 to Host (n positions, default 1), stop at margin
|
|
if ( params[0] == 0 )
|
|
params[0] = 1;
|
|
cursorLeft( params[0] );
|
|
break;
|
|
|
|
case 'H':
|
|
// ESC [ Pn ; Pn H CUP -- Cursor Position (line, column)
|
|
case 'f':
|
|
// ESC [ Pn ; Pn f HVP -- Horizontal and Vertical Position (line, column)
|
|
|
|
// The numbering of lines depends on the state of the Origin Mode (DECOM).
|
|
if ( params[0] )
|
|
params[0]--;
|
|
if ( paramCount < 2 )
|
|
params[1] = 0;
|
|
if ( params[1] )
|
|
params[1]--;
|
|
|
|
setCursor( params[0], params[1] );
|
|
break;
|
|
|
|
case 'J':
|
|
// ESC [ Ps J ED -- Erase In Display (
|
|
// 0 Erase from the active position to the end of the screen, inclusive (default)
|
|
// 1 Erase from start of the screen to the active position, inclusive
|
|
// 2 Erase all of the display -- all lines are erased, changed to single-width, and the cursor does not move.
|
|
|
|
// Erase stored cursor character
|
|
drawCursor( 0 );
|
|
EraseInDisplay( params[0], ScreenPos );
|
|
|
|
// Restore cursor
|
|
drawCursor( 1 );
|
|
break;
|
|
|
|
case 'K':
|
|
// ESC [ Ps K EL -- Erase In Line
|
|
// 0 Erase from the active position to the end of the line, inclusive (default)
|
|
// 1 Erase from the start of the screen to the active position, inclusive
|
|
// 2 Erase all of the line, inclusive
|
|
|
|
// Erase stored cursor character
|
|
drawCursor( 0 );
|
|
EraseInLine( params[0], ScreenPos );
|
|
|
|
// Restore cursor
|
|
drawCursor( 1 );
|
|
break;
|
|
|
|
case 'c':
|
|
// ESC [ Pn c DA -- Device Attributes (empty/0 from host, response from terminal:)
|
|
// No options ESC [?1;0c
|
|
// Processor option (STP) ESC [?1;1c
|
|
// Advanced video option (AVO) ESC [?1;2c (10 additional lines of 132 column display,bold...)
|
|
// AVO and STP ESC [?1;3c
|
|
// Graphics option (GPO) ESC [?1;4c
|
|
// GPO and STP ESC [?1;5c
|
|
// GPO and AVO ESC [?1;6c
|
|
// GPO, STP and AVO ESC [?1;7c
|
|
|
|
// Identify: set response to send back
|
|
snprintf(response, sizeof response, "\x1B[?1;0c");
|
|
//puts_ex( response );
|
|
|
|
break;
|
|
|
|
case 'g':
|
|
// ESC [ Ps g TBC -- Tabulation Clear (0=current, 3=all)
|
|
break;
|
|
#ifdef TERMINAL_MODES
|
|
case 'h':
|
|
// ESC [ Ps ; . . . ; Ps h SM -- Set Mode (reset mode counterpart)
|
|
while ( paramCount-- )
|
|
{
|
|
if ( !params[ paramCount ] )
|
|
continue;
|
|
if ( params[ paramCount ] == 20 )
|
|
params[ paramCount ] = 0;
|
|
if ( params[ paramCount ] > 9 )
|
|
continue;
|
|
terminalModes |= (1 << params[ paramCount ]);
|
|
}
|
|
break;
|
|
|
|
case 'l':
|
|
// ESC [ Ps ; Ps ; . . . ; Ps l RM -- Reset Mode (set mode counterpart)
|
|
while ( paramCount-- )
|
|
{
|
|
if ( !params[ paramCount ] )
|
|
continue;
|
|
if ( params[ paramCount ] == 20 )
|
|
params[ paramCount ] = 0;
|
|
if ( params[ paramCount ] > 9 )
|
|
continue;
|
|
terminalModes &= ~(1 << params[ paramCount ]);
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
#ifdef COLORS
|
|
case 'm':
|
|
// ESC [ Ps ; . . . ; Ps m SGR -- Select Graphic Rendition (attributes)
|
|
// Restore character (attribute under cursor will change)
|
|
drawChar( cursor );
|
|
|
|
while ( paramCount-- )
|
|
{
|
|
switch ( params[ paramCount ] )
|
|
{
|
|
case 0: Color = White; BgColor = Blue; break;
|
|
|
|
case 30: Color = Black; break;
|
|
case 31: Color = Red; break;
|
|
case 32: Color = Green; break;
|
|
case 33: Color = Yellow; break;
|
|
case 34: Color = Blue; break;
|
|
case 35: Color = Magenta; break;
|
|
case 36: Color = Cyan; break;
|
|
case 37: Color = LightGray; break;
|
|
|
|
case 40: BgColor = Black; break;
|
|
case 41: BgColor = Red; break;
|
|
case 42: BgColor = Green; break;
|
|
case 43: BgColor = Yellow; break;
|
|
case 44: BgColor = Blue; break;
|
|
case 45: BgColor = Magenta; break;
|
|
case 46: BgColor = Cyan; break;
|
|
case 47: BgColor = LightGray; break;
|
|
|
|
case 90: Color = DarkGray; break;
|
|
case 91: Color = LightRed; break;
|
|
case 92: Color = LightGreen; break;
|
|
case 93: Color = LightYellow; break;
|
|
case 94: Color = LightBlue; break;
|
|
case 95: Color = LightMagenta; break;
|
|
case 96: Color = LightCyan; break;
|
|
case 97: Color = White; break;
|
|
|
|
case 100: BgColor = DarkGray; break;
|
|
case 101: BgColor = LightRed; break;
|
|
case 102: BgColor = LightGreen; break;
|
|
case 103: BgColor = LightYellow; break;
|
|
case 104: BgColor = LightBlue; break;
|
|
case 105: BgColor = LightMagenta; break;
|
|
case 106: BgColor = LightCyan; break;
|
|
case 107: BgColor = White; break;
|
|
}
|
|
}
|
|
|
|
// Restore cursor
|
|
drawCursor( 1 );
|
|
|
|
break;
|
|
#endif
|
|
|
|
case 'n':
|
|
// ESC [ Ps n DSR -- Device Status Report
|
|
switch ( params[ 0 ] )
|
|
{
|
|
case 5:
|
|
// 5 Command from host -- Please report status (using a DSR control sequence)
|
|
// 0 Response from VT100 -- Ready, No malfunctions detected (default)
|
|
// 3 Response from VT100 -- Malfunction -- retry
|
|
// Report ready: set response to send back
|
|
snprintf( response, sizeof response, "\x1B[0n" );
|
|
break;
|
|
case 6:
|
|
// 6 Command from host -- Please report active position (using a CPR control sequence) response
|
|
// ESC [ Pn ; Pn R: CPR -- Cursor Position Report -- VT100 to Host (line,column)
|
|
// Report ready: set response to send back
|
|
// Abuse intermediate variable
|
|
intermediate = (ScreenPos >> 8);
|
|
|
|
if ( videoTable[0] > intermediate )
|
|
intermediate = intermediate + 120 - videoTable[0];
|
|
else
|
|
intermediate -= videoTable[0];
|
|
|
|
intermediate /= ( CHAR_HEIGHT + CHAR_LEADING );
|
|
snprintf( response, sizeof response, "\x1B[%u,%uR", intermediate + 1, ( ScreenPos & 0xff ) / CHAR_WIDTH + 1 );
|
|
break;
|
|
}
|
|
break;
|
|
#ifdef LEDS
|
|
case 'q':
|
|
// ESC [ Ps q DECLL -- Load LEDS (Linux supports L1 as scroll lock, L2 NumLock, L3 as Caps lock , )
|
|
// ESC [ Ps;Ps;...Ps q
|
|
// 0 or None All LEDs Off
|
|
// 1 L1 On
|
|
// 2 L2 On
|
|
// 3 L3 On
|
|
// 4 L4 On
|
|
|
|
// Set LEDs
|
|
while ( paramCount-- )
|
|
{
|
|
if ( !params[ paramCount ] )
|
|
{
|
|
xoutMask = 0;
|
|
}
|
|
else if ( params[ paramCount ] <= 4 )
|
|
{
|
|
// Turn number into bit mask
|
|
params[ paramCount ]--;
|
|
xoutMask |= ( 1 << params[ paramCount ] );
|
|
}
|
|
}
|
|
|
|
break;
|
|
#endif
|
|
/*
|
|
case 'r':
|
|
// ESC [ Pn; Pn r DECSTBM -- Set Top and Bottom Margins (startline, endline scroll)
|
|
break;
|
|
|
|
case 'x':
|
|
// ESC [ <sol>; <par>; <nbits>; <xspeed>; <rspeed>; <clkmul>; <flags> x DECREPTPARM -- Report Terminal Parameters
|
|
break;
|
|
|
|
case 'y':
|
|
// ESC [ 2 ; Ps y DECTST -- Invoke Confidence Test
|
|
// Test Weight
|
|
// 0: reset only
|
|
// 1: Power up self-test (ROM check sum, RAM, NVR keyboard and AVO if installed)
|
|
// 2: Data Loop Back (loop back connector required)
|
|
// 4: EIA modem control test (loop back connector required)
|
|
// 8: Repeat Selected Test(s) indefinitely (until failure or power off)
|
|
// 0 Attributes off
|
|
// 1 Bold or increased intensity
|
|
// 4 Underscore
|
|
// 5 Blink
|
|
// 7 Negative (reverse) image
|
|
break;
|
|
*/
|
|
}
|
|
}
|
|
|
|
void vt_action_control_sequence( byte _byte )
|
|
{
|
|
if ( _byte >= 0x30 && _byte <= 0x39 )
|
|
{
|
|
// Pn: Numbers: param
|
|
params[paramCount] = params[paramCount] * 10 + _byte - 0x30;
|
|
}
|
|
else if ( _byte == ';' )
|
|
{
|
|
// Ps: Next param
|
|
paramCount++;
|
|
params[paramCount] = 0;
|
|
}
|
|
else if ( _byte >= 0x40 && _byte <= 0x7E )
|
|
{
|
|
// Offset param count (0->1)
|
|
paramCount++;
|
|
|
|
// Handle Control sequence
|
|
vt_action_control_sequence_execute( _byte );
|
|
paramCount = 0;
|
|
params[0] = 0;
|
|
mode = VTPARSE_MODE_REGULAR;
|
|
}
|
|
else if ( _byte == '?' )
|
|
{
|
|
// Note that in some cases, ESC[? is sent and therefore allowed
|
|
}
|
|
}
|
|
|
|
void vt_action_escape_sequence( byte _byte )
|
|
{
|
|
switch ( _byte )
|
|
{
|
|
case '0':
|
|
// SCS -- Select Character Set
|
|
// G0 ( or G1 ) Special graphics
|
|
break;
|
|
case '1':
|
|
// SCS -- Select Character Set
|
|
// G0 ( or G1 ) Alternate ROM standard
|
|
break;
|
|
case '2':
|
|
// SCS -- Select Character Set
|
|
// G0 ( or G1 ) Alternate ROM special graphics
|
|
break;
|
|
case '3':
|
|
case '4':
|
|
// # DECDHL -- Double Height Line
|
|
// top/bottom
|
|
break;
|
|
case '5':
|
|
// # DECSWL -- Single-width Line
|
|
break;
|
|
case '6':
|
|
// # DECDWL -- Double-Width Line
|
|
break;
|
|
case '7':
|
|
// DECSC -- Save Cursor
|
|
// This sequence causes the cursor position, graphic rendition (attributes), and character set to be saved. (See DECRC).
|
|
savedCursor = ScreenPos;
|
|
break;
|
|
case '8':
|
|
// # DECALN -- Screen Alignment Display
|
|
// Fill screen with 'E'
|
|
|
|
if ( intermediate != '#' )
|
|
{
|
|
// DECRC -- Restore Cursor
|
|
if ( savedCursor != ScreenPos )
|
|
{
|
|
// Restore character behind cursor
|
|
drawChar( cursor );
|
|
ScreenPos = savedCursor;
|
|
// Draw cursor
|
|
drawCursor( 1 );
|
|
}
|
|
}
|
|
break;
|
|
case 'A':
|
|
// SCS -- Select Character Set
|
|
// G0 ( or G1 ) UK
|
|
|
|
// VT52: Cursor up (no scroll)
|
|
break;
|
|
case 'B':
|
|
// SCS -- Select Character Set
|
|
// G0 ( or G1 ) ASCII
|
|
|
|
// VT52: Cursor down (no scroll)
|
|
break;
|
|
case 'C':
|
|
// VT52: Cursor right (no scroll/newline)
|
|
break;
|
|
case 'D':
|
|
// IND -- Index (cursor down, allow scroll)
|
|
cursorDown( 1, 0 );
|
|
|
|
// VT52: Cursor left (no scroll/newline)
|
|
break;
|
|
case 'E':
|
|
// NEL -- Next Line (CRLF, allow scroll)
|
|
Newline();
|
|
drawCursor( 1 );
|
|
break;
|
|
case 'F':
|
|
// VT52: Enter Graphics Mode
|
|
break;
|
|
case 'G':
|
|
// VT52: Select ASCII character set
|
|
break;
|
|
case 'H':
|
|
// HTS -- Horizontal Tabulation Set
|
|
|
|
// VT52: Move the cursor to the home position.
|
|
break;
|
|
case 'I':
|
|
// VT52: Reverse Line Feed
|
|
break;
|
|
case 'J':
|
|
// VT52: Erase to End of Screen
|
|
break;
|
|
case 'K':
|
|
// VT52: Erase to End of Line
|
|
break;
|
|
case 'M':
|
|
// RI -- Reverse Index (cursor up, allow scoll)
|
|
cursorUp( 1, 1 );
|
|
break;
|
|
case 'Y':
|
|
// VT52: Direct Cursor Address (needs line, column)
|
|
//mode = VTPARSE_MODE_ESCAPE_CURSOR_LINE;
|
|
break;
|
|
case 'Z':
|
|
// DECID -- Identify Terminal, deprecated->ESC[?1;0c
|
|
// set response to send back
|
|
snprintf(response, sizeof response, "\x1B[?1;0c");
|
|
//puts_ex( response );
|
|
|
|
// VT52: Identify, reply with ESC / Z
|
|
break;
|
|
#ifdef TERMINAL_MODES
|
|
case '=':
|
|
// DECKPAM -- Keypad Application Mode
|
|
terminalModes |= DECKPAM;
|
|
// VT52: Enter Alternate Keypad Mode
|
|
break;
|
|
case '>':
|
|
// DECKPNM -- Keypad Numeric Mode
|
|
terminalModes &= ~DECKPAM;
|
|
#endif
|
|
// VT52: Exit Alternate Keypad Mode
|
|
break;
|
|
case '<':
|
|
// VT52: Enter ANSI Mode (ignore VT52 escape codes)
|
|
break;
|
|
}
|
|
|
|
// Note: the previous switch statement is at its max apparently
|
|
switch ( _byte )
|
|
{
|
|
case 'c':
|
|
// RIS -- Reset To Initial State
|
|
break;
|
|
case '[':
|
|
// CSI -- Control Sequence Introducer
|
|
mode = VTPARSE_MODE_CONTROL_SEQUENCE;
|
|
break;
|
|
}
|
|
|
|
// Reset mode if it was not altered
|
|
if ( mode == VTPARSE_MODE_ESCAPE_INTERMEDIATE )
|
|
mode = VTPARSE_MODE_REGULAR;
|
|
|
|
intermediate = 0;
|
|
}
|
|
|
|
void vt_action_escape_intermediate( byte _byte )
|
|
{
|
|
if ( _byte >= 0x30 && _byte <= 0x7E )
|
|
{
|
|
// Handle escape (might turn into control sequence)
|
|
vt_action_escape_sequence( _byte );
|
|
}
|
|
else if ( _byte < 0x20 || _byte >= 0x2F )
|
|
{
|
|
// TODO: Error
|
|
}
|
|
|
|
// Store intermediate (assume only 1 character)
|
|
if ( !intermediate )
|
|
intermediate = _byte;
|
|
}
|
|
|
|
byte vt_parse_control_char( byte _byte )
|
|
{
|
|
/*
|
|
if ( _byte != NUL )
|
|
{
|
|
snprintf(response, sizeof response, "%d", _byte );
|
|
puts_ex( response );
|
|
}
|
|
*/
|
|
// Check if we need to parse a control char in the stream
|
|
if ( _byte == NUL )
|
|
{
|
|
// Ignored on input (not stored in input buffer; see full duplex protocol).
|
|
}
|
|
else if ( _byte == ENQ )
|
|
{
|
|
// Transmit answerback message.
|
|
}
|
|
else if ( _byte == BEL )
|
|
{
|
|
// bell sound
|
|
}
|
|
else if ( _byte == BS )
|
|
{
|
|
// Backspace
|
|
// TODO: rollover
|
|
if ((ScreenPos & 0xff) >= CHAR_WIDTH)
|
|
{
|
|
// Remove cursor
|
|
drawChar( cursor );
|
|
|
|
ScreenPos -= CHAR_WIDTH;
|
|
|
|
// draw cursor
|
|
drawCursor( 0 );
|
|
}
|
|
}
|
|
else if ( _byte == '`'/*HT*/ )
|
|
{
|
|
// move to next tabstop (align on 8*CHAR_WIDTH pixels)
|
|
drawChar( cursor );
|
|
|
|
PutChar_ex( HT );
|
|
|
|
// Restore character behind cursor
|
|
drawCursor( 1 );
|
|
}
|
|
else if ( _byte >= LF && _byte <= FF )
|
|
{
|
|
// Line feed: depends on mode
|
|
// Note: incoming keyboard enter translates to line feed
|
|
#ifndef IOPORT
|
|
drawChar( cursor );
|
|
Newline();
|
|
drawCursor( 1 );
|
|
#endif
|
|
}
|
|
else if ( _byte == CR )
|
|
{
|
|
// (Carriage) Return
|
|
Newline();
|
|
drawCursor( 1 );
|
|
}
|
|
else if ( _byte == SO )
|
|
{
|
|
// TODO: SO 016 0E Invoke G1 character set, as designated by SCS control sequence.
|
|
}
|
|
else if ( _byte == SI )
|
|
{
|
|
// TODO: SI 017 0F Select G0 character set, as selected by ESC ( sequence.
|
|
}
|
|
else if ( _byte == XON )
|
|
{
|
|
// TODO: XON 021 11 Causes terminal to resume transmission.
|
|
}
|
|
else if ( _byte == XOFF )
|
|
{
|
|
// TODO: XOFF 023 13 Causes terminal to stop transmitted all codes except XOFF and XON.
|
|
}
|
|
else if ( _byte == ESC || _byte == CAN || _byte == SUB )
|
|
{
|
|
// Clear params/intermediates, abort or restart escape sequence
|
|
intermediate = 0;
|
|
paramCount = 0;
|
|
params[0] = 0;
|
|
|
|
// Restart or Abort?
|
|
if ( _byte == ESC )
|
|
mode = VTPARSE_MODE_ESCAPE_INTERMEDIATE;
|
|
else
|
|
mode = VTPARSE_MODE_REGULAR;
|
|
}
|
|
else if ( _byte == DEL )
|
|
{
|
|
// Ignored on input (not stored in input buffer).
|
|
}
|
|
else
|
|
{
|
|
// No control character
|
|
return 0;
|
|
}
|
|
|
|
// Control character parsed
|
|
return 1;
|
|
}
|
|
|
|
void vt_parse( byte _byte )
|
|
{
|
|
// Check if we got a control character (which will be parsed)
|
|
if ( vt_parse_control_char( _byte ) )
|
|
return;
|
|
|
|
switch ( mode )
|
|
{
|
|
case VTPARSE_MODE_REGULAR: // (control+printable characters)
|
|
vt_action_regular( _byte );
|
|
break;
|
|
|
|
case VTPARSE_MODE_ESCAPE_INTERMEDIATE: // 0x20-0x2F (attribute chars)
|
|
vt_action_escape_intermediate( _byte );
|
|
break;
|
|
|
|
case VTPARSE_MODE_CONTROL_SEQUENCE: // 0x40-x07E (characters)
|
|
vt_action_control_sequence( _byte );
|
|
break;
|
|
}
|
|
}
|
|
|
|
byte SPIExchangeKey( byte _key )
|
|
{
|
|
*(int*)(sysArgs) = (int)&_key; // Start address
|
|
*(int*)(sysArgs+2) = (int)(&_key) + 1; // End address
|
|
sysFn = SYS_SpiExchangeBytes_v4_134;
|
|
__syscall(203); // 270-134/2
|
|
|
|
return _key;
|
|
}
|
|
#endif
|