summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md16
-rw-r--r--lib/postrunner/EPO_Downloader.rb48
2 files changed, 54 insertions, 10 deletions
diff --git a/README.md b/README.md
index 96d7544..8d58728 100644
--- a/README.md
+++ b/README.md
@@ -80,6 +80,22 @@ This will provide you with a lot more information contained in the FIT
files that is not available through Garmin Connect or most other
tools.
+When you upload your FIT data to the Garmin Connect site using WiFi or
+Garmin Software, your device will be updated with 7 days worth of
+Extended Prediction Orbit (EPO) data. The GPS receiver in your device
+can use this data to acquire GPS locks much faster during the next 7
+days. To fetch the current set of EPO data, just use the following
+command while you have your device mounted via USB.
+
+```
+$ postrunner update-gps
+```
+
+This was tested on the FR620 and will probably also work on the FR220.
+Other devices may work, but you use this at your own risk. This
+feature will download a file called EPO.BIN and copy it to
+GARMIN/REMOTESW/EPO.BIN.
+
### Viewing FIT file data in your web browser
You can also view the full details of your activity in your browser.
diff --git a/lib/postrunner/EPO_Downloader.rb b/lib/postrunner/EPO_Downloader.rb
index 6121d20..30ccd9f 100644
--- a/lib/postrunner/EPO_Downloader.rb
+++ b/lib/postrunner/EPO_Downloader.rb
@@ -15,9 +15,9 @@ require 'net/http'
module PostRunner
- # This class can download the current set of ephemeris data for GPS
- # satellites and store them in the EPO.BIN file format. Some Garmin devices
- # pick up this file under GARMIN/GARMIN/REMOTESW/EPO.BIN.
+ # This class can download the current set of Extended Prediction Orbit data
+ # for GPS satellites and store them in the EPO.BIN file format. Some Garmin
+ # devices pick up this file under GARMIN/GARMIN/REMOTESW/EPO.BIN.
class EPO_Downloader
@@URI = URI('http://omt.garmin.com/Rce/ProtobufApi/EphemerisService/GetEphemerisData')
@@ -38,15 +38,17 @@ module PostRunner
@request.body = @@POST_DATA
end
- # Download the current ephemeris data from the Garmin server and write it
- # into the specified output file.
+ # Download the current EPO data from the Garmin server and write it into
+ # the specified output file.
# @param output_file [String] The name of the output file. Usually this is
# 'EPO.BIN'.
def download(output_file)
return false unless (epo = get_epo_from_server)
return false unless (epo = fix(epo))
+ return false unless check_epo_data(epo)
write_file(output_file, epo)
- Log.info "GPS caching data has been downloaded from Garmin site."
+ Log.info "Extended Prediction Orbit (EPO) data has been downloaded " +
+ "from Garmin site."
true
end
@@ -56,16 +58,18 @@ module PostRunner
def get_epo_from_server
res = @http.request(@request)
if res.code.to_i != 200
- Log.error "GPS data download failed: #{res}"
+ Log.error "Extended Orbit Prediction (EPO) data download failed: #{res}"
return nil
end
res.body
end
- # The downloaded data contains ephemeris data for 6 hour windows for 7
- # days. Each window set is 2307 bytes long, but the first 3 bytes must
- # be removed for the FR620 to understand it.
+ # The downloaded data contains Extended Prediction Orbit data for 6 hour
+ # windows for 7 days. Each EPO set is 2307 bytes long, but the first 3
+ # bytes must be removed for the FR620 to understand it.
# https://forums.garmin.com/showthread.php?79555-when-will-garmin-express-mac-be-able-to-sync-GPS-EPO-bin-file-on-fenix-2&p=277398#post277398
+ # The 2304 bytes consist of 32 sets of 72 byte GPS satellite data.
+ # http://www.vis-plus.ee/pdf/SIM28_SIM68R_SIM68V_EPO-II_Protocol_V1.00.pdf
def fix(epo)
unless epo.length == 28 * 2307
Log.error "GPS data has unexpected length of #{epo.length} bytes"
@@ -81,6 +85,30 @@ module PostRunner
epo_fixed
end
+ def check_epo_data(epo)
+ # Convert EPO string into Array of bytes.
+ epo = epo.bytes.to_a
+ unless epo.length == 28 * 72 * 32
+ Log.error "EPO file has wrong length (#{epo.length})"
+ return false
+ end
+ # Split the EPO data into Arrays of 32 * 72 bytes.
+ epo.each_slice(32 * 72).to_a.each do |epo_set|
+ # For each of the 32 satellites we have 72 bytes of data.
+ epo_set.each_slice(72).to_a.each do |sat|
+ # The last byte is an XOR checksum of the first 71 bytes.
+ xor = 0
+ 0.upto(70) { |i| xor ^= sat[i] }
+ unless xor == sat[71]
+ Log.error "Checksum error in EPO file"
+ return false
+ end
+ end
+ end
+
+ true
+ end
+
def write_file(output_file, data)
begin
File.write(output_file, data)