Raspberry PI Hacking for Garmin Data Transfer
I’m part of a group that navigates the highways and byways of England & Wales by motorcycle. Its a national organisation and our local group meets in Yarnton. Many of us use the Garmin Montana 600 (and other variants) to follow GPX routes that we like to share.
The Montana use ANT+ technology that should, in theory, allow us to wirelessly transfer GPX files from device to device at the start of a ride. In practice the process is very unreliable and frustrating. Either the Garmins can’t find each other or the transfer fails part way through.
This annoyance led me to develop a wired solution based on the Raspberry Pi. The following blog post takes the form of a technical howto so that you can build one yourself.
Pi Model B in a case cabled tied to battery
2. The Challenges
There are only 3:
- Some kind of User Interface (UI), we’re going to use your phone running a file transfer app over Wifi.
- Safely removing (unmounting) the Garmins to avoid data loss/corruption.
- Non-mains Power supply and limited power available from the Pi (aka a power budget).
3. How it works
In operation, you boot the Pi and it appears as an access point in the Wifi options on your phone – much as your router at home does.
You connect to the Pi just as you connect to Wifi at home or in a coffee shop. If you haven’t already, connect the Garmins and wait a few moments whilst they become available -this usually coincides with the Garmin logo appearing on the screen. At this point you can use the phone app to copy GPX files between devices, unmount them and power down the Pi, full details in the Usage section below.
Screenshot showing Pi as an access point
Phone app showing list of Garmins
A GPX file transfer in progress
4. The Gory details to build one yourself
For this project you’ll need a Raspberry Pi with wireless capability. I used a Model 3B plus because wireless is built in but this should work with a USB wireless dongle if you don’t have wireless onboard. The Model 3B also has wireless and should work. The SD card for your Pi should have the standard Raspbian OS on it, for me this is Debian Stretch: Linux raspberrypi 4.14.98-v7+ #1200 SMP Tue Feb 12 20:27:48 GMT 2019 armv7l GNU/Linux.
You’ll also need an sFTP client app on your phone. I’ve used the excellent Documents for ios but any sFTP client for your phone will do. This guide is quite technical, you’ll need some familiarity with Linux.
OK, power up your Pi (whether over ethernet or directly) and lets get started.
4.1 Software requirements
Install the following packages on the Pi:
apt-get install lockfile-progs liblockfile1
apt-get install pmount
apt-get install inotify-tools
apt-get install git
(if you don’t already have git.)
By default the Pi’s desktop environment mounts the Garmin’s as USB drives. This is problematic because we don’t want/need the desktop running and they’re mounted in such a way as to cause file permission problems later on. Consequently, we’re going to install
usbmount which will mount the Garmin’s without running the desktop and gives control over how they’re mounted:
git clone https://github.com/rbrito/usbmount
dpkg-buildpackage -us -uc -b
cd .. dpkg -i usbmount_0.0.24_all.deb
When the Garmins are plugged in they’ll be mounted under /media/.
4.1.1 New user
Now create a user, say trf, this will be the home directory we’ll access with your phone. Inside /home/trf/ make a sym link like this:
ln -s /media/ /home/trf/garmins
that way when you login over your phone you’ll have a quick way of navigating to all the plugged in devices.
Next we’ll configure how they’re mounted:
Alter FS_MOUNTOPTIONS to look like this:
Removable usb drives use the vfat filesystem (not ext4) and we want full permissions to write to them.
NB I also edited the MOUNTPOINTS directive so that each Garmin is mounted as garmin1a, garmin1b, garmin2a, garmin2b etc. This makes an assumption that the Montana will have an SD card installed under the battery and hence expose two mass storage devices. This is pretty typical because we all have cards with additional mapping on them and these are typically seen in Windows as the D:/ and E:/ drives.
To get the Pi working as an access point I followed these guides:
OK, we’re pretty close now. At this point you should be able to boot up, connect, have the drives mounted and copy and paste files. We just need to sort out the crucial unmounting or “safely remove hardware” as Windows likes to call it, shutdown and power away from home.
4.2 Issuing commands with only a file manager
We need to issue the umount and shutdown commands but we only have an sFTP client. This is where the pmount and inotify-tools packages come in. The former allows normal users to unmount drives and the latter watches for changes to files. We’re going to watch out for certain files to be deleted. When they are deleted (via the phone) we will immediately re-create them for next time and then trigger either an umount or shutdown.
Inside your /home/trf directory create a directory called bin:
Then inside the newly created bin directory create two files named umount.txt and shutdown.txt:
These are the files we’ll delete through the phone app when we want to disconnect the Garmins and shutdown the Pi. Now we can set up the watches. This is all the bespoke software development we need to do for this project. Create this new file and contents, note dependency on your username (4.1.1) and Garmin names from earlier in the set-up.
nano /usr/bin/pi-umount.sh #!/bin/bash
while true ; do inotifywait -e delete_self "/home/trf/bin/umount.txt" \ && touch "/home/trf/bin/umount.txt"; pumount /media/garmin1a; pumount /media/garmin1b; pumount /media/garmin2a; pumount /media/garmin2b; pumount /media/garmin3a; pumount /media/garmin3b; echo 1 >/sys/cl$ done
We’ll do the same for shutdown:
nano /usr/bin/pi-shutdown.sh #!/bin/bash touch /home/trf/bin/shutdown.txt chmod 777 /home/trf/bin/shutdown.txt while true ; do inotifywait -e delete_self "/home/trf/bin/shutdown.txt" \ && touch "/home/trf/bin/shutdown.txt"; ./sbin/shutdown -h now done
We want these watches to start at boot-up – this is a job for rc.local. Append this to /etc/rc.local
/bin/bash /usr/bin/pi-umount.sh & /usr/bin/pi-shutdown.sh &
Mine now looks like this:
more /etc/rc.local #!/bin/sh -e # # rc.local # # This script is executed at the end of each multiuser runlevel. # Make sure that the script will "exit 0" on success or any other # value on error. # # In order to enable or disable this script just change the execution # bits. # # By default this script does nothing.
# Print the IP address _IP=$(hostname -I) || true if [ "$_IP" ]; then printf "My IP address is %s\n" "$_IP" fi
iptables-restore < /etc/iptables.ipv4.nat #axa /bin/bash /usr/bin/pi-umount.sh & /usr/bin/pi-shutdown.sh & exit 0
4.3 Install the app
Jump onto your app store and find a file manager program that can do secure FTP aka sFTP. I’m using the excellent Documents app for my iPhone. I believe there are Android versions but this is untested. Any sFTP app should work. I’ve tried File Manager by Rhythm Soft on Android. It works but logs you into the root directory, not your home directory and won’t follow symlinks/shortcuts.
Once installed on your phone, start the Pi and connect to its network. Start the app, if using Documents tap Services then Add Account where you’ll be prompted for the username (trf from 4.1.1 in our example), password and a name for this service. I cunningly called mine Pi.
I’m able to power the Pi with 2 Garmins via the USB on my van radio. However, this might be spiky and not every van has a USB outlet. Consequently, I’ve used a battery powered phone charger to power mine. Each Garmin can draw 500ma and the Model B has 4 USB ports. This supply should be able to cope but at the time of writing I’ve only tested with two. Worst case you copy the file from the source Garmin directly onto the Pi itself, unmount and disconnect that and then connect two Garmins at a time. I put my Pi in a box to protect it.
Time for a test drive!
- Plug the Garmin with the route on it plus (at least) one other into the Pi. Power up your Pi and wait for the Garmin logo to appear.
- Connect to the axapi network and start the Documents app.
- Tap on Services then the name you gave your Pi. You should see a folder named garmins, tap on that to a list of all plugged in Garmins. The one labelled garmin1a should have the track on it, navigate to the GPX folder, find the track and choose Copy. Now tap your way to the destination Garmin and do a paste. Repeat for all plugged in Garmins that need the track.
- Navigate back to where you started (I added another symlink for this) and tap on the bin directory.
- Delete the umount.txt file and wait a few seconds. Finally delete the shutdown.txt file and wait until the Pi’s LED stops flashing.
- You’re done, power down the Pi and go ride!
- Untested with >2 Garmins.
- Tested with Montana 600 and 650. Not tested with other variants like the 610 or even a Monterra.
- Mostly tested with USB wireless dongle.
7. Future enhancements
- If power is an issue with 3 or 4 Garmins plugged in there is some scope to reduce the power needed by the Pi. Principally this is down clocking and/or reducing the number of CPU cores in use. I very much doubt we need 4 cores to run this.
- A cute name.