Sunday, August 31, 2025

Youtube removed my account

Yeaps - youtube removed my account last week.



I uploaded a clip of the ZX Spectrum video game "Paradise Cafe" and they determined it "went against their community standards" and decided to completely remove my account to "protect the community" from a video game from the 1980s... :)

Anyway, that's why all my videos are missing from my blog! Dozens of years of content and research...gone!

Friday, June 28, 2024

Powershell script to clean MAME roms

Here's a powershell script to identify "parent" MAME roms, moving all unique ones to a "clean" folder.

- Create a "MoveNonClones.ps1" file in your MAME rom folder:

# Create the "clean" folder if it doesn't exist

$cleanFolder = Join-Path -Path (Get-Location) -ChildPath "clean"

if (-not (Test-Path -Path $cleanFolder)) {

    New-Item -ItemType Directory -Path $cleanFolder

}

# Get all .zip files in the current directory

$files = Get-ChildItem -Path . -Filter *.zip

# Remove the .zip extension from the filenames

$fileNames = $files | ForEach-Object { [System.IO.Path]::GetFileNameWithoutExtension($_.Name) }

# Initialize an array to store the parents to keep

$parentsToKeep = @()

Write-Output "Identifying parent ROMs..."

$totalFiles = $fileNames.Count

$currentFile = 0

# Iterate through each file name

while ($fileNames.Count -gt 0) {

    $currentFile++

    # Take the first file name from the list

    $fileName = $fileNames[0]

    # Find all files that start with the current file name

    $matchingFiles = $fileNames | Where-Object { $_ -like "$fileName*" }

    # Find the one with the smallest number of characters

    $parentToKeep = $matchingFiles | Sort-Object { $_.Length } | Select-Object -First 1

    # Add the parent to the list of parents to keep

    if (-not $parentsToKeep.Contains($parentToKeep)) {

        $parentsToKeep += $parentToKeep

        # Find the corresponding file object

        $parentFile = $files | Where-Object { [System.IO.Path]::GetFileNameWithoutExtension($_.Name) -eq $parentToKeep }

        # Move the parent file to the "clean" folder

        foreach ($file in $parentFile) {

            $destination = Join-Path -Path $cleanFolder -ChildPath $file.Name

            Move-Item -Path $file.FullName -Destination $destination

            Write-Output "Identified and moved parent ROM: $($file.Name)"

        }

    }

    # Remove the matching files from the list of file names

    $fileNames = $fileNames | Where-Object { $_ -notin $matchingFiles }

    Write-Progress -Activity "Identifying parent ROMs" -Status "$currentFile of $totalFiles" -PercentComplete (($currentFile / $totalFiles) * 100)

}

Write-Output "Process completed. Moved $($parentsToKeep.Count) parent ROMs to the clean folder."

 - Run the powershell script!

This will identify all "parent" roms (basically, all the ones that are either unique OR have multiple files with the same "StartsWith()" filename (e.g. 3countb.zip is the main file and 3countba.zip is a clone version) and move the unique ones to a "clean" folder inside your current execution folder.

Its not perfect (it can remove versions of games as it does not know ddragon and ddragon2 are different games altogether) but...it does clean up the library quite a bit!

Sunday, February 9, 2020

UDP Hole Punching - VPN behind NAT research

A quick video demonstrating how to perform UDP Hole Punching to establish a VPN between two devices behind a firewall with NAT.


Friday, August 4, 2017

WiFi2DialUp: Progress update!

I've been working hard on my raspberry pi zero w serial modem project, which I'm now calling WiFi2DialUp!

In the video, I cover the latest and greatest features, namely:
  • view settings (ATI command)
  • configure wifi and dialupd services
  • shell access (in case you lose the wifi connection
  • list available wifi networks
  • busy signal sound on connection error
  • stable dial up connection at multiple speeds!
  • (very) basic web configuration interface
  • all services now start automatically!
After recording the video, I actually figured out the echo issue.
It turns out the dial up process is issuing an ATE0 command, turning off the echo!

In order to turn it back on, all you have to do is run an ATE1 command.
HOWEVER, I have patched tcpser to always turn on echo after each call.

Update: you can find the latest Wifi2DialUp Raspberry Pi Zero W image here.

Thursday, July 27, 2017

Raspberry pi zero w serial modem prototype

I had this idea about a month ago, after playing around with the WiFi232 device by Paul Rickards.
The WiFi232 allows users to encapsulate telnet over serial, by connecting to a wifi network, so I theorized that it should be possible to use it to establish a ppp connection, encapsulating a full tcp/ip stack over it.
The result was a series of small videos where I created a small proof of concept for how to implement ppp over WiFi232:


WiFi232: Implementing a full tcp/ip stack over WiFi232 interface using pppd



WiFi232: Routing traffic to the rest of my LAN and Internet

WiFi232: Fully stable tcp/ip stack over WiFi232 device!



WiFi232: dial up over WiFi232 using Windows 98 SE and pppd



WiFi232: file transfers and browsing the internet using Netscape on RedHat 6.2 over ppp



However, while doing research, I came across tcpser, which pretty much does the “same” as the WiFi232, though it requires a full OS like Linux to run, so I thought about installing tcpser on a raspberry pi and running a ppp server off of it as well!

The result would be a self contained module that could be used to implement a dial up connection over wifi, allowing old school computers to connect and browse the internet, just like we did in the 90s!

On top of this, given that the raspberry pi zero w also has audio output, I decided to add a little speaker to it to simulate that nostalgic dial up connection sound :).

The theory was pretty straight forward:
  • Buy a raspberry pi zero w
  • Solder a breakaway dual male header to the pi (for easy access to the pins)
  • Wire a MAX3232 rs232 to ttl converter to your raspberry pi
  • Configure the wifi connection, serial port and audio out on the pi
  • Run tcpser to emulate a Hayes compatible modem
  • And bind to a tcp/ip port using netcat, and have it spawn a tty that executes the ppp service

Given that tcpser has the option to create a “phonebook”, you can create an alias that makes it so that you can associate a “fake dialup number” with your netcat localhost connection. So the result is what seems like a real dial up connection!

Doing this worked beautifully! However, I had to make a one line change to tcpser’s source code in order to get the audio to play at the right time (which is why we need to run a custom tcpser version that I change to play a wav file upon CONNECT :)).

Basically, you just have to download clone the tcpser git repository and add a system() call to run “aplay” right before the CONNECT command is sent back to the modem. It is EXTREMELY LAME...but it works, and this is just a proof of concept anyway! Heh. More detailed information can be found on this at the end of this article.

If you don’t care about the audio and just want to connect, you can just use the stock tcpser version that is available with the latest raspbian version (in my case, I installed Jessie, or version 8.0)!

Also, given that tcpser is running on the serial port, you can also use this device to connect to telnet based bbses, just like you can with the WiFi232.

See it in action

Raspberry Pi Zero W serial modem proof of concept!

Raspberry Pi Zero W serial modem - the speaker!

Raspberry Pi Zero W serial modem - inner workings!


Raspberry Pi Zero W serial modem - the hardware!

Required Hardware

Raspberry Pi Zero W



Adafruit Raspberry Pi Zero Case



Mini HDMI Plug to Standard HDMI Jack Adapter



USB OTG Host Cable - MicroB OTG male to A female



Break-away 0.1" 2x20-pin Strip Dual Male Header



Thin Plastic Speaker



MAX3232 RS232 to TTL Serial Converter module from Ebay

Do note that the hdmi and usb converters are only required while setting up the wireless network on the pi. After you’ve done that, you can just connect to it using ssh!

Tutorials Followed



Pi Zero PWM Audio



Configuring The GPIO Serial Port On Raspbian Jessie Including Pi 3



One time setup

Setup wireless connection on raspberry pi

root@raspberrypi:~# cat /etc/network/interfaces
iface wlan0 inet dhcp
    wpa-ssid "my_wireless_network"
    wpa-psk "my_wireless_password"
root@raspberrypi:~#

Add audio output on GPIO pins 18 and 13

root@raspberrypi:~# tail -n 2 /boot/config.txt
# Enable audio on pins 18 and 13
dtoverlay=pwm-2chan,pin=18,func=2,pin2=13,func2=4
root@raspberrypi:~#


...restart raspberry pi to apply the dtoverlay.


Use “alsamixer” to control volume (the thin plastic speaker I used was super low, so I had to crank up the volume all the way up!) and use “aplay” to test playing a wav file.
E.g.
root@raspberrypi:~# aplay dial-up-modem-02.wav
Playing WAVE 'dial-up-modem-02.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo
root@raspberrypi:~#

Enable serial-uart in config.txt

Enable an enable_uart=1 parameter in your /boot/config.txt file.


root@raspberrypi:~# grep enable_uart /boot/config.txt
enable_uart=1
root@raspberrypi:~#

Disable serial console output

root@raspberrypi:~# cat /boot/cmdline.txt
dwc_otg.lpm_enable=0 console=tty1 root=PARTUUID=c52a940e-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait
root@raspberrypi:~# systemctl stop serial-getty@ttyS0.service
root@raspberrypi:~# systemctl disable serial-getty@ttyS0.service


Setup hosts file and ppp options file on raspberry server

root@raspberrypi:~# cat /etc/ppp/options
usehostname
domain retro
local
lock
noauth
-pap
-chap
debug
connect-delay 5000
172.16.0.1:172.16.0.2
asyncmap 1
root@raspberrypi:~#


Note that 172.16.0.1 will be assigned to the server, and 172.16.0.2 will be assigned to the client!

Setup hosts file and ppp options file on Linux client

[retro@rh62 retro]$ cat /etc/ppp/options
usehostname
domain retro
local
lock
noauth
-pap
-chap
debug
connect-delay 5000
172.16.0.2:172.16.0.1
defaultroute
asyncmap 1
[retro@rh62 retro]$


Note that 172.16.0.2 will be assigned to the client, and 172.16.0.1 will be assigned to the server!

On every raspberry pi boot

Setup NAT on raspberry pi

Turn on packet forwarding...
root@raspberrypi:~# echo 1 > /proc/sys/net/ipv4/ip_forward


...and then create an iptables masquerade rule to NAT traffic going out of wlan0
root@raspberrypi:~# iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE


Run pppd daemon on port 1234

We basically create a fifo and run pppd, tunneling stdin / stdout on port 1234 using netcat, and then we create an infinite while loop so that netcat reruns after each pppd disconnect or crash.

root@raspberrypi:~# rm -f /tmp/pppd-fifo; mkfifo /tmp/pppd-fifo
root@raspberrypi:~# while true ; do cat /tmp/pppd-fifo | python -c 'import pty; import time; time.sleep(3); pty.spawn("/usr/sbin/pppd")' 2>&1 | nc -l 127.0.0.1 1234 > /tmp/pppd-fifo ; done


Run tcpser and setup your special dialup number as a phonebook entry



You basically have two options here, depending on if you want to add the little dial up sound on connect or not.

Tcpser without speaker support

If you do not need (or do not have) speaker support in your raspberry pi, all you have to do is install tcpser from the raspbian repository.

root@raspberrypi:~# apt-get install tcpser -y


Tcpser with speaker support

If you have a speaker on your system, then you’ll have to add two small lines of code to modem_core.c.


Get the source from tcpser’s source repository:
root@raspberrypi:~# git clone https://github.com/FozzTexx/tcpser.git


...and make the following change to the mdm_connect function in src/modem_core.c:
int mdm_connect(modem_config *cfg)
{
 mdm_off_hook(cfg);
 if (cfg->conn_type == MDM_CONN_NONE) {
   if (line_connect(cfg) == 0) {
     cfg->conn_type = MDM_CONN_OUTGOING;
     mdm_set_control_lines(cfg);
     // this is the LAMEST code ever :o)
     system("/usr/bin/aplay /root/dial-up-modem-02.wav");
     mdm_print_speed(cfg);
     sleep(3);
   }
   else {
     cfg->conn_type = MDM_CONN_OUTGOING;       // so disconnect will print NO CARRIER
     mdm_disconnect(cfg);
   }
 }
 return 0;
}


This is an awful dirty hack but...it works. If you don’t like it, feel free to improve it :).

Do note that you’ll need to get a dial up connection wav file to play. I got mine from here:


Last step, running tcpser!

After setting up everything, all you need to do is run tcpser.


root@raspberrypi:~/tcpser# ./tcpser -d /dev/serial0 -s 38400 -S 38400 -l 7 -n8013614839=localhost:1234


The -d /dev/serial0 parameter makes tcpser use serial0 as the serial device (so, ttyS0 on my system), -s 38400 specifies that it should use 38400 as the serial port speed, -S 38400 specifies that the connection speed reported by tcpser upon connection will be 38400bps, -l 7 specifies 7 as the log level and the last command specifies a phonebook entry.

In the above example, tcpser will respond to connections to 8013614839 by establishing a telnet connection to port 1234 on localhost, establishing a pppd connection through netcat!

And that’s pretty much it! Hopefully you found this interesting and someone can take it from here and turn this into an actual modem (maybe even selling it as an actual product? :)).

- UPDATE -
Check out the progress on this project, which I'm now calling WiFi2DialUp:


Friday, June 9, 2017

Chain Reaction - the first video game I've EVER played! :)

Here it is, Chain Reaction, the first video game I've EVER played! :)



I remember getting home from school when I was 6 (maybe 7?) years old and my sister was playing this game on a ZX Spectrum 48k! :)

I don't think I had ever seen a video game before, so it was a REALLY big deal for me to find this game a few months ago, when I asked one of the Spectrum Facebook groups about "popular isometric games on the Spectrum"!

Friday, June 2, 2017

Global Warming, Climate Change and overall weather related predictions...

Not the first time I've said this, but I'll repeat it again, given that the Paris Climate Agreement has been all the rage over the last few days...

Some day, liberals will finally conclude that this is "no longer a problem" but will take credit for it, saying that the reason why "it isn't a problem anymore" is that we had all these agreements and that we lowered our footprint over the years "due to their heroic efforts" :D

You just wait and see...