vrEmuLcd

Character LCD emulator library (C99 engine, web front-end).

View on GitHub
Target Windows Ubuntu macOS
Native
WebAssembly

vrEmuLcd - HD44780 Character LCD Emulator

Core engine written in C with a flexible Web front-end.

This Character LCD Emulator can be used to emulate most standard LCD displays.

It accepts and responds to most commands listed in the HD44780 datasheet

It also now support most commands for a 128x64 graphics LCD 12864B datasheet

Screenshots:

Hello, World!

Hello, World!

Different Colors

Different Colors!

Different Sizes

Different Sizes!

128 x 64 Graphics LCD

HBC-56 Emulator LCD Window

Custom characters (CGRAM support)

Custom characters (CGRAM support)!

Live examples:

Usage

C

#define LCD_WIDTH 20
#define LCD_HEIGHT 4

VrEmuLcd      *lcd = vrEmuLcdNew(LCD_WIDTH, LCD_HEIGHT, EmuLcdRomA00);

// send it commands:
vrEmuLcdSendCommand(lcd, LCD_CMD_FUNCTION | LCD_CMD_FUNCTION_LCD_2LINE | 0x10);
vrEmuLcdSendCommand(lcd, LCD_CMD_CLEAR);
vrEmuLcdSendCommand(lcd, LCD_CMD_HOME);
vrEmuLcdSendCommand(lcd, LCD_CMD_DISPLAY | LCD_CMD_DISPLAY_ON);

// send it data
vrEmuLcdWriteByte(lcd, 'H');
vrEmuLcdWriteByte(lcd, 'e');
vrEmuLcdWriteByte(lcd, 'l');
vrEmuLcdWriteByte(lcd, 'l');
vrEmuLcdWriteByte(lcd, 'o');

// or cheat
vrEmuLcdWriteString(lcd, " world!");

// then periodically, render it. 
vrEmuLcdUpdatePixels(lcd);   // generates a snapshot of the pixels state

for (int y = 0; y < vrEmuLcdNumPixelsY(lcd); ++y) {
  for (int x = 0; x < vrEmuLcdNumPixelsX(lcd); ++x) {
    // do whatever you like with the pixel information. render it to a texture, output it to  a console, whatever
   // values returned are:  -1 = no pixel (character borders), 0 = pixel off, 1 = pixel on
    char pixel = vrEmuLcdPixelState(lcd, x, y);
  }
}

Web

HTML (local)

<script src="src/vrEmuLcd.js"></script>
<script src="bin/vrEmuLcdWasm.js"></script>

HTML (live)

<script src="https://visrealm.github.io/vrEmuLcd/src/vrEmuLcd.js"></script>
<script src="https://visrealm.github.io/vrEmuLcd/bin/vrEmuLcdWasm.js"></script>

Example

<canvas id="lcd"></canvas>
...
<script>
    var canv = document.getElementById('lcd');
    var ctx = canv.getContext('2d');

    vrEmuLcd.setLoadedCallback(function () {

      // create a new LCD object
      var lcd = vrEmuLcd.newLCD(16, 2, vrEmuLcd.CharacterRom.Eurpoean);

      // set up the display
      lcd.sendCommand(LCD_CMD_DISPLAY | LCD_CMD_DISPLAY_ON);

      lcd.writeString("Hello, World!");

      lcd.render(ctx, 0, 0, 800, 400);
    });
</script>

Building

Native (desktop)

cmake -S . -B build/native -DCMAKE_BUILD_TYPE=Release
cmake --build build/native --config Release
ctest --test-dir build/native --build-config Release

WebAssembly with CMake

Configure with the Emscripten toolchain and build the vrEmuLcdWasm target to produce the WebAssembly bundle:

emcmake cmake -S . -B build/wasm -DCMAKE_BUILD_TYPE=Release
cmake --build build/wasm --target vrEmuLcdWasm --config Release

Artifacts will be written to build/wasm/bin/ (the loader script is vrEmuLcdWasm.js with an accompanying .wasm file). Use -DVR_EMU_LCD_BUILD_WASM=OFF if you want to skip the wasm target when using Emscripten.

If Emscripten is not installed, a platform-independent bootstrap helper can install it and print the toolchain file path. Examples:

# POSIX shells
TOOLCHAIN=$(python tools/bootstrap_emscripten.py --emsdk-dir build/emsdk)
cmake -S . -B build/wasm -DCMAKE_TOOLCHAIN_FILE="$TOOLCHAIN" -DCMAKE_BUILD_TYPE=Release
cmake --build build/wasm --target vrEmuLcdWasm --config Release
# PowerShell
$toolchain = python tools/bootstrap_emscripten.py --emsdk-dir build/emsdk
cmake -S . -B build/wasm -DCMAKE_TOOLCHAIN_FILE=$toolchain -DCMAKE_BUILD_TYPE=Release
cmake --build build/wasm --target vrEmuLcdWasm --config Release

Use --force to ignore an existing EMSCRIPTEN environment and re-install locally, or --version <tag> to pin a specific emsdk version.

LCD API

constuctor

var lcd = vrEmuLcd.newLCD(columns, rows, charSet);

sendCommand(commandByte)

Send a command to the instruction register of the lcd Command constants are defined:

writeByte(dataByte)

Write a byte to the data register of the lcd

writeString(str)

Write a string to the data register of the lcd

getDataOffset(screenX, screenY)

Return the ddram offset for the given screen location

readByte()

Read the current byte from cgram or ddram (determined by current address)

readAddress()

Read the current address offset in cgram or ddram

pixelState(pixelX, pixelY)

Return the pixel state at the given location

colorScheme

Set/get the color scheme. eg:

lcd.colorScheme = vrEmuLcd.Schemes.WhiteOnBlue;

Standard color schemes:

or, provide your own. { BackColor: <backcolor>, PixelOnColor: <pixeloncolor>, PixelOffColor: <pixeloffcolor> }

render(ctx, x, y, width, height)

Render to a 2d canvas context

License

This code is licensed under the MIT license