Importing a bunch of pages from old websites.
[website_subgeniuskitty.com] / data / development / misc / garmin_edge_305_linux.md
diff --git a/data/development/misc/garmin_edge_305_linux.md b/data/development/misc/garmin_edge_305_linux.md
new file mode 100644 (file)
index 0000000..de49ee6
--- /dev/null
@@ -0,0 +1,132 @@
+# Linux Support #
+
+## Overview ##
+
+Linux support for Garmin GPS devices, especially those which monitor non-location data such as heartrate, is very poor. The situation is further confused by a plethora of conflicting, poorly documented file formats and outdated instructions. The following covers my process for downloading information from my Garmin Edge 305 bicycling GPS to a Linux workstation, including automatic file conversion to the TCX format since it is both supported by GoldenCheetah cycling software and, as an easily manipulated XML based format, should be easily convertable into other formats for many years to come.
+
+## Instructions ##
+
+First, disable the `garmin_gps` kernel module. On Debian wheezy this is accomplished by writing the following line to `/etc/modprobe.d/garmin-gps-blacklist.conf`
+
+    blacklist garmin_gps
+
+Download, build and install the `garmintools` package. The tarball contains a README that explains this process. This provides the `garmin_save_runs` program which will download data from your Garmin GPS and save it in the Garmin binary GMN format. It also includes the `garmin_dump` program which will convert a GMN file to an XML-life format. Note that you will need to be root, or set appropriate permissions for your user to have USB access. A sample run is shown below.
+
+    Extracting data from Garmin EDGE305 Software Version 3.20
+    Files will be saved in '/mnt/documents/Bicycling/logged_data'
+    Wrote:   /mnt/documents/Bicycling/logged_data/2014/07/20140724T230419.gmn
+    Wrote:   /mnt/documents/Bicycling/logged_data/2014/07/20140729T152915.gmn
+
+Once you have obtained a GMN file, download the garmin-dev-master zip file. The `gmn2tcx` program accepts the GMN file as its sole argument and outputs the TCX file to stdout, as well as status messages (including success messages) to stderr. You will need to have `garmin_dump` from the garmintools package in your PATH environment variable. As an example, the following will create a new TCX file from an existing GMN file while still displaying status messages on the terminal.
+
+    ataylor:~$ /usr/bin/gmn2tcx ./sample.gmn > ./sample.tcx
+    - validates
+
+To simplify the process, I created a small wrapper script that wraps these tools and performs the following operations.
+
+* Extract new tracks from GPS as GMN for archiving
+* Create TCX copy of new tracks for use performance tracking software
+* Save session log for troubleshooting
+
+The script uses python and can be configured by editing the configuration values located in the first few lines. After each cycling session you will only need to connect your Garmin device, execute the script and then launch the cycling software of your choice. 
+
+## Wrapper Script ##
+
+    #!/usr/bin/python
+    
+    # Wrapper script to dump files from Garmin Edge 305 and convert to TCX for import into GoldenCheetah
+    # Requires garmintools and garmin-dev-master packages
+    # Needs root permissions for USB access
+    
+    # Aaron Taylor
+    # ataylor@subgeniuskitty.com
+    
+    # Configuration
+    # path to garmin_save_runs, garmin_dump and libgarmintools.so
+    path_garmintools = "/home/ataylor/bin/garmintools"
+    # path to gmn2tcx and support files (saxon, etc)
+    path_gmn2tcx = "/home/ataylor/bin/gmn2tcx"
+    # path to save gmn data files
+    path_save_gmn = "/mnt/documents/Bicycling/logged_data"
+    # path to save tcx files
+    path_save_tcx = "/mnt/documents/Bicycling/logged_data/temp_tcx"
+    # path to log file for garmintools output
+    path_log = "/tmp/garmintools.log"
+    # UID/GID to set on new files
+    uid = 1000
+    gid = 1000
+    
+    import subprocess, os
+    
+    # Set up the environment. We want to append to PATH and LD_LIBRARY_PATH
+    # in case some system files are in a funky place. However, we must first
+    # check that the variables exist since they might be blank (like 
+    # LD_LIBRARY_PATH on my system).
+    my_env = os.environ
+    try:
+        my_env["PATH"]
+    except:
+        my_env["PATH"] = path_garmintools + ":" + path_gmn2tcx
+    else: 
+        my_env["PATH"] = my_env["PATH"] + ":" + path_garmintools + ":" + path_gmn2tcx
+    try:
+        my_env["LD_LIBRARY_PATH"]
+    except: 
+        my_env["LD_LIBRARY_PATH"] = path_garmintools
+    else:
+        my_env["LD_LIBRARY_PATH"] = my_env["LD_LIBRARY_PATH"] + ":" + path_garmintools
+    my_env["GARMIN_SAVE_RUNS"] = path_save_gmn
+    
+    # Export the data from the GPS as binary gmn files and store STDOUT in result.
+    result = subprocess.check_output(['/home/ataylor/bin/garmintools/garmin_save_runs'])
+    
+    # Newly written files will have a line starting with "Wrote:   " and then the full 
+    # path to the new file. We want to extract only these lines and add them to the 
+    # written_files list.
+    line_start = 0
+    written_files = []
+    n = 0
+    for i in result:
+        if i == b'\n':
+            line_start = n+1
+        elif line_start == n:
+            first_chars = "" 
+            for k in range(9):
+                first_chars += result[n+k]
+            if first_chars == b'Wrote:   ':
+                k = 9
+                temp_string = ""
+                while result[n+k] != b'\n':
+                    temp_string += result[n+k]
+                    k += 1
+                written_files.append(temp_string)
+        n += 1
+    
+    # Dump output of garmintools run for analysis in case something goes wrong
+    file_log = open(path_log, 'w')
+    file_log.write(result)
+    file_log.close()
+    
+    # For any newly written gmn files, save a copy as tcx format in directory specified
+    # by path_save_tcx so I can import to GoldenCheetah next time I start it.
+    devnull = open(os.devnull, 'w')
+    if not written_files:
+        print "No new files to process."
+    else:
+        print "New TCX files:"
+    for path_gmn in written_files:
+        path_tcx = path_save_tcx + "/" + os.path.split(path_gmn)[1].replace(".gmn", ".tcx")
+        print path_tcx
+        file_tcx = open(path_tcx, 'w')
+        subprocess.call(["gmn2tcx", path_gmn], stdout=file_tcx, stderr=devnull)
+        file_tcx.close()
+        os.chown(path_tcx, uid, gid)
+    devnull.close()
+
+## Files ##
+
+Where possible, obtain the latest version of these files from their original creators. What follows is an archived copy of the versions I used when first setting this project up, in case the author's pages disappear.
+
+* [garmintools-0.10](garmin_edge_305_linux.files/Garmintools-0.10.tar.gz)
+* [garmin-dev-master](garmin_edge_305_linux.files/Garmin-dev-master.zip)
+* [edge305.py](garmin_edge_305_linux.files/Edge305.py)