Friday, January 31, 2020

A multi-port remote RSYSLOG log server: multiple separate ports with different store forward rules for remote syslog clients

Supratim Sanyal's Blog - DECnet/Python nodes logging to Papertrail cloud-hosted log management service
DECnet/Python nodes logging to Papertrail cloud-hosted log management service

The Requirement

I have six instances of Paul Koning's DECnet/Python (e.g. PYRTR) doing DECnet routing and wanted to send log messages from all six to one central location for analysis and further distribution.

While the above goal is very specific, the general requirement is to be able to forward logs from chosen applications to a dedicated TCP port different from the standard port 514 on a multi-port remote log server so that these logs are independently processed and and can be saved into separate log files and forwarded to other log collector and analyzer tools. The second objective is to do this with minimal impact to existing system-logging infrastructure on the existing remote log server.

The Design

I have the usual RSYSLOG (the rocket-fast system for log processing) version 7.4.4 running on Ubuntu 14.04 Linux on an old VPS. I wanted to open an additional port for RSYSLOG to listen to, without disturbing existing logging and rules. I would then send over TCP/IP all DECnet/Python logs to this special port and define rules for RSYSLOG to apply to only this dedicated port. These rules would write the DECnet/Pyhton logs received over TCP/IP to a separate log file and forward only DECnet/Python logs to other log collectors including my favorite Papertrail cloud-hosted log management service.

The Implementation

Ubuntu 14.04's configuration of RSYSLOGD is simple. /etc/rsyslog.conf pretty much loads required modules and hands off specific configuration to separate files in /etc/rsyslog.d. This makes it very easy to add to the configuration by simply introducing a new configuration file in /etc/rsyslog.d.

For this example, we will use port 8514 as our dedicated log collection port for DECnet/Python. In addition to TCP/IP, we will also be ready to accept logs from remote syslog clients over UDP/IP.

First, enable the imudp and imtcp modules by uncommenting them near the top of /etc/rsyslog.conf. For internet-facing servers, you can use a firewall (UFW and friends will do fine) to block access to TCP and UDP port 514 from the internet.

# provides UDP syslog reception
$ModLoad imudp
$UDPServerRun 514

# provides TCP syslog reception
$ModLoad imtcp
$InputTCPServerRun 514

Now create a configuration file 97-pydecnet-collector.conf in /etc/rsyslog.d. This file should have contents like the following. Essentially, this configuration results in RSYSLOG listening to the ports mentioned in the last two lines, and then when it receives log entries on those ports, it performs the "actions" in the ruleset till it hits "stop". "stop" means discard the received log message at that point with no further processing.

See the inline comments for details and adjust according to your requirements.

# /etc/rsyslog.d/97-pydecnet-collector.conf

    # write the incoming log message to the indicated file
    action(type="omfile" file="/var/log/pydecnet-collect.log")

    # forward to another log server over network, queuing up at most
    # the indicated number of log entries if network link goes down
    # adjust target, port-number as per your other remote log server
    action(type="omfwd" target="<remote-hostname>" protocol="tcp" port="<remote-port>"
           queue.filename="pydecnet-queue-to-vps" queue.size="1000" queue.type="LinkedList")

    # forward to papertrail log server over network, queuing up 
    # at most the indicated number of log entries if 
    # network link goes down.
    # actual target host and port number will be provided by 
    # papertrail when you sign up
    action(type="omfwd" target="<host>" protocol="tcp" port="<remote-papertrail-port>"
           queue.filename="pydecnet-queue-to-papertrail" queue.size="1000" queue.type="LinkedList")

    # forward to yet another log server over network!
    action(type="omfwd" target="<remote-hostname>" protocol="tcp" port="<remote-port>"
           queue.filename="pydecnet-queue-to-svr2" queue.size="1000" queue.type="LinkedList")

    # More actions can of course be added ...

    # Stop processing here and discard the log message
# End of ruleset

# Listen for and process (apply ruleset) on incoming log 
# messages from remote syslog clients
input(type="imudp" port="8514" ruleset="pydecnet-collect")
input(type="imtcp" port="8514" ruleset="pydecnet-collect")


Then restart RSYSLOG. You can check the regular syslog file (/var/log/syslog in my case) for any errors reported by RSYSLOG daemon and address any reported errors in the new configuration.

Monday, January 27, 2020

Moving Thunderbird e-mail from Windows to Linux, MacOS X and other operating systems

Thunderbird Official Logo

The cheap SSD that I had put into my ancient overheated Compaq CQ61 crapped out, forcing me to replace it and reinstall my current favorite operating system MX Linux. As a bit of history, this laptop has gone through three platter hard drive and now one SSD failures. It is also on it's fourth keyboard, third power adapter, and probably 10th battery. But that is beside the point.

Thunderbird is my current email client of choice, and I once again found myself needing to copy over all of my Thunderbird email to the freshly installed MX Linux. Having multiple email and newsgroup accounts, I did not want to enter authentication details for each after the migration either.

The basic steps of grabbing Thunderbird for Windows email including account usernames and passwords are documented all over the internet. On Windows 10 (and possibly on Windows 7 onward), it boils down to:

  1. If Thunderbird is running, close the application
  2. Open File Explorer
  3. Type in the location "%APPDATA%\Thunderbird"
  4. Right-click on the file "profiles" and open in Notepad or your favorite text editor (I use Notepad++)
  5. Examine the file and identify the folder location pointed to by the "Path=" configuration line under the [Profile0] section. This is where all your email and newsgroups should live, and is referred to by Thunderbird as your "profile".
  6. You can copy the folder name from the "Path=" line and paste it into File Explorer. You will see files and folders corresponding to your email and newsgroup accounts.
  7. Assuming you have 7zip or a similar utility installed, in File Explorer select everything and zip them up into a zip archive file.
  8. Transfer this zip archive file to your Linux machine.

Now, on the Linux machine:

    Thunderbird Linux Initial Screen
  1. If Thunderbird was previously launched, there will be a hidden ".thunderbird" directory under your home directory. Delete this directory using "rm -rf $HOME/.thunderbird". Warning: If you have used Thunderbird before, this will delete all existing emails and newsgroup articles!
  2. Launch Thunderbird, but Cancel out all initial windows and exit Thunderbird. Do not create any accounts!
  3. Thunderbird has now created a new .thunderbird directory under your home directory, and inside it you will find the file "profiles.ini". Look at this file:
    cat $HOME/.thunderbird/profiles.ini
  4.  Once again, locate the directory name where your email is stored by identifying the "Path=" configuration line under the [Profile0] section. This will typically be some random letters followed by .default or .default-default or something similar. This is where you have to unzip the files into from the zip archive you copied over from the Windows machine.

Well, I transferred over the profile contents from Windows 10 laptop into the right directory on the new SSD and started Thunderbird up. And, I was immediately hit by Thunderbird asking for credentials for all the accounts in turn. Not only that, Thunderbird refused to remember the passwords, even if I remembered and entered them correctly. I could see my email transferred over, but could not get new ones or send new email without the authentication information for the accounts.

The solution to the "Thunderbird always asking for password" issue turned out to be very simple. Close Thunderbird and simply delete the pkcs11.txt file copied over from Windows in the profile folder (thank you mozillaZine).

Relaunch Thunderbird and enjoy your email on Linux! This procedure should generally work for copying or moving over Thunderbird email across different operating systems.

Update: On Mac OS X, Thunderbird profiles are stored under Library/Thunderbird directory under the user's home directory, i.e. /Users/<username>/Library/Thunderbird/Profiles has the profiles.ini file and subdirectories under there have the profile data.

Friday, January 17, 2020

Netdata Cloud on FreeBSD: First Impressions

SanyalNET Labs: Netdata on FreeBSD 12-RELEASE
Netdata Cloud on FreeBSD 12-RELEASE

Though my primary network monitoring tool for Sanyalnet Labs continues to be Pandora FMS with eHorus, I have been coming across hobbyists running Netdata Cloud and decided to give it a shot on my Dell PowerEdge 2950 FreeBSD 12-Release hypervisor that hosts a bunch of QEMU, Oracle Virtualbox, SIMH and Hercules virtual machines.

Static screenshots of Netdata Cloud do not do justice to the dynamism seen on the web interface - all the dials, gauges and graphs update at intervals in the order of single seconds - it is visual candy just by itself!

The instructions for installing Netdata Cloud on FreeBSD are fortunately simple and clear. A minor hiccup was the auto-update tool failing to install complaining "sed: -I or -i may not be used with stdin". Not a big deal for me since I am usually not keen on auto-updaters for anything, though I reported the issue. I must mention here that the ever-alert Netdata Cloud community deserves kudos - my bug-report issue #7788 was seen and assigned almost as soon as I had posted it!

This note displayed during installation is important to get Netdata Cloud to start at boot:

Note: To explicitly enable netdata automatic start, set 'netdata_enable' to 'YES' in /etc/rc.conf

Other important messages included:

netdata by default listens on all IPs on port 19999,
so you can access it with:


To stop netdata run:

  service netdata stop

To start netdata run:

  service netdata start

At the end of installation, I was happy to see:

--- We are done! --- 

  |.-.   .-.   .-.   .-.   .-.   .  netdata                          .-.   .-
  |   '-'   '-'   '-'   '-'   '-'   is installed and running now!  -'   '-'  

  enjoy real-time performance and health monitoring...

The version installed at the time of writing this post was 1.19.0-336-nightly.

Following the getting-started guide was the next step. This is where the Cloud part of Netdata kicks in. It is free for all Netdata users.

As documented at Registration and Signing in, the cloud feature is activated by registering from the "Sign In" link in the local browser itself. The cloud feature ties together all systems running Netdata Cloud registered to the same account in a single web page available from a "Nodes" link at the top. Not only that, important dynamic data for all systems are visually available on the right side of the web interface. And the most awesome cloud feature: all of this is available on the web pages presented by every individual system running Netdata Cloud logged in to the same account!

Netdata Cloud: All Systems on Onc Screen

There are two themes to chose from at this time - a dark theme as in the first screenshot at the top of this post, and a white theme as in the second screenshot above.

All information is dynamically presented by Netdata. I was impressed by the fact that even in the text below, the graphs are dynamic and keep scrolling leftwards within the text:

SANYALnet Labs: Netdata Cloud Monitoring

The default set of sensors is pretty impressive too. The Linux installation even has a sensors for software interrupts and entropy pool size which is used for random number generation, though they are missing at this time from the FreeBSD installation.
Netdata Cloud - default Linux sensors
Netdata Cloud - default FreeBSD sensors

Overall, the first impression of Netdata Cloud: it impresses! I plan on deploying it on my numerous bare-metal and virtual machines to allow me to keep an eye on all my toys from one central web interface - actually any of the web interfaces presented by the monitored systems thanks to the Cloud feature.

Friday, January 10, 2020

MVS 3.8 Operating System on IBM 3033 Mainframe: Virtualization on Linux Using Hercules and MVS 3.8J TK4- distribution

Supratim Sanyal's Blog: IBM MVS 3.8j Tur(n)key 4- ("TK4-") Operatimg System OS/VS2 MVS 3.8j under Hercules System/370, ESA/390, z/Architecture Emulator
IBM MVS 3.8j Tur(n)key 4- ("TK4-")
Knowing nothing about IBM mainframes, and never having had the opportunity to use one, I embarked on deploying an emulated IBM-3033 mainframe running their MVS 3.8 operating system using the Hercules emulator on Linux (OpenSUSE Tumbleweed) under guidance of moshix's  "IBM’s MVS 3.8 on Linux for newcomers" on YouTube. Moshix deserves all credit for everything in this post, I just followed his instructions. Here is the video:

Installation of IBM 3033 Mainframe / MVS 3.8

IBM 3033 Mainframe
IBM 3033 Mainframe
The "MVS 3.8j Tur(n)key 4- System" website has all the needed material. In addition, a IBM 3270 terminal emulator being mandatory, I simply installed the x3270 emulator from the OpenSUSE repository:

$ sudo zypper install x3270
Loading repository data...
Reading installed packages...
Resolving package dependencies...

The following NEW package is going to be installed:

1 new package to install.
Overall download size: 1.4 MiB. Already cached: 0 B. After the operation, additional 7.4 MiB will be used.
Continue? [y/n/v/...? shows all options] (y): 
Retrieving package x3270-3.5-3.1.x86_64                                          (1/1),   1.4 MiB (  7.4 MiB unpacked)
Retrieving: x3270-3.5-3.1.x86_64.rpm .............................................................[done (281.5 KiB/s)]
Checking for file conflicts: ...................................................................................[done]
(1/1) Installing: x3270-3.5-3.1.x86_64 .........................................................................[done]
Executing %posttrans scripts ...................................................................................[done]

Installation of the he MVS 3.8j Tur(n)key 4- System distribution basically consists of decompressing the current, cbt and source tarballs in turn allowing the cbt and source tarballs to overwrite any existing files.

Since I already have a Hercules IBM S/390 virtual machine running ubuntu Linux that uses TCP port 3270 for TSO User Sessions (TSO stands for "Time Sharing Option" - IBM mainframe jargon for terminal sessions), for this new MVS 3.8J virtual machine I modified conf/tk4-.conf file to define "CNSLPORT ${CNSLPORT:=3271}" instead of "CNSLPORT ${CNSLPORT:=3270}". Here is the one-line difference between the modified and original:

$ diff tk4-.cnf tk4-.cnf.orig 

I tweaked the launcher shell script "mvs" to nice the MVS virtual machine down:

$ diff mvs mvs.orig 
< nice -n 19 ionice -c 3 $force_arch hercules $DAEMON -f conf/tk4-.cnf >log/3033.log
> $force_arch hercules $DAEMON -f conf/tk4-.cnf >log/3033.log

and wrapped my usual "run" shell script around the modified launcher script "mvs".  Here is the complete

# Hercules/IBM 3033 will have TCP port 3271 open if it is running
cd /disk2/home/localuser/hercules-mvs-3.8/run/
timeout 5 bash -c 'cat < /dev/null > /dev/tcp/localhost/3271'
if [ "$?" -ne 0 ]; then
  echo "$0 - No duplicate instance found, good to launch"
  logger "$0 - No duplicate instance found, good to launch"
        logger "$0 - Error hercules ibm3033 mvs is already running, check screen -r ibm3033"
        echo "$0 - Error hercules ibm3033 mvs is already running, check screen -r ibm3033"
        echo "screens:"
        /usr/bin/screen -ls
        exit 0

echo Connect IBM3270 Terminal Emulator to TCP Port 3271 after bootup
echo e.g run x3270 X11 application or text-mode \"c3270 localhost:3271\"
#read -p "Press any key to continue..."
sleep 10

logger "$0 - starting hercules ibm3033 in screen ibm3033"
screen -S ibm3033 -m -d nice -n 10 ./mvs
sleep 5
logger "$0 - `screen -ls`"
echo "$0 - `screen -ls`"

exit 0

Booting up the MVS system is then as simple as running the script. Here is what Hercules emulator looks like:

IBM 3033 Mainframe running MVS 3.8 operating system under Hercules emulator on Linux OpenSUSE Tumbleweed

Pressing ESC in Hercules toggles a CPU and hardware oriented information screen:

IBM 3033 Mainframe running MVS 3.8 operating system under Hercules emulator on Linux OpenSUSE Tumbleweed - IBM Mainframe CPU and Hardware Details

Connecting to the MVS mainframe from a terminal is accomplished by launching the x3270 application (or in the absence of a X11 graphical windowing environment,  c3270 text-mode equivalent) and connecting to localhost:3271.

Supratim Sanyal's Blog: MVS 3.8 / 3.8J Utilities Commands Help on IBM mainframe
MVS 3.8 Utilities Help Screen

Language Compilers for IBM 3033 Mainframe / MVS 3.8

Sieve of Eratosthenes COBOL source on IBM Mainframe MVS 3.8J TK4- Operating System
Sieve of Eratosthenes COBOL source on IBM Mainframe MVS 3.8J TK4- Operating System

Following instructions in Moshix's tutorial, I could successfully edit and submit the Sieve of Eratosthenes prime-number generator programmed in COBOL to the MVS 3.8 batch execution  facility. The COBOL program is one of the included ones in the TK4- distribution. Here is the line printer output generated by Hercules:

Networking with IBM 3033 Mainframe / MVS 3.8

Well, I have not progressed far enough into the world of IBM Mainframes to attempt Networking yet. When I get to it I will write more about networking in a separate post.

Wednesday, January 8, 2020

HPUX 10.20 on HP 9000/778 PA-RISC Guest Virtualization using QEMU on FreeBSD Host: VUE Desktop Nostalgia

Supratim Sanyal's Blog: HP-VUE VUE Visual User Environment graphical desktop on HP-UX 10.20 on Qemu HP PARISC 9000 700 series server under FreeBSD

I recently brought up an emulated HPUX 11.11 PA-RISC server using QEMU on my Dell PowerEdge 2950 running FreeBSD 12 release as documented in "HPUX 11i v1 (HPUX 11.11) PA-RISC Guest Virtualization using QEMU on FreeBSD Host" including CDE desktop environment. But I was nostalgic about HP VUE graphical desktop environment and decided to relive VUE by installing a separate HPUX 10.20 server also using QEMU's PARISC 1.1 emulator on the same host.

The HPUX 10.20 installation CD-ROM is freely available at

An Open-Source GNU software collection for HPUX 10.20 is now easily available thanks to Astr0baby's efforts, from his FTP site. Check out his comment on January 3, 2020 in this post for information on his FTP server.

There are four HP-UX 10.20 Application Software CD ROM images also available at
  1. HP-UX 10.20 Application Software for HP 9000 Series 700 (December 2001) (Disc 1) [B3782-10519]
  2. HP-UX 10.20 Application Software for HP 9000 Series 700 (December 2001) (Disc 2) [B3782-10520]
  3. HP-UX 10.20 Application Software for HP 9000 Series 700 (December 2001) (Disc 3) [B3782-10521]
  4. HP-UX 10.20 Application Software for HP 9000 Series 700 (December 2001) (Disc 4) [B3782-10522]


I use VDE (Virtual Distributed Ethernet) to attach all of the SANYALnet Labs virtual machines to networks, as I have documented in detail in "Virtualization on FreeBSD Host and Oracle VirtualBox Guests with VDE Networking".

VDE has the great advantage of allowing me to extend a virtual layer-2 switch across multiple hypervisor hosts so that all VM guests are logically connected to one big ethernet switch irrespective of the physical locations of their hosts.


As is usual for all of my QEMU virtual machines, I use a shell script to launch the HPUX 10.20 instance with the QEMU monitor and HPUX 10.20 console in two different "screen" sessions.


# Launches Guest:
#    hpux1020.sanyalnet.lan hpux1020

# Change -boot to d to boot from cdrom or c to boot from hdd

# Careful of MAC address conflicts in network! Last HEX pair of MAC = last byte of guest IP.
# Also, VNC screen, if any, on dispaly number = last byte of guest IP
# And Console TELNET port = 20800 + last byte of guest IP

screen -m -d -S HPUX1020-QEMUMON \
        ./qemu-system-hppa \
            -boot c \
            -m 512 \
            -drive if=scsi,bus=0,index=0,file=./hpux10.20-striped-8gb-disk-1.qcow2.dsk \
            -drive if=scsi,bus=0,index=1,file=./hpux10.20-striped-8gb-disk-2.qcow2.dsk \
            -cdrom ./ISO/hpux-10.20.iso \
            -net nic,model=tulip,macaddr="58:9C:FC:52:54:3A" \
            -net tap,ifname=tap6,script=no \
            -serial telnet::${TELNET_CONSOLE_PORT},server \
            -serial mon:stdio \
            -nographic \
            -d nochain \
            -vnc :58 \
            -accel tcg,thread=multi
            ####-smp cpus=2

sleep 2

screen -m -d -S HPUX1020-CONSOLE telnet localhost ${TELNET_CONSOLE_PORT}

echo At this point, qemu should be on screen HPUX1020-QEMUMON and console telnet session on screen HPUX1020-CONSOLE
echo You can launch a VUE Graphical Desktop Session using Xephyr like the following:
echo Xephyr -screen 1200x720 -ac -query :58

exit 0


HPUX 10.20 HP-VUE VUE Login Screen on Qemu on FreeBSD qemu-system-hppa PARISC

To launch HPUX 10.20 VUE (Visual User Environment) graphical desktop, I use Xephyr from the QEMU host and other machines on the network that have a X11 server running:

$ Xephyr -screen 1200x720 -ac -query :58


I installed (using SAM) Netscape Communicator 4.75 (Netscape Navigator web-browser and an email client) from Application Software Disc 4, and added the MOZILLA_HOME environment variable to /etc/profile to point to the installation location /opt/netscape as indicated by the Netsccape README file. This was after I tried an older version of Netscape Communicator (version 4.04) for HPUX 10 operating system on HP PARISC 1.1 processor architecture available here.

Netscape Communicator - both the 4.75 and 4.04 versions - install fine but unfortunately so far I have been unable to launch the applications successfully; executing netscape shows me netscape is running and using considerable CPU but the window does not come up and there are no messages on the terminal session launching netscape either. I will have to revisit this to see what is going on here. (As a side note, Mozilla browser works fine on the HPUX version 11.11 installation).

Netscape Navigator / Communicator for HPUX 10.20
Netscape Communicator for HPUX

I tried to compile the text-based Lynx web-browser from the sources of a couple of versions, but will need to come back to it - one version I tried could not link with htons family of functions, and another one tried to compile with HP's cc compiler instead of gcc so the configure script needs adjustment.


Astr0baby's GNU tools collection includes working GNU C and C++ compilers gcc and g++  (GCC) 4.2.2. I could successfully compile and run my favorite ASCII terminal clock program written in C - Antoni Sawicki's aclock-vt100.c:

aclock vt100 C ascii art clock program by Antoni Sawicki running on HPUX 10.20 under QEMU PARISC HP-9000 700 series server
 Antoni Sawicki's aclock vt100.c on HPUX 10.20

In addition, I installed HP Micro Focus Object COBOL/UX and Java development environments from Application Software Disc 3. The HP Micro Focus Object COBOL/UX Release Notes for Version B.12.35 HP 9000 Computers on HP-UX 10.20 release notes are still available here. For setting environment variables needed by the COBOL compiler as indicated by the release notes, I added the following to /etc/profile:

# HP Microfocus Object Cobol Environment Variables
export COBDIR

Object Cobol/UX Developer Bundle and Java Development Kit for HPUX 10.20 Installation
Object Cobol/UX Developer Bundle and Java Development Kit for HPUX 10.20 Installation

Unfortunately, Micro Focus COBOL is also not working yet as the license file is missing.

$ cobol
HP Micro Focus Object COBOL licensing request failed.
FLEXlm Message: Cannot find license file (-1,73:2) No such file or directory
$ ls  /usr/local/flexlm/licenses/license.dat
/usr/local/flexlm/licenses/license.dat not found

Otherwise all works fine so far. I will have to come back to the HPUX 10.20 parisc QEMU virtual machine to try to close out the Netscape browser and COBOL licensing issues.

Friday, January 3, 2020

ZX Spectrum TZX TAP ZIP Cassette Loader Using Raspberry Pi

Supratim Sanyal's Blog: Sinclair ZX Spectrum Cassette Loading using Raspberry Pi
Falcon Patrol II (Virgin Games, 1995) - Sinclair ZX Spectrum Cassette Loading using Raspberry Pi

This is a follow up post to "Powering up a British ZX Spectrum after 30 years in America - The PAL UHF Analog TV and 220V AC Challenge" where I described how to run a United Kingdom targeted 220V 50Hz AC powered Sinclair ZX Spectrum microcomputer with analog PAL UHF TV video output in the 110V 60Hz and modern ATSC digital HDTV environment of the United States.

In this post I will describe how I use a Raspberry Pi to load games and software from digitized cassette tapes on the ZX Spectrum in such a fashion that the ZX Spectrum thinks it is listening to a real cassette player.

Here is the hardware you will need:

1) Raspberry Pi 3B+ or later » 

4) Stereo Audio to Mono Splitter Cable »

As for the operating system, load up the usual latest Raspbian desktop operating system on your MicroSD (a 16GB MicroSD is more than enough for this project).

I initially tried to feed audio directly from Raspberry Pi's internal headphone connector to EAR jack of ZX Spectrum, but could not get the ZX Spectrum to load the software despite claims by a few others of such a setup working. Use the USB audio adapter because it outputs the cassette sound in a loud enough volume for the ZX Spectrum to load from it. The 3-ampere power supply is imperative for providing enough juice to power the Pi and the USB Audio Card. Attach the USB Audio adapter to an available USB port of the Raspberry Pi. Also make it the default audio output device from Raspbian desktops' Preferences -> Audio Device Settings screen.

Raspberry Pi USB Audio Adapter Setup Screen

The ZX Spectrum EAR/MIC connection is mono for both audio input (EAR on the ZX Spectrum) and output (MIC on the ZX Spectrum). Connect the male stereo end of the stereo-to-mono audio splitter cable to the audio output of the USB Sound card which is usually marked with a picture of a headphone and colored green. Then connect either of the two mono female ends of the splitter cable to the "EAR" jack of the ZX Spectrum. In my case, having a ZX Spectrum +3,  this is the mono black male jack marked "EAR" of the EAR/MIC cable.

Connecting Raspberry Pi to ZX Spectrum to work as a Cassette Player to load games

I left the red mono "MIC" jack from the ZX Spectrum left unconnected. Of course, as the next experiment, I will try to save files from the ZX Spectrum to the Raspberry Pi using some audio recording software and the Microphone jack on the USB Sound card, but that is another topic.

ZX Spectrum EAR and MIC jacks conneted to Raspberry Pi Audio Cassette Player

That's it for connections. Once your Raspberry Pi boots up to the operating system, take a look at this blogger's post ("Turn your raspberry pi into a virtual cassette to load games on your Amstrad CPC or ZX Spectrum") translating to English if you don't read Spanish, and follow the steps documented there to obtain the basic tool-set. Note that you will need to also install the git package in addition to the packages listed there. Here is a touched-up excerpt.

Build and install the playtzx tool from source:

$ sudo apt-get install audacious texinfo build-essential automake git
$ git clone
$ cd cpctools/playtzx-0.12b/
$ ./configure
$ make
$ sudo make install

After building and installing the the playtzx tool, the binary should be present in /usr/local/bin/playtzx:

$ which playtzx
$ ls -l /usr/local/bin/playtzx 
-rwxr-xr-x 1 root root 241260 Dec  5 19:15 /usr/local/bin/playtzx

The "advanced" script available here supports on-the-fly decompression and playback of zipped TZX and TAP files in addition to regular TZX files. It invokes playtzx to create a VOC audio file in a temporary directory and then runs audacious to play it back. Not liking unnecessary write cycles to the MicroSD card, I created a 128 MB in-memory ramdisk for writing temporary VOC files. To create the ramdisk, become root and create a directory /ram0, then add the following to /etc/fstab and reboot:

tmpfs /ram0 tmpfs nodev,nosuid,size=128M 0 0

Here is my touched-up "advanced" script, modified as follows:
  • added output volume control to set the playback volume to the optimal value that I found (90%) for nice equal-width red and white header loader border bands on the ZX Spectrum cassette loader
  • pointed the temporary directory to /ram0 ramdisk mount-point
  • changed playtzx sampling frequency to 32000 since this resulted in the loading bars in the border scrolling slowly upwards instead of downwards
  • added verbosity to audacious

# playcdt: script bash to play TZX/CDT tape images of Amstrad CPC & ZX Spectrum
# requires playtzx and audacious (see
# version 0.1 alpha - GNU/GPL 2 Jesus Basco 2016
# modified by Supratim Sanyal - see


# Set volume of USB sound card to 90%
echo ====
echo Setting volume
amixer -c 1 cset numid=6 ${volume},${volume}
amixer -c 1 cget numid=6
echo ====

es_zit=$(file -b "$1" | grep -i zip | wc -l)
es_tzx=$(file -b "$1" | grep -i tzx | wc -l)
#USE Ramdisk instead of wearing out SD
if [ $# -ne 1 ]; then
   echo "ERROR: Hay que poner el archivo TZX/CDT"
   exit -1
if [ -f "$1" ]; then
   if [ $es_tzx == 1 ]; then
      echo Reproduciendo archivo \""$1"\"
      playtzx -voc -freq 32000 "$1" ${tmptzx}/temporal.voc

      echo ==== Playing converted file  ====
      ls -lh ${tmptzx}/temporal.voc
      echo =================================

      audacious -pqH ${tmptzx}/temporal.voc
      #rm ${tmptzx}/temporal.voc
   elif [ $es_zip == 1 ]; then
      echo AVISO: El archivo \""$1"\" es un archivo ZIP... descomprimiendo e intentando sacar un archivo CDT/TZX
      mkdir -p ${tmptzx}/tzxtmp
      unzip -C "$1" -d ${tmptzx}/tzxtmp
      for i in `ls ${tmptzx}/tzxtmp/*.{tzx,cdt}`;
          playcdt "$i"
      #rm -rf ${tmptzx}/tzxtmp
      echo ERROR: El archivo \""$1"\" no es un CDT/TZX
   echo ERROR: El archivo \""$1"\" no existe
   exit -1

I saved this script in ~/playcdt-script/ directory under my home directory (and chmoded it executable, of course).

$ pwd
$ ls -l playcdt-script/
total 12
-rwxr-xr-x 1 pi pi 1486 Dec  6 10:14
-rw-r--r-- 1 pi pi 1143 Dec  5 20:57
-rw-r--r-- 1 pi pi 1090 Dec  5 19:19

As for TZX Cassette Games and Utilities, I found a huge collection at this web-site. The 285MB "Games Collections's TZX Format (7z Archive)", for example, has 12,466 TZX files! I decompressed all the .TZX files into a  ~/TZX/tzxgames/ directory under my home directory:

$ pwd
$ ls TZX/tzxgames/
007 De-Pulsar (19xx)(Tony Bryan).tzx
007 - Live And Let Die (19xx)(Encore)[Re-Release].tzx
007 - Lord Bromley's Estate (1990)(Domark)[a][Lightgun].tzx
007 - Lord Bromley's Estate (1990)(Domark)[Lightgun].tzx
007 - Lord Bromley's Estate (1990)(Domark).tzx
007 - Q's Armoury (1990)(Domark)[a][Lightgun].tzx
007 - Q's Armoury (1990)(Domark)[Lightgun].tzx
007 - Q's Armoury (1990)(Domark).tzx
007 Super File 2 (19xx)(-)(Side A).tzx
007 Super File 2 (19xx)(-)(Side B).tzx
100 KM Race (19xx)(Coyote Software)(It).tzx

With all the pieces now in place, you can now command the ZX Spectrum to load from tape the usual way - LOAD "" in 48K mode or using the Tape Loader in 128K mode - and then play back a TZX  cassette tape image on the Raspberry Pi using a command like this:

$ ~/playcdt-script/ ~/TZX/tzxgames/Cyclone\ \(1985\)\(Vortex\ Software\).tzx 
Setting volume
numid=6,iface=MIXER,name='Speaker Playback Volume'
  ; type=INTEGER,access=rw---R--,values=2,min=0,max=151,step=0
  : values=136,136
  | dBminmax-min=-28.37dB,max=-0.06dB
numid=6,iface=MIXER,name='Speaker Playback Volume'
  ; type=INTEGER,access=rw---R--,values=2,min=0,max=151,step=0
  : values=136,136
  | dBminmax-min=-28.37dB,max=-0.06dB
Reproduciendo archivo "/home/pi/TZX/tzxgames/Cyclone (1985)(Vortex Software).tzx"

ZXTape Utilities - Play TZX , TZX to VOC Converter and TZX Info v0.12b for Linux

ZXTape file revision 1.01
Number of Blocks: 6

Creating .VOC file using 32000 Hz frequency.

Block   1:    Program : Cyclone     Length:    19  Normal Speed ,Pause: 1.000s
Block   2:    --------------------  Length:   146  Normal Speed ,Pause: 1.000s
Block   3:      Bytes : loader      Length:    19  Normal Speed ,Pause: 1.000s
Block   4:    --------------------  Length:   514  Normal Speed ,Pause: 1.000s
Block   5:    --------------------  Length:  6914   Speed: 155% ,Pause: 1.000s
Block   6:    --------------------  Length: 40632   Speed: 155% 

==== Playing converted file ====
-rw-r----- 1 pi pi 5.5M Jan  2 18:31 /ram0/temporal.voc

ERROR [guess_element]: No suitable mixer element found.
WARNING [voc]: <0x728a0af0> Estimating duration from bitrate, this may be inaccurate
WARNING [voc]: <0x728a5580> Estimating duration from bitrate, this may be inaccurate
WARNING [voc]: <0x728a3f10> Estimating duration from bitrate, this may be inaccurate

The ZX Spectrum home computer now loads the digitized cassette in TZX format played back by the Raspberry Pi, as you can see in the video at the top of this post. I have even tried a bunch of Fast Loaders, they all work fine, too. Here is Falcon Patrol II - one of the most difficult games to load from cassette due to the fast loader (at a whopping 211% of normal ZX Spectrum microcomputer cassette data transfer speed) - loading fine with the setup described in this post.

Download: You can download » all the tools and TZX collection mentioned in this post from my google drive or dropbox.

Recommended Products from Amazon