Terminal emulator for the Sequent Microsystems SMLCD 4x20 LCD HAT. Runs on any machine without the hardware, with a drop-in replacement for the SMlcd Python library.
╔══════════════════════════════╗
║ SMLCD EMULATOR ║
╠══════════════════════════════╣
║ LCD DISPLAY ║
║ == SMLCD Emulator == ║
║ Hello, World! ║
║ Type to write... ║
║ q=quit c=clear ║
╠══════════════════════════════╣
║ Disp:ON Cursor:BLK AC:0x68 ║
║ Backlight R: 50 G:200 B: 50 ║
║ Line:1 Col:00 Encoder: 300 ║
╠══════════════════════════════╣
║ 1 2 3 4 5 6 ║
╠══════════════════════════════╣
║ 1-4:line <-> c:clr q:quit ║
║ +/-:BL !@#$%^:btn toggle ║
╚══════════════════════════════╝
Python 3.10+. No external dependencies.
python3 tui.pyThis launches an interactive terminal display showing the LCD contents, backlight values, button states, and encoder position.
| Key | Action |
|---|---|
1 2 3 4 |
Jump cursor to that line |
LEFT / RIGHT |
Move cursor left / right |
| Any printable char | Write character at cursor |
Backspace |
Delete character to the left |
+ / - |
Increase / decrease backlight brightness |
! @ # $ % ^ |
Toggle buttons 1-6 (Shift+1 through Shift+6) |
c |
Clear display |
q / Ctrl+C |
Quit |
smlcd_shim.py implements the same interface as SMlcd from the real library. Swap the import and everything else stays the same:
# Real hardware
from smlcd import SMlcd
lcd = SMlcd(1)
# Emulator
from smlcd_shim import SMlcd
lcd = SMlcd()All SMlcd methods are implemented: cmd, data_write, data_read, busy, cursor_set, text_write, text_write_at, bl_single, bl_rgb, get_button, get_all_buttons, get_button_int, get_all_buttons_int, get_encoder_int, get_encoder_val, reset_encoder.
Two emulator-only helpers are available for scripted testing:
lcd.inject_button(3, True) # press button 3
lcd.inject_encoder(10) # rotate encoder by +10Pass mmap_path to share the register state across processes. The file is created automatically if it does not exist.
# Process A: emulator
lcd = SMlcd(mmap_path='/tmp/smlcd.mmap')
tui = TUI(lcd.hd, lcd.mem)
tui.run()
# Process B: reads the same state
import mmap
from memory import Memory
with open('/tmp/smlcd.mmap', 'r+b') as f:
shm = mmap.mmap(f.fileno(), 256)
backlight = shm[Memory.I2C_LCD_BL]Three-layer architecture. HD44780 models the controller chip (DDRAM, CGRAM, instruction decode). Memory models the I2C register map that sits between the Pi and the chip on the real hardware. SMlcd is the user-facing API. Keeping these separate means the register map and the chip logic can be tested independently.
Flat DDRAM array. The HD44780 uses non-contiguous DDRAM addresses for a 4-line display: lines start at 0x00, 0x40, 0x14, 0x54. The emulator allocates 104 bytes to cover the full address range (0x00 to 0x67) rather than remapping, matching how the hardware actually works.
mmap-backed registers. Memory.registers is optionally backed by mmap rather than a bytearray. The two share the same index/slice interface, so no other code changes. This allows an external process to read and write the register file directly without any IPC layer.
No smbus2 dependency. Rather than shimming smbus2, the emulator replicates the SMlcd class interface directly. Code that uses SMlcd needs only a one-line import change to run against the emulator.