Showing posts with label Raspberry PI. Show all posts
Showing posts with label Raspberry PI. Show all posts

Sunday, September 06, 2020

Commodore Educator 64 Mini: Part 3

11 comments
Here we are at the final article in the Commodore Educator 64 Mini series and there are a surprising number of loose ends to tie off; very probably the reason why it's taken a while to actually get around to documenting them.

This article more or less sums things up and provides some instruction on how get the project up and running. If you haven't read Part 1 or Part 2, I'd suggest starting from the beginning so that it all makes sense.

All files required to build the Educator Mini are made available at the end of the post.

The Final Producst
The Final Product: The Commodore Educator 64 Mini

Fitting the Keyboard and Daughter Board

The keyboard is designed to sit quite firmly in the Educator case, it shouldn't require any glue but you may need to file and / or sand the 3D printed case lightly to gain that perfect fit.

The Raspberry PI Daughter Board and monitor cables should be fitted before placing the Raspberry Pi in it's Educator case, as there is not a lot of height to play with right up the back. Cabling running to the keyboard can be inserted at any time.


Raspberry Pi Daughter Board
Educator Min Keyboard to Raspberry Pi Daughter Board / Interface

When fitting the keyboard you need to pay attention to the labels at the header pins. The numbers and letters correspond with a similar arrangement found on the PI Daughter Board. As a plus, the naming scheme also matches that used on a real 64 keyboard.


Keyboard Fitted / back view
Commodore 64 Mini Keyboard fitted Snuggly: Pay attention to the jumper setting.

In addition there is a jumper setting to be made, for use in the Mini. A Jumper should be set across pins 1 & 2. The Jumper determines the behaviour of the Shift Lock key, unfortunately there are not enough free GIPO pins on the PI to take advantage of this feature for now.


The Educator Internals
Inside the Educator MIni

Finalising Model Styling

You'd have noticed by now that the Educator Mini 64 has a somewhat different set of stickers to Lorenzo's PET (much like the real thing really). I've made up a couple of additional mini replica decals to suit the 64, the most obvious of these being the BASIC reference panel.

The BASIC keyword panel is a fairly good approximation the original full sized version and depending on how good your eyes are and the resolution of the printers used to produce the decal sheet could well come in useful.

I've also included Lorenzo's decals for the back of the monitor and the Serial Number Name Plate for the sake of completeness.

Educator 64 Mini Decal Sheet, Including everything an old computer needs.

Getting the Educator Mini up and Running

RetroPie is normally your friend for an easy Linux retro solution. Disclaimer time, I decided not to use RetroPie for this build and went with a standard versions of Raspberry Pi OS (previously called Raspbian).

There are a number of reasons I'm using Raspbian, the main ones for me being,
  1. It's just simpler to get the keyboard working with the Vice emulator.
  2. I'm only intending to use Vice and Commodore Emulation on the Mini.
Of course your needs may vary, and what ever I've done is really only a suggestion.

Installing the Vice Emulator

Raspberry Pi OS does not include the Vice Emulator as a standard package, or even an optional downloadable package, so you'll need to install it manually. I simply followed the Installation guide on krystof.io 

Once Vice is installed you'll be wanting to add a configuration file to get the emulator looking and feeling right.

Run the following commands to create a sdl-vicerc config file:
mkdir -p ~/.config/vice
nano ~/.config/vice/sdl-vicerc
[C64SC]
MenuKey=293
MenuKeyUp=273
MenuKeyDown=274
MenuKeyLeft=276
MenuKeyRight=275
MenuKeyPageUp=280
MenuKeyPageDown=281
MenuKeyHome=278
MenuKeyEnd=279
WarpMode=0
Sound=1
SoundDeviceName="sdl"
SoundSampleRate=8000
SoundBufferSize=100
SoundFragmentSize=0
SoundVolume=100
SoundOutput=1
AspectRatio="1.000000"
SDLCustomWidth=480
SDLCustomHeight=320
SDLWindowWidth=480
SDLWindowHeight=320
SDLGLAspectMode=0
VirtualDevices=1
IECReset=1
CIA1Model=0
CIA2Model=0
VICIIVideoCache=1
VICIIDoubleScan=0
VICIIDoubleSize=0
VICIIFilter=0
VICIIModel=0
SidEngine=0
SidModel=0
JoyPort4Device=0
JoyDevice1=4
JoyDevice2=4
AutostartBasicLoad=1
AutostartPrgMode=0
DriveSoundEmulation=0
Drive8Type=1571
GlueLogic=0
ETHERNETCARTBase=56832
Acia1Base=56832
AutostartWarp=1
KeyboardMapping=1

Setting Up the keyboard

There are multiple was to of configuring a keyboard for use with the vice Emulator, I've chosen the path of least resistance. Feel free to delve deeper into the heavy customisation that Vice affords. That said intense configuring is a little above what's really required for what is essentially a very cute desk toy.

For the initial steps, we'll basically be following those documented in PJ Evens's MagPi issue 67 article on page 26, make some changes specifically for the Commodore Educator 64 keyboard.

1) install Libsuinput: From your home directory:
cd
sudo apt install get libudev-dev python-dev python-pip
sudo pip install wiringpi
cd git clone github.com/tuomasjjrasanen/libsuinput
cd libsuinput
./autogen
./configure
make
sudo make install
Add the following line to /etc/modules-load.d/modules.conf
uinput

2) Install Python-uinput: From your home directory:
cd
git clone github.com/
tuomasjjrasanen/pythonuinput
cd python-uinput
sudo python setup.py build
sudo python setup.py install

3) Install cbmscanner python scripts:  Download these scripts and uncompress the file. We'll mimic the original Magi Article and install them in a subdirectory off the home dir.
cd
wget  -P ~ "http://dasteph.com/cgi/pet/files/cbmscanner.tar"
tar -xvf cbmscanner.tar

4) Create a new Service: We need to setup a new service to run keyboard scanner on boot by creating a new config file.
sudo nano /usr/lib/systemd/cbmscanner.service
[Unit]
Description=Commodore 64 Keyboard Scanner
After=multi-user.target
 
[Service]
Type=simple
ExecStart=/usr/bin/python /home/pi/cbmscanner/cbmscanner.py
Restart=on-abort
 
[Install]
WantedBy=multi-user.target
sudo systemctl enable /usr/lib/systemd/cbmscanner.service

5) Configure Keyboard Layout: Edit the keyboard file and ensure we're setup for a US keyboard layout.
sudo nano /etc/default/keyboard
# KEYBOARD CONFIGURATION FILE
# Consult the keyboard(5) manual page.
 
XKBMODEL="pc105"
XKBLAYOUT="us"
XKBVARIANT=""
XKBOPTIONS=""
 
BACKSPACE="guess"
We can the reboot the Raspberry Pi, the keyboard should then work as intended.


All the Educator 64 Files to Download

Please be sure to refer back to the official  Commodore PET Mini site for the full build details and project history not covered in this series of blog articles.


See all entries for this project:  Part 1Part 2 and Part 3


Read More

Tuesday, June 09, 2020

Commodore Educator 64 Mini: Part 2

Leave a Comment
When I embarked on the Educator 64 journey I had no idea this would end up being my particular quarantine pass time. Who would have thought being stuck at home would be so useful.

So where are we up to? By the end of Part 1 I'd covered the printing of the Educator 64 Mini Case and very briefly mentioned sending a keyboard PCB of for manufacturing. This time around I'll get into the design of the keyboard and detail some additional modifications I've made to Lorenzo Herreras' Commodore PET Mini.


Mini Keyboards for Tiny LCDs

On the whole I've not diverted much from the general design of the Commodore PET MINI. The main inclusion is that of the working keyboard, I did however choose to make things slightly easier where possible in other respects.

As I was going to be ordering a PCB for the keyboard I decided I might as well design an extra PCB that would plug into the back of the LCD panel. Lorenzo's PET screen design has you dissecting a ribbon cable, then hand wiring the various bits to the back of the the Waveshare LCD screen. To much effort I thought, a nice little PCB would save all that hand rerouting trouble. I also thought mounting a reassuring yellow glowing LED at the back night add some CRT realism (or not, turned out you can't really see it once installed, oh well).

LCD Mounting PCB

I addition to the LCD mounting PCB I took the opportunity to deign and order a Pi Zero sized prototyping board which extended the pin header out and added had just enough space to the end of the board for some diodes and the like. The board was a bit of an after thought, although as it turned out I needed it.

Keyboard Design

There's no shortage of people out there hacking old Commodore 64s and making them work with modern equipment. One of the largest set of modifications to dead 64s is in the re-purposing of their keyboards for use with emulators.

To this end the schematics for the 64s keyboard are well know and have been pretty convincingly documented by Simon Inns on his page Waiting for Friday. Simon interestingly points out that the official Commodore Keyboard Schematic is wrong; that certainly spared me some confusion as not having a 64 myself I had nothing else to go by other than the published designs.

Commodore Educator 64 Mini Keyboard Circuit 

I made one minor change to the keyboard schematic; the inclusion of a jumper allowing the SHIFT LOCK key to be placed on the same Column as the Restore Key,  or in its normal state as an extra LEFT SHIFT key. On a Commodore 64 keyboard the SHIFT LOCK actually locks in place if pressed, this functionality isn't possible with the TAC switches I planned on using, so I opened the option to simulate that behaviour in software latter (This option wasn't to be, read on). 

With a known working layout for a Commodore keyboard to hand, all that need to be done was getting all to fit onto a 105x38mm PCB. As mentioned in Part 1 I'd found the perfectly sized switch in the KMR431G which has a footprint of 4.2mm x 2.8mm. The resulting layout mimics the design of a full sized Commodore keyboard. As there are to be no keycaps, Legends are printed on the PCB, some additional PCB styling gives the impression of a full space bar and a silk screened separator between the main keyboard and function keys implies the existence of the metal or plastic case shroud.

The Commodore Educator 64 Mini Keyboard PCB

Reading the Keyboard

My initial plan was to use an Arduino Proc Micro acting in HID mode for decoding the keyboard inputs and passing key presses onto the Pi. The other option I'd considered was procuring a Commodore USB Keyboard Kit from Tynemouth Software. Both of these methods required a spare USB port on the Raspberry PI, being that by this time I'd decided to us a Pi 3A+ for the project (which only has one port) I really didn't have a USB port to spare, particularly if I need to connect another device such as a joystick.

A long time ago for the AZ15 build I'd considered connecting a ZX81 matrix keyboard directly to a Pi, but thought the method a little to cumbersome and unreliable. What I couldn't find at the time was a good way of sending key presses back to the LINUX kernel, sure you could detect a keypad, but only in the active program doing the decoding, not much use for emulators. Fortunately time passes and things get developed and now there are off the shelf solutions.

Enter an article in The MagPi Page 25 by PJ Evans, where he describes, and provides many of the necessities required for reading a ZX Spectrum Keyboard directly, then injecting those key presses back into the LINUX kernel. This Sounded just the ticket for the Commodore Educator keyboard, All that's needed are some software libraries, libsuinput for handling the kernel injection, and wiringpi to run some keyboard scanning code. The only possible road block being the availability of enough free GPIO ports to handle the Commodore Keyboard.

Mapping Raspberry Pi GPIO pins to the Waveshare LCD and C64 Keyboard

At a minimum we need 17 free GPIO ports to read the c64 keyboard (without worrying about multiplexing), 8 Data lines, 8 Address lines and 1 for detecting the RESTORE key. In reality I has hoping for 18 spare GPIO pins so we could enable SHIFT LOCKing. After consulting the Waveshare LCD manual it appeared all requirements could be met, but appearances can be deceptive.

Out of 28 GPIO pins the LCD panel uses 8, leaving 20 pins. Not so fast, GPIO23 is taken when using analogue audio (which we need) and on testing I also found GPIO27 and GPIO22 also seemed to be in use by the LCD panel. That left 17 ports. However GPIO14 & 15 are used as serial lines, that's now down to 15 ports. Fortunately serial can be disabled in the /boot/config.txt file. Phew, we have just enough ports free without having to stuff around with multiplexing.

The rather messy prototyping Board full of Diodes

To get things moving along I wired up my prototyping PCB much as documented in The MagPi article, I adjusting the data and address lines (see earlier image above). I then downloaded the required zxscanner code by PJ Evens, modifying sufficiently to accommodate the C64 keyboard, the result a working keyboard.

Testing the tiny Commodore 64 Keyboard

That is of course just the start, I still need to go back though the zxscanner code and turn it into c64scanner code. As it stands zxscanner is just that, it's geared towards ZX Spectrum emulators, Commodore emulators such as Vice take a somewhat different path when mapping keys from PC-like keyboards and that is something we can tackle in Part 3.

Commodore Pet Mini
C64 Keyboard Installed and some final Decals Added to the Case

Until the next article here's a quick preview of the keyboard in action:




See all entries for this project:  Part 1Part 2 and Part 3




Read More

Saturday, May 30, 2020

Commodore Educator 64 Mini: Part 1

1 comment
What do you do with a new 3D printer, a governmental advised quarantine stay at home order and the freely available plans for a Commodore PET Mini build? Why build a Commodore Educator 64 with a functional keyboard of course.

Commodore Educator 64 - drawing by David A Stephenson 2020

Printing your own PETs.

A  little over a year ago Lorenzo Herrera launched the Commodore Pet Mini on the world, a very cute miniature PET model 8032 housing a Raspberry Pi. Nicely he also included all the 3D models and a full material list so you could build your own (and a lot of people have). 

This all looked like a really fun project, the only problem being I didn't have 3D printer.  Then quite unexpectedly and just before the world locked down the family presented me a with a Flash Forge Finder 3D printer for my birthday. Thanks Family!

And so the initial stage of building a PET (soon to become an Educator 64) Mini began in earnest.

The Making of a Model

While the PET mini is quite the functional beauty as is, what with its Pi core, tiny LCD screen and USB ports, it does almost criminally lack the most important part of an early home / office / school computer, a functional keyboard.

Before going to far along the process of 3D printing I first need to know if I could get a keyboard to fit into the PET Mini. I managed to find some very diminutive KMR431G surface mount TAC switches on Element 14, tiny but not tiny enough to build a full PET keyboard.

The KMR431G switches would just squeeze in nicely when arranged in a 64 style. As luck would have it the Case design of the PET 8032 (and Lorenzo's 3D model) is near identical to that of a Educator 64. For those that don't know, an Educator 64 is basically a Commodore 64 in a PET case sold primarily to schools; possibly making it the best 80s game playing school computer ever.

Educator 64 Mini Keyboard PCB
Educator 64 Mini Keyboard PCB

I'll cover the full details of the keyboard and how it's intended to work in Part 2: For now though I laid out a PCB that followed the C64 key mappings and sent it off for Fabrication. The important part being that I now had the measurements required to adjust the top half of the PET case to fit the keyboard. 

Case Adjustments to be Made

To fit the keyboard into the Mini I simply cutout the keyboard space from the original model and designed a shelf for the new keyboard PCB to sit on. Additionally I removed the magnet clips which would normally be located under a printed keyboard and replaced these with clips located on either side of the modified case design.

Lorenzo provides bottom case templates for Raspberry Pi 2/3's and for the 4. I had a Pi 3A on hand and further modified the lower case to fit that in place. The shorter Pi 3A board would came in handy later when cramming many additional keyboard wires into the case. 

Exploded View of the Commodore Educator 64 Mini Case.

Unfortunately the cases main top and bottom sections proved slightly too large for my printer. So I broke these down into separate components with some additional tabs put in place to make gluing them together convenient  and providing some structural strength. I also decided to divide the monitor stand into a bottom an top piece facilitating slightly easier 3D printing and finishing.


The other large-ish change I made to the original model was in redesigning the monitor frame, that part holding the LCD panel. This I made this slightly wider and a little less ovaloid in keeping with the source material. The clasp holding the monitor in place I also reduced in size considerably, minimising the likelihood of snapping an LCD panel accidentally. 

Printing and Finishing the Model

With all the adjustments made the model printed out quite easily. Finishing the the plastics took a little extra effort.

From other modelling activities I had a set of small files and sandpaper which went to good use. Quite a lot of time went into smoothing of the rougher areas and obvious layering from the 3D printing process. I wasn't intent on removing all traces of the printing technique, the model should reflect the process at least to some extent. 

Once sanded down and finished, the little Educator 64  parts were spray painted with a couple of colour combinations. The white panels being a mix of Tamiya TS-26 Pure White for the under layers and TS-7 Racing White for the finishing coats, lending a nice retro feel as the Racing White is slightly creamy in colour.

The black areas of the model were first painted in Citadel Lead Belcher, although any steel or silvery colour would be just as fine (It just happened to be the colour I had available).  The top coat is a Tamiya TS-6 Matt Black, applied relatively lightly, just enough to appear black while allowing the metallic undercoat to maintain some presence. All the components were then sealed with a Satin Spray varnish. The end result being really quite pleasing.

Commodore Educator 64 Mini based on the Commodore Pet Mini

Next Time: The Electronics

The Educator 64 fits together much as the PET mini. The major electronic components are pretty much listed at commodorepetmini.com. In Part 2 I'll attempt to go over how the keyboard is configured and how it works in conjunction with the original PET design.


See all entries for this project:  Part 1, Part 2 and Part 3

 
Read More

Sunday, August 28, 2016

AZ15 Raspberry PI 3 Upgrade

Leave a Comment
I've taken the opportunity to upgrade the heart of the AZ15 to a Raspberry PI 3, up from a PI 2. The neat thing about the last few models of PIs' has been the unchanging form factor with increasing capabilities.

There has been a noticeable speed boost between the PI 2 and PI 3, this has been most evident when using the ZEsarUX emulator. Previously ZEsarUX has seemed somewhat sluggish on the PI 2, leaving SZ81 as my emulator of choice. With the performance improvements on the PI 3, the choice of emulator is now wide open, a nice change indeed.

Also  the PI 3s' addition of baked in Bluetooth and WIFI has meant that a number of the USB ports formerly dedicated to these tasks are suddenly free. With the PI 2, I had dedicated one of the internal (to the AZ15) USB ports to a WIFI dongle, with the advent of the PI 3 new found connectivity option, I've instead inserted a small in stature and capacity USB flash drive for ZX81 ''P" file storage. Additionally with Bluetooth now available, wireless mice in particular are easy to add.

AZ15 With Bluetooth Mouse and WIFI

AZ15 Concept Image

A What's in the Box Shot


All the nice additions to the PI 3 bring the whole AZ15 project pretty damn close to the original concept image; thanks to the addition of a Bluetoooth mouse and the ever unseen WIFI.

So now it's time for a new glory shot, a shot which I've taken at as close to the same angles and lighting conditions as manageable.

What do you think?


Read More

Saturday, August 13, 2016

ZX81 Kiosk Mode for Raspberry Pi / AZ15 (Part 2)

Leave a Comment

In Part 1, we setup the AZ15 to boot into a kiosk mode that relied on X11. This is all well and good, but why use an X11 windows manager when we don't really need to.

All the major ZX81 Emulators available for use on the Raspberry Pi have SDL versions available, and SDL dosn't require an X11 windows manager. Booting right into an emulator will speed up the startup process and get us "programming" our ZX81 in not time at all.

All the hard work such as installing the sz81 emulator was covered in Part 1. This time around we only need to make some minor alterations.

Auto Login the PI User to the CLI


First off, a couple of minor config changes from the last blog entry. We need to set auto login to the CLI instead of the Desktop. From the X11 desktop (startx if you need to), access the graphical config utility using the “Preferences” > “Raspberry Pi Configuration” menu. Set the options as below:


Auto Run the ZX81 Emulator at Login


Next up add the following Code to the end of your /home/pi/.bashrc file.


# Run if tty1
if [ $(tty) == /dev/tty1 ]; then
 # *** Configure and Run the ZX81 emulator ***
 # If you have ZX81 P files / Roms in a handy Dirctory, cd to it first.
 # This obviously makes life easier later on.
 cd ~/Files/emulation/zx81

 #Set az15 keyboard options, if you haven't built a az15 the comment this out.
 echo emulator bell beep off dbem on> /dev/ttyACM0

 # Run the sz81 emulator in fullscreen mode
 sz81 -f -1024x768

 #Set az15 keyboard options, if you haven't built a az15 the comment this out.
 echo standard bell beep on dbem off> /dev/ttyACM0
fi


That's it, we can now boot right on into the emulator after the next "reboot".

A Little Extra Visual Config Enhancement


Normally when the Pi boots up a whole load of logging and informational messages scroll down the screen. While this is all very useful information (depending on your perspective), it's not exactly helping generate that 80s mircro-computer vibe.

So let's hide the information overload by adding some extra switches into the Raspberries "cmdline.txt" file.

sudo nano /boot/cmdline.txt

All the configuration options will be on the first line of the file, change the following details.

Find:
console=tty1

Change to:
console=tty3

Next, add the following commands to the end of the line.

loglevel=3 logo.nologo

If you reboot now, having made the above changes in combination with Part 1's instructions, then you should see something very similar to the video clip below. (You'll probably also notice I changed the Splash Screen).



Now the AZ15 has booted up, we're ready to do some serious programming, or the somewhat more likely scenario, play the excellent "Crozxy Road" from Bobs Stuff.




Read More

Wednesday, August 03, 2016

ZX81 Kiosk Mode for Raspberry Pi / AZ15 (Part 1)

Leave a Comment

The final piece to the ZX81 keyboard puzzle is to get the Raspberry Pi / AZ15 to boot like it's 1981, arriving straight at the Sinclair "K" prompt after being switched on. Booting won't be measured in seconds (actually it comes in at about 20 seconds) as it was in 1981, after all 35 years of progress takes extra time. Though to be fair, the loading of software after booting up a ZX81 was measured in aeons.

There are many ways to boot a Pi into a Kiosk like mode, I've gone with one of the easiest, simply hijacking the pre-existing Openbox Xsession. The process outlined below is applied on top of a default Raspbian Jessie installation.

Installing the sz81 Emulator


Fist up you'll need a ZX81 emulator, I've been using various sz81 versions to test the AZ15, and have found the last official release, sz81-2.1.7,  the most stable for my purposes.

- Download the official sz81-2.1.7 release of sz81 from http://sz81.sourceforge.net/
- Alternatively, experiment with the unofficial updates provided at http://rullf2.xs4all.nl/sz81/

After downloading and decompressing the sz81-2.1.7-source.tar.gz file, edit the makefile in the source directory, and change the installation type to system wide. Full details can be found in the sz81 REAME file.


# Comment/uncomment these to choose an installation destination
# System wide installation
PREFIX?=/usr/local
BINDIR?=$(PREFIX)/bin
DOCDIR?=$(PREFIX)/share/doc/$(TARGET)
PACKAGE_DATA_DIR?=$(PREFIX)/share/$(TARGET)


Also, if not already installed grab, the SDL develpment libararies from the repositories, as these will be required before compiling the sz81 source.

sudo apt-get install libsdl1.2-dev

Then from the sz81 source directory, make and install sz81 itself.

make
sudo make install


Auto Login the PI User


Now that we have an emulator installed, we'll want it to execute on boot up.

If the Pi isn't already configured to Boot to the Desktop and / or Auto Login, you can access the graphical config utility using the “Preferences” > “Raspberry Pi Configuration” menu. Set the preferences as below:


If your Raspberry Pi wasn't previously configured to boot to the desktop, reboot it now before continuing, in order to test all is well so far.

Simple PI / ZX81 Emulator Kiosk


Raspbian Jessie ships with 3 pre-configured desktop environments:


  1. Default Xsession: An LDXE enironment using version 3 GTK+ of toolkit
  2. LDXE: An LDXE enironment using version 2 GTK+ of toolkit
  3. Openbox: Amazingly configurable Desktop


For our purposes we'll essentially hijack Openbox for auto logon and startup the sz81 emulator. Openbox is a very user configurable and we shall be ignoring most of that power co-opt it for our Kiosk style login.

Editing or create an OpenBox autostart file (using Geany or Nano from a console) in a sub-directory off the pi users home directory.

nano ~/.config/openbox/autostart


# *** Set some Openbox options ***
# Set a background colour to Black
BG=""
if which hsetroot >/dev/null; then
  BG=hsetroot
elif which esetroot >/dev/null; then
  BG=esetroot
elif which xsetroot >/dev/null; then
  BG=xsetroot
fi
test -z $BG || $BG -solid "#000000"

# *** Configure and Run the ZX81 emulator ***

# If you have ZX81 P files / Roms in a handy Dirctory, cd to it first.
# This obviously makes life easier later on.
cd ~/Files/emulation/zx81

#Set az15 keyboard options, if you haven't built a az15 the comment this out.
echo emulator bell beep off> /dev/ttyACM0

# Run the sz81 emulator in fullscreen mode
sz81 -f -1280x900

# *** On emulator Close exit Openbox ***

#Set az15 keyboard options, if you haven't built a az15 the comment this out.
echo standard bell beep on> /dev/ttyACM0

openbox --exit


Save the files and that's the basic kiosk like configuration completed.

Now log out of the default LXD environment. Once back to the logon screen, select Openbox from the drop down menu on the top left of the screen. If everything has gone to plan the sz81 emulator should startup.

If you now exit the sz81 emulator, you should once again be dropped back to the logon screen. This time select Restart from the power menu and the PI should boot directly into Openbox and open the emulator, as by default the last Desktop Environment will be selected on a system restart.

Retro Pixel Inducing Splash Screen

Setup a Splash Screen


Get into that 80s spirit with a Loading Screen. Technically there were no splash screens on a ZX81, unless you count the wavy lines that take over the screen when loading from tapes, but lets no spoil things. I've made up a rather retro and referential black and light grey image for the purpose, but use what ever image floats your boat.

Log onto the console and create a directory.

sudo mkdir /etc/images

Copy your chosen image into that directory, make sure your image is in the PNG format.

sudo cp /home/pi/"YOUR IMAGE".png /etc/images/az15-splash.png

Now we need a FrameBuffer Image viewer to run on boot.

sudo apt-get install fbi

Create a startup file and edit the contents.

sudo nano /etc/init.d/az15-splash-screen


#! /bin/sh
### BEGIN INIT INFO
# Provides:          az15-splash-screen
# Required-Start:
# Required-Stop:
# Should-Start:      
# Default-Start:     S
# Default-Stop:
# Short-Description: Show custom splashscreen
# Description:       Show custom splashscreen
### END INIT INFO

do_start () {
  /usr/bin/fbi -T 1 -noverbose -a /etc/images/az15-splash.png    
  exit 0
}

case "$1" in
  start|"")
    do_start
    ;;
  restart|reload|force-reload)
    echo "Error: argument '$1' not supported" >&2
    exit 3
    ;;
  stop)
    # No-op
    ;;
  status)
    exit 0
    ;;
  *)
    echo "Usage: az15-splash-screen [start|stop]" >&2
    exit 3
    ;;
esac

:


Now, make the file executable and get the system to recognise it as an init script.

sudo chmod a+x /etc/init.d/az15-splash-screen
sudo insserv /etc/init.d/az15-splash-screen

Reboot and you should have something very similar to the video clip below.


Credit Where It's Due Most


Much thanks to the following sites and blogs describing the exact or very similar processes, leading to an article that's boarding on plagiarism.

Run a ZX81 Emulator in "kiosk" mode on a Raspberry Pi
Building a Raspberry Pi Kiosk
Openbox Wiki Entry on Autostart


Read More

Thursday, December 31, 2015

Build Your Own AZ15

Leave a Comment
Why not round out the year be building your AZ15, the Raspberry Pi, Arduino and ZX81 keyboarded wonder of a mini computer.

There have been a number of requests asking where to get the case, all the parts etc, so after ironing out a couple of minor issues I've made the Case available on Shapeways, and below is detailed most of everything else you'll require to complete your own AZ15 project.

This little is adventure has always been about achieving a fun build in the spirit of  "just because it's possible I think I'll give it a go", so please  don't expect this thing to be a cheep enterprise (3D Printing the case is the largest single cost factor here). This project is a learning experience and one undertaken to just see what could be achieved with 3D printing, off the shelf Arduino components and some hard graft.

Before you rush of and purchase everything, keep in mind that this is also not a professional product and doesn't come with a warranty, though if you ask nicely I'll do my best to provide some help along the way, should you decide to give it a go.

Major Case Components List


These are the major components, the ones responsible for all the heavy lifting, style substance and the impress (or not) your friends bits at the heart of the AZ15. 

Major& Miscellaneous Parts Shopping List


Amount Part Type Properties
1 AZ15 Computer Case Main AZ15 Case to hold the Raspberry Pi2 and Keyboard Converter Board etc
1 AZ15 Computer Case Lid For a Complete case the lid component is also required
1 Raspberry Pi2 Specifically a Raspberry Pi2 is required to fit inside the AZ15 Case.
1 LeoStick Freetronics LeoStick (Arduino Compatible)
1 ZX81 Keyboard ZX8-KDLX - PCB replacement keyboard for ZX81. These can be purchase fully assembled or un-assembled depending on preference. There is also a ZX80 variant available, compatible with the AZ15 project, if you're feeling super retro. (some minor changes to Arduino code to match the layout may be required).
1 Rubber Feet Rubber Feet, Small Stick On, Size: 12 x 12mm- Height 6mm
1 Compact Right Angled USB Cable This goes inside the AZ15 case and connects the Pi to the Leostick. A 15cm length of cable should be plenty. I got one of these from Ebay.
1 Mini USB WIFI Dongle Optional, for plugging into the internal USB port.
1 Double Sided Tape Black Double sided tape for mounting the ZX81 Keyboard into the case keyboard tray.
1 Hot Glue Hot glue and glue gun, used to permanently attach LEDs to case.


Converter Board Components and Minor Case Furnishings


In this section is listed everything required to build the Converter Board. I've linked to the exact components I used in my original board for clarification. You should be able to match the linked components to you're local supplier if needed.

Shopping List


Amount Part Type Properties
1 Molex 22-02-3053 header - 5 pins hole size 1.0mm,0.508mm; row single; package THT; pins 5; form ♀ (female); variant variant 4; pin spacing 0.1in (2.54mm)
1 Molex 22-02-3083 header - 8 pins hole size 1.0mm,0.508mm; row single; package THT; pins 8; form ♀ (female); variant variant 5; pin spacing 0.1in (2.54mm)
4 Locking male header - 2 pins 2 Pin 0.1 Straight Locking Header - 2.54 pitch - Single; form ♂ (male); pin spacing 0.1in (2.54mm)
2 Generic male header - 14 pins hole size 1.0mm,0.508mm; row single; package THT; pins 14; form ♂ (male); pin spacing 0.1in (2.54mm)
4 Header with Crimp Pins - 2 pins 2 Pin 0.1 Header with Crimp Pins - 2.54 pitch (2.54mm). Connect LEDs and switch to Board
3 Red (633nm) LED color Red (633nm); package 5 mm [THT]; leg yes. Use hookup wire and Header to Connect to Board and Mounting in Case
1 LeoStick As above, don't panic, you don't require 2 of these. Assemble separately with female header at bottom. Plugs into J7 and J8
3 220Ω Resistor tolerance ±5%; package THT; bands 4; resistance 220Ω; pin spacing 400 mil
1 10kΩ Resistor tolerance ±5%; package THT; bands 4; resistance 10kΩ; pin spacing 400 mil
1 Round Pushbutton switching circuit SPST; default state Normally Open. Mounting hole 12mm
1 Hook Up Wire Various Colours, For connecting LEDs and Switch to Board via Headers
1 Heatshrink For isolating LEDs, prevent contact with Raspberry PI etc


Converter Board Assembly


ZX81 Keyboard Converter Board PCB Layout.
There is not a great deal to assemble on the
Converter Board, just a couple of resistors, pin headers and the Molex sockets, over all is a very basic solder job.

All the files required files for ordering a PCB from a fabrication house are contained in AZ15_PCB_layout.zip. Or do as I did, and use the same files to to create your own PCB. I outlined the basic process earlier in the blog. Extra details on construction of the Converter Board have also been documented previously.

Of course you'll nee the latest Arduino sketch to fuel the Leostick, and that can be found in the zx81usbkeyboard_20151.tar.gz file.

Components highlighted in bold green, under Properties, are not soldered / attached directly to the converter board. These components are for attaching via hookup wires and headers to the board, and are mounted in or on the AZ15 Case.

Assembly List


Label Part Type Properties
J1 Molex 22-02-3053 header - 5 pins hole size 1.0mm,0.508mm; row single; package THT; pins 5; form ♀ (female); variant variant 4; pin spacing 0.1in (2.54mm)
J2 Molex 22-02-3083 header - 8 pins hole size 1.0mm,0.508mm; row single; package THT; pins 8; form ♀ (female); variant variant 5; pin spacing 0.1in (2.54mm)
J3 Locking male header - 2 pins 2 Pin 0.1 Straight Locking Header - 2.54 pitch - Single; form ♂ (male); pin spacing 0.1in (2.54mm)
J4 Locking male header - 2 pins 2 Pin 0.1 Straight Locking Header - 2.54 pitch - Single; form ♂ (male); pin spacing 0.1in (2.54mm)
J5 Locking male header - 2 pins 2 Pin 0.1 Straight Locking Header - 2.54 pitch - Single; form ♂ (male); pin spacing 0.1in (2.54mm)
J6 Locking male header - 2 pins 2 Pin 0.1 Straight Locking Header - 2.54 pitch - Single; form ♂ (male); pin spacing 0.1in (2.54mm)
J7 Generic male header - 14 pins hole size 1.0mm,0.508mm; row single; package THT; pins 14; form ♂ (male); pin spacing 0.1in (2.54mm)
J8 Generic male header - 14 pins hole size 1.0mm,0.508mm; row single; package THT; pins 14; form ♂ (male); pin spacing 0.1in (2.54mm)
LED1 Red (633nm) LED color Red (633nm); package 5 mm [THT]; leg yes
LED2 Red (633nm) LED color Red (633nm); package 5 mm [THT]; leg yes
LED3 Red (633nm) LED color Red (633nm); package 5 mm [THT]; leg yes
LeoStick Arduino Assemble separately with female header at bottom. Plugs into J7 and J8
R1 220Ω Resistor tolerance ±5%; package THT; bands 4; resistance 220Ω; pin spacing 400 mil
R2 220Ω Resistor tolerance ±5%; package THT; bands 4; resistance 220Ω; pin spacing 400 mil
R3 220Ω Resistor tolerance ±5%; package THT; bands 4; resistance 220Ω; pin spacing 400 mil
R4 10kΩ Resistor tolerance ±5%; package THT; bands 4; resistance 10kΩ; pin spacing 400 mil
S1 Round Pushbutton switching circuit SPST; default state Normally Open. Mounting hole 12mm

Read More

Wednesday, December 09, 2015

AZ15 and a Tale of two Features

Leave a Comment

Feature One: As seen on the GuardianWitness


A big thanks to the The Guardian and Matthew Holmes in particular, for featuring this humble Raspberry Pi, Arduino and ZX81 keyboard project in the article Best reader Raspberry Pi projects – and some of the most pointless. There are loads of other interesting Pi related constructions to peruse through, the article is a fun sample of all the ways people are finding to enjoy the Pi. I particularly enjoyed the Raspberry Pi hacked into a Holga 120 Film Camera, and its taking of photos old school.

The AZ15, as seen in all the best online newspapers.


Feature Two: New Keyboard Functionality


The nice thing about making something yourself is that you can continue to work on it, even if to all external appearances the project may seem complete.

Having used the AZ15 for almost two weeks now I decided to add a little extra functionality, addressing some minor usability issues, the main one being my forgetting to switch between Emulator and Standard keyboard modes. When using a ZX81 emulator with the keyboard, the button on the right side of the case is pressed, this changes the keyboard mode, and the LEDs on top visually tell you what mode you're in. This is all fine, except I keep forgetting to press the button.

The solution is simple enough, have the keyboard change modes automatically. Nicely the Raspberry Pi can talk to the LeoStick via serial link and vice versa. A couple of commands directed at the serial interface before launching an Emulator automatically selecting the correct keyboard mode and things soon become more user friendly.

For example, emulator mode can be selected and a notification bell passed with the following redirection to the serial port the LeoStick / Keyboard is attached to.

echo emulator bell > /dev/ttyACM0

Putting the above in a start script that launches the emulator and then sets all back to normal after exiting solves my main issues.



#!/bin/bash
# Put keyboard in Emulator Mode
echo emulator bell > /dev/ttyACM0
# Launch the sz80 emulator
sz81
# Set keyboard back to Standard Mode
echo standard > /dev/ttyACM0

If the USB port assignment changes around, "dmesg" could always be used to parse for the correct device.


Command Line, Mode and Options Selection
BELLSound the LeoStick Piezo. Could be used to forward audio system notifications etc. 
BEEP OFFTurn off Keyboard Sounds. Sounds are off by default.
BEEP ONTurn on Keyboard Sounds. Similar to the keyboard clicks made by ZX Spectrum when typing. The keyboard only emits clicks in Standard mode. In Emulation mode sound is always off.
DEVICEReturns message "ZX81_KEYS" to the console. Useful if unsure you have the correct serial port. You must be monitoring incoming streams to get the return message. eg cat /dev/ttyACM0
EMULATORSwitch the keyboard into emulator mode.
STANDARDSwitch the keyboard into standard mode.


The latest Arduino sketch can be downloaded here: http://zx81.dasteph.com/files/zx81usbkeyboard_20151205.tar.gz

Read More

Friday, November 27, 2015

Presenting the AZ15, a not Actuall Clone of a ZX81 Assembled

Leave a Comment
I was confident it would look pretty cool, yet once the case arrived (after some timely industrial action at customs and excise) my expectations were exceeded by far. It does in fact look damn amazing, this 3D printing thing and by extension Shapeways ability to turn home design into reality is brilliant.


As expected the surface on the final product is lightly rough to touch and has a non-gloss finish. It kind of reminds me of suede, if suede assumed a plasticky form. You can still see the layers where the object has been built up but that certainly doesn't detract from the looks of the AZ15 case. Invariably I couldn't wait to put it all together, and thus the beginning of the end phase ensued.

Firstly I gathered all the disparate parts together. Internally the case had the following items to be installed, a Raspberry Pi 2, the LeoStick and Converter board, a right-angled usb cable to connect to the LeoStick, a WIFI dongle, LEDs and the mode selector switch. The keyboard would sit nicely on the tray, with it's cable sliding through a gap provided at the upper right corner much, like on the original ZX81.


The Pi, USB cable and WIFI dongle were installed first. I was relived that this all fit exactly as planned, being that the AZ15 case was designed specifically to hide one of the USB port banks and thus give the appearance of one complete unit to the casual observer.


Next the LEDs were hot glued into position, the mode switch installed and the keyboard converter board were inserted. Working in the confined space was a little challenging but everything so far went in without to much difficultly. As I'd made the converter myself and therefore drilled the mounting holes by hand, the mounting points were designed to allow a little slip and slide for easy adjustment. The one thing I hadn't counted on was not being able to affix the bolt heads due to access issues at the far right corners, luckily for me the drill holes in the converter board are nice and tight, so the bolts screwed in and held the board firmly enough.


Time to plug in the brains of the keyboard ie. the LeoStick. It's all a tight little fit, leaving just enough room to smuggle in the cables coming directly from the keyboard. The keyboard was mounted with some doubled sided tape on the keyboard tray.


Flipping the case over, some handy dandy rubber feet are slotted into position to provide much needed non slipping action, necessary when typing on a keyboard of diminutive weight and size.


Now it was a simple matter of plonking the lid on, except that the plonking didn't quite plonk as one might have expected. Unfortunately I'd made the little tabs on the side of the lid slight to small, meaning that the lid slides about a little bit to much. The immediate solution was to use some tiny strips of double sided tape to hold the movable lid in position. At a later date I might opt to get the lid reprinted and permanently fix this relatively minor issue.


So that's it, time for some sitting back a marveling at my creation. I'm very pleased with the final look of the AZ15 case, and hopefully I've managed to do the original ZX81 design justice and possibly at least slightly amuse Rick Dickinson the creator of the ZX81's iconic looks.


Read More

Monday, November 09, 2015

Final Case Design Shipped to Shapeways

Leave a Comment
Az15 Raspberry Pi Computer / LeosStick Computer with ZX81 Keyboard
AZ15 Deign Impression
The final AZ15 case design has been shipped off to Shapeways for printing and the nervous wait for a tangible object to arrive in the post has begun. All being well, the physical product will work as designed; meeting all expectations generated by the on screen version of reality.

The case was designed using the modeler AC3D, I've been using this tool for various projects over a number of years (though never for a 3d printed model before), so am pretty comfortable using it. A Raspberry PI 2 / B+ model was sourced from Thingiverse to construct the case around. I can't locate the exact model I used now, however there are a number to chose from including this one by jayftee. It's always a bonus when somebody else has done the hard work of modeling and exacting object for you.

AZ15 Case Design, Side View
Some decisions taken early on that dictated the shape and size of the AZ15 case. The choice not to de-solder the USB and Ethernet ports from Raspberry PI 2 lent extensively to the final design. The PI 2 has four USB ports, and I've designed the case such that two of these ports are only available internally. This layout allows the Leostick to connect internally and invisibly to one of these ports, giving the overall external appearance of one complete unit. The other internally USB port could be used to house a WIFI or Bluetooth adapter.

AZ15 Case Design, Rear View
The choice of configuration for the USB ports has given a rather unique cut-out appearance at the back of the computer, a nice little design touch that also helps maintain a compact and tidy feel when external USB devices are plugged in at the side.

From the outset I hadn't intended to clone a ZX81 case, the original being a design classic in its own right. What I'm after is something reminiscent of a classic 80s microcomputer but with a contemporary feel. A kind of modern clone. Hopefully within the next week or so I'll find out just how successful I've been.


Read More

Wednesday, November 04, 2015

Some More Arduino Code for the ZX81 Keyboard

4 comments
I've made  a fair number of changes to the ZX81 keyboard Arduino sketch. The most noticeable being that the code is now broken into multiple files / libraries; all feeling a little more C++ like. Of course real microcontroller programmers use C, but we wont discus that here.

In general the keyboard functions as earlier. The main physically tangible improvement being that the keyboard performs a whole lot better in ZX81 emulators. It's not perfect and it's definitely not ideal for playing real time games with, though It works as advertised when typing normally, ie. using the keyboard to program with.

Emulator comparability wise, the keyboard will work with  sz81 and ZEsarUX. I'd recommend using sz81, as the keyboard still functions best with that particular emulator. I've also had a go at using Fuse with the keyboard, and to the extent that a ZX81 keyboard can be used on ZX Spectrum it functions okay, though it is missing those couple of crucial extra keys for proper Spectrum emulation.

When using the keyboard in standard mode as a regular USB input device in Linux or with a Raspberry Pi there are no issues, unfortunately, as with the emulators, games that require SDL libraries suffer from the "keys not being registered when you'd like them to be" syndrome. This issue I'm afraid may be down to problems with the Arduino USB Keyboard library and beyond my immediate control.

Presented For Your Amusement, Code Caught in the Wild


Main Program (zx81usbkeyboard.ino)

As the name on the implies, here be the general program.


// **************************************************************************
// **** ZX81 USB Keyboard for Funtronics LeoStick (based on a Leonardo). ****
// **** zx81usbkeyboard.ino                                              ****
// **************************************************************************
// ** David Stephenson 2015-11-03  **
// **                              **
// ** Originally based on code by: **
// ** Dave Curran  2013-04-27      **
// ** Tony Smith 2014-02-15        **
// **********************************

 #include "Arduino.h"
 #include "zx81keyboard.h"
 #include "zx81modestate.h"
 
// ************************
// *** Global Variables ***
// ************************

// Setup Global Variables for keyboard.
ZxKeyBoard MyKeyboard;

// Setup LeoStick pins for mode switch and indicator LEDs.
ModeState MyModeState(A5,A0,A1,A2);

// Setup LeoStick pins for Keyboard rows and columns.
const byte bColPins[NUM_COLS] = {13,12,10,9,8};
const byte bRowPins[NUM_ROWS] = {7,6,5,4,3,2,1,0};


// ******************
// *** Main Setup ***
// ******************
void setup() {
  
 // Set all Keyboard pins as inputs and activate pull-ups.
 for (byte bColCount = 0 ; bColCount < NUM_COLS ; bColCount++)
 {
  pinMode(bColPins[bColCount], INPUT);
  digitalWrite(bColPins[bColCount], HIGH);
 }
 
 // Set all Keyboard pins as inputs.
 for (byte bRowCount = 0 ; bRowCount < NUM_ROWS ; bRowCount++)
 {
  pinMode(bRowPins[bRowCount], INPUT);
 }
 
 // initialize control over the keyboard.
 //Serial.begin(9600);
 Keyboard.begin();
 
}
 
// ************************
// *** Main loop        ***
// *** Lets get Busy-ah ***
//*************************
void loop() {

 bool boShifted = false;
 byte bKeyPressed = 0;
 
 // Set Keyboard Mode.
 KEYMODES eMyKeyMode = MyModeState.GetMode();
 KEYSTATES eMyKeyState = MyModeState.GetState();
 
 // Check for the Shift key being pressed.
 pinMode(bRowPins[SHIFT_ROW], OUTPUT);
 
 if (digitalRead(bColPins[SHIFT_COL]) == LOW) boShifted = true;
 
 pinMode(bRowPins[SHIFT_ROW], INPUT);
 
 for (byte bRow = 0 ; bRow < NUM_ROWS ; bRow++){
  // Run through the rows, turn them on.
  
  pinMode(bRowPins[bRow], OUTPUT);
  digitalWrite(bRowPins[bRow], LOW);
  
  for (byte bCol = 0 ; bCol < NUM_COLS ; bCol++){
   if (digitalRead(bColPins[bCol]) == LOW){
    if (boShifted && eMyKeyMode == STANDARD){
     // Select correct Keyboard layout for current state For STANDARD mode. 
     // Shift alters the Current state selection. eg. gets Red Shift symbols in Normal State. 
     switch (eMyKeyState) {
      case NORMAL:
       bKeyPressed = MyKeyboard.bKeyPress(bRow, bCol, NORMAL_SHIFTED, eMyKeyMode);
       if (bKeyPressed == KEY_RETURN) { 
        eMyKeyState = FUNCTION;
        bKeyPressed = 0;
        MyKeyboard.KeyDisable(bRow, bCol);
       }
       if (bKeyPressed == '9') {
        eMyKeyState = GRAPHICS;
        bKeyPressed = 0;
        MyKeyboard.KeyDisable(bRow, bCol);
       }
      break;
       
      case FUNCTION:
       bKeyPressed = MyKeyboard.bKeyPress(bRow, bCol, NORMAL_SHIFTED, eMyKeyMode);
       if (bKeyPressed == KEY_RETURN) { 
        eMyKeyState = NORMAL;
        bKeyPressed = 0;
        MyKeyboard.KeyDisable(bRow, bCol);
       }
       if (bKeyPressed == '9') {
        eMyKeyState = GRAPHICS;
        bKeyPressed = 0;
        MyKeyboard.KeyDisable(bRow, bCol);
       }
      break;
       
      case GRAPHICS:
       bKeyPressed = MyKeyboard.bKeyPress(bRow, bCol, GRAPHICS_SHIFTED, eMyKeyMode);
       if (bKeyPressed == KEY_RETURN) { 
        eMyKeyState = FUNCTION;
        bKeyPressed = 0;
        MyKeyboard.KeyDisable(bRow, bCol);
       }
       if (bKeyPressed == '9') {
        eMyKeyState = NORMAL;
        bKeyPressed = 0;
        MyKeyboard.KeyDisable(bRow, bCol);
       }
      break;
       
     }
    } else {
     // Emulator keyboard, the keyboard states are controlled by a ZX81 emulator.
     // Keyboard mimics unaltered PS2 Keyboard presses as expected by an emulator.
     bKeyPressed = MyKeyboard.bKeyPress(bRow, bCol, eMyKeyState, eMyKeyMode);
    }
    
    if (bKeyPressed > 0 ) {
     //Serial.write(bKeyPressed);
     if (eMyKeyMode == EMULATOR){
      if (bKeyPressed && boShifted) Keyboard.press(KEY_LEFT_SHIFT);
      Keyboard.press(bKeyPressed);
      // Many Emulators don't use standard OS keyboard routines and require a pause
      // for key to register. There is some variance, but 100ms seems to cover most.  
      delay(DEBOUNCE_DELAY/2);
     } else {
      if (eMyKeyState == GRAPHICS && bKeyPressed > 96 && bKeyPressed < 123){
       if (boShifted){
        Keyboard.press(KEY_LEFT_ALT);
       } else {
        Keyboard.press(KEY_LEFT_CTRL);
       }
      }
      Keyboard.press(bKeyPressed);
      // Some audio feedback if not in EMULATOR mode.
      // Kill the line if you hate beepy beep beeps.
      tone(11, 31, 20);
     }
     
     Keyboard.releaseAll();
    }
    
   } else {
    MyKeyboard.KeyPressReset(bRow, bCol);
   }
  }
  pinMode(bRowPins[bRow], INPUT);
 }
 
 digitalWrite(bRowPins[SHIFT_ROW], LOW);
 
 // Update LED panel and check for Mode change switch press.
 MyModeState.SetState(eMyKeyState);
 
 }

Keyboard Class (zx81keyboard.h)

Main guts of the keyboard setup and initial handling is in here.


// ***********************
// ** zx81keyboard.h    **
// ** Class Definitions **
// ** For ZX81 keyboard **
// ***********************

enum KEYMODES {EMULATOR, STANDARD};
enum KEYSTATES {NORMAL, NORMAL_SHIFTED, GRAPHICS, GRAPHICS_SHIFTED, FUNCTION};

#define NUM_ROWS 8
#define NUM_COLS 5 

#define SHIFT_COL 4
#define SHIFT_ROW 5
//#define FUNCTION_COL 4
//#define FUNCTION_ROW 6
//#define GRAPHICS_COL 3
//#define GRAPHICS_ROW 2

#define DEBOUNCE_DELAY 200 //debounce countdown value.
#define DEBOUNCE_DELAY_REPEAT 600

// Defines a single key and its 4 possible Major KEYSTATES: NORMAL, NORMAL_SHIFTED, GRAPHICS, GRAPHICS_SHIFTED
// Returns 5 KEYSTATES, adds FUNCTION: Caps Lock).
class ZxKey  {
 private:
  // Standard Keyboard Characters for Normal PC Use
  byte bNormal;   // Standard ZX keyboard only in lower case. EMULATOR KEYMODE should use bNormal only.
  // Extra Modes for using keyboard as a normal(ish) PS2 / USB device.
  byte bNormalShifted; // Red Symbols & Words (replaced by Symbols)  
  byte bGraphics;   // Standard ZX keyboard but should be used with CTL characters. Numbers = F1 - F10 etc
  byte bGraphicsShifted; // Standard ZX keyboard but should be used with ALT characters. Numbers = F11 - F12, 5 = home, 6 PGUP etc 
  
  // Monitor Keys last press / activity.
  short iDebounceCount = DEBOUNCE_DELAY;
  short iDebounceCountHighest = iDebounceCount;

  byte KeyValue(KEYSTATES eKeystate) {
   // Get Keyboard character for correct Key state.
   byte bKeyValue = 0;

   switch (eKeystate) {
    case FUNCTION:
     bKeyValue = bNormal;
     // Adjust for Capital Letters
     if (bKeyValue > 96 && bKeyValue < 123){
      bKeyValue = bKeyValue - 32;
     }
     break;
     
    case NORMAL_SHIFTED:
     bKeyValue = bNormalShifted;
     break;
     
    case GRAPHICS:
     bKeyValue = bGraphics;
     break;
     
    case GRAPHICS_SHIFTED:
     bKeyValue = bGraphicsShifted;
     break;
     
    default:
     // Standard normal and Emulator mode keyboard.
     // Shift key modifier used later to select functions etc in a ZX81 Emulator.
     bKeyValue = bNormal;
     break;
   }
   return bKeyValue;
  }
  
 public:
  ZxKey (byte, byte, byte, byte);
   
  byte KeyPressDetected(KEYSTATES eKeystate, KEYMODES eKeymode){
   byte bKeyValue = 0;
   iDebounceCount--;
   if (iDebounceCount == 0){
    switch (iDebounceCountHighest) {
     case DEBOUNCE_DELAY:
      iDebounceCount = DEBOUNCE_DELAY_REPEAT;
      iDebounceCountHighest = iDebounceCount;
     break;
     
     case DEBOUNCE_DELAY_REPEAT:
      if (eKeymode == EMULATOR){
       iDebounceCount = DEBOUNCE_DELAY;
      } else {
       iDebounceCount = DEBOUNCE_DELAY / 2;
      }
     break;
     
     default:
      iDebounceCount = DEBOUNCE_DELAY;
     break;
    }
    bKeyValue = KeyValue(eKeystate);
   }
   return bKeyValue;
  }
  
  void KeyPressReset(){
   iDebounceCount = DEBOUNCE_DELAY;
   iDebounceCountHighest = iDebounceCount;
  }
 
  void KeyDisable(){
   iDebounceCount = -1;
  }
};


// ZxKey constructor
ZxKey::ZxKey (byte Normal, byte NormalShifted, byte Graphics, byte GraphicsShifted){
 bNormal = Normal;
 bNormalShifted = NormalShifted;
 bGraphics = Graphics;
 bGraphicsShifted = GraphicsShifted;
}


// Defines entire keyboard, includes ZxKey class.
class ZxKeyBoard {
 private:
  // Setup 4 versions of keyboard states into keyboard.
  // Keyboard mapped for US, might need changing for other configurations eg. UK keyboard.
  ZxKey keyMap[NUM_ROWS][NUM_COLS] = 
  {
   {{'5',KEY_LEFT_ARROW,KEY_F5,KEY_HOME},{'4','%',KEY_F4,KEY_INSERT},{'3','#',KEY_F3,KEY_ESC},{'2','@',KEY_F2,KEY_F12},{'1','!',KEY_F1,KEY_F11}},
   {{'t','_','t','t'},{'r','&','r','r'},{'e','^','e','e'},{'w','`','w','w'},{'q','~','q','q'}},
   {{'6',KEY_DOWN_ARROW,KEY_F6,KEY_PAGE_DOWN},{'7',KEY_UP_ARROW,KEY_F7,KEY_PAGE_UP},{'8',KEY_RIGHT_ARROW,KEY_F8,KEY_END},{'9','9',KEY_F9,'9'},{'0',KEY_BACKSPACE,KEY_F10,'0'}},
   {{'g','\\','g','g'},{'f','}','f','f'},{'d','{','d','d'},{'s',']','s','s'},{'a','[','a','a'}},
   {{'y','|','y','y'},{'u','$','u','u'},{'i','(','i','i'},{'o',')','o','o'},{'p','"','p','p'}},
   {{'v','/','v','v'},{'c','?','c','c'},{'x',';','x','x'},{'z',':','z','z'},{0,0,0,0}},
   {{'h','\'','h','h'},{'j','-','j','j'},{'k','+','k','k'},{'l','=','l','l'},{KEY_RETURN,KEY_RETURN,KEY_RETURN,KEY_RETURN}},
   {{'b','*','b','b'},{'n','<','n','n'},{'m','>','m','m'},{'.',',','.','.'},{' ',KEY_TAB,'£',' '}}
  };
  
 public:
  // Return from ZxKey matching specified state.
  byte bKeyPress(byte bRow, byte bCol, KEYSTATES eKeystate, KEYMODES eKeymode){
   return keyMap[bRow][bCol].KeyPressDetected(eKeystate, eKeymode);
  }
  
  void KeyPressReset(byte bRow, byte bCol){;
   keyMap[bRow][bCol].KeyPressReset();
  }
  
  void KeyDisable(byte bRow, byte bCol){;
   keyMap[bRow][bCol].KeyDisable();
  }
};

Mode Switch & LED Class (zx81modestate.h)

This ones still a work in progress, I'm wanting to add some more functionality to the Mode selection button at some point. Works well enough for the moment.


// *****************************
// ** zx81modestate.h         **
// ** Class Definitions       **
// ** For Mode Switch  & LEDs **
// *****************************

// Defines LED / Mode switch panel and its behaviour.
// Three LEDs are configured to report on keyboard mode and states.
// 
// In STANDARD mode:
//  Left LED on = GRAPHICS state.
//  Middle LED on = FUNCTION state.
//  Right LED on = NORMAL state.
//
// In EMULATOR mode:
//  Left and Right LEDs = on.

class ModeState {
private:
 KEYMODES eKeyboardMode = STANDARD;
 KEYSTATES eKeyboardState = NORMAL;
 byte bModeSwitchPin;
 byte bGraphicsPin;
 byte bFunctionPin;
 byte bModePin;
 
 bool boDebounce = false;
 
 byte SetMode(){
  if (digitalRead(bModeSwitchPin) == HIGH && boDebounce == false) {
   //Serial.println("high ");
   if (eKeyboardMode == STANDARD){
    eKeyboardMode = EMULATOR;
   } else {
    eKeyboardMode = STANDARD;
   }
   
   delay(DEBOUNCE_DELAY_REPEAT);
   boDebounce = true;
  } else if (digitalRead(bModeSwitchPin) == LOW) {
   boDebounce = false;
  }
 }
 
public:
 ModeState (byte, byte, byte, byte);
 
 byte SetState(KEYSTATES eKeystate){
  
  eKeyboardState = eKeystate;
  
  // Check and set mode if Mode switch is pressed
  SetMode();
  
  if (eKeyboardMode != EMULATOR){
   switch (eKeyboardState) {
    
    case FUNCTION:
     digitalWrite(bGraphicsPin, LOW);
     digitalWrite(bFunctionPin, HIGH);
     digitalWrite(bModePin, LOW);
     break;
     
    case GRAPHICS:
     digitalWrite(bGraphicsPin, HIGH);
     digitalWrite(bFunctionPin, LOW);
     digitalWrite(bModePin, LOW);
     break;
     
    default:
     digitalWrite(bGraphicsPin, LOW);
     digitalWrite(bFunctionPin, LOW);
     digitalWrite(bModePin, HIGH);
     eKeyboardState = NORMAL;
     break;
   }
  } else {
   digitalWrite(bGraphicsPin, HIGH);
   digitalWrite(bFunctionPin, LOW);
   digitalWrite(bModePin, HIGH);
   eKeyboardState = NORMAL;
  }
 }
 
 KEYMODES GetMode(){
  return eKeyboardMode;
 }
 
 KEYSTATES GetState(){
  return eKeyboardState;
 }
};

// ModeState constructor.
ModeState::ModeState (byte ModeSwitchPin, byte GraphicsPin, byte FunctionPin, byte ModePin){
 
 bModeSwitchPin = ModeSwitchPin;
 bGraphicsPin = GraphicsPin;
 bFunctionPin = FunctionPin;
 bModePin = ModePin;
 
 pinMode(bModeSwitchPin, INPUT);
 pinMode(bGraphicsPin, OUTPUT);
 pinMode(bFunctionPin, OUTPUT);
 pinMode(bModePin, OUTPUT);
 
}
Read More