A hacker-style terminal UI for the M5Stack Tab5
Plug in a keyboard. Type commands. Feel like you own the system.
|
π Home β select connection method |
π Home β UART card selected |
|
π Scan β discovering nearby BLE devices |
π» Terminal β neofetch system info |
A terminal emulator UI built with LVGL v9 running on the M5Stack Tab5 β a 5-inch 1280Γ720 IPS touchscreen device powered by the ESP32-P4 (RISC-V dual-core @ 360MHz) and an ESP32-C6 wireless coprocessor.
Connect a CardKB2 keyboard over UART and you get a fully interactive retro-terminal: colored output, line numbers, scrollable history, command autocomplete β all on a palm-sized device.
Tab5@terminal : ~ $ neofetch
######## ######## ###### tab5@terminal
## ## ## ## ## ## βββββββββββββββββββββββββ
## ####### ###### OS CardKB-Linux 1.0
## ## ## Host ESP32-P4 + C6
## ## ## Kernel 5.15.0-esp32p4
## ## ## Shell bash 5.1.16
BLE CardKB2 [CONNECTED]
ESPNOW [ACTIVE] ch.6
RAM 16MB Flash / 32MB PSRAM
Display 1280Γ720 IPS
|
M5Stack Tab5 β ESP32-P4, 5" 1280Γ720 IPS |
| Component | Spec |
|---|---|
| Main SoC | ESP32-P4 Β· RISC-V dual-core 360 MHz + LP core 40 MHz |
| Wireless | ESP32-C6-MINI-1U Β· Wi-Fi 6 / BLE 5 / Thread / Zigbee |
| Flash | 16 MB |
| PSRAM | 32 MB |
| Display | 5-inch IPS TFT Β· 1280Γ720 (720p) Β· ST7123 TDDI |
| Touch | Capacitive Β· built-in to ST7123 |
| Keyboard | M5Stack CardKB2 Β· connected via UART |
| UART pins | TX β GPIO 53 / RX β GPIO 54 Β· 115200 baud Β· HY2.0-4P port |
β οΈ Current Status
Mode Status UART (CardKB2 via HY2.0-4P) β Works Bluetooth HID (CardKB2 via BLE) π§ UI Present β Not Functional Yet
- ESP-IDF v5.3+
- M5Stack Tab5 connected via USB-C
git clone <this-repo>
cd TerminalDemo
idf.py set-target esp32p4
idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.bsp.m5stack_tab5" build
idf.py -p /dev/ttyUSB0 flash monitorConnect the CardKB2 to Tab5's HY2.0-4P (PORT.A) socket:
CardKB2 HY2.0-4P (PORT.A)
GND βββββββββββββ GND
3.3V βββββββββββββ 5V
TX βββββββββββββ G54 (UART RX)
RX βββββββββββββ G53 (UART TX)
π‘ On the home screen, tap the UART card once to select it, then tap again to enter the terminal directly.
ββββββββββββββββββββββββββββββββββββββββββββββββ
β π Home Screen β
β β
β ββββββββββββββββ ββββββββββββββββ β
β β UART β β BLUETOOTH HIDβ β
β β β
Working β β π§ WIP β β
β ββββββββββββββββ ββββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββ
β tap UART card twice
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββ
β π» Terminal β
β Blinking cursor Β· colored output β
β Line numbers Β· scrollable Β· autocomplete β
ββββββββββββββββββββββββββββββββββββββββββββββββ
(BLE path, WIP)
β tap BLUETOOTH HID β SCAN DEVICES
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββ
β π Scan Screen β
β Live BLE discovery Β· RSSI Β· device name β
ββββββββββββββββββββββββββββββββββββββββββββββββ
β tap CONNECT
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββ
β β‘ Connecting... β
β 12-dot spinner animation β
ββββββββββββββββββββββββββββββββββββββββββββββββ
Once in the terminal, the CardKB2 input appears in the bottom bar with a blinking cursor. Press Enter to run.
| Command | Returns |
|---|---|
help |
All commands grouped by category |
clear |
Clear the screen |
neofetch |
Stylized system info banner |
uname -a |
Linux tab5 5.15.0-esp32p4 #1 SMP PREEMPT |
uptime |
Live uptime since boot |
date |
Current date/time |
pwd |
/home/tab5 |
whoami |
tab5 |
| Command | Returns |
|---|---|
ls |
bin etc home proc tmp usr |
ls -la |
Detailed listing with permissions |
cat /etc/motd |
Message of the day |
| Command | Returns |
|---|---|
ifconfig |
wlan0 interface with IP/MAC |
ping / ping 8.8.8.8 |
Animated 5-packet ping with RTT |
ble status |
BLE connection state |
espnow scan |
Simulated ESP-NOW node discovery |
| Command | Returns |
|---|---|
top |
Live FreeRTOS task table β CPU %, stack, name |
ps |
Process snapshot |
| Command | Returns |
|---|---|
fortune |
"Any sufficiently advanced bug is indistinguishable from a feature." |
sudo |
Sorry, try again. Γ 3 |
sudo rm -rf / |
Permission denied, phew. |
reboot |
Fake reboot β neofetch splash |
| Key | Action |
|---|---|
Enter |
Execute command |
Backspace |
Delete character |
β / β |
Command history (last 20) |
Tab |
Autocomplete from catalog |
TerminalDemo/
βββ main/
β βββ main.c # Entry: BSP init β wireless β UI
β βββ CMakeLists.txt
β βββ wireless/
β β βββ wireless_mgr.c/h # Shared node list, WiFi/BLE init
β β βββ ble_mgr.c # NimBLE HID central (CardKB2 BLE)
β β βββ espnow_mgr.c # ESP-NOW scan & receive
β β βββ uart_mgr.c/h # UART driver (CardKB2, GPIO53/54)
β βββ ui/
β β βββ ui_common.h # Colors, fonts, layout constants
β β βββ ui_home.c # Home: UART / BT HID selection
β β βββ ui_scan.c # BLE scan list
β β βββ ui_connect.c # Connection spinner animation
β β βββ ui_connected.c # Connected status page
β β βββ ui_terminal.c # Interactive terminal (500-line scrollback)
β βββ assets/
β βββ fonts/ # Inter typeface β 14 weight/size variants
β βββ images/ # Icons: arrows, BT logo, ESP-NOW, etc.
βββ readme/ # Screenshots & demo GIF
βββ sdkconfig.defaults
βββ sdkconfig.bsp.m5stack_tab5
βββ partitions.csv
| Swatch | Hex | Role |
|---|---|---|
| π§ | #E07B39 |
Prompt Tab5@terminal : ~ $ |
| π¨ | #F0C27F |
User input |
| π¦ | #60A5FA |
Info / headings |
| π© | #4ADE80 |
Success |
| π₯ | #F87171 |
Error |
| π‘ | #FBBF24 |
Warning |
| π£ | #E879F9 |
Highlight |
| β¬ | #0E0E11 |
Background |
Add a command β in main/ui/ui_terminal.c:
} else if (strcmp(start, "hello") == 0) {
term_append_line(T_SUCCESS, "Hello, world!");
}Add it to the autocomplete catalog at the top of the same file:
static const char *s_cmd_catalog[] = {
"help", "clear", ...,
"hello", // β add here
};Change UART pins β in main/wireless/uart_mgr.h:
#define UART_KB_TX_PIN 53
#define UART_KB_RX_PIN 54
#define UART_KB_BAUD_RATE 115200CC0-1.0 β public domain. Do whatever you like.