OpenCrashCart - A $50 USB KVM Console

Plug your laptop into another computer, and use it like a keyboard, monitor and mouse

Jul 3, 2023

Gallery

notion image
notion image
notion image
notion image

UI

Keymapper Setup Script
Keymapper Setup Script
Main UI view with display input
Main UI view with display input
Main Settings Page
Main Settings Page
Program being used within windows
Program being used within windows

Project Progress Documentation/Notes


To-do:
Full Mouse Support
left/right/middle click working
send commands to serial adapter
interpret properly with Arduino
Only send mouse movement+clicks+keyboard when within window and within camera area
Make mouse movement stick within the camera window area
modify the window_focused code, I’ll bet. Probably go with making it check if the main window is in focus, if not, send nothing
  • this will fix the whole “can’t physically paste” issue yep
now maybe streamline that code a bit?
Full Keyboard Support
keyboard hooking (support alt+tab), etc
only send keyboard when window is focused
Keyboard mapper script
handle file being done
start button
map keys
undo button
need to make this update the “file output” box
pause/stop buttons
fix serial communication issues (need a start byte or checksum)
add a “checksum” byte:
either figure out how actual checksums work, or use a specific start byte (or two bytes, to be safe?)
Proper Hardware Integration
re-add COM selection dropdown at top of window
auto-selects device!
add hardware type dropdown in settings (serial adapter model). could also be text box with default, idk
^now I need to make that persistent, so json settings file it is!
open video capture pre-set to properly detect the HDMI capture card
also dropdown, just in case.
Other Features/fixes
copy to host (via OCR)
paste from host
Keyboard remapper script (GUI-based)
back button to undo previous assignemnt
Migrate settings and states from global variables to classes!
Settings:
persistent .yaml settings file
“save settings as default” button
per-setting default indicator
  • PrusaSlicer-esque - setting indicates if it’s not default, but adds button to set it as a default
Allow Resizing - should make all the scaling numbers factors of the window size, if that makes sense
figure out texture resizing for the camera feed (720p no matter what, but can scale up/down for window sizing reasons
drag to resize shouldn’t get smaller than camera feed
DPI scaling awareness (should influence manual scaling, probably)
try to get upscaling working or something? might need to mess around with text size)
should we try to render at higher res but show the same size? ideally
Add “full reload” to re-draw window if necessary
option to backup config
further UI customization
Font options
In-depth color options?
color themes
Style points
Package as .exe (portable or installer)
include all the required dependencies
case design
PCB design (headers for pre-made bits)
 

Supported video formats:

~$ v4l2-ctl --list-formats-ext ioctl: VIDIOC_ENUM_FMT Type: Video Capture [0]: 'MJPG' (Motion-JPEG, compressed) Size: Discrete 1920x1080 Interval: Discrete 0.017s (60.000 fps) Interval: Discrete 0.033s (30.000 fps) Interval: Discrete 0.040s (25.000 fps) Interval: Discrete 0.050s (20.000 fps) Interval: Discrete 0.100s (10.000 fps) Size: Discrete 1600x1200 Interval: Discrete 0.017s (60.000 fps) Interval: Discrete 0.033s (30.000 fps) Interval: Discrete 0.040s (25.000 fps) Interval: Discrete 0.050s (20.000 fps) Interval: Discrete 0.100s (10.000 fps) Size: Discrete 1360x768 Interval: Discrete 0.017s (60.000 fps) Interval: Discrete 0.033s (30.000 fps) Interval: Discrete 0.040s (25.000 fps) Interval: Discrete 0.050s (20.000 fps) Interval: Discrete 0.100s (10.000 fps) Size: Discrete 1280x1024 Interval: Discrete 0.017s (60.000 fps) Interval: Discrete 0.033s (30.000 fps) Interval: Discrete 0.040s (25.000 fps) Interval: Discrete 0.050s (20.000 fps) Interval: Discrete 0.100s (10.000 fps) Size: Discrete 1280x960 Interval: Discrete 0.017s (60.000 fps) Interval: Discrete 0.033s (30.000 fps) Interval: Discrete 0.040s (25.000 fps) Interval: Discrete 0.050s (20.000 fps) Interval: Discrete 0.100s (10.000 fps) Size: Discrete 1280x720 Interval: Discrete 0.017s (60.000 fps) Interval: Discrete 0.020s (50.000 fps) Interval: Discrete 0.033s (30.000 fps) Interval: Discrete 0.050s (20.000 fps) Interval: Discrete 0.100s (10.000 fps) Size: Discrete 1024x768 Interval: Discrete 0.017s (60.000 fps) Interval: Discrete 0.020s (50.000 fps) Interval: Discrete 0.033s (30.000 fps) Interval: Discrete 0.050s (20.000 fps) Interval: Discrete 0.100s (10.000 fps) Size: Discrete 800x600 Interval: Discrete 0.017s (60.000 fps) Interval: Discrete 0.020s (50.000 fps) Interval: Discrete 0.033s (30.000 fps) Interval: Discrete 0.050s (20.000 fps) Interval: Discrete 0.100s (10.000 fps) Size: Discrete 720x576 Interval: Discrete 0.017s (60.000 fps) Interval: Discrete 0.020s (50.000 fps) Interval: Discrete 0.033s (30.000 fps) Interval: Discrete 0.050s (20.000 fps) Interval: Discrete 0.100s (10.000 fps) Size: Discrete 720x480 Interval: Discrete 0.017s (60.000 fps) Interval: Discrete 0.020s (50.000 fps) Interval: Discrete 0.033s (30.000 fps) Interval: Discrete 0.050s (20.000 fps) Interval: Discrete 0.100s (10.000 fps) Size: Discrete 640x480 Interval: Discrete 0.017s (60.000 fps) Interval: Discrete 0.020s (50.000 fps) Interval: Discrete 0.033s (30.000 fps) Interval: Discrete 0.050s (20.000 fps) Interval: Discrete 0.100s (10.000 fps) [1]: 'YUYV' (YUYV 4:2:2) Size: Discrete 1920x1080 Interval: Discrete 0.200s (5.000 fps) Size: Discrete 1600x1200 Interval: Discrete 0.200s (5.000 fps) Size: Discrete 1360x768 Interval: Discrete 0.125s (8.000 fps) Size: Discrete 1280x1024 Interval: Discrete 0.125s (8.000 fps) Size: Discrete 1280x960 Interval: Discrete 0.125s (8.000 fps) Size: Discrete 1280x720 Interval: Discrete 0.100s (10.000 fps) Size: Discrete 1024x768 Interval: Discrete 0.100s (10.000 fps) Size: Discrete 800x600 Interval: Discrete 0.050s (20.000 fps) Interval: Discrete 0.100s (10.000 fps) Interval: Discrete 0.200s (5.000 fps) Size: Discrete 720x576 Interval: Discrete 0.040s (25.000 fps) Interval: Discrete 0.050s (20.000 fps) Interval: Discrete 0.100s (10.000 fps) Interval: Discrete 0.200s (5.000 fps) Size: Discrete 720x480 Interval: Discrete 0.033s (30.000 fps) Interval: Discrete 0.050s (20.000 fps) Interval: Discrete 0.100s (10.000 fps) Interval: Discrete 0.200s (5.000 fps) Size: Discrete 640x480 Interval: Discrete 0.033s (30.000 fps) Interval: Discrete 0.050s (20.000 fps) Interval: Discrete 0.100s (10.000 fps) Interval: Discrete 0.200s (5.000 fps) ~$ for d in /dev/video* ; do echo $d ; v4l2-ctl --device=$d -D --list-formats ; echo '===============' ; done /dev/video0 Driver Info: Driver name : uvcvideo Card type : USB Video: USB Video Bus info : usb-0000:02:03.0-1 Driver version : 5.15.99 Capabilities : 0x84a00001 Video Capture Metadata Capture Streaming Extended Pix Format Device Capabilities Device Caps : 0x04200001 Video Capture Streaming Extended Pix Format ioctl: VIDIOC_ENUM_FMT Type: Video Capture [0]: 'MJPG' (Motion-JPEG, compressed) [1]: 'YUYV' (YUYV 4:2:2) =============== /dev/video1 Driver Info: Driver name : uvcvideo Card type : USB Video: USB Video Bus info : usb-0000:02:03.0-1 Driver version : 5.15.99 Capabilities : 0x84a00001 Video Capture Metadata Capture Streaming Extended Pix Format Device Capabilities Device Caps : 0x04a00000 Metadata Capture Streaming Extended Pix Format ioctl: VIDIOC_ENUM_FMT Type: Video Capture
 
note! Aaron Pritzker might be interested, let him know when it’s all done :)
LOL looks like someone kinda made one with a pi zero here: :SAD:
Pi Zero W
Updated Jul 28, 2021
hm nvm zeroes are expensive AF now
great twitter thread about the USB capture cards:
 
will be adapting info found here:
The code:
makefu provides an amazing starting place - everything is technically working. I just want to turn it into a cleaner final product. Much of the work of which will actually be in coding.

Parts List:

  • Atmega32u4-based Arduino
    • I chose this one because the USB “header” will be significantly easier to solder to because of the exposed contacts.
  • PCB-based USB 2.0 hub
    • chosen because it’s the only type out there (except maybe PC internal USB splitters for fan control/accessories?)
 

Wiring Diagram:

notion image

The Plan (going in blind)

This is my plan without having the hardware in hand, including modifications, ideas, etc.

Arduino Code Mods:

The code actually looks really simple - for my part, all I’m going to do is add a kill switch using a simple while() loop in the setup section. For now.
#define killSwitch 1 //defines switch pin void setup() { pinMode (killSwitch, INPUT); //initializes killSwitch pin as input while (digitalRead(killSwitch) == HIGH) //if switch is pulled to ground, loop infinitely { delay(1); } // or in one line: while (digitalRead(killSwitch) == HIGH) {delay(1);} }
Why? I’ve had issues with Arduino Leonardo(s) being almost impossible to program when initialized as a USB HID device/keyboard, requiring either really lucky timing or a reprogram with another Arduino. This way the keyboard device won’t initialize if I don’t pull killSwitch to LOW first. This is more of a peace-of-mind debugging thing that would likely be removed or altered (internal switch, or something) on a production device.
 

Python Script (software keyboard) Mods

This is a bit trickier. I don’t know Python! (At least, not until I did this project) Ultimately I’d like to make this an installer/packaged program.
  • Currently planned mods for ease of use:
    • Fetch, list & allow selection of device ports (to select proper TTL COM port)
    • Open VLC or alternative (maybe ffmpeg has something?) pre-set to properly detect the HDMI capture card
    • If possible, “combine” video & fake keyboard window so that when you click on the video window, keystrokes are forwarded, and when you click off, they no longer are.
      • make a “capture” option with hotkey? so shortcuts are sent properly. Might not be required though!
Stretch Goals [warning: may cause intense frustration to implement!]
  • Package as .exe (portable or installer)
    • if it’s an exe, do we need everything else installed or does it kinda handle that itself? I guess I might find out!
  • Have said installer install:
    • All the required dependencies
      • Pygame, anything else?
    • Drivers - not sure how signing works here
      • can also link to official driver downloads, and check if they’re installed before proceeding. If doing this, add override button in installer so that people with different drivers/adapters can bypass
  • Maybe a webserver?? would be cool to implement PiKvm in the future, seems a bit silly though.
  • Include portable version of .exe attached to small flash storage on the internal “hub” so that it doesn’t require install/launch each time
    • potentially auto-launch script? not sure if those still work though!

Arduino:

//at beginning of code: #define killSwitch 11 //defines switch pin // in void setup(): pinMode (killSwitch, INPUT_PULLUP); //initializes killSwitch pin as input while (digitalRead(killSwitch) == HIGH) {delay(1);} //loop infinitely until switch is pulled to ground
^ interesting idea for final product, could use non-arduino firmware (probably ideal anyways) that would allow changing of device ID to something more official
 

Code (Python, Arduino C++):

notes:
alt+tab freewheels when keyboard input isn’t locked. maybe prevent by either:
detecting loss of focus and releasing tab
change tab to only press+release
General serial notes:
NEED to add an extra byte or two to enable:
checksum
“start” command (to refresh connection/prevent sync loss)
do all this on a fresh slate program with the arduino just printing what keys it should press to the serial monitor so you don’t have to deal with the mess that is a broken serial connection keyboard lol
 

📡
Serial Communication

🖱️
Revamped Mouse Capture

⌨️
Revamped Keyboard Capture

🪝
pyWinHook (Hooking keyboard input for shortcuts)

📺
Video Feed Display

Case:


notion image
notion image
Issues:
  • USB port is not centered
    • reason: I measured wrong (oops)
  • USB port hole too small
    • reason: 3D printer overhangs cause tolerance issues, I didn’t add quite enough wiggle room

Prototype Board:

notion image
I soldered everything to a pcb - this was a frustrating setup, but it was worth it long-term. Time to make it official!

PCB Design: Future Plans

  • Add empty USB port for small flash storage for program - means it’d just exist on the storage and would be runnable when plugging the device in

Ok so - I have a few options:
  1. Try and get the schematics & firmware from those HDMI converter boards
      • Pro/con:
        • Pro: would be a clean design
        • Con: probably impossible to do
  1. Use that open-source capture card
      • Pro/con:
        • Pro: probably “easiest” when we’re talking complete PCB.
        • Con: not sure how the license works, might cause issues because it’s usb 3
          • fix: make usb 3.0 hub internally? or just limit hardware to usb 2.0 capabilities
^USB 2.0 hub pcb design
https://www.sparkfun.com/datasheets/IC/cp2102.pdf