Skip to content

lmacken/doom-pager

Repository files navigation

DOOM for WiFi Pineapple Pager

Play the classic 1993 FPS on your WiFi Pineapple Pager!

Darren Kitchen playing DOOM on the Pager Darren Kitchen demoing DOOM on the Pager β€” watch the full video

Quick Install

Using Pull Payload PR

If you have the general β†’ Pull Payload PR payload on your pager, type PR 130 to install.

Manual Install

Copy the pre-built files to your Pager:

scp -r payloads/user/games/doom root@172.16.52.1:/root/payloads/user/games/

Then find DOOM in: Payloads β†’ Games β†’ DOOM

Supported WADs

Pager Menu Games Menu

Bring your own WADs! Only the shareware doom1.wad is included. Place your legally obtained WAD files in the wads/ directory to play the full games.

IWADs (Base Games)

Game WAD File Status
DOOM Shareware doom1.wad βœ… Works
DOOM Registered doom.wad βœ… Works
DOOM II doom2.wad βœ… Works
Final DOOM: TNT Evilution tnt.wad βœ… Works
Final DOOM: Plutonia plutonia.wad βœ… Works
DOOM DOOM II
Final DOOM: Plutonia Final DOOM: TNT

PWADs (Add-ons)

Add-on WAD File Requires Status
No Rest for the Living nerve.wad doom2.wad βœ… Works
Master Levels masterlevels.wad doom2.wad βœ… Works
SIGIL sigil.wad doom.wad βœ… Works (Episode 3)
SIGIL II sigil2.wad doom.wad ❌ Incompatible
SIGIL SIGIL Gameplay
Master Levels No Rest for the Living

Installing Additional WADs

  1. Place your WAD files in the wads/ directory
  2. Run the installer:
./install-wads.sh list      # Show available configurations
./install-wads.sh install   # Create payload directories
./install-wads.sh deploy    # Deploy to Pager via SSH

WAD Compatibility Notes

  • SIGIL uses the "compat" version which replaces Episode 3 (select Episode 3 in menu)
  • SIGIL II is NOT compatible (requires UMAPINFO support)

Controls

Input Action
D-pad Move/Turn
Red Fire
Power Next Weapon
Green Select (menus)
Green + Up Open doors/Use
Green + Down Automap
Green + Left/Right Strafe
Green + Power Quicksave
Red + Power Quickload
Red + Green ESC (Menu/Quit)

USB Keyboard Support

External USB keyboards work alongside the Pager's built-in buttons. Plug in your keyboard before launching the game - input devices are detected at startup.

Multiplayer Deathmatch

Connect to our public DOOM servers for multiplayer deathmatch!

Deathmatch Options Server Browser
Lobby Deathmatch Gameplay

Run the DOOM Deathmatch payload from: Payloads β†’ Games

Connection Modes:

  • Auto - Instant matchmaking to best available server
  • Browse - Manual server selection with real-time status
  • Direct - Connect to specific IP:port

Desktop players can join with Chocolate Doom:

chocolate-doom -iwad doom1.wad -connect 64.227.99.100:2342

Network Features

  • Chocolate Doom 3.1.x protocol compatibility
  • Works with vanilla Chocolate Doom server
  • POSIX socket-based network layer (no SDL dependency)

Build from Source

./build.sh

This will:

  1. Download the OpenWrt SDK (~400MB, cached in build/)
  2. Clone our doomgeneric fork (pager branch)
  3. Cross-compile for MIPS
  4. Deploy to Pager (if connected)

For experimental builds, use ./build.sh --dev which pulls from the dev branch and creates a separate DOOM DEV payload.

Requirements

  • Linux (tested on Ubuntu/Debian)
  • curl, git, make
  • qemu-user-static (on non-x86_64 hosts)
sudo apt install curl git make qemu-user-static

Screenshots

Capture a screenshot from your Pager's framebuffer and save it locally:

./screenshot.sh                  # Landscape (default)
./screenshot.sh -n               # Portrait (raw framebuffer)
./screenshot.sh my_shot.png      # Custom filename

Technical Details

  • CPU: MIPS 24KEc @ 580MHz (soft-float, 8-stage pipeline)
  • RAM: 64MB DDR2
  • Display: 222Γ—480 RGB565 via SPI (~20 FPS refresh limit)
  • Input: GPIO buttons via /dev/input/event0

Rendering Limits (Increased for SIGIL and Complex WADs)

The vanilla DOOM engine has static limits that can cause crashes on complex maps like SIGIL. These have been increased:

Limit Original Modified
MAXVISPLANES 128 512
MAXVISSPRITES 128 256
MAXDRAWSEGS 256 512

Engine Modifications

Display Pipeline

  • 16-bit RGB565 framebuffer support with direct writes
  • 90Β° CCW rotation for portrait display orientation
  • Full-screen stretched scaling with widened FOV (gameplay)
  • Aspect-correct rendering with letterboxing (menus/title)
  • Precomputed lookup tables for X/Y scaling (32-byte cache-aligned)

Frame Pacing

  • Default 35 FPS cap matches DOOM's native TICRATE
  • clock_nanosleep() with absolute timing for precise frame pacing
  • Reduces CPU usage and heat compared to uncapped rendering
  • Display limited to ~20 FPS via SPI, but 35 FPS ensures smooth game logic

Input System

  • GPIO button mapping (red/green buttons)
  • Button combo detection with proper state tracking
  • Strafe combos: Green+Left/Right for strafing
  • USB keyboard support (detected at startup)

Performance Optimizations

Optimization Status Notes
Link-Time Optimization (LTO) ON Cross-module inlining, 10% smaller binary
GCC Auto-Prefetch ON -fprefetch-loop-arrays adds ~140 prefetch instructions
GCC 13 IPA Optimizations ON -fipa-pta, -fmodulo-sched, -fsched-pressure, -fsplit-paths
Precomputed Row Offsets ON Eliminates multiply in inner render loop
RGB565 Palette Precomputation ON 256-entry palette converted to RGB565 once at load
4-Pixel Loop Unrolling ON Inner render loop processes 4 pixels per iteration
Cache-Aligned Tables ON Lookup tables aligned to 32-byte cache lines
DSP Indexed Loads ON ~1000 lbux/lwx instructions (-march=24kec auto-enables -mdsp)
mobj_t Cache Layout ON Hot fields grouped in first 2 cache lines
Binary Stripping ON ~700KB vs 1.4MB with debug symbols

Compiler Flags (MIPS 24KEc @ 580MHz, GCC 13.3)

-O3 -flto -march=24kec -mtune=24kec -mbranch-likely
-ffast-math -funroll-loops -fomit-frame-pointer -finline-functions
-fprefetch-loop-arrays
-fipa-pta -fmodulo-sched -fsched-pressure -fsplit-paths

Payload Optimizations

The payload scripts stop background services before launching DOOM to maximize available CPU and RAM:

# Services stopped during gameplay
/etc/init.d/php8-fpm stop    # PHP FastCGI
/etc/init.d/nginx stop        # Web server  
/etc/init.d/bluetoothd stop   # Bluetooth daemon
/etc/init.d/pineapplepager stop
/etc/init.d/pineapd stop

All services are automatically restored when DOOM exits.

Files

β”œβ”€β”€ build.sh              # Main build script
β”œβ”€β”€ install-wads.sh       # WAD installer tool
β”œβ”€β”€ screenshot.sh         # Pager screenshot utility
β”œβ”€β”€ doomgeneric/          # Engine fork (github.com/lmacken/doomgeneric-pager)
β”œβ”€β”€ wads/                 # Place your WAD files here
β”œβ”€β”€ img/                  # Screenshots
β”œβ”€β”€ ansible/              # Deathmatch server playbook
└── payloads/             # Pager payload directories
    └── user/games/
        β”œβ”€β”€ doom/              # Base DOOM (shareware)
        β”œβ”€β”€ doom-deathmatch/   # Multiplayer
        β”œβ”€β”€ doom2/             # DOOM II
        β”œβ”€β”€ doom-sigil/        # SIGIL
        └── ...

Future Ideas

  • UMAPINFO support for SIGIL II compatibility
  • Kernel module (doom_fb.ko) for bypassing fbtft overhead and direct USB bulk transfers
  • DMA transfers for framebuffer writes (CH347 USB-to-SPI bridge currently lacks DMA)
  • Dirty rectangle tracking to only update changed screen regions
  • Vibrate when hit using the Pager's vibration motor
  • DOOM theme ringtone using the piezoelectric buzzer

License

About

DOOM port for the Hak5 WiFi Pineapple Pager πŸ“Ÿ

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors