Dynamic visualizations On ‘non-canonical’ keyboard-input and terminal escape-sequences for visualization effects
Our course’s theme Using the computer to study the computer
Two ‘dynamic visualizations’ Showing the Linux kernel’s algorithm for setting up ‘permanent kernel mappings’ Showing the dual-CPUs’ responses to device-interrupts and CPU-exceptions
Some application tools We need to modify the terminal-console’s normal way of processing keyboard-input and of displaying its line-at-a-time output ANSI terminal escape-sequences allow page-oriented output (i.e., left-and-right, up-and-down), control of cursor-visibility and of character-attributes (e.g., colors)
The ‘tty’ interface ‘tty’ is an acronyn for ‘TeleTYpe’ terminal Such devices have a keyboard and screen Behavior emulates technology from 1950s Usually a tty operates in ‘canonical’ mode: –Each user-keystroke is ‘echoed’ to screen –Some editing is allowed (e.g., backspace) –The keyboard-input is internally buffered –The -key signals an ‘end-of-line’ –Programs receive input one-line-at-a-time
‘tty’ customization Sometimes canonical mode isn’t suitable (an example: animated computer games) The terminal’s behavior can be modified! UNIX provides a convenient interface: –#include –struct termios tty; –int tcgetattr( int fd, struct termios *tty ); –int tcsetattr( int fd, int flag, struct termios *tty );
How does the ‘tty’ work? TeleTYpe display device HARDWARE SOFTWARE application tty_driver c_lflag input handling c_iflag c_cc output handling c_oflag terminal_driver c_cflag User space Kernel space struct tty { c_iflag; c_oflag; c_cflag; c_lflag; c_line; c_cc[ ]; };
The ‘c_lflag’ field This field is just an array of flag bits Individual bits have symbolic names Names conform to a POSIX standard Linux names match other UNIX’s names Though actual symbol values may differ Your C/C++ program should use: #include for portability to other UNIX environments
ICANON and ECHO Normally the ‘c_lflag’ field has these set They can be cleared using bitwise logic: tty.c_lflag &= ~ECHO;// inhibit echo tty.c_lflag &= ~ICANON;// no buffering tty.c_lflag &= ~ISIG;// no CTRL-C
The ‘c_cc[ ]’ array ‘struct termios’ objects include an array The array-indices have symbolic names Symbol-names are standardized in UNIX Array entries are ‘tty’ operating parameters Two useful ones for our purposes are: tty.c_cc[ VMIN ] and tty.c_cc[ VTIME ]
How to setup ‘raw’ terminal-mode Step 1: Use ‘tcgetattr()’ to get a copy of the current tty’s ‘struct termios’ settings Step 2: Make a working copy of that object Step 3: Modify its flags and control-codes Step 4: Use ‘tcsetattr()’ to install changes Step 5: Perform desired ‘raw’ mode input Step 6: Use ‘tcsetattr()’ to restore the terminal to its original default settings
Input-mode needs five settings tty.c_cc[ VMIN ] = 0; –so the ‘read()’ function will return -- even if there is not at least one new input-character available tty.c_cc[ VTIME ] = 0; –so there will be no time-delay, after each new key pressed, until the ‘read()’ function returns tty.c_lflag &= ~ECHO;// no input-echoing tty.c_lflag &= ~ICANON;// no buffering tty.c_lflag &= ~ISIG;// no -C
Demo program: ‘noncanon.cpp’ This program may soon prove useful It shows the keyboard scancode values It demonstrates ‘noncanonical’ tty mode It clears the ISIG bit (in ‘c_lflags’ field) This prevents -C from being used to abort the program: the user must ‘quit’ by hitting the -key; so default terminal-settings will get reinstalled
‘Noncanonical’ terminal i/o We’ve now learned how to reprogram the terminal to allow “raw” keyboard input #include struct termiostty; tcgetattr( 0, &tty );// get tty settings tty.c_lflag &= ~( ICANON | ECHO | ISIG ); tty.c_cc[ VMIN ] = 1; tty.c_cc[ VTIME ] = 0; tcsetattr( 0, TCSAFLUSH, &tty );// install
ANSI command-sequences A look at some terminal emulation features utilized in the “console- redirection” mechanism
Clearing the screen Here is an ANSI command-sequence that clears the terminal’s display-screen: charcmd[] = “\033[2J”; intlen = strlen( cmd ); write( 1, cmd, len );
Reposition the cursor Here is an ANSI command-sequence that moves the cursor to row 12, column 40: charcmd[] = “\033[12;40H”; intlen = strlen( cmd ); write( 1, cmd, len );
ANSI color-codes 0 = black 1 = red 2 = green 3 = brown 4 = blue 5 = magenta 6 = cyan 7 = gray
Setting text attributes Here is an ANSI command-sequence that sets foreground and background colors: charcmd[] = “\033[32;44m”; intlen = strlen( cmd ); write( 1, cmd, len );
Cursor visibility commands Here are ANSI command-sequences that will ‘hide’ or ‘show’ the terminal’s cursor: charhide[] = “\033[?25l”;// lowercase L charshow[] = “\033[?25h”;// lowercase H
In-class exercise #1 Modify this simple C++ program so that it will print its “Hello” message in colors and be located in the center of the screen: #include int main( void ) { printf( “Hello, world! \n” ); }
In-class exercise #2 Compile and install our ‘pkmaps.c’ module Then download, compile and execute our ‘mapwatch.cpp’ visualization-application While ‘mapwatch’ continues to run in one window of your graphical desktop, open a second window nearby and execute some common commands, for example: $ ls $ mmake pkmaps
In-class exercise #3 Compile and install our ‘smpwatch.c’ LKM Then download, compile and execute our ‘smpwatch.cpp’ visualization-application In a nearby window, try hitting some keys and moving the mouse Try executing the ‘ping’ command to see if another machine responds, for example: $ ping stargate