retroTerm is an Arduino library for creating user interfaces in a terminal emulator with a microcontroller.
Now that many microcontrollers have Bluetooth or Wi-Fi it might seem superfluous but there are also many that do not and occasions when you want to configure or interact with them without having a network available.
retroTerm allows you to create clickable 'buttons', 'checkboxes', 'list boxes' and so on and simple line editing of text.
The name comes from being able to create 'retro terminal' interfaces like this, which can be interacted freely with using the mouse and keyboard, within the fundamental limitations of them running on a microcontroller.
- About retoTerm
- Project status
- Getting Started
- Versioning
- Version history
- How to Get Help
- Further Reading
- Contributing
- License
- Authors
- Acknowledgements
retroTerm is an Arduino library for creating user interfaces in a terminal emulator with a microcontroller.
By default this is expected to be the Serial interface, but it could also be any Stream. Testing is done with the popular terminal emulator PuTTY as it is open source, available across several platforms and supports many terminal features others do not. Please use PuTTY first before reporting issues. The Arduino IDE terminal is not usable with retroTerm, it supports almost no ANSI/VT terminal features.
Both direct control of the terminal and the use of 'widgets' that allow for an almost-GUI are possible, but mixing the two requires care. It tracks the current cursor state and tries to reduce the number of state changes sent to improve performance over the serial connection.
This project was originally created to help with making a fake 'mainframe' that somebody can interact with running on an ESP8266.
- Detect size and type
- Set the terminal 'title'
- Clear/reset the terminal
- Move the cursor to specific co-ordinates
- Hide/show the cursor
- Limit scrolling to certain regions
- Set various character colours/attributes
- Print at specific co-ordinates
- Draw boxes
- Enable 'capture' of the mouse and record clicks
Creation and management of GUI-esque objects
- Buttons
- Checkboxes
- Radio buttons
- List boxes
- Text boxes (editable text) single line editing of text, with support for 'expected' behaviour like home/end/insert/delete and the arrow keys
- Text boxes (fixed text) with scrollbars, word wrapping and basic markdown support
- Text boxes (changing text) for 'logging' windows that scroll content
- Keyboard shortcuts for use without a mouse
- Basic styling for widget outlines/labels
As you might expect, this library can use a lot of working memory. There is explicit support for storing strings in flash memory using the F()
macro on several architectures. You should use flash storage whenever possible for things like labels on buttons that will not change.
This is the very first public release, which is working for the specific project I wrote it for. However I'm aware my naming of methods, approaches to passing arguments and so on are messy and inconsistent so some of this may change frequently. This is reflected in the version numbering, which is currently 0.1.2.
From the project page, select 'Code' -> 'Download ZIP' and save the file somewhere appropriate.
You can then install in the Arduino IDE by choosing 'Sketch' -> 'Include Library' -> 'Add .ZIP Library...'.
After installation, the retroTerm examples will be available under "File" -> "Examples" -> "retroTerm" in the Arduino IDE.
You should try the first two example sketches to check it works with your terminal emulator, then try the 'Alarm Clock' example which is a very simple application that will work on most microcontrollers.
Capability Test - basic terminal features
Widget Test - widget features
Alarm Clock - a simple interactive application
There are then further examples that serve as a demonstration of how to use each individual type of widget.
This library has no specific dependencies, but you will need a fully featured terminal emulator that can connect to your target microcontroller over a serial or USB-serial interface. Testing is done with PuTTY and it is strongly recommend you start with using this.
It is only fully tested on the handful of microcontrollers below and some of these have specific code, usually related to storing strings/character arrays in flash memory to save working memory. Other microcontrollers may use working memory for all strings.
- Arduino AVR (Arduino "Uno" and "Mega2560" tested) Note the full widget example is now overly large for an Uno.
- ESP8266 (WeMos D1 mini tested).
- ESP32 ("Espressif ESP32-S2-Saola-1R" and "WeMos WiFi&Bluetooth Battery" tested).
- RP2040 (Raspberry Pi Pico tested with this unofficial Arduino support).
- ARM Cortex-M4 (Teensy 3.1 tested).
Note that the Espressif ESP8266/ESP32 bootloader sends characters to the serial port on reset, which may cause the bell to sound or be seen as an 'XOFF' that prevents further input. If compiled on ESP8266/ESP32 the library sends an 'XON' at initialisation.
Any device that does its own USB support (eg. Raspberry Pi Pico and Teensy) rather than having a separate USB to UART device will lose some initial output to the terminal at start up. You should take this into account by perhaps delaying output, waiting for a keypress etc. before starting your retroTerm UI. If tried immediately on these, probing the terminal size, enabling the mouse and so on will fail.
This project is hosted on GitHub.
From the project page, select 'Code' -> 'Download ZIP' and save the file somewhere appropriate.
You can then install in the Arduino IDE by choosing 'Sketch' -> 'Include Library' -> 'Add .ZIP Library...'.
Documentation for retroTerm is included as markdown in the 'documentation' directory.
Broadly to create widgets you need something along lines of the code below. This will create a single button at co-ordinates 1,1 that detects mouse clicks and prints below when it happens.
This example (which is in examples\Example04_singleButton) shows a lot of core concepts.
#include <retroTerm.h> //Include terminal library
retroTerm terminal; //Create a terminal instance
uint8_t buttonId = 0; //Record the button ID globally
uint32_t numberOfClicks = 1; //Record the number of clicks
void setup() {
Serial.begin(115200); //Initialise the Serial stream
terminal.begin(Serial); //Initialise the library
terminal.eraseScreen(); //Clear the screen
terminal.hideCursor(); //Hide the terminal cursor
terminal.enableMouse(); //Capture the mouse so it can be used with widgets
terminal.setScrollWindow(4,12); //Set up somewhere to show the events without disrupting the button
buttonId = terminal.newButton(1, 1, 15, 3, F("Button label"), COLOUR_GREEN, OUTER_BOX | BOX_SINGLE_LINE); //Create a green button in a box
terminal.widgetShortcutKey(buttonId,f1Pressed); //Assign a shortcut key of F1
terminal.showWidget(buttonId); //Make the button visible, all widgets start 'invisible' for later display
}
void loop() {
if(terminal.widgetClicked(buttonId)) //This clears the 'click' on checking
{
terminal.scroll("Button click " + String(numberOfClicks++)); //Print inside the scroll window
}
terminal.houseKeeping(); //You MUST run housekeeping to show/detect any changes or events
}
The code includes the library then assigns a global variable for the widget. Widgets have simple numeric IDs from 1-255, 0 is considered invalid. If you delete a button its ID may be re-used.
Effective setup for displaying widgets needs quite a few steps, but is then simpler to interact with.
- Pass the library the Stream used for display in
begin()
. Normally this is 'Serial' but it could be another Stream, for example Serial2. - Erase the screen to clear any mess from startup. Not necessary on all microcontrollers but ESP8266 & ESP32 output boot messages.
- Hide the cursor, for tidiness. If you use a widget that allows text editing it will make the cursor visible while editing.
- Enable the mouse, otherwise you will have to rely on keyboard shortcuts for interaction.
- Set a scroll window. This is not a widget, but reduces the scrolling region of the terminal, making for trivial diagnostic/logging output.
- Create the widget.
- Assign a shortcut key to the widget. If you press the shortcut key it registers as a 'click' as if clicked with the mouse.
- Make the widget visible.
Once in the loop all it does is.
- Check for button clicks and print in the scrolling window when this happens.
- Run a housekeeping routine. This does all screen updating and processing of inputs, normally you should run it frequently. The more frequently it runs, the more responsive the application will be to inputs. If you are expecting no inputs, it is OK to run it only when you have changed the widgets.
This example should look like this in a terminal.
This project uses Semantic Versioning to be compatible with the Arduino library standards.
First public release.
For a full list of available versions, see the repository tag list. There is also a change log included in the documentation.
Drop me a message on [email protected], I can't promise to be super-responsive but I'll try.
I'd love to get help with this work, either drop me a message here or on [email protected]. I'm new to using git for collaboration so please be patient. Ongoing work is happening in the 'dev' branch for a later release.
Serial 'dumb' terminals got quite smart over time, I took information from a variety of sources to help write this library including the ones linked below. Broadly it uses features you would expect in a VT420.
Paul Bourke's list of VT commands
Copyright (c) 2021 Nick Reynolds
This project is licensed under the GNU Lesser General Public License - see LICENSE.md file for details.
This project wouldn't be useful without the excellent open source terminal emulator PuTTY, which I have used for what feels like decades.
Markdown documentation mostly written in Typora.