Menu

Create Extra Consoles for Your Program. Control Your Extra Console with Escaping.

2022-09-03 - General Programming

Introduction

You might want an extra console for your program. However, you may realize that you can only have one console per process. Functions like AllocConsole may fail if you already have a console. Usually, solution would be like creating a console client process and using pipe to emulate the created stdin and stdout. You might want to write this console client program on your own, but actually it’s unnecessary. There are already great programs you may use.

PuTTY is a great implementation of console client. You may run this program for your extra consoles. In order to create a console, you may create a process with following command:

putty -serial \\.\pipe\console_pipename

In this way, the PuTTY would connect to the named pipe and become your extra console.

Control Characters

The control characters are the cornerstone of console controlling. However, only a few of them are commonly used:

NameC Escape SequenceHexadecimalDescription
Null\00x00Null-Terminator of a string
Backspace\b0x08Move the cursor one unit backwards
Horizontal Tab\t0x09Advance the cursor to next tab stop
Line Feed\n0x0AAdvance the cursor to one line downwards
Carriage Return\r0x0DReset the cursor to the beginning of a line
Escape\e0x1BInvoke an alternative interpretation of sequence
Commonly-used Control Characters

The Escape Sequence

Most control characters are very common. Everyone should be familiar with \n because we use that to change to a new line. However, the \e sequence is not so common. Yet this control character is mostly powerful.

Most usage with escape sequence starts with Control Sequence Introducer (abbreviated as CSI), encoded as 0x5B, the left square bracket. Following the CSI, you will put a series “parameter bytes” in the range of 0x30-0x3F, then by a series of “intermediate bytes” in the range of 0x20-0x2F, then eventually by a single final byte in the range 0x40-0x7E. Common “parameter bytes” would be an array of decimal integers separated by semicolons, such as 1;2;3 (0x31 0x3B 0x32 0x3B 0x33 in hexadecimal). If there are missing numbers in the array, such as 1;;3 (0x31 0x3B 0x3B 0x33 in hexadecimal), the missing numbers will be treated as zeroes like 1;0;3. Intermediate bytes are rare, so this blog will skip it. The final byte should be a letter or other character in the range 0x40-0x7E.

Colored Console

To bring the console with colorful characters, you will escape the console with CSI and end the escaping with character m, meaning Select Graphic Rendition (SGR). You may find complete introduction from Wikipedia. Please note that the colors you set on the console include two dimensions: the foreground colors and background colors. You have three options for setting colors: 4-bit (16 colors), 8-bit (256 colors) and 24-bit (true colors).

Cursor Positioning

In order to reposition the cursor of the console, you escape the console with CSI and end the escaping with a capital character from A to H. Note that missing integers will be treated as ones instead of zeroes.

Miscellaneous Operations

You may erase the display by escaping the console with CSI and end the escape sequence with capital J. The decimal number between CSI and J determines how the display would be erased:

You may erase the current line by escaping the console with CSI and end the escape sequence with capital K. The decimal integer between CSI and K determines how the line would be erased:

You may scroll the console page up and down by escaping the console with CSI and end the escape sequence with capital S or T The decimal integer between CSI and S or T determines how many lines would be scrolled up or down.

Implementing Console Communications

One important thing is that PuTTY supports fully-duplex communication, meaning that you may implement a fully-duplex console, even though you don’t have to do so.

Implementing Serial Console on Bare-Metal

Traditional serial consoles are easy to implement in bare-metal environment in that the serial hardware is easy to drive. You may read the serial port introduction on OSDev wiki.

If you are running your program on UEFI, you may use EFI_SERIAL_IO_PROTOCOL to operate the serial ports. However, it is still possible to drive serial ports by using I/O instructions. In order to do so, you will have to parse AML (ACPI Machine Language) in DSDT and find resource usage of serial ports defined in ACPI namespace.

For virtual machines running on VMware, serial ports can be emulated by named pipes. You may run PuTTY on your physical machine to be the extra console for the virtual machine.

Implementing Extra Console within OS

In order to implement your extra console within an OS, the named pipe is a great choice.

For example, if you write .NET applications, you may use NamedPipeServerStream Class to create a named pipe and let PuTTY to connect to it. Since this class inherits the PipeStream Class, you may use Read, Write to communicate with PuTTY.
You might want to specify PipeOptions.Asynchronous option when instantiating a named pipe for fully-duplex serial operations.

Likewise, you may use CreateNamedPipe function for Windows applications, and any similar functions on other OS platforms. The general idea is to let your program be the server of named pipe.

What if My Environment Cannot Create Named Pipes

You may set up a TCP server and use telnet to connect to your server. Typical Linux distributions include the telnet program. For Windows, you may install WSL, or use PuTTY.

Conclusion

This blog has briefly introduced methods of creating extra consoles for your program. You may even use ASCII-escaping to control the console’s behavior of outputting characters. To display your extra console, you may use the PuTTY program, instead of writing your own.

References

Leave a Reply

Your email address will not be published. Required fields are marked *