Merge branch 'master' into master
This commit is contained in:
commit
76dd3b8566
@ -20,18 +20,18 @@ Garmin wearables SKU numbers
|
||||
| fenix 5X/tactix Charlie | 006-B2604-00 | 16,000 MB | X | 006-B2663-00 | | 006-B2957-00 | 006-B2196-01 | | 006-B2605-00 |
|
||||
| Forerunner 935 | 006-B2691-00 | 64 MB | X | 006-B2665-00 | | 006-B2957-00 | 006-B2196-01 | | |
|
||||
| fenix 5/quatix 5 | 006-B2697-00 | 64 MB | X | 006-B2661-00 | | 006-B2957-00 | 006-B2196-01 | | |
|
||||
| D2 Charlie | 006-B2819-00 | 16,000 MB | X | 006-B2663-00 | | 006-B2957-00 | 006-B2196-01 | | 006-B2820-00 |
|
||||
| D2 Charlie | 006-B2819-00 | 16,000 MB | X | 006-B2663-00 | | 006-B3750-00 | 006-B2196-01 | | 006-B2820-00 |
|
||||
| Descent Mk1 | 006-B2859-00 | 16,000 MB | X | 006-B2664-00 | | 006-B1621-00 | 006-B2196-01 | | 006-B2869-00 |
|
||||
| Forerunner 645 Music | 006-B2888-00 | 4,000 MB | X | 006-B2897-00 | 006-B2887-00 | 006-B1621-00 | 006-B2196-02 | 006-B2822-00 | |
|
||||
| Forerunner 645 Music | 006-B2886-00 | 4,000 MB | X | 006-B2897-00 | 006-B2887-00 | 006-B1621-00 | 006-B2196-02 | 006-B2822-01 | |
|
||||
| fenix 5S Plus | 006-B2900-00 | 16,000 MB | X | 006-B3013-00 | 006-B3153-00 | 006-B3750-00 | 006-B2196-02 | 006-B2822-01 | |
|
||||
| Forerunner 645M APAC | 006-B3004-00 | 4,000 MB | X | 006-B3009-00 | 006-B3199-00 | 006-B1621-00 | 006-B2196-02 | 006-B2822-00 | |
|
||||
| fenix 5S Plus | 006-B2900-00 | 16,000 MB | X | 006-B3013-00 | 006-B3153-00 | 006-B2957-00 | 006-B2196-02 | 006-B2822-01 | |
|
||||
| Forerunner 245 Music | 006-B3077-00 | 4,000 MB | G3 | 006-B3079-00 | 006-B3205-00 | 006-B1621-00 | 006-B2196-03 | | |
|
||||
| fenix 5 Plus | 006-B3110-00 | 16,000 MB | X | 006-B3014-00 | 006-B3153-00 | 006-B2957-00 | 006-B2196-02 | 006-B2822-01 | |
|
||||
| fenix 5X Plus | 006-B3111-00 | 16,000 MB | POx | 006-B3015-00 | 006-B3153-00 | 006-B2957-00 | 006-B2196-02 | 006-B2822-01 | |
|
||||
| fenix 5 Plus | 006-B3110-00 | 16,000 MB | X | 006-B3014-00 | 006-B3153-00 | 006-B3750-00 | 006-B2196-02 | 006-B2822-01 | |
|
||||
| fenix 5X Plus | 006-B3111-00 | 16,000 MB | POx | 006-B3015-00 | 006-B3153-00 | 006-B3750-00 | 006-B2196-02 | 006-B2822-01 | |
|
||||
| Forerunner 945 | 006-B3113-00 | 16,000 MB | G3 | 006-B3114-00 | 006-B3303-00 | 006-B3107-00 | | | |
|
||||
| D2 Delta S | 006-B3196-00 | 16,000 MB | X | 006-B3014-00 | 006-B3260-00 | 006-B2957-00 | 006-B2196-02 | 006-B2822-01 | |
|
||||
| D2 Delta | 006-B3197-00 | 16,000 MB | X | 006-B3014-00 | 006-B3260-00 | 006-B2957-00 | 006-B2196-02 | 006-B2822-01 | |
|
||||
| D2 Delta PX | 006-B3198-00 | 16,000 MB | POx | 006-B3014-00 | 006-B3260-00 | 006-B2957-00 | 006-B2196-02 | 006-B2822-01 | |
|
||||
| D2 Delta S | 006-B3196-00 | 16,000 MB | X | 006-B3014-00 | 006-B3260-00 | 006-B3750-00 | 006-B2196-02 | 006-B2822-01 | |
|
||||
| D2 Delta | 006-B3197-00 | 16,000 MB | X | 006-B3014-00 | 006-B3260-00 | 006-B3750-00 | 006-B2196-02 | 006-B2822-01 | |
|
||||
| D2 Delta PX | 006-B3198-00 | 16,000 MB | POx | 006-B3014-00 | 006-B3260-00 | 006-B3750-00 | 006-B2196-02 | 006-B2822-01 | |
|
||||
| MARQ Driver | 006-B3246-00 | 32,000 MB | G3 | 006-B3252-00 | 006-B3253-00 | 006-B3107-00 | | | |
|
||||
| MARQ Aviator | 006-B3247-00 | 32,000 MB | G3 | 006-B3252-00 | 006-B3253-00 | 006-B3107-00 | | | |
|
||||
| MARQ Captain | 006-B3248-00 | 32,000 MB | G3 | 006-B3252-00 | 006-B3253-00 | 006-B3107-00 | | | |
|
||||
@ -45,6 +45,7 @@ Garmin wearables SKU numbers
|
||||
| Fenix 6 Pro | 006-B3290-00 | 32,000 MB | G3 | 006-B3295-00 | 006-B3293-00 | | | | |
|
||||
| Fenix 6X Pro | 006-B3291-00 | 32,000 MB | G3 | 006-B3296-00 | 006-B3293-00 | | | | |
|
||||
| MARQ Adventurer | 006-B3624-00 | 32,000 MB | G3 | | | | | | |
|
||||
| Venu Sq - Music | 006-B3596-00 | 4,000 MB | | 006-B3602-00 | 006-B3597-00 | 006-B3799-12 | 006-B2196-03 | | 006-B3598-00 |
|
||||
|
||||
|
||||
|
||||
@ -55,3 +56,4 @@ Notes
|
||||
* ANT/BLE/BT firmwares of the D2 Delta and fenix 5 Plus series are identical par the SKU number
|
||||
* GPS firmwares 1621 and 2957 are for the same chip, but 2957 has Galileo support, 1621 does not
|
||||
* GPS firmwares 3107 and 3506 are the new Sony chipset (introduced with the MARQ series)
|
||||
* fenix 5 Plus and D2 Delta series switched GPS from 006-B2957-00 to 006-B3750-00 in recent firmwares
|
||||
|
28
README.md
28
README.md
@ -1,11 +1,11 @@
|
||||
Garmin Firmware Tools
|
||||
=====================
|
||||
|
||||
This is a parser and some tools for working with GCD files (firmware updates).
|
||||
This is a parser and some tools for working with Garmin firmware updates (GCD/RGN files).
|
||||
|
||||
It's in Python, so feel free to add cool new features and submit pull requests.
|
||||
|
||||
Thanks to TurboCCC, kunix and Alex W. for your work.
|
||||
Thanks to TurboCCC, kunix and AlexWhiter for your work.
|
||||
|
||||
Most info from:
|
||||
|
||||
@ -14,12 +14,22 @@ Most info from:
|
||||
* hours of looking at hex numbers
|
||||
|
||||
|
||||
How YOU can help
|
||||
----------------
|
||||
|
||||
If you'd like to help, feel free to get all the SKU numbers from your `GarminDevice.xml`
|
||||
(numbers starting with 006-B...) and post them under "Issues" (create a new issue with the
|
||||
name of your device).
|
||||
|
||||
Of course, pull requests are much appreciated, too.
|
||||
|
||||
|
||||
Tools
|
||||
-----
|
||||
|
||||
### gcdstruct.py [gcdfile]
|
||||
### gcdstruct.py [gcdfile] / rgnstruct.py [rgnfile]
|
||||
|
||||
Will show the general structure of the GCD file and also validate the contained checksums, e.g.:
|
||||
Will show the general structure of the GCD/RGN file and also validate the contained checksums, e.g.:
|
||||
|
||||
```
|
||||
$ ./gcdstruct.py fenix5Plus_510.gcd
|
||||
@ -167,3 +177,13 @@ Checks Express and WebUpdater for updates for the given hw_ids (1-4 digits) or f
|
||||
The first one is used as the main device in the query. Shouldn't make a big difference in the results, though.
|
||||
|
||||
Special thanks to Alex W. for [his update check](https://github.com/AlexWhiter/GarminRelatedStuff).
|
||||
|
||||
|
||||
### list_missing_hwids.py
|
||||
|
||||
Shows a list of hw_ids not yet listed in the `devices.py`. It prepends a call to `get_updates.py` for an
|
||||
easy way to check the update servers for new devices.
|
||||
|
||||
To find future devices, you can supply a parameter (can be anything) and it will output 300 more hw_ids
|
||||
after the last known.
|
||||
|
||||
|
14
TODO.md
Normal file
14
TODO.md
Normal file
@ -0,0 +1,14 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
* RGN file support
|
||||
* convert between RGN and GCD
|
||||
* Express-like updater
|
||||
* should be text interface or ncurses
|
||||
* detect Garmin MTP devices or /GARMIN directory in mounted roots
|
||||
* MTP support: https://github.com/wangjiezhe/pymtp
|
||||
* fetch GarminDevice.xml
|
||||
* upload to Express, list returned files
|
||||
* ask user, then download files and push to device
|
||||
* maybe: support for additional downloads (languages, icons, etc.)
|
||||
* maybe: support for running under Windows (although there you have the real Express)
|
113
binbase_find.py
Normal file
113
binbase_find.py
Normal file
@ -0,0 +1,113 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# https://github.com/mncoppola/ws30/blob/master/basefind.py
|
||||
|
||||
import os
|
||||
import re
|
||||
import signal
|
||||
import struct
|
||||
import sys
|
||||
from operator import itemgetter
|
||||
|
||||
chars = "A-Za-z0-9/\\-:.,_$%'\"()[\]<> "
|
||||
min_length = 10
|
||||
scores = []
|
||||
top_score = 0
|
||||
|
||||
regexp = bytes("[{}]{{{:d},}}".format(chars, min_length), "us-ascii")
|
||||
pattern = re.compile(regexp)
|
||||
regexpc = bytes("[{}]{{1,}}".format(chars), "us-ascii")
|
||||
patternc = re.compile(regexpc)
|
||||
|
||||
def get_strings(filename, size):
|
||||
table = set()
|
||||
offset = 0
|
||||
with open(filename, "rb") as f:
|
||||
while True:
|
||||
if offset >= size:
|
||||
break
|
||||
f.seek(offset)
|
||||
try:
|
||||
data = f.read(10)
|
||||
except:
|
||||
break
|
||||
match = pattern.match(data)
|
||||
if match:
|
||||
f.seek(offset - 1)
|
||||
try:
|
||||
char = f.read(1)
|
||||
except:
|
||||
continue
|
||||
if not patternc.match(char):
|
||||
table.add(offset)
|
||||
offset += len(match.group(0))
|
||||
offset += 1
|
||||
return table
|
||||
|
||||
def get_pointers(filename):
|
||||
table = {}
|
||||
with open(filename, "rb") as f:
|
||||
while True:
|
||||
try:
|
||||
value = struct.unpack("<L", f.read(4))[0]
|
||||
try:
|
||||
table[value] += 1
|
||||
except KeyError:
|
||||
table[value] = 1
|
||||
except:
|
||||
break
|
||||
return table
|
||||
|
||||
def high_scores(signal, frame):
|
||||
print("\nTop 20 base address candidates:")
|
||||
for score in sorted(scores, key=itemgetter(1), reverse=True)[:20]:
|
||||
print("0x{:x}\t{:d}".format(*score))
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser()
|
||||
def auto_int(x):
|
||||
return int(x, 0)
|
||||
parser.add_argument("--min_addr", type=auto_int, help="start searching at this address", default=0)
|
||||
parser.add_argument("--max_addr", type=auto_int, help="stop searching at this address", default=0xfe000000)
|
||||
parser.add_argument("--page_size", type=auto_int, help="search every this many byte", default=0x1000)
|
||||
parser.add_argument("infile", help="file to scan")
|
||||
args = parser.parse_args()
|
||||
|
||||
size = os.path.getsize(args.infile)
|
||||
scores = []
|
||||
|
||||
print("Scanning binary for strings...")
|
||||
str_table = get_strings(args.infile, size)
|
||||
print("Total strings found: {:d}".format(len(str_table)))
|
||||
|
||||
print("Scanning binary for pointers...")
|
||||
ptr_table = get_pointers(args.infile)
|
||||
print("Total pointers found: {:d}".format(len(ptr_table)))
|
||||
|
||||
signal.signal(signal.SIGINT, high_scores)
|
||||
|
||||
for base in range(args.min_addr, args.max_addr, args.page_size):
|
||||
if base % ( args.page_size * 1000 ) == 0:
|
||||
print("Trying base address 0x{:x}".format(base))
|
||||
print("\u001b[F\u001b[K", end="")
|
||||
score = 0
|
||||
ptrs = list(ptr_table.keys())
|
||||
for ptr in ptrs:
|
||||
if ptr < base:
|
||||
#print("Removing pointer 0x{:x} from table".format(ptr))
|
||||
del ptr_table[ptr]
|
||||
continue
|
||||
if ptr >= (base + size):
|
||||
continue
|
||||
offset = ptr - base
|
||||
if offset in str_table:
|
||||
score += ptr_table[ptr]
|
||||
if score:
|
||||
scores.append((base, score))
|
||||
if score > top_score:
|
||||
top_score = score
|
||||
print("New highest score, 0x{:x}: {:d}".format(base, score))
|
||||
|
||||
high_scores(0, 0)
|
73
binbase_kunix.py
Normal file
73
binbase_kunix.py
Normal file
@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Many thanks to kunix!
|
||||
|
||||
"""
|
||||
Calculates possible base address.
|
||||
"""
|
||||
|
||||
from struct import unpack
|
||||
import os.path
|
||||
import sys
|
||||
|
||||
FILE = sys.argv[1]
|
||||
OFFSET = 0
|
||||
if len(sys.argv) > 2:
|
||||
OFFSET = int(sys.argv[2])
|
||||
BLOCKSIZE = 4096
|
||||
|
||||
END_MARKER = b"\xff\xff\x5a\xa5"
|
||||
|
||||
first_block = True
|
||||
end_marker_pos = 0xffffffff
|
||||
print("Reading {} ...".format(FILE))
|
||||
with open(FILE, "rb") as f:
|
||||
f.read(OFFSET)
|
||||
while True:
|
||||
block = f.read(BLOCKSIZE)
|
||||
if first_block:
|
||||
dw = unpack("<LLLLL", block[0:20])
|
||||
first_block = False
|
||||
if END_MARKER in block:
|
||||
end_pos = block.find(END_MARKER)
|
||||
found_pos = f.tell() - len(block) + end_pos + 2
|
||||
if found_pos > end_marker_pos:
|
||||
print("Found a second endmarker! Using that one.")
|
||||
end_marker_pos = found_pos
|
||||
#break
|
||||
if len(block) < BLOCKSIZE:
|
||||
break
|
||||
f.close()
|
||||
|
||||
size = os.path.getsize(FILE)
|
||||
|
||||
print("File is {} (0x{:x}) Bytes.".format(size, size))
|
||||
print("First double-words: 0x{:x} / 0x{:x} / 0x{:x} / 0x{:x} / 0x{:x}".format(dw[0], dw[1], dw[2], dw[3], dw[4]))
|
||||
print("Assuming this is end marker location in memory: 0x{:x}".format(dw[1]))
|
||||
print("Found end marker in file at: 0x{:x}".format(end_marker_pos))
|
||||
|
||||
base_addr = dw[1] - (end_marker_pos - OFFSET)
|
||||
if base_addr < 0:
|
||||
base_addr += 0xffffffff
|
||||
|
||||
print("This would make Base address probably 0x{:x}".format(base_addr))
|
||||
|
||||
if base_addr % 4 != 0:
|
||||
print("However, bad alignment. Calculated base address not aligned to doublewords.")
|
||||
|
||||
if base_addr + size > 0xffffffff:
|
||||
print("However, base address can't fit whole file.")
|
||||
|
||||
# Assumes second dword points to hwid
|
||||
#if dw[2] % 2 != 0 or dw[2] - base_addr >= end_marker_pos - 3:
|
||||
# print("Align & Bounds dw2 wrong.")
|
||||
# sys.exit(1)
|
||||
|
||||
# Assumes third dword points to fwid
|
||||
#if dw[3] % 2 != 0 or dw[3] - base_addr >= end_marker_pos - 3:
|
||||
# print("Align & Bounds dw3 wrong.")
|
||||
# sys.exit(1)
|
||||
|
||||
# hwid = dw[2] - base_addr
|
||||
# fwid = dw[3] - base_addr
|
@ -35,7 +35,7 @@ with open(FILE, "rb") as f:
|
||||
start += 4
|
||||
hwid = unpack("<H", block[start+24:start+24+2])[0]
|
||||
fver = unpack("<H", block[start+28:start+28+2])[0]
|
||||
print("- Hardware ID: 0x{:04x} / {:d} ({})".format(hwid, hwid, devices.DEVICES.get(hwid, "Unknown device")))
|
||||
print("- Hardware ID: 0x{:04x} / {:d} ({})".format(hwid, hwid, devices.get_name(hwid, 0, "Unknown device")))
|
||||
print("- Firmware Version: 0x{:04x} / {:04d}".format(fver, fver))
|
||||
first_block = False
|
||||
if END_MARKER in block:
|
||||
|
240
components.txt
Normal file
240
components.txt
Normal file
@ -0,0 +1,240 @@
|
||||
GUP1630:forerunner/Forerunner620.rgn
|
||||
GUP1630:forerunner/Forerunner920XT.rgn
|
||||
GUP1752:forerunner/Forerunner220.rgn
|
||||
GUP1752:forerunner/Forerunner620.rgn
|
||||
GUP1850:forerunner/Forerunner220.rgn
|
||||
GUP1850:forerunner/Forerunner620.rgn
|
||||
GUP1851:forerunner/Forerunner220.rgn
|
||||
GUP1851:forerunner/Forerunner620.rgn
|
||||
GUP1908:vivo/vivoactive.rgn
|
||||
GUP1909:fenix_D2_tactix/D2Bravo.rgn
|
||||
GUP1909:fenix_D2_tactix/D2BravoTitanium.rgn
|
||||
GUP1909:fenix_D2_tactix/fenix3HRBeta.zip
|
||||
GUP1909:fenix_D2_tactix/fenix3HR.rgn
|
||||
GUP1909:fenix_D2_tactix/fenix3.rgn
|
||||
GUP1909:fenix_D2_tactix/fenix3_tactixBravo_quatix3Beta.zip
|
||||
GUP1909:fenix_D2_tactix/fenix3_tactixBravo_quatix3.rgn
|
||||
GUP1909:vivo/vivoactive.rgn
|
||||
GUP1909:vivo/vivosmartHRplus.rgn
|
||||
GUP1909:vivo/vivosmart_HR.rgn
|
||||
GUP1909:vivo/vivosmartHR.rgn
|
||||
GUP1942:forerunner/Forerunner920XT.rgn
|
||||
GUP1955:vivo/vivosmartAPAC.rgn
|
||||
GUP1955:vivo/vivosmart.rgn
|
||||
GUP1969:forerunner/Forerunner15.rgn
|
||||
GUP2005:vivo/vivosmartAPAC.rgn
|
||||
GUP2005:vivo/vivosmart.rgn
|
||||
GUP2047:astro_alpha/T5_TT15Mini.rgn
|
||||
GUP2047:edge/Edge25.rgn
|
||||
GUP2047:edge/HMD_regionfileonly_.rgn
|
||||
GUP2047:edge/VariaVision.rgn
|
||||
GUP2047:forerunner/Forerunner225.rgn
|
||||
GUP2047:forerunner/Forerunner25.rgn
|
||||
GUP2047:forerunner/Forerunner30.rgn
|
||||
GUP2047:forerunner/Forerunner35.rgn
|
||||
GUP2047:forerunner/Forerunner920XTBeta.zip
|
||||
GUP2047:forerunner/Forerunner920XT.rgn
|
||||
GUP2047:misc_marine/GarminNautix_regionfileonly_.rgn
|
||||
GUP2051:fenix_D2_tactix/D2Bravo.rgn
|
||||
GUP2051:fenix_D2_tactix/fenix3.rgn
|
||||
GUP2051:fenix_D2_tactix/fenix3_tactixBravo_quatix3.rgn
|
||||
GUP2059:vivo/vivoactive.rgn
|
||||
GUP2108:fenix_D2_tactix/D2Bravo.rgn
|
||||
GUP2108:fenix_D2_tactix/fenix3.rgn
|
||||
GUP2108:fenix_D2_tactix/fenix3_tactixBravo_quatix3.rgn
|
||||
GUP2151:forerunner/Forerunner225.rgn
|
||||
GUP2159:forerunner/Forerunner230.gcd
|
||||
GUP2159:forerunner/Forerunner235.gcd
|
||||
GUP2159:forerunner/Forerunner630.gcd
|
||||
GUP2196:fenix_D2_tactix/D2BravoTitanium.rgn
|
||||
GUP2196:fenix_D2_tactix/D2Charlie.gcd
|
||||
GUP2196:fenix_D2_tactix/DescentAPAC_GCDfileonly_.gcd
|
||||
GUP2196:fenix_D2_tactix/DescentMk1.gcd
|
||||
GUP2196:fenix_D2_tactix/fenix3HRBeta.zip
|
||||
GUP2196:fenix_D2_tactix/fenix3HR.rgn
|
||||
GUP2196:fenix_D2_tactix/fenix5Beta.zip
|
||||
GUP2196:fenix_D2_tactix/fenix5.gcd
|
||||
GUP2196:fenix_D2_tactix/fenix5PlusBeta.zip
|
||||
GUP2196:fenix_D2_tactix/fenix5SBeta.zip
|
||||
GUP2196:fenix_D2_tactix/fenix5S.gcd
|
||||
GUP2196:fenix_D2_tactix/fenix5SPlusBeta.zip
|
||||
GUP2196:fenix_D2_tactix/fenix5XBeta.zip
|
||||
GUP2196:fenix_D2_tactix/fenix5X.gcd
|
||||
GUP2196:fenix_D2_tactix/fenix5XPlusBeta.zip
|
||||
GUP2196:fenix_D2_tactix/fenix6ProBeta.zip
|
||||
GUP2196:fenix_D2_tactix/fenix6SProBeta.zip
|
||||
GUP2196:fenix_D2_tactix/fenix6XProBeta.zip
|
||||
GUP2196:forerunner/Forerunner630.gcd
|
||||
GUP2196:forerunner/Forerunner935.gcd
|
||||
GUP2196:MARQ/MARQAdventurerBeta.zip
|
||||
GUP2196:MARQ/MARQAthleteBeta.zip
|
||||
GUP2196:MARQ/MARQAviatorBeta.zip
|
||||
GUP2196:MARQ/MARQBeta.zip
|
||||
GUP2196:MARQ/MARQCaptainBeta.zip
|
||||
GUP2196:MARQ/MARQCommanderBeta.zip
|
||||
GUP2196:MARQ/MARQDriverBeta.zip
|
||||
GUP2196:MARQ/MARQExpeditionBeta.zip
|
||||
GUP2197:forerunner/Forerunner630.gcd
|
||||
GUP2202:baseball_golf/TruSwing.rgn
|
||||
GUP2202:golf_baseball/TruSwing.rgn
|
||||
GUP2228:forerunner/Forerunner225.rgn
|
||||
GUP2338:vivo/vivoactiveHR.gcd
|
||||
GUP2339:vivo/vivoactiveHR.gcd
|
||||
GUP2340:vivo/vivoactiveHR.gcd
|
||||
GUP2358:vivo/vivosmart_HR.rgn
|
||||
GUP2358:vivo/vivosmartHR.rgn
|
||||
GUP2369:forerunner/Forerunner235Beta.zip
|
||||
GUP2369:forerunner/Forerunner235.gcd
|
||||
GUP2392:fenix_D2_tactix/fenixChronosBeta_USB.zip
|
||||
GUP2392:fenix_D2_tactix/fenixChronosBeta.zip
|
||||
GUP2392:fenix_D2_tactix/fenixChronos.gcd
|
||||
GUP2393:fenix_D2_tactix/fenixChronosBeta_USB.zip
|
||||
GUP2393:fenix_D2_tactix/fenixChronosBeta.zip
|
||||
GUP2393:fenix_D2_tactix/fenixChronos.gcd
|
||||
GUP2403:baseball_golf/ApproachS20.rgn
|
||||
GUP2403:golf_baseball/ApproachS20.rgn
|
||||
GUP2405:baseball_golf/ApproachX40.rgn
|
||||
GUP2405:golf_baseball/ApproachX40.rgn
|
||||
GUP2414:fenix_D2_tactix/D2BravoTitanium.rgn
|
||||
GUP2414:fenix_D2_tactix/fenix3HR.rgn
|
||||
GUP2415:fenix_D2_tactix/fenix3HRBeta.zip
|
||||
GUP2415:fenix_D2_tactix/fenix3HR.rgn
|
||||
GUP2423:fenix_D2_tactix/fenixChronos.gcd
|
||||
GUP2423:forerunner/Forerunner230Beta.zip
|
||||
GUP2423:forerunner/Forerunner230.gcd
|
||||
GUP2423:forerunner/Forerunner235Beta.zip
|
||||
GUP2423:forerunner/Forerunner235.gcd
|
||||
GUP2423:forerunner/Forerunner630Beta.zip
|
||||
GUP2423:forerunner/Forerunner630.gcd
|
||||
GUP2423:forerunner/Forerunner735XTBeta.zip
|
||||
GUP2423:forerunner/Forerunner735XT.gcd
|
||||
GUP2423:vivo/vivoactiveHR.gcd
|
||||
GUP2447:edge/HMD_regionfileonly_.rgn
|
||||
GUP2447:edge/VariaVision.rgn
|
||||
GUP2447:misc_marine/GarminNautix_regionfileonly_.rgn
|
||||
GUP2510:forerunner/Forerunner735XT.gcd
|
||||
GUP2511:forerunner/Forerunner735XT.gcd
|
||||
GUP2527:baseball_golf/ApproachX40.rgn
|
||||
GUP2527:golf_baseball/ApproachX40.rgn
|
||||
GUP2527:vivo/vivosmartHRplus.rgn
|
||||
GUP2560:fenix_D2_tactix/D2BravoTitanium.rgn
|
||||
GUP2583:astro_alpha/DeltaSmart.rgn
|
||||
GUP2583:delta/DeltaSmart.rgn
|
||||
GUP2605:fenix_D2_tactix/fenix5XBeta.zip
|
||||
GUP2605:fenix_D2_tactix/fenix5X.gcd
|
||||
GUP2657:baseball_golf/ApproachS60Beta.zip
|
||||
GUP2657:golf_baseball/ApproachS60Beta.zip
|
||||
GUP2661:fenix_D2_tactix/fenix5Beta.zip
|
||||
GUP2661:fenix_D2_tactix/fenix5.gcd
|
||||
GUP2662:fenix_D2_tactix/fenix5SBeta.zip
|
||||
GUP2662:fenix_D2_tactix/fenix5S.gcd
|
||||
GUP2663:fenix_D2_tactix/D2Charlie.gcd
|
||||
GUP2663:fenix_D2_tactix/fenix5XBeta.zip
|
||||
GUP2663:fenix_D2_tactix/fenix5X.gcd
|
||||
GUP2664:fenix_D2_tactix/DescentMk1.gcd
|
||||
GUP2665:forerunner/Forerunner935_1157_SNS_623_Beta.zip
|
||||
GUP2665:forerunner/Forerunner935_1157_SNS_625_Beta.zip
|
||||
GUP2665:forerunner/Forerunner935Beta.zip
|
||||
GUP2665:forerunner/Forerunner935.gcd
|
||||
GUP2666:vivo/vivoactive3.gcd
|
||||
GUP2699:vivo/vivoactive3.gcd
|
||||
GUP2699:vivo/vivoactive3t.gcd
|
||||
GUP2752:baseball_golf/ApproachS60Beta.zip
|
||||
GUP2752:baseball_golf/ApproachS60.gcd
|
||||
GUP2752:golf_baseball/ApproachS60Beta.zip
|
||||
GUP2752:golf_baseball/ApproachS60.gcd
|
||||
GUP2792:foretrex/Foretrex601_701_WebUpdater_.gcd
|
||||
GUP2818:xero/XeroA1_i_.gcd
|
||||
GUP2820:fenix_D2_tactix/D2Charlie.gcd
|
||||
GUP2822:vivo/vivoactive3.gcd
|
||||
GUP2827:baseball_golf/Impact.rgn
|
||||
GUP2827:golf_baseball/Impact.rgn
|
||||
GUP2869:fenix_D2_tactix/DescentAPAC_GCDfileonly_.gcd
|
||||
GUP2869:fenix_D2_tactix/DescentMk1.gcd
|
||||
GUP2887:forerunner/Forerunner645MusicBeta.zip
|
||||
GUP2896:forerunner/Forerunner645BetaBeta.zip
|
||||
GUP2897:forerunner/Forerunner645MusicBeta.zip
|
||||
GUP2957:chipset_firmware/Type_M/GPSChipsetTypeM5_2957_Beta.zip
|
||||
GUP2957:fenix_D2_tactix/fenix5Beta.zip
|
||||
GUP2957:fenix_D2_tactix/fenix5PlusBeta.zip
|
||||
GUP2957:fenix_D2_tactix/fenix5SBeta.zip
|
||||
GUP2957:fenix_D2_tactix/fenix5SPlusBeta.zip
|
||||
GUP2957:fenix_D2_tactix/fenix5XBeta.zip
|
||||
GUP2957:fenix_D2_tactix/fenix5XPlusBeta.zip
|
||||
GUP2957:fenix_D2_tactix/fenixChronosBeta_USB.zip
|
||||
GUP2957:fenix_D2_tactix/fenixChronosBeta.zip
|
||||
GUP2957:forerunner/Forerunner935Beta.zip
|
||||
GUP2983:vivo/vivoactive3t.gcd
|
||||
GUP2993:fenix_D2_tactix/DescentAPAC_GCDfileonly_.gcd
|
||||
GUP3013:fenix_D2_tactix/fenix5PlusBeta.zip
|
||||
GUP3013:fenix_D2_tactix/fenix5SPlusBeta.zip
|
||||
GUP3013:fenix_D2_tactix/fenix5XPlusBeta.zip
|
||||
GUP3014:fenix_D2_tactix/fenix5PlusBeta.zip
|
||||
GUP3014:fenix_D2_tactix/fenix5SPlusBeta.zip
|
||||
GUP3014:fenix_D2_tactix/fenix5XPlusBeta.zip
|
||||
GUP3015:fenix_D2_tactix/fenix5PlusBeta.zip
|
||||
GUP3015:fenix_D2_tactix/fenix5SPlusBeta.zip
|
||||
GUP3015:fenix_D2_tactix/fenix5XPlusBeta.zip
|
||||
GUP3044:baseball_golf/ApproachS20.rgn
|
||||
GUP3044:golf_baseball/ApproachS20.rgn
|
||||
GUP3078:forerunner/Forerunner245Beta.zip
|
||||
GUP3079:forerunner/Forerunner245MBeta.zip
|
||||
GUP3107:chipset_firmware/Type_S/GPSChipsetTypeS1_3107_Beta.zip
|
||||
GUP3114:forerunner/Forerunner945Beta.zip
|
||||
GUP3127:fenix_D2_tactix/InstinctBeta.gcd
|
||||
GUP3127:fenix_D2_tactix/InstinctBeta.zip
|
||||
GUP3127:fenix_D2_tactix/Instinct.gcd
|
||||
GUP3153:fenix_D2_tactix/fenix5PlusBeta.zip
|
||||
GUP3153:fenix_D2_tactix/fenix5SPlusBeta.zip
|
||||
GUP3153:fenix_D2_tactix/fenix5XPlusBeta.zip
|
||||
GUP3204:forerunner/Forerunner245Beta.zip
|
||||
GUP3205:forerunner/Forerunner245MBeta.zip
|
||||
GUP3252:MARQ/MARQAdventurerBeta.zip
|
||||
GUP3252:MARQ/MARQAthleteBeta.zip
|
||||
GUP3252:MARQ/MARQAviatorBeta.zip
|
||||
GUP3252:MARQ/MARQBeta.zip
|
||||
GUP3252:MARQ/MARQCaptainBeta.zip
|
||||
GUP3252:MARQ/MARQCommanderBeta.zip
|
||||
GUP3252:MARQ/MARQDriverBeta.zip
|
||||
GUP3252:MARQ/MARQExpeditionBeta.zip
|
||||
GUP3252:MARQ/MARQSensorHubBeta.zip
|
||||
GUP3253:MARQ/MARQAdventurerBeta.zip
|
||||
GUP3253:MARQ/MARQANT_BLE_BTBeta.zip
|
||||
GUP3253:MARQ/MARQAthleteBeta.zip
|
||||
GUP3253:MARQ/MARQAviatorBeta.zip
|
||||
GUP3253:MARQ/MARQBeta.zip
|
||||
GUP3253:MARQ/MARQCaptainBeta.zip
|
||||
GUP3253:MARQ/MARQCommanderBeta.zip
|
||||
GUP3253:MARQ/MARQDriverBeta.zip
|
||||
GUP3253:MARQ/MARQExpeditionBeta.zip
|
||||
GUP3292:fenix_D2_tactix/fenix6Beta.zip
|
||||
GUP3292:fenix_D2_tactix/fenix6SBeta.zip
|
||||
GUP3293:fenix_D2_tactix/fenix6ProBeta.zip
|
||||
GUP3293:fenix_D2_tactix/fenix6S_6_6XPro_ANT_BLE_BTBeta.zip
|
||||
GUP3293:fenix_D2_tactix/fenix6SProBeta.zip
|
||||
GUP3293:fenix_D2_tactix/fenix6XProBeta.zip
|
||||
GUP3294:fenix_D2_tactix/fenix6SBeta.zip
|
||||
GUP3294:fenix_D2_tactix/fenix6SProBeta.zip
|
||||
GUP3294:fenix_D2_tactix/fenix6SProSensorHubBeta.zip
|
||||
GUP3294:fenix_D2_tactix/fenix6SSensorHubBeta.zip
|
||||
GUP3295:fenix_D2_tactix/fenix6Beta.zip
|
||||
GUP3295:fenix_D2_tactix/fenix6ProBeta.zip
|
||||
GUP3295:fenix_D2_tactix/fenix6ProSensorHubBeta.zip
|
||||
GUP3295:fenix_D2_tactix/fenix6SensorHubBeta.zip
|
||||
GUP3296:fenix_D2_tactix/fenix6XProBeta.zip
|
||||
GUP3296:fenix_D2_tactix/fenix6XProSensorHubBetaBeta.zip
|
||||
GUP3296:fenix_D2_tactix/fenix6XProSensorHubBeta.zip
|
||||
GUP3296:fenix_D2_tactix/fenix6XSensorHubBeta.zip
|
||||
GUP3303:forerunner/Forerunner945Beta.zip
|
||||
GUP3315:baseball_golf/ApproachS40.gcd
|
||||
GUP3315:golf_baseball/ApproachS40.gcd
|
||||
GUP3316:baseball_golf/ApproachS40.gcd
|
||||
GUP3316:golf_baseball/ApproachS40.gcd
|
||||
GUP3406:swim/Swim2BetaBeta.zip
|
||||
GUP3506:chipset_firmware/Type_S/GPSChipsetTypeS1_3506_Beta.zip
|
||||
GUP5423:vivo/vivosmartAPAC.rgn
|
||||
GUP5424:vivo/vivosmartAPAC.rgn
|
||||
GUP6182:edge/HMD_regionfileonly_.rgn
|
||||
GUP6182:edge/VariaVision.rgn
|
||||
GUP6182:misc_marine/GarminNautix_regionfileonly_.rgn
|
||||
GUP7124:vivo/vivoactive3t.gcd
|
1728
components2.txt
Normal file
1728
components2.txt
Normal file
File diff suppressed because it is too large
Load Diff
40
find_hwids.py
Executable file
40
find_hwids.py
Executable file
@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Parses a binary file for 006-Bxxxx-xx or 006Bxxxxxx occurrances.
|
||||
"""
|
||||
|
||||
import os.path
|
||||
import re
|
||||
import sys
|
||||
from grmn import devices
|
||||
|
||||
FILE = sys.argv[1]
|
||||
|
||||
pattern = re.compile(rb"006-?B\d\d\d\d-?[0-9A-F]{2}")
|
||||
|
||||
print("Reading {} ...".format(FILE))
|
||||
with open(FILE, "rb") as f:
|
||||
data = f.read()
|
||||
f.close()
|
||||
|
||||
matches = pattern.findall(data)
|
||||
results = []
|
||||
|
||||
for i in matches:
|
||||
i = i.decode("utf-8")
|
||||
if len(i) == 10:
|
||||
i = "{}-{}-{}".format(i[0:3], i[3:8], i[8:])
|
||||
results.append(i)
|
||||
|
||||
results = sorted(set(results))
|
||||
|
||||
for r in results:
|
||||
print(r, end="")
|
||||
hw_id = r[5:9]
|
||||
sub_id = r[10:]
|
||||
device_name = devices.get_name(hw_id, sub_id)
|
||||
if device_name:
|
||||
print(" - {}".format(device_name), end="")
|
||||
print()
|
@ -18,6 +18,7 @@ optp.add_option("-c", "--changelog", action="store_true", dest="changelog", help
|
||||
optp.add_option("-l", "--license", action="store_true", dest="license", help="also show license")
|
||||
optp.add_option("-E", "--express", action="store_false", dest="webupdater", default=True, help="Only query Garmin Express")
|
||||
optp.add_option("-W", "--webupdater", action="store_false", dest="express", default=True, help="Only query WebUpdater")
|
||||
optp.add_option("-q", "--quiet", action="store_true", dest="quiet", default=False, help="Only output results (if any)")
|
||||
optp.add_option("--id", dest="unit_id", help="Specify custom Unit ID")
|
||||
optp.add_option("--code", action="append", dest="unlock_codes", metavar="UNLOCK_CODE", default=[], help="Specify map unlock codes")
|
||||
optp.add_option("--devicexml", dest="devicexml", metavar="FILE", help="Use specified GarminDevice.xml (also implies -E)")
|
||||
@ -83,10 +84,11 @@ for i, sku in enumerate(device_skus):
|
||||
if len(sku) <= 4:
|
||||
device_skus[i] = "006-B{:>04}-00".format(sku)
|
||||
|
||||
if device_skus[0][0:5] == "006-B":
|
||||
if device_skus[0][0:5] == "006-B" and not opts.quiet:
|
||||
primary_hwid = int(device_skus[0][5:9])
|
||||
device_name = devices.DEVICES.get(primary_hwid, "Unknown device")
|
||||
print("Device (guessed): {}".format(device_name))
|
||||
primary_subid = device_skus[0][10:]
|
||||
device_name = devices.get_name(primary_hwid, primary_subid, "Unknown device")
|
||||
print("Device {:04d}-{:02} (guessed): {}".format(primary_hwid, primary_subid, device_name))
|
||||
|
||||
if opts.unit_id:
|
||||
print("Custom Unit ID: {}".format(opts.unit_id))
|
||||
@ -99,14 +101,18 @@ for uc in opts.unlock_codes:
|
||||
results = []
|
||||
|
||||
if opts.express:
|
||||
print("Querying Garmin Express ...", end="", flush=True)
|
||||
if not opts.quiet:
|
||||
print("Querying Garmin Express ...", end="", flush=True)
|
||||
results += us.query_express(device_skus)
|
||||
print(" done.")
|
||||
if not opts.quiet:
|
||||
print(" done.")
|
||||
|
||||
if opts.webupdater:
|
||||
print("Querying Garmin WebUpdater ...", end="", flush=True)
|
||||
if not opts.quiet:
|
||||
print("Querying Garmin WebUpdater ...", end="", flush=True)
|
||||
results += us.query_webupdater(device_skus)
|
||||
print(" done.")
|
||||
if not opts.quiet:
|
||||
print(" done.")
|
||||
|
||||
for r in results:
|
||||
print(r)
|
||||
|
@ -15,7 +15,8 @@ class ChkSum:
|
||||
with open(filename, "rb") as f:
|
||||
while True:
|
||||
block = f.read(blocksize)
|
||||
self.add(block)
|
||||
if len(block) != 0:
|
||||
self.add(block)
|
||||
if print_progress:
|
||||
print(".", end="", flush=True)
|
||||
if len(block) < blocksize:
|
||||
|
2848
grmn/devices.py
2848
grmn/devices.py
File diff suppressed because it is too large
Load Diff
@ -129,7 +129,7 @@ class RgnBin:
|
||||
def __str__(self):
|
||||
txt = "Binary payload, {} Bytes".format(len(self.payload))
|
||||
if self.hwid:
|
||||
txt += "\n - hw_id: 0x{:04x} / {:d} ({})".format(self.hwid, self.hwid, devices.DEVICES.get(self.hwid, RED + "Unknown device" + RESET))
|
||||
txt += "\n - hw_id: 0x{:04x} / {:d} ({})".format(self.hwid, self.hwid, devices.get_name(self.hwid, 0, RED + "Unknown device" + RESET))
|
||||
if self.version:
|
||||
txt += "\n - Version: 0x{:04x} / {:d}".format(self.version, self.version)
|
||||
cksum = ChkSum()
|
||||
|
51
grmn/tlv.py
51
grmn/tlv.py
@ -21,6 +21,13 @@ TLV_TYPES = {
|
||||
0x051b: "Binary Region 1b",
|
||||
0x052b: "Binary Region 2b",
|
||||
0x0533: "Binary Region 33 (dskimg)",
|
||||
0x0534: "Binary Region 34",
|
||||
0x0535: "Binary Region 35",
|
||||
0x0536: "Binary Region 36",
|
||||
0x0537: "Binary Region 37",
|
||||
0x0538: "Binary Region 38",
|
||||
0x0539: "Binary Region 39",
|
||||
0x053a: "Binary Region 3a",
|
||||
0x0549: "Binary Region 49",
|
||||
0x0555: "Binary Region 55 (fw)",
|
||||
0x0556: "Binary Region 56",
|
||||
@ -33,6 +40,8 @@ TLV_TYPES = {
|
||||
0x0599: "Binary Region 99",
|
||||
0x059e: "Binary Region 9e (resources)",
|
||||
0x05a2: "Binary Region a2",
|
||||
0x05a4: "Binary Region a4",
|
||||
0x05a5: "Binary Region a5",
|
||||
0x05ab: "Binary Region ab",
|
||||
0x05f5: "Binary Region f5",
|
||||
0x05f9: "Binary Region f9",
|
||||
@ -47,9 +56,10 @@ TLV_TYPES = {
|
||||
0xffff: "EOF marker",
|
||||
}
|
||||
|
||||
BINARY_TLVS = [ 0x0008, 0x02bd, 0x0505, 0x0510, 0x051b, 0x052b, 0x0533, 0x0549, 0x0555, 0x0556,
|
||||
0x0557, 0x0566, 0x057f, 0x0588, 0x0590, 0x0595, 0x0599, 0x059e, 0x05a2, 0x05ab,
|
||||
0x05f5, 0x05f9, 0x05fa, 0x05fb, 0x05fc, 0x05fd, 0x05fe, 0x07d1, 0x07d2, 0x07d3 ]
|
||||
BINARY_TLVS = [ 0x0008, 0x02bd, 0x0505, 0x0510, 0x051b, 0x052b, 0x0533, 0x0534, 0x0535, 0x0536,
|
||||
0x0537, 0x0538, 0x0539, 0x053a, 0x0549, 0x0555, 0x0556, 0x0557, 0x0566, 0x057f,
|
||||
0x0588, 0x0590, 0x0595, 0x0599, 0x059e, 0x05a2, 0x05a4, 0x05a5, 0x05ab, 0x05f5,
|
||||
0x05f9, 0x05fa, 0x05fb, 0x05fc, 0x05fd, 0x05fe, 0x07d1, 0x07d2, 0x07d3 ]
|
||||
|
||||
class TLV:
|
||||
def __init__(self, type_id: int, expected_length: int, value=None, offset: int=None):
|
||||
@ -232,13 +242,13 @@ class TLV6(TLV):
|
||||
def __init__(self, type_id: int, expected_length: int, value=None, offset: int=None):
|
||||
super().__init__(type_id, expected_length, value, offset)
|
||||
self.fids = []
|
||||
self.format = ""
|
||||
self.format = []
|
||||
self.fields = []
|
||||
|
||||
def add_fid(self, fid: int):
|
||||
fdef = self.FIELD_TYPES[fid]
|
||||
self.fids.append(fid)
|
||||
self.format += fdef[0]
|
||||
self.format.append(fdef[0])
|
||||
self.fields.append(fdef[1])
|
||||
|
||||
def parse(self):
|
||||
@ -249,7 +259,7 @@ class TLV6(TLV):
|
||||
raise Exception(RED + "Invalid TLV6 payload length!" + RESET)
|
||||
|
||||
self.fids = []
|
||||
self.format = ""
|
||||
self.format = []
|
||||
self.fields = []
|
||||
for i in range(0, len(self.value), 2):
|
||||
fid = unpack("<H", self.value[i:i+2])[0]
|
||||
@ -304,7 +314,7 @@ class TLV7(TLV):
|
||||
#print("Got {} Bytes.".format(len(self.value)))
|
||||
#print("Format: {}".format(self.tlv6.format))
|
||||
#print(repr(self.value))
|
||||
values = unpack("<" + self.tlv6.format, self.value)
|
||||
values = unpack("<" + "".join(self.tlv6.format), self.value)
|
||||
for i, v in enumerate(values):
|
||||
fid = self.tlv6.fids[i]
|
||||
self.attr.append((fid, v))
|
||||
@ -320,7 +330,7 @@ class TLV7(TLV):
|
||||
fdesc = self.tlv6.fields[i]
|
||||
(fid, v) = pair
|
||||
if fid == 0x1009:
|
||||
txt += "\n - Field {:d} ({:04x}): {:>20}: 0x{:04x} / {:d} ({})".format(i+1, fid, fdesc, v, v, devices.DEVICES.get(v, RED + "Unknown device" + RESET))
|
||||
txt += "\n - Field {:d} ({:04x}): {:>20}: 0x{:04x} / {:d} ({})".format(i+1, fid, fdesc, v, v, devices.get_name(v, 0, RED + "Unknown device" + RESET))
|
||||
elif fid == 0x2015:
|
||||
txt += "\n - Field {:d} ({:04x}): {:>20}: {} Bytes".format(i+1, fid, fdesc, v)
|
||||
elif fid == 0x4007:
|
||||
@ -331,7 +341,7 @@ class TLV7(TLV):
|
||||
|
||||
def set_binary_length(self, new_length):
|
||||
self.tlv6.parse()
|
||||
values = unpack("<" + self.tlv6.format, self.value)
|
||||
values = unpack("<" + "".join(self.tlv6.format), self.value)
|
||||
new_values = []
|
||||
for i, v in enumerate(values):
|
||||
fid = self.tlv6.fids[i]
|
||||
@ -339,7 +349,7 @@ class TLV7(TLV):
|
||||
new_values.append(new_length)
|
||||
else:
|
||||
new_values.append(v)
|
||||
self.value = pack("<" + self.tlv6.format, *new_values)
|
||||
self.value = pack("<" + "".join(self.tlv6.format), *new_values)
|
||||
self.is_parsed = False
|
||||
|
||||
def dump(self):
|
||||
@ -354,12 +364,15 @@ class TLV7(TLV):
|
||||
continue
|
||||
elif k[0:2] != "0x":
|
||||
continue
|
||||
numval = int(v, 0)
|
||||
if v[0:2] == "0x":
|
||||
numval = int(v, 0)
|
||||
else:
|
||||
numval = unhexlify(v)
|
||||
new_values.append(numval)
|
||||
if not self.tlv6.is_parsed:
|
||||
# Make sure we have the structure analysed (need format attr)
|
||||
self.tlv6.parse()
|
||||
self.value = pack("<" + self.tlv6.format, *new_values)
|
||||
self.value = pack("<" + "".join(self.tlv6.format), *new_values)
|
||||
self.length = len(self.value)
|
||||
|
||||
class TLVbinary(TLV):
|
||||
@ -386,7 +399,7 @@ class TLVbinary(TLV):
|
||||
elif valtype == "Q":
|
||||
valstr = "0x{:08x}".format(v)
|
||||
elif valtype == "31s":
|
||||
valstr = repr(v)
|
||||
valstr = hexlify(v).decode("utf-8")
|
||||
else:
|
||||
valstr = "0x{:08x}".format(v)
|
||||
data.append(("0x{:04x}".format(fid), valstr, fdesc))
|
||||
@ -401,10 +414,18 @@ class TLVbinary0401(TLVbinary):
|
||||
sku = self.value[10:20].decode("utf-8")
|
||||
hwid = int(sku[4:8])
|
||||
txt += "\n - SKU: {}-{}-{}".format(sku[0:3], sku[3:8], sku[8:10])
|
||||
txt += "\n - hw_id: 0x{:04x} / {:d} ({})".format(hwid, hwid, devices.DEVICES.get(hwid, RED + "Unknown device" + RESET))
|
||||
txt += "\n - hw_id: 0x{:04x} / {:d} ({})".format(hwid, hwid, devices.get_name(hwid, 0, RED + "Unknown device" + RESET))
|
||||
txt += "\n - Version: 0x{:04x} / {:d}".format(version, version)
|
||||
elif skuprobe == b"SW_I":
|
||||
swistring = self.value[10:20].decode("utf-8")
|
||||
payloadprobe = self.value[0x40:0x42]
|
||||
txt += "\n - Type: Software Inventory ({}) - actual payload starts at 0x40".format(swistring)
|
||||
if payloadprobe == b"PK":
|
||||
txt += "\n Probably ZIP archive"
|
||||
elif payloadprobe == b"Fi":
|
||||
txt += "\n Probably CSV file"
|
||||
else:
|
||||
txt += "\n - Unknown header format (0x{:04x} / 0x{:04x})".format(hdr1, hdr2)
|
||||
txt += "\n - Unknown header format (0x{})".format(hexlify(skuprobe).decode("utf-8"))
|
||||
#if not self.is_parsed:
|
||||
# self.parse()
|
||||
return txt
|
||||
|
@ -13,7 +13,8 @@ import requests
|
||||
|
||||
PROTO_API_GETALLUNITSOFTWAREUPDATES_URL = "http://omt.garmin.com/Rce/ProtobufApi/SoftwareUpdateService/GetAllUnitSoftwareUpdates"
|
||||
WEBUPDATER_SOFTWAREUPDATE_URL = "https://www.garmin.com/support/WUSoftwareUpdate.jsp"
|
||||
GRMN_CLIENT_VERSION = "6.17.0.0"
|
||||
GRMN_CLIENT_VERSION = "6.19.4.0"
|
||||
|
||||
|
||||
class UpdateInfo:
|
||||
def __init__(self):
|
||||
@ -106,6 +107,7 @@ class UpdateInfo:
|
||||
def __repr__(self):
|
||||
return "[{}] {} {} {}".format(self.source, self.sku, self.device_name, self.fw_version)
|
||||
|
||||
|
||||
class UpdateServer:
|
||||
|
||||
def __init__(self):
|
||||
@ -235,7 +237,7 @@ class UpdateServer:
|
||||
def get_unit_updates(self, device_xml):
|
||||
query = GetAllUnitSoftwareUpdates_pb2.GetAllUnitSoftwareUpdates()
|
||||
query.client_data.client = "express"
|
||||
query.client_data.language ="en_GB"
|
||||
query.client_data.language = "en_GB"
|
||||
query.client_data.client_platform = "Windows"
|
||||
query.client_data.client_platform_version = "1000 "
|
||||
query.device_xml = device_xml
|
||||
|
70
list_kenwood_updates.py
Normal file
70
list_kenwood_updates.py
Normal file
@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import requests
|
||||
import re
|
||||
|
||||
BASE_URL = "https://kenwood.garmin.com"
|
||||
MAIN_URL = "/kenwood/site/filterHeadUnitList"
|
||||
|
||||
reqs = requests.Session()
|
||||
|
||||
def get_url(url, params = {}, outfile = None):
|
||||
global reqs
|
||||
print("Now fetching {} ...".format(url))
|
||||
#print(repr(params))
|
||||
req = reqs.get(url, params=params)
|
||||
page = req.content
|
||||
#if outfile:
|
||||
# with open(outfile, "wb") as f:
|
||||
# f.write(page)
|
||||
page = str(page).replace("\\n", "").replace("\\r", "").replace("\\t", "")
|
||||
page = re.sub(r"\s+", " ", page)
|
||||
return page
|
||||
|
||||
devlist = get_url(BASE_URL + MAIN_URL, {"regionKey": 0, "seriesKey": 0}, "kenmain.html")
|
||||
devices = re.findall(r"<div class=\"item\"> <a href=\"(.*?)\">(.*?)</a> </div>", devlist)
|
||||
|
||||
print("Found {} devices.".format(len(devices)))
|
||||
#print(repr(devices))
|
||||
|
||||
f = open("kenfiles.txt", "wt")
|
||||
f.write("# Download with: wget -x -nc -i kenfiles.txt\n\n")
|
||||
|
||||
for dev in devices:
|
||||
(url, devname) = dev
|
||||
print("Checking updates for {} ...".format(devname.strip()))
|
||||
url = url.strip()
|
||||
(url, paramstr) = url.split("?", 1)
|
||||
parampairs = paramstr.split("&")
|
||||
params = {}
|
||||
for p in parampairs:
|
||||
(key, val) = p.split("=", 1)
|
||||
params[key] = val
|
||||
params["origin"] = "productUpdate" # gets added via JavaScript?
|
||||
|
||||
devpage = get_url(BASE_URL + url, params, "kendev.html")
|
||||
|
||||
updateLink = re.search(r"(/kenwood/site/softwareUpdates.*?)\\", devpage)
|
||||
|
||||
if not updateLink:
|
||||
print("### No updates for {} found.".format(devname))
|
||||
continue
|
||||
|
||||
updateLink = updateLink.group(1)
|
||||
#print(repr(updateLink))
|
||||
|
||||
updpage = get_url(BASE_URL + updateLink, {}, "kenupd.html")
|
||||
#print(repr(updpage))
|
||||
|
||||
links = re.findall(r"(https?://.*?)[\\\"']", updpage)
|
||||
|
||||
f.write("# {}\n".format(devname))
|
||||
for l in links:
|
||||
if l.endswith(("favicon.ico", "garmin.png", "termsOfUse.htm", "privacy-statement", "/us/")):
|
||||
continue
|
||||
#print(repr(l))
|
||||
f.write(l)
|
||||
f.write("\n")
|
||||
f.write("\n")
|
||||
|
||||
f.close()
|
@ -6,13 +6,19 @@
|
||||
from grmn import devices
|
||||
import sys
|
||||
|
||||
largest_gap = -1
|
||||
gap_counter = 0
|
||||
last_id = 0
|
||||
missing = []
|
||||
for i in range(0, 9999):
|
||||
if i in devices.DEVICES:
|
||||
last_id = i
|
||||
if gap_counter > largest_gap:
|
||||
largest_gap = gap_counter
|
||||
gap_counter = 0
|
||||
continue
|
||||
missing.append(i)
|
||||
gap_counter += 1
|
||||
|
||||
missing_count = 0
|
||||
cur_line = []
|
||||
@ -20,36 +26,37 @@ queue = []
|
||||
for i in range(0, last_id+1):
|
||||
if i % 10 == 0:
|
||||
if len(cur_line) + len(queue) > 15:
|
||||
print("./get_updates.py {}".format(" ".join(cur_line)))
|
||||
print("./get_updates.py -q {}".format(" ".join(cur_line)))
|
||||
cur_line = queue
|
||||
else:
|
||||
cur_line += queue
|
||||
queue = []
|
||||
if not i in missing:
|
||||
if i not in missing:
|
||||
continue
|
||||
queue.append("{:04}".format(i))
|
||||
missing_count += 1
|
||||
|
||||
cur_line += queue
|
||||
if len(cur_line) > 0:
|
||||
print("./get_updates.py {}".format(" ".join(cur_line)))
|
||||
print("./get_updates.py -q {}".format(" ".join(cur_line)))
|
||||
|
||||
known_count = len(devices.DEVICES)
|
||||
print()
|
||||
print("{} unknown ids.".format(missing_count))
|
||||
print("Last known id is: {:04}".format(last_id))
|
||||
print("{} known, {} unknown ids. Last known id is: {:04d}".format(known_count, missing_count, last_id))
|
||||
print("Largest gap is: {}".format(largest_gap))
|
||||
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
print("-" * 100)
|
||||
print("Here are some possible future ids:")
|
||||
|
||||
print("./get_updates.py", end="")
|
||||
print("./get_updates.py -q", end="")
|
||||
|
||||
cur_line = 0
|
||||
for i in range(last_id + 1, last_id + 200):
|
||||
for i in range(last_id + 1, last_id + 300):
|
||||
if i % 10 == 0 and cur_line > 5:
|
||||
print()
|
||||
print("./get_updates.py", end="")
|
||||
print("./get_updates.py -q", end="")
|
||||
cur_line = 0
|
||||
print(" {:04}".format(i), end="")
|
||||
cur_line += 1
|
||||
|
Loading…
x
Reference in New Issue
Block a user