Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save claytonrcarter/847fe44f5a5066ce6a1e33524740b037 to your computer and use it in GitHub Desktop.

Select an option

Save claytonrcarter/847fe44f5a5066ce6a1e33524740b037 to your computer and use it in GitHub Desktop.

Downloading Photos and Videos from a LeapPad2 onto a Raspberry Pi

The Problem

In some dark corner of the house, I found an old LeapPad2 that hadn't been used for years. Before sending it to Goodwill, I wanted to wipe any data off of it, but before I could get to that, I found a number of old photos on the it. The OEM software (LeapFrog Connect) would download some of them, but not all of them. Do we have any other options for saving these crude, blurry, sentimental photos and videos?!

Disclaimers

I am not an expert in USB devices, nor embedded Linux, nor even Linux. This worked for me, and I'm writing it up in case it works for someone else, but if you try it and run into a problem, there is functionally no chance that I will be able to help you. Please proceed at your own caution.

The steps below involve putting your LeapPad2 into "developer" mode. If you are unable to complete these steps, this may make the device impossible to use. (This was not the case for me, but I repeat the warning out of an abundance of caution.) Again, proceed at your own caution.

This was all done in early 2019, with a LeapPad2 Explorer and a Raspberry Pi 3 B+ running Raspbian Stretch 9.6. If your software or hardware are different than that, proceed at your own caution.

Background

Some searching turned up a number of resources, none of which were able to help me completely. Rather, I was able to piece together portions of each of them to get the job done. These are some of the resources that kept me moving forward:

https://blog.katharsys.com/?p=4091

https://github.com/jrspruitt/OpenLFConnect

https://spiffyhacks.com/thread-215.html

https://elinux.org/LeapPad2_Explorer

I had hoped to be able to just noodle around with exotic block device formats, mount the device like a USB drive and copy the files directly, but ... no dice. Something about UBI formats on embedded Linux devices with USB mode switching. In the end, I was able to put the device into developer mode, which boots it with a USB networking interface and an FTP server, and I was able to use this to download the files I wanted.

Details

  1. Power on your LeapPad, ssh to your pi and plug in your LeapPad to one of it's USB ports. Confirm it's recognized by running the usb-devices command, which should print an entry for the LeapPad. (Look for "Vendor: LeapFrog" or something similar.)

  2. Clone the OpenLFConnect repo: git clone https://github.com/jrspruitt/OpenLFConnect.git

  3. cd OpenLFConnect

  4. make sure SCSI generic utils are installed: sudo apt install sg3-utils (OpenLFConnect requires access to the sg_raw command.)

  5. OpenLFConnect has not been maintained for ~5 years as I write this. In that time, some of the device management rules have changed for Linux, and the /dev/leapfrog device will not be automatically created for you. So... create it manually: sudo ln -s /dev/sda /dev/leapfrog (My LeapPad connected as /dev/sda, check the output of usb-devices or lsusb to see where yours in parked.)

  6. Ditto for making sure that the normal user can access the device: sudo chmod 666 /dev/sda (optional, you can also just run the following OpenLFConnect.py commands as root)

  7. Start OpenLFConnect: ./OpenLFConnect.py

  8. OK, now quit: exit (It will have created some default files for you.)

  9. touch files/developer (We'll use this later, in step 15.)

  10. OK, back in: ./OpenLFConnect.py

  11. Load the LeapPad2 configuration: device_profile_load Extras/Profiles/leappad2.cfg and while you're at it, make it the default for next time you start: device_profile_default

  12. Now connect to the device: dftp_connect - after a short pause your prompt should change to remote>. If it doesn't something went wrong. If you see "File not found" or "No such file or directory" or such, make sure that sg_raw is installed (see step 4)

  13. At this point, you can poke around the device with ls. I found all of the data that I wanted was stored in /LF/Bulk/Data/Local/All/Photos and .../Videos. OpenLFConnect also includes a command to download files, but I found that it wouldn't work. It would act like it was working, but it would fail or hang or just produce corrupt output.

  14. cd /flags

  15. OK, the point of no return: instruct the device to reboot into developer mode: upload developer

  16. Confirm the file was uploaded: ls - you should see several files, including one called "developer"

  17. Disconnect: dftp_disconnect

  18. Now unplug the LeapPad, power it down (press the power button) and then turn it back on (press the power button again).

  19. While it's starting, install an old school ftp client: sudo apt install ftp (optional if you already have an ftp client installed. Note the sftp, ftps, etc will not work, and also that you have to ftp to the LeapPad from the device that it's plugged into, not from another device (eg the laptop you're ssh'ing from))

  20. OK, now try usb-devices again. You should see that something has changed: instead of connecting as a usb-storage device, it will have connected as a networking device. (You'll see something about eth in the Driver section.)

  21. List your network interfaces: ifconfig - you should see an eth0 and an eth1 entry (and possibly others). For me, eth0 was the built in interface on the Pi, and eth1 was new and exciting. You should see that it's bound to a 192.168.x.x address.

  22. OK, heres another point of no return: in developer mode, the LeapPad will bind to a static IP of 192.168.0.111. In order to connect to the LeapPad, I had to reconfigure eth1 to bind to the 192.168.0.x subnet. (The terminology may be wrong here.) If you're already using 192.168.0.x via eth0 or wifi (wlan0), then PROCEED WITH CAUTION. I was fortunate and my wifi is on a subnet of 192.168.254.x, so I was able to set eth1 to 192.168.0.1 without issue. If you're already using 192.168.0.x, be careful and make sure you know what you're doing, lest you lose access to your Pi or other devices.

    Anyway, assuming you're comfortable with it: sudo ifconfig eth1 192.168.0.1

  23. Now FTP like it's '93: ftp 192.168.0.111 (username: root (yeah!), password: <none, blank, nada> (hell yeah!))

  24. If all goes well, you should be in. Now you can ls and cd around. I was able to cd /LF/Bulk/Data/Local/All/Photos and then ls, then get each of the files via get lf_photo_000000.jpg. (Remember, old school ftp doesn't support wildcards. If you have a lot of files, you may want to find another client. I only had ~40, so it didn't seem worth it.)

  25. Done? Don't forget ../Videos or art or sound files.

  26. Double check your files. You have downloaded them from the LeapPad to the Pi, so you'll have to now get them to your regular computer. I used scp pi@pi:OpenLFConnect/\*.jpg . from my laptop but you can do whatever you normally do to copy files from your Pi. Double check that they all look good and that you can view them all.

  27. OK, now done? Great. Still in ftp, you will need to remove the "developer" mode file we uploaded previously. Start with cd /flags then delete developer. If that doesn't work, you can try rm developer. For some reason, these didn't work for me, so I just renamed the file: rename developer foo

  28. Done! Now: exit

  29. Now unplug the USB cord and power cycle the LeapPad again.

  30. Double check that it's not in developer mode: plug it back in and use usb-devices to confirm that it's using the usb-storage driver again.

  31. OK, now finally done for real! Connect the LeapPad back to your computer and use the OEM LeapFrog Connect software to reset the device to factory settings before sending it off into the hands of some other deserving family.

@JulianNicolai
Copy link
Copy Markdown

JulianNicolai commented Apr 13, 2026

Just wanted to say thank you so much for writing this whole guide up. I was able to get very old candid photos of my family and my grandfather. It means the world to me!

Just some things to note, some issues I ran into while doing this (also on a LeapPad2 Explorer). When I initially ran the script I was getting an error:

 File "/home/user/OpenLFConnect/./OpenLFConnect.py", line 60
    print 'OpenLFConnect Version 1.0.5'
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?

Of course, if you read the documentation for OpenLFConnect, this is because it requires installing Python 2. As I was using Debian 12 Bookworm on a Raspberry Pi 5, Python 2 is not longer available. As such I had to compile Python 2.7 on-device like so:

sudo apt install build-essential zlib1g-dev libssl-dev libffi-dev libreadline-dev
wget https://www.python.org/ftp/python/2.7.18/Python-2.7.18.tgz
tar -xzf Python-2.7.18.tgz
cd Python-2.7.18
./configure
make
sudo make altinstall

Despite doing step 6, I ran into a weird error when trying to run dftp_connect:

OpenLFConnect Version 1.0.5
local> device_profile_load Extras/Profiles/leappad2.cfg
local> device_profile_default Extras/Profiles/leappad2.cfg
Saved leappad2.cfg as default profile.
local> dftp_connect
Connecting with DFTP v2 Mass Storage.
DFTP Error: Receiving error: Receiving error: Receiving error: Receiving error: Receiving error: Receiving error: Receiving error: Receiving error: Receiving error: Receiving error: argument of type 'bool' is not iterable
local>

After digging in and debugging the code, I realized that it all came down to /dev/leapfrog (i.e. /dev/sda) requiring elevated privileges to access so no data was coming through. Running sudo python2.7 OpenLFConnect.py completely fixed it. Doh!

When I finally got to step 15 and ran the command upload developer, it returned with an error, something along the lines of 'bytes' was referenced before assignment. Initially I thought this made it so that it was not booting into developer mode, because although the ethernet interface appeared, no IP was assigned and I could not connect to it. I eventually came across someone online saying that if you go into parent mode (with the device on and not connected by USB, hold volume up and home buttons at the same time) you should see "debug" and "cheats" in the list (which I did see, so that indicated it was in developer mode).

My ifconfig eth1 looked like this:

eth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::14b3:eb29:8b9e:610a  prefixlen 64  scopeid 0x20<link>
        ether 80:38:fd:90:c1:01  txqueuelen 1000  (Ethernet)
        RX packets 113  bytes 12414 (12.1 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 52  bytes 8210 (8.0 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

No IPv4 assigned as you can see. Pinging 192.168.0.111 returned:

ping 192.168.0.111
PING 192.168.0.111 (192.168.0.111) 56(84) bytes of data.
From 142.124.41.213 icmp_seq=1 Destination Net Unreachable
From 142.124.41.213 icmp_seq=2 Destination Net Unreachable

And my routing table (route -n) looked like:

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.2.1     0.0.0.0         UG    600    0        0 wlan0
192.168.2.0     0.0.0.0         255.255.255.0   U     600    0        0 wlan0

To fix this, I ran: sudo ifconfig eth1 192.168.0.1 netmask 255.255.255.0

This resulted it changing to:

user@user:~ $ ifconfig eth1
eth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.0.1  netmask 255.255.255.0  broadcast 192.168.0.255
        ether 80:38:fd:90:c1:01  txqueuelen 1000  (Ethernet)
        RX packets 254  bytes 24274 (23.7 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 112  bytes 17098 (16.6 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
user@user:~ $ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.2.1     0.0.0.0         UG    600    0        0 wlan0
192.168.0.0     0.0.0.0         255.255.255.0   U     0      0        0 eth1
192.168.2.0     0.0.0.0         255.255.255.0   U     600    0        0 wlan0
user@user:~ $ ping 192.168.0.111
PING 192.168.0.111 (192.168.0.111) 56(84) bytes of data.
64 bytes from 192.168.0.111: icmp_seq=1 ttl=64 time=0.636 ms
64 bytes from 192.168.0.111: icmp_seq=2 ttl=64 time=0.323 ms

As you can see, I could now ping the device. From this point I was able to resume at step 23 and onwards without issue.

Also, I found a way to pull all the files (had a lot of images). Use the following when in ftp environment:

cd /LF/Bulk/Data/Local/All/Photos
prompt off
mget *

Just cd into the folders, so Photos, Videos, and Art for me, turn off prompts (yes/no), and run mget with a wildcard to pull them all.

Thanks again Clayton for all your work on this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment