Merge pull request #24 from VorpalBlade/feature/code-cleanup

Major code cleanup:
This commit is contained in:
uunicorn 2020-08-06 22:41:07 +12:00 committed by GitHub
commit 6a7ae704e7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 2205 additions and 1007 deletions

394
.style.yapf Normal file
View file

@ -0,0 +1,394 @@
[style]
# Align closing bracket with visual indentation.
align_closing_bracket_with_visual_indent=True
# Allow dictionary keys to exist on multiple lines. For example:
#
# x = {
# ('this is the first element of a tuple',
# 'this is the second element of a tuple'):
# value,
# }
allow_multiline_dictionary_keys=False
# Allow lambdas to be formatted on more than one line.
allow_multiline_lambdas=False
# Allow splitting before a default / named assignment in an argument list.
allow_split_before_default_or_named_assigns=True
# Allow splits before the dictionary value.
allow_split_before_dict_value=True
# Let spacing indicate operator precedence. For example:
#
# a = 1 * 2 + 3 / 4
# b = 1 / 2 - 3 * 4
# c = (1 + 2) * (3 - 4)
# d = (1 - 2) / (3 + 4)
# e = 1 * 2 - 3
# f = 1 + 2 + 3 + 4
#
# will be formatted as follows to indicate precedence:
#
# a = 1*2 + 3/4
# b = 1/2 - 3*4
# c = (1+2) * (3-4)
# d = (1-2) / (3+4)
# e = 1*2 - 3
# f = 1 + 2 + 3 + 4
#
arithmetic_precedence_indication=False
# Number of blank lines surrounding top-level function and class
# definitions.
blank_lines_around_top_level_definition=2
# Insert a blank line before a class-level docstring.
blank_line_before_class_docstring=False
# Insert a blank line before a module docstring.
blank_line_before_module_docstring=False
# Insert a blank line before a 'def' or 'class' immediately nested
# within another 'def' or 'class'. For example:
#
# class Foo:
# # <------ this blank line
# def method():
# ...
blank_line_before_nested_class_or_def=False
# Do not split consecutive brackets. Only relevant when
# dedent_closing_brackets is set. For example:
#
# call_func_that_takes_a_dict(
# {
# 'key1': 'value1',
# 'key2': 'value2',
# }
# )
#
# would reformat to:
#
# call_func_that_takes_a_dict({
# 'key1': 'value1',
# 'key2': 'value2',
# })
coalesce_brackets=False
# The column limit.
column_limit=100
# The style for continuation alignment. Possible values are:
#
# - SPACE: Use spaces for continuation alignment. This is default behavior.
# - FIXED: Use fixed number (CONTINUATION_INDENT_WIDTH) of columns
# (ie: CONTINUATION_INDENT_WIDTH/INDENT_WIDTH tabs or
# CONTINUATION_INDENT_WIDTH spaces) for continuation alignment.
# - VALIGN-RIGHT: Vertically align continuation lines to multiple of
# INDENT_WIDTH columns. Slightly right (one tab or a few spaces) if
# cannot vertically align continuation lines with indent characters.
continuation_align_style=SPACE
# Indent width used for line continuations.
continuation_indent_width=4
# Put closing brackets on a separate line, dedented, if the bracketed
# expression can't fit in a single line. Applies to all kinds of brackets,
# including function definitions and calls. For example:
#
# config = {
# 'key1': 'value1',
# 'key2': 'value2',
# } # <--- this bracket is dedented and on a separate line
#
# time_series = self.remote_client.query_entity_counters(
# entity='dev3246.region1',
# key='dns.query_latency_tcp',
# transform=Transformation.AVERAGE(window=timedelta(seconds=60)),
# start_ts=now()-timedelta(days=3),
# end_ts=now(),
# ) # <--- this bracket is dedented and on a separate line
dedent_closing_brackets=False
# Disable the heuristic which places each list element on a separate line
# if the list is comma-terminated.
disable_ending_comma_heuristic=False
# Place each dictionary entry onto its own line.
each_dict_entry_on_separate_line=True
# Require multiline dictionary even if it would normally fit on one line.
# For example:
#
# config = {
# 'key1': 'value1'
# }
force_multiline_dict=False
# The regex for an i18n comment. The presence of this comment stops
# reformatting of that line, because the comments are required to be
# next to the string they translate.
i18n_comment=
# The i18n function call names. The presence of this function stops
# reformattting on that line, because the string it has cannot be moved
# away from the i18n comment.
i18n_function_call=
# Indent blank lines.
indent_blank_lines=False
# Put closing brackets on a separate line, indented, if the bracketed
# expression can't fit in a single line. Applies to all kinds of brackets,
# including function definitions and calls. For example:
#
# config = {
# 'key1': 'value1',
# 'key2': 'value2',
# } # <--- this bracket is indented and on a separate line
#
# time_series = self.remote_client.query_entity_counters(
# entity='dev3246.region1',
# key='dns.query_latency_tcp',
# transform=Transformation.AVERAGE(window=timedelta(seconds=60)),
# start_ts=now()-timedelta(days=3),
# end_ts=now(),
# ) # <--- this bracket is indented and on a separate line
indent_closing_brackets=False
# Indent the dictionary value if it cannot fit on the same line as the
# dictionary key. For example:
#
# config = {
# 'key1':
# 'value1',
# 'key2': value1 +
# value2,
# }
indent_dictionary_value=False
# The number of columns to use for indentation.
indent_width=4
# Join short lines into one line. E.g., single line 'if' statements.
join_multiple_lines=True
# Do not include spaces around selected binary operators. For example:
#
# 1 + 2 * 3 - 4 / 5
#
# will be formatted as follows when configured with "*,/":
#
# 1 + 2*3 - 4/5
no_spaces_around_selected_binary_operators=
# Use spaces around default or named assigns.
spaces_around_default_or_named_assign=False
# Adds a space after the opening '{' and before the ending '}' dict delimiters.
#
# {1: 2}
#
# will be formatted as:
#
# { 1: 2 }
spaces_around_dict_delimiters=False
# Adds a space after the opening '[' and before the ending ']' list delimiters.
#
# [1, 2]
#
# will be formatted as:
#
# [ 1, 2 ]
spaces_around_list_delimiters=False
# Use spaces around the power operator.
spaces_around_power_operator=False
# Use spaces around the subscript / slice operator. For example:
#
# my_list[1 : 10 : 2]
spaces_around_subscript_colon=False
# Adds a space after the opening '(' and before the ending ')' tuple delimiters.
#
# (1, 2, 3)
#
# will be formatted as:
#
# ( 1, 2, 3 )
spaces_around_tuple_delimiters=False
# The number of spaces required before a trailing comment.
# This can be a single value (representing the number of spaces
# before each trailing comment) or list of values (representing
# alignment column values; trailing comments within a block will
# be aligned to the first column value that is greater than the maximum
# line length within the block). For example:
#
# With spaces_before_comment=5:
#
# 1 + 1 # Adding values
#
# will be formatted as:
#
# 1 + 1 # Adding values <-- 5 spaces between the end of the statement and comment
#
# With spaces_before_comment=15, 20:
#
# 1 + 1 # Adding values
# two + two # More adding
#
# longer_statement # This is a longer statement
# short # This is a shorter statement
#
# a_very_long_statement_that_extends_beyond_the_final_column # Comment
# short # This is a shorter statement
#
# will be formatted as:
#
# 1 + 1 # Adding values <-- end of line comments in block aligned to col 15
# two + two # More adding
#
# longer_statement # This is a longer statement <-- end of line comments in block aligned to col 20
# short # This is a shorter statement
#
# a_very_long_statement_that_extends_beyond_the_final_column # Comment <-- the end of line comments are aligned based on the line length
# short # This is a shorter statement
#
spaces_before_comment=2
# Insert a space between the ending comma and closing bracket of a list,
# etc.
space_between_ending_comma_and_closing_bracket=True
# Use spaces inside brackets, braces, and parentheses. For example:
#
# method_call( 1 )
# my_dict[ 3 ][ 1 ][ get_index( *args, **kwargs ) ]
# my_set = { 1, 2, 3 }
space_inside_brackets=False
# Split before arguments
split_all_comma_separated_values=False
# Split before arguments, but do not split all subexpressions recursively
# (unless needed).
split_all_top_level_comma_separated_values=False
# Split before arguments if the argument list is terminated by a
# comma.
split_arguments_when_comma_terminated=False
# Set to True to prefer splitting before '+', '-', '*', '/', '//', or '@'
# rather than after.
split_before_arithmetic_operator=False
# Set to True to prefer splitting before '&', '|' or '^' rather than
# after.
split_before_bitwise_operator=True
# Split before the closing bracket if a list or dict literal doesn't fit on
# a single line.
split_before_closing_bracket=True
# Split before a dictionary or set generator (comp_for). For example, note
# the split before the 'for':
#
# foo = {
# variable: 'Hello world, have a nice day!'
# for variable in bar if variable != 42
# }
split_before_dict_set_generator=True
# Split before the '.' if we need to split a longer expression:
#
# foo = ('This is a really long string: {}, {}, {}, {}'.format(a, b, c, d))
#
# would reformat to something like:
#
# foo = ('This is a really long string: {}, {}, {}, {}'
# .format(a, b, c, d))
split_before_dot=False
# Split after the opening paren which surrounds an expression if it doesn't
# fit on a single line.
split_before_expression_after_opening_paren=False
# If an argument / parameter list is going to be split, then split before
# the first argument.
split_before_first_argument=False
# Set to True to prefer splitting before 'and' or 'or' rather than
# after.
split_before_logical_operator=True
# Split named assignments onto individual lines.
split_before_named_assigns=True
# Set to True to split list comprehensions and generators that have
# non-trivial expressions and multiple clauses before each of these
# clauses. For example:
#
# result = [
# a_long_var + 100 for a_long_var in xrange(1000)
# if a_long_var % 10]
#
# would reformat to something like:
#
# result = [
# a_long_var + 100
# for a_long_var in xrange(1000)
# if a_long_var % 10]
split_complex_comprehension=False
# The penalty for splitting right after the opening bracket.
split_penalty_after_opening_bracket=300
# The penalty for splitting the line after a unary operator.
split_penalty_after_unary_operator=10000
# The penalty of splitting the line around the '+', '-', '*', '/', '//',
# ``%``, and '@' operators.
split_penalty_arithmetic_operator=300
# The penalty for splitting right before an if expression.
split_penalty_before_if_expr=0
# The penalty of splitting the line around the '&', '|', and '^'
# operators.
split_penalty_bitwise_operator=300
# The penalty for splitting a list comprehension or generator
# expression.
split_penalty_comprehension=80
# The penalty for characters over the column limit.
split_penalty_excess_character=7000
# The penalty incurred by adding a line split to the unwrapped line. The
# more line splits added the higher the penalty.
split_penalty_for_added_line_split=30
# The penalty of splitting a list of "import as" names. For example:
#
# from a_very_long_or_indented_module_name_yada_yad import (long_argument_1,
# long_argument_2,
# long_argument_3)
#
# would reformat to something like:
#
# from a_very_long_or_indented_module_name_yada_yad import (
# long_argument_1, long_argument_2, long_argument_3)
split_penalty_import_names=0
# The penalty of splitting the line around the 'and' and 'or'
# operators.
split_penalty_logical_operator=300
# Use the Tab character for indentation.
use_tabs=False

View file

@ -1,15 +1,13 @@
#!/usr/bin/env python3
import os
from binascii import unhexlify
from enum import Enum
from validitysensor.flash import read_flash
from validitysensor.sensor import *
from validitysensor import init
from time import sleep
from usb import core as usb_core
from validitysensor import init
from validitysensor.sensor import glow_start_scan, glow_end_scan
from validitysensor.tls import tls
from validitysensor.util import assert_status
if __name__ == "__main__":
if os.geteuid() != 0:
@ -23,10 +21,9 @@ if __name__ == "__main__":
glow_end_scan()
sleep(0.05)
led_script = unhexlify(
'39ff100000ff03000001ff002000000000ffff0000ffff0000ff03000001ff00' \
'200000000000000000ffff0000ff03000001ff002000000000ffff0000000000' \
'0000000000000000000000000000000000000000000000000000000000000000' \
'0000000000000000000000000000000000000000000000000000000000')
led_script = unhexlify('39ff100000ff03000001ff002000000000ffff0000ffff0000ff03000001ff00'
'200000000000000000ffff0000ff03000001ff002000000000ffff0000000000'
'0000000000000000000000000000000000000000000000000000000000000000'
'0000000000000000000000000000000000000000000000000000000000')
assert_status(tls.app(led_script))

View file

@ -20,17 +20,17 @@
import argparse
import os
import shutil
import subprocess
import sys
import tempfile
import urllib.request
import shutil
from enum import Enum
from enum import Enum, auto
from time import sleep
from usb import core as usb_core
python_validity_data='/usr/share/python-validity/'
python_validity_data = '/usr/share/python-validity/'
# FIXME: supported usb ids are duplicated in usb.py
class VFS(Enum):
@ -38,6 +38,7 @@ class VFS(Enum):
DEV_97 = (0x138a, 0x0097)
DEV_9a = (0x06cb, 0x009a)
DEFAULT_URIS = {
VFS.DEV_90: {
'driver': 'https://download.lenovo.com/pccbbs/mobiles/n1cgn08w.exe',
@ -76,15 +77,12 @@ def download_and_extract_fw(dev_type, fwdir, fwuri=None):
with open(fwarchive, 'wb') as out_file:
out_file.write(response.read())
subprocess.check_call(['innoextract',
'--output-dir', fwdir,
'--include', fwname,
'--collisions', 'overwrite',
subprocess.check_call([
'innoextract', '--output-dir', fwdir, '--include', fwname, '--collisions', 'overwrite',
fwarchive
])
fwpath = subprocess.check_output([
'find', fwdir, '-name', fwname]).decode('utf-8').strip()
fwpath = subprocess.check_output(['find', fwdir, '-name', fwname]).decode('utf-8').strip()
print('Found firmware at {}'.format(fwpath))
if not fwpath:
@ -92,6 +90,7 @@ def download_and_extract_fw(dev_type, fwdir, fwuri=None):
return fwpath
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('--driver-uri')
@ -111,8 +110,7 @@ if __name__ == "__main__":
raise Exception('No supported validity device found')
try:
subprocess.check_call(['innoextract', '--version'],
stdout=subprocess.DEVNULL)
subprocess.check_call(['innoextract', '--version'], stdout=subprocess.DEVNULL)
except Exception as e:
print('Impossible to run innoextract: {}'.format(e))
sys.exit(1)

View file

@ -1,6 +1,8 @@
#!/usr/bin/env python3
import argparse
import logging
import logging.handlers
import os
import pwd
import re
@ -16,21 +18,18 @@ import dbus
import dbus.mainloop.glib
import dbus.service
import yaml
from gi.repository import GLib
from usb import core as usb_core
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
from gi.repository import GLib
import logging
import logging.handlers
from validitysensor import init
from validitysensor.tls import tls
from validitysensor.usb import usb
from validitysensor.sid import sid_from_string
from validitysensor.db import subtype_to_string, db, SidIdentity, User
from validitysensor.sensor import sensor, RebootException
from validitysensor.sid import sid_from_string
from validitysensor.tls import tls
from validitysensor.usb import usb
from validitysensor.winbio_constants import finger_ids
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
GLib.threads_init()
INTERFACE_NAME = 'io.github.uunicorn.Fprint.Device'
@ -64,9 +63,7 @@ class Device(dbus.service.Object):
"""Resolve user name to database object"""
return db.lookup_user(self.user2identity(user))
@dbus.service.method(dbus_interface=INTERFACE_NAME,
in_signature="s",
out_signature="as")
@dbus.service.method(dbus_interface=INTERFACE_NAME, in_signature="s", out_signature="as")
def ListEnrolledFingers(self, user):
try:
logging.debug('In ListEnrolledFingers %s' % user)
@ -82,9 +79,7 @@ class Device(dbus.service.Object):
except Exception as e:
raise e
@dbus.service.method(dbus_interface=INTERFACE_NAME,
in_signature='s',
out_signature='')
@dbus.service.method(dbus_interface=INTERFACE_NAME, in_signature='s', out_signature='')
def DeleteEnrolledFingers(self, user):
logging.debug('In DeleteEnrolledFingers %s' % user)
usr = self.user2record(user)
@ -94,9 +89,7 @@ class Device(dbus.service.Object):
db.del_record(usr.dbid)
@dbus.service.method(dbus_interface=INTERFACE_NAME,
in_signature='ss',
out_signature='')
@dbus.service.method(dbus_interface=INTERFACE_NAME, in_signature='ss', out_signature='')
def VerifyStart(self, user, finger):
logging.debug('In VerifyStart for %s, %s' % (user, finger))
@ -130,15 +123,11 @@ class Device(dbus.service.Object):
thread.daemon = True
thread.start()
@dbus.service.method(dbus_interface=INTERFACE_NAME,
in_signature='',
out_signature='')
@dbus.service.method(dbus_interface=INTERFACE_NAME, in_signature='', out_signature='')
def Cancel(self):
sensor.cancel()
@dbus.service.method(dbus_interface=INTERFACE_NAME,
in_signature='ss',
out_signature='')
@dbus.service.method(dbus_interface=INTERFACE_NAME, in_signature='ss', out_signature='')
def EnrollStart(self, user, finger_name):
logging.debug('In EnrollStart %s for %s' % (finger_name, user))
@ -169,11 +158,9 @@ class Device(dbus.service.Object):
logging.exception(e)
self.EnrollStatus('enroll-failed', True)
if index == None:
logging.exception(
'Unknown finger name passed to enroll? ' +
finger_name + ' (' + winbio_name + ')'
)
if index is None:
logging.exception('Unknown finger name passed to enroll? ' + finger_name + ' (' +
winbio_name + ')')
self.EnrollStatus('enroll-failed', True)
else:
thread = Thread(target=run)
@ -192,9 +179,7 @@ class Device(dbus.service.Object):
def EnrollStatus(self, result, done):
logging.debug('EnrollStatus')
@dbus.service.method(dbus_interface=INTERFACE_NAME,
in_signature='s',
out_signature='s')
@dbus.service.method(dbus_interface=INTERFACE_NAME, in_signature='s', out_signature='s')
def RunCmd(self, cmd):
logging.debug('RunCmd')
return hexlify(tls.app(unhexlify(cmd))).decode()
@ -228,7 +213,10 @@ def main():
parser = argparse.ArgumentParser('Open fprintd DBus service')
parser.add_argument('--debug', help='Enable tracing', action='store_true')
parser.add_argument('--devpath', help='USB device path: usb-<busnum>-<address>')
parser.add_argument('--configpath', default='/etc/python-validity', type=Path, help='Path to config files')
parser.add_argument('--configpath',
default='/etc/python-validity',
type=Path,
help='Path to config files')
args = parser.parse_args()
if args.debug:

View file

@ -1,13 +1,11 @@
#!/usr/bin/env python3
import argparse
import re
import dbus
import dbus.mainloop.glib
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
from gi.repository import GObject, GLib
import sys
import dbus.mainloop.glib
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
bus = dbus.SystemBus()
o = bus.get_object('net.reactivated.Fprint', '/net/reactivated/Fprint/Manager', introspect=False)
o = o.GetDefaultDevice()

View file

@ -1,6 +1,5 @@
from validitysensor.usb import usb
from validitysensor.sensor import factory_reset, RebootException
from validitysensor.usb import usb
try:
usb.open()

View file

@ -1,13 +1,8 @@
#!/usr/bin/env python3
import argparse
import re
import dbus
import dbus.mainloop.glib
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
from gi.repository import GObject, GLib
import pwd
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
bus = dbus.SystemBus()
o = bus.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus')
@ -16,10 +11,10 @@ ls = o.ListNames()
for n in ls:
if n[0] != ':':
continue
pid = o.GetConnectionUnixProcessID(n)
with open('/proc/%d/cmdline' % pid) as f:
s=f.read()
s=s.split('\0')
s = f.read()
s = s.split('\0')
print('%-10s %-5d %s' % (n, pid, ' '.join(s)))

View file

@ -1,3 +1,7 @@
import code
import logging
from binascii import hexlify
from validitysensor.tls import tls
from validitysensor.usb import usb
from validitysensor.db import db
@ -7,11 +11,10 @@ from validitysensor.sid import *
from validitysensor.init import open as open9x
from threading import Condition
from time import sleep
import logging
import code
#usb.trace_enabled = True
#tls.trace_enabled = True
# usb.trace_enabled = True
# tls.trace_enabled = True
def identify():
def update_cb(e):
@ -21,6 +24,7 @@ def identify():
print('Got finger %x for user recordid %d. Hash: %s' % (subtype, usrid, hexlify(hsh).decode()))
def enroll(sid, finger):
def update_cb(x, e):
if e is not None:
@ -31,4 +35,3 @@ def enroll(sid, finger):
recid = sensor.enroll(sid, finger, update_cb)
print('Created a finger record with dbid %d' % recid)

View file

@ -3,26 +3,19 @@
from setuptools import setup
setup(name='python-validity',
version='0.9',
py_modules = [],
packages=['validitysensor'],
scripts=[
'bin/validity-led-dance',
'bin/validity-sensors-firmware',
],
install_requires=[
'cryptography >= 2.1.4',
'pyusb >= 1.0.0',
'pyyaml >= 3.12'
],
data_files=[
('share/dbus-1/system.d/', ['dbus_service/io.github.uunicorn.Fprint.conf']),
('lib/python-validity/', ['dbus_service/dbus-service']),
('share/python-validity/playground/', [
'scripts/dbus-cmd.py',
'scripts/lsdbus.py',
'scripts/factory-reset.py',
'scripts/prototype.py'
]),
]
)
version='0.9',
py_modules=[],
packages=['validitysensor'],
scripts=[
'bin/validity-led-dance',
'bin/validity-sensors-firmware',
],
install_requires=['cryptography >= 2.1.4', 'pyusb >= 1.0.0', 'pyyaml >= 3.12'],
data_files=[
('share/dbus-1/system.d/', ['dbus_service/io.github.uunicorn.Fprint.conf']),
('lib/python-validity/', ['dbus_service/dbus-service']),
('share/python-validity/playground/', [
'scripts/dbus-cmd.py', 'scripts/lsdbus.py', 'scripts/factory-reset.py',
'scripts/prototype.py'
]),
])

View file

@ -1,13 +1,4 @@
from enum import Enum, auto
class Blobs(Enum):
init_hardcoded = auto()
init_hardcoded_clean_slate = auto()
reset_blob = auto()
db_write_enable = auto()
def __load_blob(blob):
def __load_blob(blob: str) -> bytes:
from .usb import usb
if usb.usb_dev().idVendor == 0x138a:
@ -22,6 +13,8 @@ def __load_blob(blob):
globals()[blob] = getattr(blobs, blob)
return globals()[blob]
for p in dir(Blobs):
if isinstance(getattr(Blobs, p), Blobs):
globals()[p] = lambda bname=p: __load_blob(bname)
init_hardcoded = lambda: __load_blob('init_hardcoded')
init_hardcoded_clean_slate = lambda: __load_blob('init_hardcoded_clean_slate')
reset_blob = lambda: __load_blob('reset_blob')
db_write_enable = lambda: __load_blob('db_write_enable')

View file

@ -1,7 +1,6 @@
from .util import unhex
init_hardcoded=unhex('''
init_hardcoded = unhex('''
06020000013917b3dda91383b5bcac64fa4ad35dce96570a9d2d974b80926a431f9cd46248980a263c6fcef6a82839a90b59ac590848859
afac817b7d53bf51cd3205c1b8f43048be8253c3bd247937c837aca8b18d3cc8ee8c8971ac4f688813cf3d8550d71496985b7ec07ff2dc7
896d330fdab263a0ee433a5c4bc910439d1c6161853feb03f5502209502e7308beb7919473cfe69f422c30502d226a4d0a34d96c8c77956
@ -13,9 +12,9 @@ e024ca6b9a48332c1a69a5a3fdd24b964cf7e7c55229bb0b48a6e339eb2c42d07ec850a4ee780660
b3d5cad8d5bd7cea37e58a31307a6d50e6ae379a53f1366678c0741a3d872b8dcfefa7f63128dc8245
''')
init_hardcoded_clean_slate=unhex('')
init_hardcoded_clean_slate = unhex('')
reset_blob=unhex('''
reset_blob = unhex('''
0602000001d6123241376f110935a7ae38b614ced9952eaa38e2984842d0552d984b69ab5c1a70175513319970225d9ca25be063a7d70a2
9dff803240c099ba5386910b69c3b7ca8d0b26ec9a5684fe92af9c6d8068ace0954eb8582adc6208aa6c116b1778ff531dd2b6817a10d66
7e0385d18ac7ccb47eb67f1f54b5b94c84d65529c6e9fe9039218ae9cde123f38ffa52a953ed589d0d8bb48680aeea6544b7ceedbea3216
@ -226,7 +225,7 @@ f72aea07e183577f591a081845ea340797b79c6c8742e8826a6d7df773ec8564025fbb570bfbc001
a5d4483f1
''')
db_write_enable=unhex('''
db_write_enable = unhex('''
06020000015ddf5d76a8e3bab8b10d9f82f0b31652d5b208dff1d20745b7c5442e09db880c80ca103d5b2071d8bdcaab452b900d1785be2
de478669e72a9d082273f0f6176b700ffb65a026af052e76de5f9e247e994bed7c79e34815b465a8070a76da7d365525d7285dfb152d24c
732a471f031d22ebb67d6e27bfff74b3ab1c4780461a460c0ea5710fbd32ab59a6ca9ca3e3e24264640b15245a6c48b6bd20c6848c2307e
@ -262,7 +261,7 @@ a2da95eb8445a6381f3941917bed7fcf01ab199228eadd1968847e4b9a40022d2b0ec68318abf97c
''')
# FIXME this must be very specific to a particular device and constructed on the fly from multiple hardcoded tables:
identify_prg=unhex('''
identify_prg = unhex('''
02980000002300000020000800002000800000010032007000000000802020050024200000502077362820010030200100082170000c210
000482102004c210000582000005c20000060200000682005006c20012970200121742001887820018084202000942001809c200902a020
0b19b4200000b8203b04bc201400c0200200c4200100c82002003300100000000080cc200000f503d0200000a1013200440000000080dc2
@ -295,7 +294,7 @@ c1e1e1c221f201d21201e1c1f34242221201f20221f201e241e241d2020221e2420231d221e211e1
''')
# The following blob has only 1 byte difference from the above
enroll_prg=unhex('''
enroll_prg = unhex('''
02980000002300000020000800002000800000010032007000000000802020050024200000502077362820010030200100082170000c210
000482102004c210000582000005c20000060200000682005006c20012970200121742001887820018084202000942001809c200902a020
0b19b4200000b8203b04bc201400c0200200c4200100c82002003300100000000080cc200000f503d0200000a1013200440000000080dc2
@ -327,7 +326,7 @@ c1e1e1c221f201d21201e1c1f34242221201f20221f201e241e241d2020221e2420231d221e211e1
81808180818081808180818081808180818081808080808080808080807f807f807f807f7f7e7e
''')
calibrate_prg=unhex('''
calibrate_prg = unhex('''
0298006103230000002000080000200080000001003200700000000080202005002420000050207736282
0010030200100082170000c210000482102004c210000582000005c20000060200000682005006c200129
70200121742001887820018084202000942001809c200902a0200b19b4200000b8203b04bc201400c0200
@ -365,4 +364,3 @@ c2d182e1e30182e1c321d341d341e321c301e1e241e201f201d1c321a301e1c211e21341f1e20202
8080808180818081808080818081808180818081808180808081808180818081808180818081808180818
0818081808180818081808080808080808080807f807f807f807f7f7e7e
''')

View file

@ -1,7 +1,6 @@
from .util import unhex
init_hardcoded=unhex('''
init_hardcoded = unhex('''
06020000014a231406e5542fc6dc3b1aedebe68f55596ad3ca13f6e019994c6f71672fff756fbde0511d09d45978b12ba415b3694a0e763
48c8cfe9dbb9abf86813fc0c67c1005519a6f87360c2fb3e12bd0a9e012b06d9f5c9b44ccc6645b0fbd47afe45c8c874fcb88fbfd18fb7a
9b3241351f256acce689f9586a52b01f8fdcb66cdf3b340b1f9f386d58ca24fdfcdfbcebefb5f3a3c2a08357721040235a20ce1ee2f4f78
@ -15,7 +14,7 @@ f3135c5e78820e36653fa3db535f57c71897242939d7da50f81070ce9ab81c61af6ac29a6c6c4a5d
2999d1c0e7acf67e598696cd58cc4bdb1b7c037ee9a085f784c4
''')
init_hardcoded_clean_slate=unhex('''
init_hardcoded_clean_slate = unhex('''
06020000012c40c9d271378bc0912ef5dced69bd81b7fc16972c7b46e621af54a00e2cc6baca6eb83ea30222dfc6c925262006ae93412ea
cf482f2034ee7b13297474b7e1e91f279cac2ccb7195443e4dd3328cfd292ade073fcc2eaa8f07b77231130ba997f921b9be7b4fb6cc691
0d2976b3e050913b27dbe73afd6e964260b9435ebab5117e71f7cb68464d4b6f8afc7e1a421f671f5854a1d0c8ab93ed3b88b2bc1a42875
@ -32,7 +31,7 @@ b4c74c39900830abc6906a1004bef1b5b7dbbbeb5ec1b22604ac86429b9f56511b746a7124c449b8
aa41249faeef4d838e280cb5d6fc19cfe86c75f
''')
reset_blob=unhex('''
reset_blob = unhex('''
06020000018772bd56dd58d64023e1745f7c253a49b32dd6a02bc32347195b6763bfcc23c9e0beb0c5809e06a5628629f28c4048530a5cd
df6f48391ea0c2cb5a7ffe93ef04c8b4dad584117e65aac085c25062a0f12a8ee432c7ecbb6613c28b743e4a75e382afc6b8037e342d466
7b66a73691edc6b25698c15e78d9d67f7cc56274e99e6b7bb5fba32dd42d74dfa672f414c4a29302b30a202d00a2571d2a884169e82106c
@ -252,7 +251,7 @@ f20332657d2ca6728b9865a6bfdc9a9055a6ab86cb782307c2c0255525884bf8060f8aed7ec034f3
20f8bb8d94784228934870046f60ac937af4957c9414bcc33895fcc183062be4e4bff56f9c89838ead8e433dc604536938
''')
db_write_enable=unhex('''
db_write_enable = unhex('''
0602000001f48001074892b6c57deb7889b5ebf86bc3040f6d91ff1f68765f046591184be08cf36c154b7ec5368139d0f9532382214379a
ff3ffbfe4659e2f274e864bd0ad660f99e21da2bab677dbfa907a66ce110c180d2ddc5dfe40b8ed975cbedffc11631f12f8bd646a0ee82d
44d2a6c1ec9cfbd40f485cb3d9124376b97b4a3349b0a730adda626d8ac28ec20e886aab1b8851deee3431c4d89c8bb3e787eaa9c0323df

View file

@ -1,7 +1,6 @@
from .util import unhex
init_hardcoded=unhex('''
init_hardcoded = unhex('''
06020000014a231406e5542fc6dc3b1aedebe68f55596ad3ca13f6e019994c6f71672fff756fbde0511d09d45978b12ba415b3694a0e763
48c8cfe9dbb9abf86813fc0c67c1005519a6f87360c2fb3e12bd0a9e012b06d9f5c9b44ccc6645b0fbd47afe45c8c874fcb88fbfd18fb7a
9b3241351f256acce689f9586a52b01f8fdcb66cdf3b340b1f9f386d58ca24fdfcdfbcebefb5f3a3c2a08357721040235a20ce1ee2f4f78
@ -15,7 +14,7 @@ f3135c5e78820e36653fa3db535f57c71897242939d7da50f81070ce9ab81c61af6ac29a6c6c4a5d
2999d1c0e7acf67e598696cd58cc4bdb1b7c037ee9a085f784c4
''')
init_hardcoded_clean_slate=unhex('''
init_hardcoded_clean_slate = unhex('''
06020000012c40c9d271378bc0912ef5dced69bd81b7fc16972c7b46e621af54a00e2cc6baca6eb83ea30222dfc6c925262006ae93412ea
cf482f2034ee7b13297474b7e1e91f279cac2ccb7195443e4dd3328cfd292ade073fcc2eaa8f07b77231130ba997f921b9be7b4fb6cc691
0d2976b3e050913b27dbe73afd6e964260b9435ebab5117e71f7cb68464d4b6f8afc7e1a421f671f5854a1d0c8ab93ed3b88b2bc1a42875
@ -32,7 +31,7 @@ b4c74c39900830abc6906a1004bef1b5b7dbbbeb5ec1b22604ac86429b9f56511b746a7124c449b8
aa41249faeef4d838e280cb5d6fc19cfe86c75f
''')
reset_blob=unhex('''
reset_blob = unhex('''
06020000018772bd56dd58d64023e1745f7c253a49b32dd6a02bc32347195b6763bfcc23c9e0beb0c5809e06a5628629f28c4048530a5cd
df6f48391ea0c2cb5a7ffe93ef04c8b4dad584117e65aac085c25062a0f12a8ee432c7ecbb6613c28b743e4a75e382afc6b8037e342d466
7b66a73691edc6b25698c15e78d9d67f7cc56274e99e6b7bb5fba32dd42d74dfa672f414c4a29302b30a202d00a2571d2a884169e82106c
@ -252,7 +251,7 @@ f20332657d2ca6728b9865a6bfdc9a9055a6ab86cb782307c2c0255525884bf8060f8aed7ec034f3
20f8bb8d94784228934870046f60ac937af4957c9414bcc33895fcc183062be4e4bff56f9c89838ead8e433dc604536938
''')
db_write_enable=unhex('''
db_write_enable = unhex('''
0602000001f48001074892b6c57deb7889b5ebf86bc3040f6d91ff1f68765f046591184be08cf36c154b7ec5368139d0f9532382214379a
ff3ffbfe4659e2f274e864bd0ad660f99e21da2bab677dbfa907a66ce110c180d2ddc5dfe40b8ed975cbedffc11631f12f8bd646a0ee82d
44d2a6c1ec9cfbd40f485cb3d9124376b97b4a3349b0a730adda626d8ac28ec20e886aab1b8851deee3431c4d89c8bb3e787eaa9c0323df

View file

@ -1,62 +1,70 @@
import typing
from .tls import tls
from .util import assert_status
from binascii import hexlify
from struct import pack, unpack
from .blobs import db_write_enable
from .flash import call_cleanups
from .sid import *
from .sid import SidIdentity, sid_from_bytes
from .tls import tls
from .util import assert_status
from .winbio_constants import finger_names
class UserStorage():
def __init__(self, dbid, name):
self.dbid=dbid
self.name=name
self.users=[]
class UserStorage:
def __init__(self, dbid: int, name: str):
self.dbid = dbid
self.name = name
self.users = []
def __repr__(self):
return '<UserStorage: dbid=%04x name=%s users=%s>' % (self.dbid, repr(self.name), repr(self.users))
return '<UserStorage: dbid=%04x name=%s users=%s>' % (self.dbid, repr(
self.name), repr(self.users))
class User():
def __init__(self, dbid, identity):
self.dbid=dbid
self.identity=identity
self.fingers=[]
class User:
def __init__(self, dbid: int, identity: str):
self.dbid = dbid
self.identity = identity
self.fingers: typing.List[typing.Mapping[str, int]] = []
def __repr__(self):
return '<User: dbid=%04x identity=%s fingers=%s>' % (self.dbid, repr(self.identity), repr(self.fingers))
return '<User: dbid=%04x identity=%s fingers=%s>' % (self.dbid, repr(
self.identity), repr(self.fingers))
def subtype_to_string(s: int):
finger_name = finger_names.get(s, None)
return finger_name or 'Unknown'
def parse_user_storage(rsp):
def parse_user_storage(rsp: bytes):
rc, = unpack('<H', rsp[:2])
if rc == 0x04b3:
return None
assert_status(rsp[:2])
rsp=rsp[2:]
rsp = rsp[2:]
hdr, rsp = rsp[:8], rsp[8:]
recid, usercnt, namesz, unknwn = unpack('<HHHH', hdr)
usrtab, rsp = rsp[:4*usercnt], rsp[4*usercnt:]
usrtab, rsp = rsp[:4 * usercnt], rsp[4 * usercnt:]
name, rsp = rsp[:namesz], rsp[namesz:]
if len(rsp) > 0:
raise Exception('Junk at the end of the storage info response: %s' % rsp.hex())
storage=UserStorage(recid, name)
storage = UserStorage(recid, name)
while len(usrtab) > 0:
rec, usrtab = usrtab[:4], usrtab[4:]
urid, valsz = unpack('<HH', rec)
storage.users += [ { 'dbid': urid, 'valueSize': valsz } ]
storage.users += [{'dbid': urid, 'valueSize': valsz}]
return storage
def parse_identity(b):
def parse_identity(b: bytes):
t, b = b[:4], b[4:]
t, = unpack('<L', t)
@ -65,45 +73,48 @@ def parse_identity(b):
l, = unpack('<L', l)
return sid_from_bytes(b[:l])
raise Exception('Don''t know how to handle identity type %d' % t)
raise Exception('Don' 't know how to handle identity type %d' % t)
def parse_user(rsp: bytes):
assert_status(rsp[:2])
rsp=rsp[2:]
rsp = rsp[2:]
hdr, rsp = rsp[:8], rsp[8:]
recid, fingercnt, unknwn, identitysz = unpack('<HHHH', hdr)
fingertab, rsp = rsp[:8*fingercnt], rsp[8*fingercnt:]
fingertab, rsp = rsp[:8 * fingercnt], rsp[8 * fingercnt:]
identity, rsp = rsp[:identitysz], rsp[identitysz:]
if len(rsp) > 0:
raise Exception('Junk at the end of the user info response: %s' % rsp.hex())
identity = parse_identity(identity)
user=User(recid, identity)
user = User(recid, identity)
while len(fingertab) > 0:
rec, fingertab = fingertab[:8], fingertab[8:]
frid, subtype, stgid, valsz = unpack('<HHHH', rec)
user.fingers += [ { 'dbid': frid, 'subtype': subtype, 'storage': stgid, 'valueSize': valsz } ]
user.fingers += [{'dbid': frid, 'subtype': subtype, 'storage': stgid, 'valueSize': valsz}]
return user
def identity_to_bytes(identity: str):
if isinstance(identity, SidIdentity):
b=identity.to_bytes()
b = identity.to_bytes()
b = pack('<LL', 3, len(b)) + b
# May not be neccessary, but windows union has a minimum size of 0x4c bytes
# May not be neccessary, but windows union has a minimum size of 0x4c bytes
# and search by identity treats same SIDs with different sizes as different keys
while len(b) < 0x4c:
b += b'\0'
return b
else:
raise Exception('Don''t know how to handle identity %s' % repr(identity))
class DbRecord():
raise Exception('Don' 't know how to handle identity %s' % repr(identity))
class DbRecord:
def __init__(self):
self.dbid = 0
self.type = 0
@ -113,29 +124,24 @@ class DbRecord():
def __repr__(self):
return '<DbRecord: dbid=%d type=%d storage=%d value=%s children=%s>' % (
self.dbid,
self.type,
self.storage,
repr(self.value),
repr(self.children)
)
self.dbid, self.type, self.storage, repr(self.value), repr(self.children))
class Db():
class Info():
def __init__(self, total, used, free, records, roots):
self.total = total # partition size
self.used = used # used (not deleted)
self.free = free # unallocated space
self.records = records # total number, including deleted
class Db:
class Info:
def __init__(self, total: int, used: int, free: int, records: int, roots):
self.total = total # partition size
self.used = used # used (not deleted)
self.free = free # unallocated space
self.records = records # total number, including deleted
self.roots = roots
def __repr__(self):
return 'Db.Info(total=%d, used=%d, free=%d, records=%d, roots=%s)' % (
self.total, self.used, self.free, self.records, repr(self.roots))
self.total, self.used, self.free, self.records, repr(self.roots))
def get_user_storage(self, dbid=0, name=''):
name=name.encode()
name = name.encode()
if len(name) > 0:
name += b'\0'
@ -148,15 +154,15 @@ class Db():
def get_storage_data(self):
stg = self.get_user_storage(name='StgWindsor')
rc = self.get_record_children(stg.dbid).children
return [i['dbid'] for i in rc if i['type'] == 8] # 8 == "data" type
return [i['dbid'] for i in rc if i['type'] == 8] # 8 == "data" type
def get_user(self, dbid):
def get_user(self, dbid: int):
return parse_user(tls.cmd(pack('<BHHH', 0x4a, dbid, 0, 0)))
def lookup_user(self, identity: str) -> typing.Optional[User]:
stg = self.get_user_storage(name='StgWindsor')
data = identity_to_bytes(identity)
rsp = tls.cmd(pack('<BHHH', 0x4a, 0, stg.dbid, len(data)) + data)
rc, = unpack('<H', rsp[:2])
@ -165,31 +171,31 @@ class Db():
else:
return parse_user(rsp)
def get_record_value(self, dbid):
def get_record_value(self, dbid: int):
rsp = tls.cmd(pack('<BH', 0x49, dbid))
assert_status(rsp)
rec = DbRecord()
rec.dbid, rec.type, rec.storage, sz = unpack('<xxHHHHxx', rsp[:12])
rec.value = rsp[12:12+sz]
rec.value = rsp[12:12 + sz]
return rec
def get_record_children(self, dbid):
def get_record_children(self, dbid: int):
rsp = tls.cmd(pack('<BH', 0x46, dbid))
assert_status(rsp)
rec = DbRecord()
rec.dbid, rec.type, rec.storage, sz, cnt = unpack('<xxHHHHHxx', rsp[:14])
rsp = rsp[14:]
rec.children=[]
rec.children = []
for i in range(0, cnt):
dbid, typ = unpack('<HH', rsp[i*4:i*4+4])
rec.children += [{ 'dbid': dbid, 'type': typ }]
dbid, typ = unpack('<HH', rsp[i * 4:i * 4 + 4])
rec.children += [{'dbid': dbid, 'type': typ}]
return rec
def del_record(self, dbid):
def del_record(self, dbid: int):
assert_status(tls.cmd(pack('<BH', 0x48, dbid)))
def db_info(self):
@ -200,12 +206,12 @@ class Db():
unknown1, unknown0, total, used, free, records, nroots = unpack('<LLLLLHH', rsp[:0x18])
# Seems to always be unknown1 == 1, unknown0 == 0
rsp = rsp[0x18:]
roots = [unpack('<H', rsp[i*2:i*2+2])[0] for i in range(0, nroots)]
roots = [unpack('<H', rsp[i * 2:i * 2 + 2])[0] for i in range(0, nroots)]
return Db.Info(total, used, free, records, roots)
def new_record(self, parent, typ, storage, data):
self.db_info() # TODO check free space, compact the partition when out of storage
def new_record(self, parent: int, typ: int, storage: int, data: bytes):
self.db_info() # TODO check free space, compact the partition when out of storage
assert_status(tls.cmd(db_write_enable))
try:
rsp = tls.cmd(pack('<BHHHH', 0x47, parent, typ, storage, len(data)) + data)
@ -215,21 +221,21 @@ class Db():
call_cleanups()
return recid
def new_user(self, identity):
def new_user(self, identity: str):
data = identity_to_bytes(identity)
stg = self.get_user_storage(name='StgWindsor')
rec = self.new_record(stg.dbid, 5, stg.dbid, data)
return rec
def new_finger(self, userid, template):
def new_finger(self, userid: int, template: bytes):
stg = self.get_user_storage(name='StgWindsor')
# We ask to create an object of type 0xb,
# We ask to create an object of type 0xb,
# but because of the magical `db_write_enable` in the new_record() it ends up being 0x6
rec = self.new_record(userid, 0xb, stg.dbid, template)
return rec
def new_data(self, parent, data):
def new_data(self, parent: int, data: bytes):
stg = self.get_user_storage(name='StgWindsor')
data = pack('<HH', 1, len(data)) + data
rec = self.new_record(parent, 0x8, stg.dbid, data)
@ -240,11 +246,11 @@ class Db():
val = hexlify(rec.value).decode()
if len(val) > 80:
val = val[:80] + '...'
print('%s%d (type %d) %s' % (' '*depth, rec.dbid, rec.type, val))
print('%s%d (type %d) %s' % (' ' * depth, rec.dbid, rec.type, val))
rec = self.get_record_children(root)
for c in rec.children:
self.dump_raw(c['dbid'], depth+1)
self.dump_raw(c['dbid'], depth + 1)
def dump_all(self):
stg = self.get_user_storage(name='StgWindsor')
@ -252,7 +258,8 @@ class Db():
for u in usrs:
print('%2d: User %s with %d fingers:' % (u.dbid, repr(u.identity), len(u.fingers)))
for f in u.fingers:
print(' %2d: %02x (%s)' % (f['dbid'], f['subtype'], subtype_to_string(f['subtype'])))
print(' %2d: %02x (%s)' %
(f['dbid'], f['subtype'], subtype_to_string(f['subtype'])))
db = Db()

View file

@ -1,50 +1,66 @@
from .tls import tls
import typing
from struct import pack, unpack
from .util import assert_status, unhex
from .blobs import db_write_enable
from .hw_tables import flash_ic_table_lookup
from .hw_tables import flash_ic_table_lookup, FlashIcInfo
from .tls import tls
from .util import assert_status, unhex
class FlashInfo():
def __init__(self, ic, blocks, unknown0, blocksize, unknown1, partitions):
self.ic, self.blocks, self.unknown0, self.blocksize, self.unknown1, self.partitions = ic, blocks, unknown0, blocksize, unknown1, partitions
def __repr__(self):
return 'FlashInfo(%s, 0x%x, 0x%x, 0x%x, 0x%x, %s)' % (repr(self.ic), self.blocks, self.unknown0, self.blocksize, self.unknown1, repr(self.partitions))
# type 01 is for the firmware - written blocks are decrypted on the fly using fw key
# access lvl:
# 2 -- write only
# 7 -- can read/write even without TLS
class PartitionInfo():
def __init__(self, id, type, access_lvl, offset, size):
class PartitionInfo:
def __init__(self, id: int, type: int, access_lvl: int, offset: int, size: int):
self.id, self.type, self.access_lvl, self.offset, self.size = id, type, access_lvl, offset, size
def __repr__(self):
return 'PartitionInfo(0x%02x, 0x%02x, 0x%04x, 0x%08x, 0x%08x)' % (self.id, self.type, self.access_lvl, self.offset, self.size)
return 'PartitionInfo(0x%02x, 0x%02x, 0x%04x, 0x%08x, 0x%08x)' % (
self.id, self.type, self.access_lvl, self.offset, self.size)
class FlashInfo:
def __init__(self, ic: FlashIcInfo, blocks: int, unknown0: int, blocksize: int, unknown1: int,
partitions: typing.Sequence[PartitionInfo]):
self.ic = ic
self.blocks = blocks
self.unknown0 = unknown0
self.blocksize = blocksize
self.unknown1 = unknown1
self.partitions = partitions
def __repr__(self):
return 'FlashInfo(%s, 0x%x, 0x%x, 0x%x, 0x%x, %s)' % (repr(
self.ic), self.blocks, self.unknown0, self.blocksize, self.unknown1,
repr(self.partitions))
def get_flash_info():
rsp=tls.cmd(unhex('3e'))
rsp = tls.cmd(unhex('3e'))
assert_status(rsp)
rsp=rsp[2:]
hdr=rsp[:0xe]
rsp=rsp[0xe:]
rsp = rsp[2:]
hdr = rsp[:0xe]
rsp = rsp[0xe:]
jid0, jid1, blocks, unknown0, blocksize, unknown1, pcnt = unpack('<HHHHHHH', hdr)
ic=flash_ic_table_lookup(jid0, jid1, blocks*blocksize)
if ic == None:
raise Exception('Unknown flash IC. JEDEC id=%x:%x, size=%dx%d' % (jid0, jid1, blocks, blocksize))
ic = flash_ic_table_lookup(jid0, jid1, blocks * blocksize)
partitions=[rsp[i*0xc:(i+1)*0xc] for i in range(0, pcnt)]
partitions=[unpack('<BBHLL', i) for i in partitions]
partitions=[PartitionInfo(*i) for i in partitions]
if ic is None:
raise Exception('Unknown flash IC. JEDEC id=%x:%x, size=%dx%d' %
(jid0, jid1, blocks, blocksize))
partitions = [rsp[i * 0xc:(i + 1) * 0xc] for i in range(0, pcnt)]
partitions = [unpack('<BBHLL', i) for i in partitions]
partitions = [PartitionInfo(*i) for i in partitions]
return FlashInfo(ic, blocks, unknown0, blocksize, unknown1, partitions)
# >>> 4302 -- get partition header (get fwext info)
# b004 -- no fw detected
# 0000
# 0100 (major) 0100 (minor) 0800 (modules) c28c745a (buildtime)
# 0100 (major) 0100 (minor) 0800 (modules) c28c745a (buildtime)
# type subtype major minor size
# 0100 3446 0200 0700 d03e0000
# 0100 8408 0100 0700 00040000
@ -54,64 +70,74 @@ def get_flash_info():
# 0200 2377 0000 0100 802f0000
# 0200 6637 0100 0c00 f0220200
# 0100 2556 0000 0100 60040000
class ModuleInfo():
def __init__(self, type, subtype, major, minor, size):
class ModuleInfo:
def __init__(self, type: int, subtype: int, major: int, minor: int, size: int):
self.type, self.subtype, self.major, self.minor, self.size = type, subtype, major, minor, size
def __repr__(self):
return 'ModuleInfo(0x%04x, 0x%04x, %d, %d, %d)' % (self.type, self.subtype, self.major, self.minor, self.size)
return 'ModuleInfo(0x%04x, 0x%04x, %d, %d, %d)' % (self.type, self.subtype, self.major,
self.minor, self.size)
class FirmwareInfo():
def __init__(self, major, minor, buildtime, modules):
class FirmwareInfo:
def __init__(self, major: int, minor: int, buildtime: int,
modules: typing.Sequence[ModuleInfo]):
self.major, self.minor, self.buildtime, self.modules = major, minor, buildtime, modules
def __repr__(self):
return 'FirmwareInfo(%d, %d, %d, %s)' % (self.major, self.minor, self.buildtime, repr(self.modules))
return 'FirmwareInfo(%d, %d, %d, %s)' % (self.major, self.minor, self.buildtime,
repr(self.modules))
def get_fw_info(partition):
rsp=tls.cmd(pack('<BB', 0x43, partition))
def get_fw_info(partition: int):
rsp = tls.cmd(pack('<BB', 0x43, partition))
# don't want to throw exception here - it is normal not to have FW when we're about to upload it
if len(rsp) == 2 and rsp[1] == 4 and rsp[0] == 0xb0:
return None
assert_status(rsp)
rsp=rsp[2:]
hdr=rsp[:0xa]
rsp=rsp[0xa:]
rsp = rsp[2:]
hdr = rsp[:0xa]
rsp = rsp[0xa:]
major, minor, modcnt, buildtime = unpack('<HHHL', hdr)
modules=[rsp[i*0xc:(i+1)*0xc] for i in range(0, modcnt)]
modules=[unpack('<HHHHL', i) for i in modules]
modules=[ModuleInfo(*i) for i in modules]
modules = [rsp[i * 0xc:(i + 1) * 0xc] for i in range(0, modcnt)]
modules = [unpack('<HHHHL', i) for i in modules]
modules = [ModuleInfo(*i) for i in modules]
return FirmwareInfo(major, minor, buildtime, modules)
def write_enable():
assert_status(tls.cmd(db_write_enable))
def call_cleanups():
rsp = tls.cmd(b'\x1a')
err = unpack('<H', rsp[:2])[0]
if err == 0x0491: # Nothing to commit
return # don't throw an exception, just ignore
if err == 0x0491: # Nothing to commit
return # don't throw an exception, just ignore
assert_status(rsp)
def erase_flash(partition):
def erase_flash(partition: int):
assert_status(tls.cmd(db_write_enable))
try:
assert_status(tls.cmd(pack('<BB', 0x3f, partition)))
finally:
call_cleanups()
def read_flash(partition, addr, size):
def read_flash(partition: int, addr: int, size: int) -> bytes:
cmd = pack('<BBBHLL', 0x40, partition, 1, 0, addr, size)
rsp = tls.cmd(cmd)
assert_status(rsp)
sz, = unpack('<xxLxx', rsp[:8])
return rsp[8:8+sz]
return rsp[8:8 + sz]
def write_flash(partition, addr, buf):
def write_flash(partition: int, addr: int, buf: bytes):
tls.cmd(db_write_enable)
cmd = pack('<BBBHLL', 0x41, partition, 1, 0, addr, len(buf)) + buf
try:
@ -120,21 +146,25 @@ def write_flash(partition, addr, buf):
finally:
call_cleanups()
def write_flash_all(partition, ptr, buf):
def write_flash_all(partition: int, ptr: int, buf: bytes):
bs = 0x1000
while len(buf) > 0:
chunk, buf = buf[:bs], buf[bs:]
chunk, buf = buf[:bs], buf[bs:]
write_flash(partition, ptr, chunk)
ptr += len(chunk)
def read_flash_all(partition, start, size):
def read_flash_all(partition: int, start: int, size: int):
bs = 0x1000
blocks = [read_flash(partition, addr, bs) for addr in range(start, start+size, bs)]
blocks = [read_flash(partition, addr, bs) for addr in range(start, start + size, bs)]
return b''.join(blocks)[:size]
def write_fw_signature(partition, signature):
rsp=tls.cmd(pack('<BBxH', 0x42, partition, len(signature)) + signature)
def write_fw_signature(partition: int, signature: bytes):
rsp = tls.cmd(pack('<BBxH', 0x42, partition, len(signature)) + signature)
assert_status(rsp)
def read_tls_flash():
return read_flash(1, 0, 0x1000)

View file

@ -1,81 +1,775 @@
from .table_types import SensorTypeInfo, SensorCaptureProg
SensorTypeInfo.table=[
SensorTypeInfo(sensor_type=0x00db, bytes_per_line=0x98, repeat_multiplier=1, lines_per_calibration_data=144, line_width=144, calibration_blob='101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f'),
SensorTypeInfo(sensor_type=0x00e4, bytes_per_line=0x78, repeat_multiplier=2, lines_per_calibration_data=100, line_width=112, calibration_blob='9392918f8e8d8b8a898786858382817f7e7d7b7a797776757372716f6e6d6b6a696766656362615f5e5d5b5a595756555251504e4d4c4a49484645444241403e3d3c3a39383635343231302e2d2c2a29282625242221201e1d1c1a19181615141211100e'),
SensorTypeInfo(sensor_type=0x00ed, bytes_per_line=0x78, repeat_multiplier=2, lines_per_calibration_data=112, line_width=112, calibration_blob='9b9a999796959392918f8e8d8b8a898786858382817f7e7d7b7a797776757372716f6e6d6b6a696766656362615f5e5d5b5a595756555251504e4d4c4a49484645444241403e3d3c3a39383635343231302e2d2c2a29282625242221201e1d1c1a19181615141211100e0d0c0a090806'),
SensorTypeInfo(sensor_type=0x0199, bytes_per_line=0x78, repeat_multiplier=2, lines_per_calibration_data=112, line_width=112, calibration_blob='9b9a999796959392918f8e8d8b8a898786858382817f7e7d7b7a797776757372716f6e6d6b6a696766656362615f5e5d5b5a595756555251504e4d4c4a49484645444241403e3d3c3a39383635343231302e2d2c2a29282625242221201e1d1c1a19181615141211100e0d0c0a090806'),
SensorTypeInfo(sensor_type=0x00b5, bytes_per_line=0x78, repeat_multiplier=2, lines_per_calibration_data=112, line_width=112, calibration_blob='9b9a999796959392918f8e8d8b8a898786858382817f7e7d7b7a797776757372716f6e6d6b6a696766656362615f5e5d5b5a595756555251504e4d4c4a49484645444241403e3d3c3a39383635343231302e2d2c2a29282625242221201e1d1c1a19181615141211100e0d0c0a090806'),
SensorTypeInfo(sensor_type=0x0885, bytes_per_line=0x78, repeat_multiplier=2, lines_per_calibration_data=112, line_width=112, calibration_blob='9b9a999796959392918f8e8d8b8a898786858382817f7e7d7b7a797776757372716f6e6d6b6a696766656362615f5e5d5b5a595756555251504e4d4c4a49484645444241403e3d3c3a39383635343231302e2d2c2a29282625242221201e1d1c1a19181615141211100e0d0c0a090806'),
SensorTypeInfo(sensor_type=0x1055, bytes_per_line=0x78, repeat_multiplier=2, lines_per_calibration_data=112, line_width=112, calibration_blob='9b9a999796959392918f8e8d8b8a898786858382817f7e7d7b7a797776757372716f6e6d6b6a696766656362615f5e5d5b5a595756555251504e4d4c4a49484645444241403e3d3c3a39383635343231302e2d2c2a29282625242221201e1d1c1a19181615141211100e0d0c0a090806'),
SensorTypeInfo(sensor_type=0x1825, bytes_per_line=0x78, repeat_multiplier=2, lines_per_calibration_data=112, line_width=112, calibration_blob='9b9a999796959392918f8e8d8b8a898786858382817f7e7d7b7a797776757372716f6e6d6b6a696766656362615f5e5d5b5a595756555251504e4d4c4a49484645444241403e3d3c3a39383635343231302e2d2c2a29282625242221201e1d1c1a19181615141211100e0d0c0a090806'),
SensorTypeInfo(sensor_type=0x1ff5, bytes_per_line=0x78, repeat_multiplier=2, lines_per_calibration_data=112, line_width=112, calibration_blob='9b9a999796959392918f8e8d8b8a898786858382817f7e7d7b7a797776757372716f6e6d6b6a696766656362615f5e5d5b5a595756555251504e4d4c4a49484645444241403e3d3c3a39383635343231302e2d2c2a29282625242221201e1d1c1a19181615141211100e0d0c0a090806'),
SensorTypeInfo(sensor_type=0x00b3, bytes_per_line=0x60, repeat_multiplier=2, lines_per_calibration_data=84, line_width=85, calibration_blob='898786858382817f7e7d7b7a797776757372716f6e6d6b6a696766656362615f5e5d5b5a595756555251504e4d4c4a49484645444241403e3d3c3a39383635343231302e2d2c2a29282625242221201e1d1c1a19'),
SensorTypeInfo(sensor_type=0x143b, bytes_per_line=0x5c, repeat_multiplier=2, lines_per_calibration_data=84, line_width=84, calibration_blob='898786858382817f7e7d7b7a797776757372716f6e6d6b6a696766656362615f5e5d5b5a595756555251504e4d4c4a49484645444241403e3d3c3a39383635343231302e2d2c2a29282625242221201e1d1c1a19'),
SensorTypeInfo(sensor_type=0x08b1, bytes_per_line=0x58, repeat_multiplier=2, lines_per_calibration_data=78, line_width=78, calibration_blob='9b9a9996959392918f8e8d8b8a89878685837d7b7a7977767573716f6d6b6a695d5b5a595756555251504e4d4c4a41403e3d3c3a393432312c2a28261e1d1c1a19181615141211100d0c0a090806'),
SensorTypeInfo(sensor_type=0x00e1, bytes_per_line=0x58, repeat_multiplier=2, lines_per_calibration_data=78, line_width=78, calibration_blob='9b9a9996959392918f8e8d8b8a89878685837d7b7a7977767573716f6d6b6a695d5b5a595756555251504e4d4c4a41403e3d3c3a393432312c2a28261e1d1c1a19181615141211100d0c0a090806'),
SensorTypeInfo(sensor_type=0x00ea, bytes_per_line=0x5c, repeat_multiplier=1, lines_per_calibration_data=84, line_width=84, calibration_blob='898786858382817f7e7d7b7a797776757372716f6e6d6b6a696766656362615f5e5d5b5a595756555251504e4d4c4a49484645444241403e3d3c3a39383635343231302e2d2c2a29282625242221201e1d1c1a19'),
SensorTypeInfo(sensor_type=0x0194, bytes_per_line=0x7c, repeat_multiplier=3, lines_per_calibration_data=84, line_width=114, calibration_blob='000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f50515253'),
SensorTypeInfo(sensor_type=0x0126, bytes_per_line=0xa0, repeat_multiplier=2, lines_per_calibration_data=56, line_width=144, calibration_blob='0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243'),
SensorTypeInfo(sensor_type=0x0117, bytes_per_line=0xa0, repeat_multiplier=4, lines_per_calibration_data=56, line_width=144, calibration_blob='0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243'),
SensorTypeInfo(sensor_type=0x08f3, bytes_per_line=0xa0, repeat_multiplier=1, lines_per_calibration_data=56, line_width=144, calibration_blob='0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243'),
SensorTypeInfo(sensor_type=0x08f6, bytes_per_line=0xa0, repeat_multiplier=1, lines_per_calibration_data=56, line_width=144, calibration_blob='0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243'),
SensorTypeInfo(sensor_type=0x0121, bytes_per_line=0xa0, repeat_multiplier=2, lines_per_calibration_data=56, line_width=144, calibration_blob='0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243'),
SensorTypeInfo(sensor_type=0x0b4b, bytes_per_line=0xa0, repeat_multiplier=2, lines_per_calibration_data=56, line_width=144, calibration_blob='0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243'),
SensorTypeInfo(sensor_type=0x0b4d, bytes_per_line=0xa0, repeat_multiplier=2, lines_per_calibration_data=56, line_width=144, calibration_blob='0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243'),
SensorTypeInfo(sensor_type=0x0130, bytes_per_line=0xa0, repeat_multiplier=2, lines_per_calibration_data=40, line_width=144, calibration_blob='15161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3b'),
SensorTypeInfo(sensor_type=0x0be2, bytes_per_line=0xa0, repeat_multiplier=2, lines_per_calibration_data=40, line_width=144, calibration_blob='15161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3b'),
SensorTypeInfo(sensor_type=0x0be1, bytes_per_line=0xa0, repeat_multiplier=2, lines_per_calibration_data=40, line_width=144, calibration_blob='15161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3b'),
SensorTypeInfo(sensor_type=0x0518, bytes_per_line=0xa0, repeat_multiplier=2, lines_per_calibration_data=40, line_width=144, calibration_blob='15161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3b'),
SensorTypeInfo(sensor_type=0x0179, bytes_per_line=0x98, repeat_multiplier=3, lines_per_calibration_data=56, line_width=144, calibration_blob='3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172'),
SensorTypeInfo.table = [
SensorTypeInfo(
sensor_type=0x00db,
bytes_per_line=0x98,
repeat_multiplier=1,
lines_per_calibration_data=144,
line_width=144,
calibration_blob=
'101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f'
),
SensorTypeInfo(
sensor_type=0x00e4,
bytes_per_line=0x78,
repeat_multiplier=2,
lines_per_calibration_data=100,
line_width=112,
calibration_blob=
'9392918f8e8d8b8a898786858382817f7e7d7b7a797776757372716f6e6d6b6a696766656362615f5e5d5b5a595756555251504e4d4c4a49484645444241403e3d3c3a39383635343231302e2d2c2a29282625242221201e1d1c1a19181615141211100e'
),
SensorTypeInfo(
sensor_type=0x00ed,
bytes_per_line=0x78,
repeat_multiplier=2,
lines_per_calibration_data=112,
line_width=112,
calibration_blob=
'9b9a999796959392918f8e8d8b8a898786858382817f7e7d7b7a797776757372716f6e6d6b6a696766656362615f5e5d5b5a595756555251504e4d4c4a49484645444241403e3d3c3a39383635343231302e2d2c2a29282625242221201e1d1c1a19181615141211100e0d0c0a090806'
),
SensorTypeInfo(
sensor_type=0x0199,
bytes_per_line=0x78,
repeat_multiplier=2,
lines_per_calibration_data=112,
line_width=112,
calibration_blob=
'9b9a999796959392918f8e8d8b8a898786858382817f7e7d7b7a797776757372716f6e6d6b6a696766656362615f5e5d5b5a595756555251504e4d4c4a49484645444241403e3d3c3a39383635343231302e2d2c2a29282625242221201e1d1c1a19181615141211100e0d0c0a090806'
),
SensorTypeInfo(
sensor_type=0x00b5,
bytes_per_line=0x78,
repeat_multiplier=2,
lines_per_calibration_data=112,
line_width=112,
calibration_blob=
'9b9a999796959392918f8e8d8b8a898786858382817f7e7d7b7a797776757372716f6e6d6b6a696766656362615f5e5d5b5a595756555251504e4d4c4a49484645444241403e3d3c3a39383635343231302e2d2c2a29282625242221201e1d1c1a19181615141211100e0d0c0a090806'
),
SensorTypeInfo(
sensor_type=0x0885,
bytes_per_line=0x78,
repeat_multiplier=2,
lines_per_calibration_data=112,
line_width=112,
calibration_blob=
'9b9a999796959392918f8e8d8b8a898786858382817f7e7d7b7a797776757372716f6e6d6b6a696766656362615f5e5d5b5a595756555251504e4d4c4a49484645444241403e3d3c3a39383635343231302e2d2c2a29282625242221201e1d1c1a19181615141211100e0d0c0a090806'
),
SensorTypeInfo(
sensor_type=0x1055,
bytes_per_line=0x78,
repeat_multiplier=2,
lines_per_calibration_data=112,
line_width=112,
calibration_blob=
'9b9a999796959392918f8e8d8b8a898786858382817f7e7d7b7a797776757372716f6e6d6b6a696766656362615f5e5d5b5a595756555251504e4d4c4a49484645444241403e3d3c3a39383635343231302e2d2c2a29282625242221201e1d1c1a19181615141211100e0d0c0a090806'
),
SensorTypeInfo(
sensor_type=0x1825,
bytes_per_line=0x78,
repeat_multiplier=2,
lines_per_calibration_data=112,
line_width=112,
calibration_blob=
'9b9a999796959392918f8e8d8b8a898786858382817f7e7d7b7a797776757372716f6e6d6b6a696766656362615f5e5d5b5a595756555251504e4d4c4a49484645444241403e3d3c3a39383635343231302e2d2c2a29282625242221201e1d1c1a19181615141211100e0d0c0a090806'
),
SensorTypeInfo(
sensor_type=0x1ff5,
bytes_per_line=0x78,
repeat_multiplier=2,
lines_per_calibration_data=112,
line_width=112,
calibration_blob=
'9b9a999796959392918f8e8d8b8a898786858382817f7e7d7b7a797776757372716f6e6d6b6a696766656362615f5e5d5b5a595756555251504e4d4c4a49484645444241403e3d3c3a39383635343231302e2d2c2a29282625242221201e1d1c1a19181615141211100e0d0c0a090806'
),
SensorTypeInfo(
sensor_type=0x00b3,
bytes_per_line=0x60,
repeat_multiplier=2,
lines_per_calibration_data=84,
line_width=85,
calibration_blob=
'898786858382817f7e7d7b7a797776757372716f6e6d6b6a696766656362615f5e5d5b5a595756555251504e4d4c4a49484645444241403e3d3c3a39383635343231302e2d2c2a29282625242221201e1d1c1a19'
),
SensorTypeInfo(
sensor_type=0x143b,
bytes_per_line=0x5c,
repeat_multiplier=2,
lines_per_calibration_data=84,
line_width=84,
calibration_blob=
'898786858382817f7e7d7b7a797776757372716f6e6d6b6a696766656362615f5e5d5b5a595756555251504e4d4c4a49484645444241403e3d3c3a39383635343231302e2d2c2a29282625242221201e1d1c1a19'
),
SensorTypeInfo(
sensor_type=0x08b1,
bytes_per_line=0x58,
repeat_multiplier=2,
lines_per_calibration_data=78,
line_width=78,
calibration_blob=
'9b9a9996959392918f8e8d8b8a89878685837d7b7a7977767573716f6d6b6a695d5b5a595756555251504e4d4c4a41403e3d3c3a393432312c2a28261e1d1c1a19181615141211100d0c0a090806'
),
SensorTypeInfo(
sensor_type=0x00e1,
bytes_per_line=0x58,
repeat_multiplier=2,
lines_per_calibration_data=78,
line_width=78,
calibration_blob=
'9b9a9996959392918f8e8d8b8a89878685837d7b7a7977767573716f6d6b6a695d5b5a595756555251504e4d4c4a41403e3d3c3a393432312c2a28261e1d1c1a19181615141211100d0c0a090806'
),
SensorTypeInfo(
sensor_type=0x00ea,
bytes_per_line=0x5c,
repeat_multiplier=1,
lines_per_calibration_data=84,
line_width=84,
calibration_blob=
'898786858382817f7e7d7b7a797776757372716f6e6d6b6a696766656362615f5e5d5b5a595756555251504e4d4c4a49484645444241403e3d3c3a39383635343231302e2d2c2a29282625242221201e1d1c1a19'
),
SensorTypeInfo(
sensor_type=0x0194,
bytes_per_line=0x7c,
repeat_multiplier=3,
lines_per_calibration_data=84,
line_width=114,
calibration_blob=
'000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f50515253'
),
SensorTypeInfo(
sensor_type=0x0126,
bytes_per_line=0xa0,
repeat_multiplier=2,
lines_per_calibration_data=56,
line_width=144,
calibration_blob=
'0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243'
),
SensorTypeInfo(
sensor_type=0x0117,
bytes_per_line=0xa0,
repeat_multiplier=4,
lines_per_calibration_data=56,
line_width=144,
calibration_blob=
'0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243'
),
SensorTypeInfo(
sensor_type=0x08f3,
bytes_per_line=0xa0,
repeat_multiplier=1,
lines_per_calibration_data=56,
line_width=144,
calibration_blob=
'0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243'
),
SensorTypeInfo(
sensor_type=0x08f6,
bytes_per_line=0xa0,
repeat_multiplier=1,
lines_per_calibration_data=56,
line_width=144,
calibration_blob=
'0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243'
),
SensorTypeInfo(
sensor_type=0x0121,
bytes_per_line=0xa0,
repeat_multiplier=2,
lines_per_calibration_data=56,
line_width=144,
calibration_blob=
'0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243'
),
SensorTypeInfo(
sensor_type=0x0b4b,
bytes_per_line=0xa0,
repeat_multiplier=2,
lines_per_calibration_data=56,
line_width=144,
calibration_blob=
'0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243'
),
SensorTypeInfo(
sensor_type=0x0b4d,
bytes_per_line=0xa0,
repeat_multiplier=2,
lines_per_calibration_data=56,
line_width=144,
calibration_blob=
'0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243'
),
SensorTypeInfo(
sensor_type=0x0130,
bytes_per_line=0xa0,
repeat_multiplier=2,
lines_per_calibration_data=40,
line_width=144,
calibration_blob=
'15161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3b'),
SensorTypeInfo(
sensor_type=0x0be2,
bytes_per_line=0xa0,
repeat_multiplier=2,
lines_per_calibration_data=40,
line_width=144,
calibration_blob=
'15161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3b'),
SensorTypeInfo(
sensor_type=0x0be1,
bytes_per_line=0xa0,
repeat_multiplier=2,
lines_per_calibration_data=40,
line_width=144,
calibration_blob=
'15161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3b'),
SensorTypeInfo(
sensor_type=0x0518,
bytes_per_line=0xa0,
repeat_multiplier=2,
lines_per_calibration_data=40,
line_width=144,
calibration_blob=
'15161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3b'),
SensorTypeInfo(
sensor_type=0x0179,
bytes_per_line=0x98,
repeat_multiplier=3,
lines_per_calibration_data=56,
line_width=144,
calibration_blob=
'3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172'
),
]
SensorCaptureProg.table=[
SensorCaptureProg(major=0x6, minor=0x0, build=0x0, u1=0x0, dev_type=0x0, a0=0x0, a1=0x0, blobs=['23000000320074000000008000200000502077322820020030200000082110000c211000482105004c2105002020000024200000582000005c20000060204300682014006c2001247020012c842020008c20900190202c01942001809c200902a0200b19b4200000b8203a00bc201400c0200200c4200200c82008003300100000000080cc200000a101d0200000a10132004c0000000080dc20e803e0206401e420d002e8200001ec201400f0200500fc200000b8203a00140800000008040008080000080802001408300008080300140831001c081a004c11240050110000', '2a00080020010100100100002c002800802080200000000000013f4000000000080f080f00000000279c1000279c10000000000000000000340040000300000007160000240a59085a0701c9500aaa07010ada08db0701c9460b2107010800800a0088c9590a5a07010aa908aa0701c91f0ac900000c040100000000', '29000400000000003500040000000000']),
SensorCaptureProg(major=0x6, minor=0x6, build=0x0, u1=0x0, dev_type=0x0, a0=0x0, a1=0x0, blobs=['23000000320074000000008000200000502077322820020030200000082110000c211000482105004c2105002020000024200000582000005c20000060204300682014006c2001247020012c842020008c20900190202c01942001809c200902a0200b19b4200000b8203a00bc201400c0200200c4200200c82008003300100000000080cc200000a101d0200000a10132004c0000000080dc20e803e0206401e420d002e8200001ec201400f0200500fc200000b8203a00140800000008040008080000080802001408300008080300140831001c081a004c11240050110000', '2a00080020010100100100002c002800802080200000000000013f4000000000080f080f00000000279c1000279c10000000000000000000340040000300000007160000240a59085a0701c9500aaa07010ada08db0701c9460b2107010800800a0088c9590a5a07010aa908aa0701c91f0ac900000c040100000000', '29000400000000003500040000000000']),
SensorCaptureProg(major=0x6, minor=0x7, build=0x0, u1=0x0, dev_type=0x0, a0=0x0, a1=0x0, blobs=['23000000320074000000008000200000502077322820020030200000082110000c211000482105004c2105002020000024200000582000005c20000060204300682014006c2001247020012c842020008c20900190202c01942001809c200902a0200b19b4200000b8203a00bc201400c0200200c4200200c82008003300100000000080cc200000a101d0200000a10132004c0000000080dc20e803e0206401e420d002e8200001ec201400f0200500fc200000b8203a00140800000008040008080000080802001408300008080300140831001c081a004c11240050110000', '2a00080020010100100100002c002800802080200000000000013f4000000000080f080f00000000279c1000279c10000000000000000000340040000300000007160000240a59085a0701c9500aaa07010ada08db0701c9460b2107010800800a0088c9590a5a07010aa908aa0701c91f0ac900000c040100000000', '29000400000000003500040000000000']),
SensorCaptureProg(major=0x6, minor=0x8, build=0x0, u1=0x0, dev_type=0x0, a0=0x0, a1=0x0, blobs=['23000000320074000000008000200000502077322820020030200000082110000c211000482105004c2105002020000024200000582000005c20000060204300682014006c2001247020012c842020008c20900190202c01942001809c200902a0200b19b4200000b8203a00bc201400c0200200c4200200c82008003300100000000080cc200000a101d0200000a10132004c0000000080dc20e803e0206401e420d002e8200001ec201400f0200500fc200000b8203a00140800000008040008080000080802001408300008080300140831001c081a004c11240050110000', '2a00080020010100100100002c002800802080200000000000013f4000000000080f080f00000000279c1000279c10000000000000000000340040000300000007160000240a59085a0701c9500aaa07010ada08db0701c9460b2107010800800a0088c9590a5a07010aa908aa0701c91f0ac900000c040100000000', '29000400000000003500040000000000']),
SensorCaptureProg(major=0x6, minor=0xa, build=0x0, u1=0x0, dev_type=0x0, a0=0x0, a1=0x0, blobs=['230000003200680000000080002000002020000024200000382000002820df0b2c20df0b302000003420000050200a005c20000064204300602000004c2000006c20100070201000742005007820050084202000b4200000b8203b00bc201400c0200200c4200100c82002007403000233001c000000008054202a2203005820272f0300cc200000ef03d0200000ef033200480000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203b00002804001428000008280000082800001428300008280000142831001c281a006411240068110000', '2a00080020010100100100002c002800802080200000000000013f4000000000080f080f00000000279c1000279c10000000000000000000340040000300000007160000240a59085a0701c9500aaa07010ada08db0701c9460b2107010800800a0088c9590a5a07010aa908aa0701c91f0ac900000c040100000000', '29000400000000003500040000000000']),
SensorCaptureProg(major=0x6, minor=0xb, build=0x0, u1=0x0, dev_type=0x0, a0=0x0, a1=0x0, blobs=['230000003200680000000080002000002020000024200000382000002820df0b2c20df0b302000003420000050200a005c20000064204300602000004c2000006c20100070201000742005007820050084202000b4200000b8203b00bc201400c0200200c4200100c82002007403000233001c000000008054202a2203005820272f0300cc200000ef03d0200000ef033200480000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203b00002804001428000008280000082800001428300008280000142831001c281a006411240068110000', '2a00080020010100100100002c002800802080200000000000013f4000000000080f080f00000000279c1000279c10000000000000000000340040000300000007160000240a59085a0701c9500aaa07010ada08db0701c9460b2107010800800a0088c9590a5a07010aa908aa0701c91f0ac900000c040100000000', '29000400000000003500040000000000']),
SensorCaptureProg(major=0x6, minor=0x14, build=0x0, u1=0x0, dev_type=0x0, a0=0x0, a1=0x0, blobs=['230000003200680000000080002000002020000024200000382000002820df0b2c20df0b302000003420000050200a005c20000064204300602000004c2000006c20100070201000742005007820050084202000b4200000b8203b00bc201400c0200200c4200100c82002007403000233001c000000008054202a2203005820272f0300cc200000ef03d0200000ef033200480000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203b00002804001428000008280000082800001428300008280000142831001c281a006411240068110000', '2a00080020010100100100002c002800802080200000000000013f4000000000080f080f00000000279c1000279c10000000000000000000340040000300000007160000240a59085a0701c9500aaa07010ada08db0701c9460b2107010800800a0088c9590a5a07010aa908aa0701c91f0ac900000c040100000000', '29000400000000003500040000000000']),
SensorCaptureProg(major=0x6, minor=0x6, build=0x0, u1=0x0, dev_type=0x885, a0=0x18, a1=0x19, blobs=['23000000200008000020008000000100320074000000008020200400242000005020773628200100302001003c208000082150000c210000482105004c210000582000005c2000006020000068200a006c20014970200141742001887820018084202000942001809c200902a0200b19b4200300b8203b04bc201400c0200200c4200100c82002003300100000000080cc200000f503d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203a00000804001408000008080000080800001408300008080000140831001c081a00', '32000c0000000080501101004c111e00340070010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010221710221710221610221610221601066310250101000007c8078c06ff4f80006d0300200307030b90098db08d099186890b9108c180910ac190ba2c928f099382890b938889898908c881910ac8888a9189099a82890b9a8889898908d081910ad0888a9189080282890a02095a80890b5a888908d981890ad98891898a095e81890b5e8889898908e181890ae18891898a096481890b64888989096e8108e9810b6e880ae9889191ba096f828f0b6f8889918908f082890af08891898a097681890b7690b9928f08f882910af8908a8a91097c818a0b7c88090181890b018889892491097f818a0b7f900908818a0b0890898a910c0703030720040200002f0004007000000029000400700000003500040080000000']),
SensorCaptureProg(major=0x6, minor=0x7, build=0x0, u1=0x0, dev_type=0x885, a0=0x18, a1=0x19, blobs=['23000000200008000020008000000100320074000000008020200400242000005020773628200100302001003c208000082150000c210000482105004c210000582000005c2000006020000068200a006c20014970200141742001887820018084202000942001809c200902a0200b19b4200300b8203b04bc201400c0200200c4200100c82002003300100000000080cc200000f503d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203a00000804001408000008080000080800001408300008080000140831001c081a00', '32000c0000000080501101004c111e00340070010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010221710221710221610221610221601066310250101000007c8078c06ff4f80006d0300200307030b90098db08d099186890b9108c180910ac190ba2c928f099382890b938889898908c881910ac8888a9189099a82890b9a8889898908d081910ad0888a9189080282890a02095a80890b5a888908d981890ad98891898a095e81890b5e8889898908e181890ae18891898a096481890b64888989096e8108e9810b6e880ae9889191ba096f828f0b6f8889918908f082890af08891898a097681890b7690b9928f08f882910af8908a8a91097c818a0b7c88090181890b018889892491097f818a0b7f900908818a0b0890898a910c0703030720040200002f0004007000000029000400700000003500040080000000']),
SensorCaptureProg(major=0x6, minor=0x0, build=0x0, u1=0x0, dev_type=0x1055, a0=0x18, a1=0x19, blobs=['23000000200008000020008000000100320074000000008020200400242000005020773628200100302001003c208000082138000c210000482103004c210000582000005c20000060200000682005006c20014970200141742001887820018084202000942001809c200902a0200b19b4200300b8203b04bc201400c0200200c4200100c82002003300100000000080cc200000f503d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203a00000804001408000008080000080800001408300008080000140831001c081a00', '32000c0000000080501101004c111e00340070010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010221710221710221610221610221601066310250101000007c8078c06ff4f80006d0300200307030b90098db08d099186890b9108c180910ac190ba2c928f099382890b938889898908c881910ac8888a9189099a82890b9a8889898908d081910ad0888a9189080282890a02095a80890b5a888908d981890ad98891898a095e81890b5e8889898908e181890ae18891898a096481890b64888989096e8108e9810b6e880ae9889191ba096f828f0b6f8889918908f082890af08891898a097681890b7690b9928f08f882910af8908a8a91097c818a0b7c88090181890b018889892491097f818a0b7f900908818a0b0890898a910c0703030720040200002f0004007000000029000400700000003500040080000000']),
SensorCaptureProg(major=0x6, minor=0x0, build=0x0, u1=0x0, dev_type=0x1825, a0=0x18, a1=0x19, blobs=['23000000200008000020008000000100320074000000008020200400242000005020773628200100302001003c208000082138000c210000482108004c210000582000005c20000060200000682005006c20014970200141742001887820018084202000942001809c200902a0200b19b4200300b8203b04bc201400c0200200c4200100c82002003300100000000080cc200000f503d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203a00000804001408000008080000080800001408300008080000140831001c081a00', '32000c0000000080501101004c111e00340074010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010221710221710221610221610221601062810250101000007c8078c06ff4f80006d0300200307030990098db00b90880991858e08c1810b9190910ac1b828928a0993878a890b9388898908c88191890ac8889289099a818a890b9a88898908d08191890ad08892890802818a095a810a0288890b5a8808d98189890ad9908989095e8289890b5e88898908e18189890ae190898909648289890b648889096e8108e981890b6e880ae99091b9096f828a8f0b6f88918908f0818a890af090898909768289910b76b8918a08f88792910af8888a92097c81898a0b7c09018089890b01888991097f812089920b7f09088089920b088889920c07030307200402000000002f0004007000000029000400700000003500040080000000']),
SensorCaptureProg(major=0x6, minor=0x0, build=0x0, u1=0x0, dev_type=0xb5, a0=0x18, a1=0x19, blobs=['23000000200008000020008000000100320074000000008020200400242000005020773628200100302001003c208000082138000c210000482106004c210000582000005c20000060200000682005006c20014970200141742001887820018084202000942001809c200902a0200b19b4200300b8203b04bc201400c0200200c4200100c82002003300100000000080cc200000f503d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203a00000804001408000008080000080800001408300008080000140831001c081a00', '32000c0000000080501101004c111e0034007801000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001023171023171023161023161023160106635205001025010100000007c8078c06ff00004f80006d0300280307030990098db00b90880991858e08c1810b9190910ac1b8928a0993878a890b9388898908c88191890ac8889289099a818a890b9a88898908d08191890ad08892890802818a095a810a0288890b5a8808d98189890ad9908989095e8289890b5e88898908e18189890ae190898909648289890b648889096e8108e981890b6e880ae99091b9096f828a8f0b6f88918908f0818a890af090898909768289910b76b8918a08f88792910af8888a92097c81898a0b7c09018089890b01888991097f8189920b7f09088089920b088889920c07030307200402000000002f0004007000000029000400700000003500040080000000']),
SensorCaptureProg(major=0x6, minor=0x0, build=0x0, u1=0x0, dev_type=0x1ff5, a0=0x18, a1=0x19, blobs=['23000000200008000020008000000100320074000000008020200400242000005020773628200100302001003c208000082138000c210000482106004c210000582000005c20000060200000682005006c20014970200141742001887820018084202000942001809c200902a0200b19b4200300b8203b04bc201400c0200200c4200100c82002003300100000000080cc200000f503d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203a00000804001408000008080000080800001408300008080000140831001c081a00', '32000c0000000080501101004c111e00340074010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010221710221710221610221610221601062810250101000007c8078c06ff4f80006d0300200307030990098db00b90880991858e08c1810b9190910ac1b828928a0993878a890b9388898908c88191890ac8889289099a818a890b9a88898908d08191890ad08892890802818a095a810a0288890b5a8808d98189890ad9908989095e8289890b5e88898908e18189890ae190898909648289890b648889096e8108e981890b6e880ae99091b9096f828a8f0b6f88918908f0818a890af090898909768289910b76b8918a08f88792910af8888a92097c81898a0b7c09018089890b01888991097f812089920b7f09088089920b088889920c07030307200402000000002f0004007000000029000400700000003500040080000000']),
SensorCaptureProg(major=0x6, minor=0x7, build=0x0, u1=0x0, dev_type=0x1825, a0=0x18, a1=0x19, blobs=['23000000200008000020008000000100320074000000008020200400242000005020773628200100302001003c208000082138000c210000482108004c210000582000005c20000060200000682005006c20014970200141742001887820018084202000942001809c200902a0200b19b4200300b8203b04bc201400c0200200c4200100c82002003300100000000080cc200000f503d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203a00000804001408000008080000080800001408300008080000140831001c081a00', '32000c0000000080501101004c111e00340074010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010221710221710221610221610221601065010240101000007c8078c06ff00004f80006d0300280307030990098db00b90880991858e08c1810b9190910ac1b8928a0993878a890b9388898908c88191890ac8889289099a818a890b9a88898908d08191890ad08892890802818a095a810a0288890b5a8808d98189890ad9908989095e8289890b5e88898908e18189890ae190898909648289890b648889096e8108e981890b6e880ae99091b9096f828a8f0b6f88918908f0818a890af090898909768289910b76b8918a08f88792910af8888a92097c81898a0b7c09018089890b01888991097f8189920b7f09088089920b088889920c07030307200402000000002f0004007000000029000400700000003500040080000000']),
SensorCaptureProg(major=0x6, minor=0x0, build=0x0, u1=0x0, dev_type=0xe4, a0=0x18, a1=0x19, blobs=['23000000200008000020008000000100320070000000008020200400242000005020773628200100302001003c208000082138000c210000482108004c210000582000005c20000060200000682005006c20014970200141742001887820018084202000942001809c200902a0200b19b4200300bc201400c0200200c4200100c82002003300100000000080cc200000f503d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203a00000804001408000008080000080800001408300008080000140831001c081a00', '32000c0000000080501101004c111e00340070010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010221410221410221410221410221401066510250101000007c8078c06ff4f80006d0300280307030990098db00b90880991858e08c1810b9190910ac1b8928a0993878a890b9388898908c88191890ac8889289099a818a890b9a88898908d08191890ad08892890802818a095a810a0288890b5a8808d98189890ad9908989095e8289890b5e88898908e18189890ae190898909648289890b648889096e8108e981890b6e880ae99091b9096f828a8f0b6f88918908f0818a890af090898909768289910b76b8918a08f88792910af8888a92097c81898a0b7c09018089890b01888991097f8189920b7f09088089920b088889920c0703030720040200002f0004006400000029000400700000003500040080000000']),
SensorCaptureProg(major=0x6, minor=0x0, build=0x0, u1=0x0, dev_type=0xed, a0=0x18, a1=0x19, blobs=['23000000200008000020008000000100320074000000008020200400242000005020773628200100302001003c208000082138000c210000482104004c210000582000005c20000060200000682005006c20014970200141742001887820018084202000942001809c200902a0200b19b4200300b8203b04bc201400c0200200c4200100c82002003300100000000080cc200000f503d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203a00000804001408000008080000080800001408300008080000140831001c081a00', '32000c0000000080501101004c111e00340074010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010221710221710221610221610221601065010240101000007c8078c06ff00004f80006d0300280307030990098db00b90880991858e08c1810b9190910ac1b8928a0993878a890b9388898908c88191890ac8889289099a818a890b9a88898908d08191890ad08892890802818a095a810a0288890b5a8808d98189890ad9908989095e8289890b5e88898908e18189890ae190898909648289890b648889096e8108e981890b6e880ae99091b9096f828a8f0b6f88918908f0818a890af090898909768289910b76b8918a08f88792910af8888a92097c81898a0b7c09018089890b01888991097f8189920b7f09088089920b088889920c07030307200402000000002f0004007000000029000400700000003500040080000000']),
SensorCaptureProg(major=0x6, minor=0x7, build=0x0, u1=0x0, dev_type=0x143b, a0=0x18, a1=0x19, blobs=['23000000200008000020008000000100320070000000008020200400242000005020773628200100302001003c208000082138000c210000482108004c210000582000005c2000006020000068200a006c20014970200141742001887820018084202000942001809c200902a0200b19b4200300bc201400c0200200c4200100c82002003300100000000080cc200000d600d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203a00000804001408000008080000080800001408300008080000140831001c081a00', '32000c0000000080501101004c1117003400340200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101c11101c11101c11101c11101c10010657101e0101000007c8078c06ff00004f80006d03002c03070308c608c709930703800ac60994800ac70995800b930996800b940997800b950998800b9608c8800b9708ca800b9808cb800ac808cc800aca08ce800acb08cf800acc099a800ace099b800acf099c800b9a099d800b9b099e800b9c099f800b9d08d0800b9e08d2800b9f08d3800ad008d4800ad208d6800ad308d7800ad40802800ad60803800ad7095a800a02095b800a03095c800b5a095d800b5b08d9800b5c08da800b5d08db800ad908dd800ada08de800adb08df800add095e800ade095f800adf0960800b5e0961800b5f0962800b600963800b6108e1800b6208e2800b6308e3800ae108e5800ae208e6800ae308e7800ae50964800ae60965800ae70966800b640967800b650968800b66096e800b6708e9800b6808ea800b6e08eb800ae908ed800aea08ef800aeb08ee800aed096f800aef0970800aee0971800b6f0972800b700974800b710975800b7208f0800b7408f1800b7508f2800af008f4800af108f5800af208f6800af40976800af50977800af60979800b760978800b77097a800b79097b800b7808f8800b7a08fa800b7b08fc800af808fd800afa08fe800afc0900800c2007030307200402002f0004005400000029000400580000003500040068000000']),
SensorCaptureProg(major=0x6, minor=0x7, build=0x0, u1=0x0, dev_type=0xb3, a0=0x18, a1=0x19, blobs=['23000000200008000020008000000100320070000000008020200400242000005020773628200100302001003c208000082140000c210000482106004c210000582000005c2000006020000068200a006c20012970200121742001887820018084202000942001809c200902a0200b19b4200300bc201400c0200100c4200100c82002003300100000000080cc2000002c01d0200000a1013200440000000080dc205302e0206401e420a901e8200001f0200500f8200500fc200000b8203a00000804001408000008080000080800001408300008080000140831001c081a00', '32000c0000000080501101004c11180034003c0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101c11101c11101c11101c11101c10010657101e0101000007c8078c06ff00004f80006d03002c0308c608c70703800ac60993800ac70994800b930995800b940996800b950997800b960998800b9708c8800b9808ca800ac808cb800aca08cc800acb08ce800acc08cf800ace099a800acf099b800b9a099c800b9b099d800b9c099e800b9d099f800b9e08d0800b9f08d2800ad008d3800ad208d4800ad308d6800ad408d7800ad60802800ad70803800a02095a800a03095b800b5a095c800b5b095d800b5c08d9800b5d08da800ad908db800ada08dd800adb08de800add08df800ade095e800adf095f800b5e0960800b5f0961800b600962800b610963800b6208e1800b6308e2800ae108e3800ae208e5800ae308e6800ae508e7800ae60964800ae70965800b640966800b650967800b660968800b67096e800b6808e9800b6e08ea800ae908eb800aea08ed800aeb08ef800aed08ee800aef096f800aee0970800b6f0971800b700972800b710974800b720975800b7408f0800b7508f1800af008f2800af108f4800af208f5800af408f6800af50976800af60977800b760979800b770978800b79097a800b78097b800b7a08f8800b7b08fa800af808fc800afa08fd800afc08fe800afd090080808080240c0703030720040200000000002f0004005400000029000400580000003500040068000000']),
SensorCaptureProg(major=0x6, minor=0x0, build=0x0, u1=0x0, dev_type=0xe1, a0=0x18, a1=0x19, blobs=['2300000020000800002000800000010032006c000000008020200400242000005020773628200100302001003c208000082138000c210000482105004c210000582000005c2000006020000068200a006c20014970200141742001887820018084203000942001809c200902a0200b19bc201400c0200200c4200100c82002003300100000000080cc2000006401d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203b00000804001408000008080000080800001408300008080000140831001c081a00', '32000c0000000080501101004c11160034001402000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101b10101b10101b10101b0f101b0f010656101e0101000007c8078c06ff4f80006d03002c03070308c108bf098f0703800ac10990800abf098d800b8f0991800b900992800b8d08c5800b9108c3800b9208c6800ac508c4800ac308cb800ac608c7800ac40993800acb0994800ac70995800b930997800b940996800b950998800b9708ce800b9608cc800b9808cf800ace08d0800acc08d2800acf08dd800ad0099a800ad2099b800add099c800b9a0803800b9b095a800b9c095b800a0308de800b5a08df800b5b08e1800ade08eb800adf08ed800ae108f1800aeb095c800aed0962800af10963800b5c096f800b620970800b630971800b6f08f2800b7008f5800b7108f6800af208fa800af508f8800af608fc800afa0974800af80976800afc097b800b74097a800b76097f800b7b097e800b7a08fd800b7f08fe800b7e090b800afd090c800afe090d800b0b090f800b0c0980800b0d0982800b0f0983800b80097d800b820978800b83097c800b7d0914800b780908800b7c0909800b140907800b080905800b090904800b070979800b050977800b040975800b790972800b77096c800b750936800b7209348080800c20070303072004020000002f0004004e00000029000400540000003500040064000000']),
SensorCaptureProg(major=0x6, minor=0x0, build=0x0, u1=0x0, dev_type=0x8b1, a0=0x18, a1=0x19, blobs=['2300000020000800002000800000010032006c000000008020200400242000005020773628200100302001003c208000082138000c210000482107004c210000582000005c2000006020000068200a006c20014970200141742001887820018084203000942001809c200902a0200b19bc201400c0200200c4200100c82002003300100000000080cc2000002c00d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203a00000804001408000008080000080800001408300008080000140831001c081a00', '32000c0000000080501101004c11160034001402000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101b10101b10101b10101b0f101b0f010656101e0101000007c8078c06ff4f80006d03002c03070308c108bf098f0703800ac10990800abf098d800b8f0991800b900992800b8d08c5800b9108c3800b9208c6800ac508c4800ac308cb800ac608c7800ac40993800acb0994800ac70995800b930997800b940996800b950998800b9708ce800b9608cc800b9808cf800ace08d0800acc08d2800acf08dd800ad0099a800ad2099b800add099c800b9a0803800b9b095a800b9c095b800a0308de800b5a08df800b5b08e1800ade08eb800adf08ed800ae108f1800aeb095c800aed0962800af10963800b5c096f800b620970800b630971800b6f08f2800b7008f5800b7108f6800af208fa800af508f8800af608fc800afa0974800af80976800afc097b800b74097a800b76097f800b7b097e800b7a08fd800b7f08fe800b7e090b800afd090c800afe090d800b0b090f800b0c0980800b0d0982800b0f0983800b80097d800b820978800b83097c800b7d0914800b780908800b7c0909800b140907800b080905800b090904800b070979800b050977800b040975800b790972800b77096c800b750936800b7209348080800c20070303072004020000002f0004004e00000029000400540000003500040064000000']),
SensorCaptureProg(major=0x6, minor=0x0, build=0x0, u1=0x0, dev_type=0xea, a0=0x18, a1=0x19, blobs=['23000000200008000020008000000100320070000000008020200400242000005020773628200100302001003c208000082138000c210000482106004c210000582000005c2000006020000068200a006c20014970200141742001887820018084202000942001809c200902a0200b19b4200300bc201400c0200200c4200100c82002003300100000000080cc200000d600d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203b00000804001408000008080000080800001408300008080000140831001c081a00', '32000c0000000080501101004c11170034003002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101b11101b11101b11101b11101b1001064d101d0101000007c8078c06ff00004f80006d03002c03070308c608c709930703800ac60994800ac70995800b930996800b940997800b950998800b9608c8800b9708ca800b9808cb800ac808cc800aca08ce800acb08cf800acc099a800ace099b800acf099c800b9a099d800b9b099e800b9c099f800b9d08d0800b9e08d2800b9f08d3800ad008d4800ad208d6800ad308d7800ad40802800ad60803800ad7095a800a02095b800a03095c800b5a095d800b5b08d9800b5c08da800b5d08db800ad908dd800ada08de800adb08df800add095e800ade095f800adf0960800b5e0961800b5f0962800b600963800b6108e1800b6208e2800b6308e3800ae108e5800ae208e6800ae308e7800ae50964800ae60965800ae70966800b640967800b650968800b66096e800b6708e9800b6808ea800b6e08eb800ae908ed800aea08ef800aeb08ee800aed096f800aef0970800aee0971800b6f0972800b700974800b710975800b7208f0800b7408f1800b7508f2800af008f4800af108f5800af208f6800af40976800af50977800af60979800b760978800b77097a800b79097b800b7808f8800b7a08fa800b7b08fc800af808fd800afa08fe800afc0900800c2007030307200402002f0004005400000029000400540000003500040064000000']),
SensorCaptureProg(major=0x6, minor=0x0, build=0x0, u1=0x0, dev_type=0x199, a0=0x18, a1=0x19, blobs=['23000000200008000020008000000100320074000000008020200400242000005020773628200100302001003c208000082138000c210000482107004c210000582000005c20000060200000682005006c20014970200141742001887820018084202000942001809c200902a0200b19b4200300b8203b04bc201400c0200200c4200100c82002003300100000000080cc200000f503d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203a00000804001408000008080000080800001408300008080000140831001c081a00', '32000c0000000080501101004c111e00340078010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010221710221710221610221610221601065010250101000007c8078c06ff0000000000004f80006d0300280307030990098db00b90880991858e08c1810b9190910ac1b8928a0993878a890b9388898908c88191890ac8889289099a818a890b9a88898908d08191890ad08892890802818a095a810a0288890b5a8808d98189890ad9908989095e8289890b5e88898908e18189890ae190898909648289890b648889096e8108e981890b6e880ae99091b9096f828a8f0b6f88918908f0818a890af090898909768289910b76b8918a08f88792910af8888a92097c81898a0b7c09018089890b01888991097f8189920b7f09088089920b088889920c07030307200402000000002f0004007000000029000400700000003500040080000000']),
SensorCaptureProg(major=0x6, minor=0x14, build=0x0, u1=0x0, dev_type=0x8f3, a0=0x18, a1=0x19, blobs=['2300000020000800002000800000010032006000000000802020040024200000382000002820df0b2c20df0b302000003420000050200a015c200000602000004c2003006c20700070207000742001007820010084202000b4200000bc201400c0200200c4200100c820020074030002a0030000330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a00', '330064030000008064200000a10c642000109f0c64200020a20c642000309e0c64200040a30c642000509d0c64200060a40c642000709c0c64200080a60c642000909b0c642000a0a70c642000b09a0c642000c0a80c642000d0990c642000e0a90c642000f0980c64200000af0c64200010950c64200020b00c64200030940c64200040b10c64200050930c64200060b20c64200070920c64200080b30c642000908b0c642000a0b70c642000b08a0c642000c0b80c642000d0890c642000e0b90c642000f0880c64200000ba0c64200010870c64200020bb0c64200030810c64200040bf0c64200050800c64200060c00c642000707f0c64200080c10c642000907e0c642000a0c20c642000b07d0c642000c0c50c642000d0720c642000e0c60c642000f0710c64200000c70c64200010700c64200020c80c642000306f0c64200040c90c64200050630c642000606c0c64200070620c642000806b0c64200090610c642000a06a0c642000b0600c642000c0690c642000d05f0c642000e05e0c642000f04f0c642000005d0c642000104e0c642000205c0c642000304d0c642000405b0c642000504c0c642000605a0c642000704b0c64200080310c642000904a0c642000a0300c642000b0490c642000c02f0c642000d0480c642000e02e0c642000f0470c642000002d0c64200010460c64200020ca0c642000303b0c64200040cb0c642000503a0c64200060cc0c64200070390c64200080cd0c64200090380c642000a0ce0c642000b02c0c642000c0d10c642000d02b0c642000e0d20c642000f02a0c64200000d30c64200010290c64200020d60c64200030280c64200040d70c642000501d0c64200060d80c642000701c0c64200080d90c642000901b0c642000a0da0c642000b01a0c642000c0de0c642000d0190c642000e0df0c642000f0150c64200000e00c64200010140c64200020e10c64200030130c64200040e20c64200050120c64200060e40c64200070110c64200080e50c642000900d0c642000a0e60c642000b00c0c642000c0e70c642000d00b0c642000e0e80c642000f00a0c64200000ea0c64200010070c64200020eb0c64200030060c64200040ec0c64200050050c64200060ed0c64200070040c64200080ee0c64200090030c642000a0ef0c642000b0020c642000c0f00c642000d0010c642000e0f10c642000f0000c', '32000c000000008068110100641126003400180200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007e007e0102a13102a13102a12010000061e102d0101000007c8078c060b5d00005e00004f80005080006d030059940b070100002403089808a9089908a8089a08a7089b08a6089c08a4089d08a3089e08a2089f08a1c0102c03088808b9088908b8088a08b7088b08b3089208b2089308b1089408b0089508afc01003087108c6087208c5087d08c2087e08c1087f08c0088008bf088108bb088708bac0100628070103084f085e085f08690860086a0861086b0862086c086308c9086f08c8087008c7c010030847082e0848082f08490830084a0831084b085a084c085b084d085c084e085dc01003082a08d2082b08d1082c08ce083808cd083908cc083a08cb083b08ca0846082dc0100632070103081508df081908de081a08da081b08d9081c08d8081d08d7082808d6082908d3c01059940b03080a08e8080b08e7080c08e6080d08e5081108e4081208e2081308e1081408e0c0102403080008f1080108f0080208ef080308ee080408ed080508ec080608eb080708eac0100c0720070c2003040200004200080002089000000000002f00040038000000290004009000000035000400a0000000']),
SensorCaptureProg(major=0x6, minor=0x14, build=0x0, u1=0x0, dev_type=0x8f6, a0=0x18, a1=0x19, blobs=['2300000020000800002000800000010032005c00000000802020040024200000382000002820df0b2c20df0b302000003420000050200a015c200000602000004c2003006c20500070205000742000007820000084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a00330064030000008064200000a10c642000109f0c64200020a20c642000309e0c64200040a30c642000509d0c64200060a40c642000709c0c64200080a60c642000909b0c642000a0a70c642000b09a0c642000c0a80c642000d0990c642000e0a90c642000f0980c64200000af0c64200010950c64200020b00c64200030940c64200040b10c64200050930c64200060b20c64200070920c64200080b30c642000908b0c642000a0b70c642000b08a0c642000c0b80c642000d0890c642000e0b90c642000f0880c64200000ba0c64200010870c64200020bb0c64200030810c64200040bf0c64200050800c64200060c00c642000707f0c64200080c10c642000907e0c642000a0c20c642000b07d0c642000c0c50c642000d0720c642000e0c60c642000f0710c64200000c70c64200010700c64200020c80c642000306f0c64200040c90c64200050630c642000606c0c64200070620c642000806b0c64200090610c642000a06a0c642000b0600c642000c0690c642000d05f0c642000e05e0c642000f04f0c642000005d0c642000104e0c642000205c0c642000304d0c642000405b0c642000504c0c642000605a0c642000704b0c64200080310c642000904a0c642000a0300c642000b0490c642000c02f0c642000d0480c642000e02e0c642000f0470c642000002d0c64200010460c64200020ca0c642000303b0c64200040cb0c642000503a0c64200060cc0c64200070390c64200080cd0c64200090380c642000a0ce0c642000b02c0c642000c0d00c642000d02b0c642000e0d10c642000f02a0c64200000d20c64200010290c64200020d30c64200030280c64200040d60c642000501c0c64200060d70c642000701b0c64200080d80c642000901a0c642000a0d90c642000b0190c642000c0da0c642000d0150c642000e0df0c642000f0140c64200000e00c64200010130c64200020e10c64200030120c64200040e20c64200050110c64200060e40c642000700e0c64200080e50c642000900d0c642000a0e60c642000b00c0c642000c0e70c642000d00b0c642000e0e80c642000f00a0c64200000ea0c64200010070c64200020eb0c64200030060c64200040ec0c64200050050c64200060ed0c64200070040c64200080ee0c64200090030c642000a0ef0c642000b0020c642000c0f00c642000d0010c642000e0f10c642000f0000c', '32000c0000000080681101006411260034001c0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007e007e0102a13102a13102a12010000061e102d0101000007c8078c060b5d00005e00004f80005080006d030059940b070100000720240308a1089f08a2089e08a3089d08a4089c08a6089b08a7089a08a8089908a90898c0102c0308af089508b0089408b1089308b2089208b3088b08b7088a08b8088908b90888c0100308ba088708bb088108bf088008c0087f08c1087e08c2087d08c5087208c60871c010062807010308c7087008c8086f08c90863086c0862086b0861086a08600869085f085e084fc01003085d084e085c084d085b084c085a084b0831084a08300849082f0848082e0847c01003082d084608ca083b08cb083a08cc083908cd083808ce082c08d0082b08d1082ac010063207010308d2082908d3082808d6081c08d7081b08d8081a08d9081908da081508df0814c0100308e0081308e1081208e2081108e4080e08e5080d08e6080c08e7080b08e8080ac010240308ea080708eb080608ec080508ed080408ee080308ef080208f0080108f10800c010070320030c07030703072004020000004200080002089000000000002f00040038000000', '2f00040038000000290004009000000035000400a0000000']),
SensorCaptureProg(major=0x6, minor=0x14, build=0x0, u1=0x0, dev_type=0x121, a0=0x18, a1=0x19, blobs=['2300000020000800002000800000010032005c00000000802020040024200000382000002820df0b2c20df0b302000003420000050200a015c200000602000004c2003006c20720070207200742001007820010084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a00', '330064030000008064200000a10c642000109f0c64200020a20c642000309e0c64200040a30c642000509d0c64200060a40c642000709c0c64200080a60c642000909b0c642000a0a70c642000b09a0c642000c0a80c642000d0990c642000e0a90c642000f0980c64200000af0c64200010950c64200020b00c64200030940c64200040b10c64200050930c64200060b20c64200070920c64200080b30c642000908b0c642000a0b70c642000b08a0c642000c0b80c642000d0890c642000e0b90c642000f0880c64200000ba0c64200010870c64200020bb0c64200030810c64200040bf0c64200050800c64200060c00c642000707f0c64200080c10c642000907e0c642000a0c20c642000b07d0c642000c0c50c642000d0720c642000e0c60c642000f0710c64200000c70c64200010700c64200020c80c642000306f0c64200040c90c642000506d0c642000607a0c642000706c0c64200080790c642000906b0c642000a0780c642000b06a0c642000c06e0c642000d0690c642000e0630c642000f05e0c64200000620c642000105d0c64200020610c642000305c0c64200040600c642000505b0c642000605f0c642000705a0c64200080310c642000904a0c642000a0300c642000b0490c642000c02f0c642000d0480c642000e02e0c642000f0470c642000002d0c64200010460c64200020ca0c642000303b0c64200040cb0c642000503a0c64200060cc0c64200070390c64200080cd0c64200090380c642000a0ce0c642000b02c0c642000c0d00c642000d02b0c642000e0d10c642000f02a0c64200000d20c64200010290c64200020d30c64200030280c64200040d60c642000501c0c64200060d70c642000701b0c64200080d80c642000901a0c642000a0d90c642000b0190c642000c0da0c642000d0150c642000e0df0c642000f0140c64200000e00c64200010130c64200020e10c64200030120c64200040e20c64200050110c64200060e40c642000700e0c64200080e50c642000900d0c642000a0e60c642000b00c0c642000c0e70c642000d00b0c642000e0e80c642000f00a0c64200000ea0c64200010070c64200020eb0c64200030060c64200040ec0c64200050050c64200060ed0c64200070040c64200080ee0c64200090030c642000a0ef0c642000b0020c642000c0f00c642000d0010c642000e0f10c642000f0000c', '32000c000000008068110100641126003400180200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007e007e0102a13102a13102a120100000620102d0101000007c8078c060b5d00005e00004f80005080006d030059940b07010000240308a1089f08a2089e08a3089d08a4089c08a6089b08a7089a08a8089908a90898c0102c0308af089508b0089408b1089308b2089208b3088b08b7088a08b8088908b90888c0100308ba088708bb088108bf088008c0087f08c1087e08c2087d08c5087208c60871c010062807010308c7087008c8086f08c9086d087a086c0879086b0878086a086e08690863085ec010030862085d0861085c0860085b085f085a0831084a08300849082f0848082e0847c01003082d084608ca083b08cb083a08cc083908cd083808ce082c08d0082b08d1082ac010063007010308d2082908d3082808d6081c08d7081b08d8081a08d9081908da081508df0814c01059940b0308e0081308e1081208e2081108e4080e08e5080d08e6080c08e7080b08e8080ac010240308ea080708eb080608ec080508ed080408ee080308ef080208f0080108f10800c0100c0720070c2003040200004200080002089000000000002f00040038000000290004009000000035000400a0000000']),
SensorCaptureProg(major=0x6, minor=0x15, build=0x0, u1=0x0, dev_type=0x121, a0=0x18, a1=0x19, blobs=['2300000020000800002000800000010032005c00000000802020040024200000382000002820df0b2c20df0b302000003420000050200a015c200000602000004c2003006c20720070207200742001007820010084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a00', '330064030000008064200000a10c642000109f0c64200020a20c642000309e0c64200040a30c642000509d0c64200060a40c642000709c0c64200080a60c642000909b0c642000a0a70c642000b09a0c642000c0a80c642000d0990c642000e0a90c642000f0980c64200000af0c64200010950c64200020b00c64200030940c64200040b10c64200050930c64200060b20c64200070920c64200080b30c642000908b0c642000a0b70c642000b08a0c642000c0b80c642000d0890c642000e0b90c642000f0880c64200000ba0c64200010870c64200020bb0c64200030810c64200040bf0c64200050800c64200060c00c642000707f0c64200080c10c642000907e0c642000a0c20c642000b07d0c642000c0c50c642000d0720c642000e0c60c642000f0710c64200000c70c64200010700c64200020c80c642000306f0c64200040c90c642000506d0c642000607a0c642000706c0c64200080790c642000906b0c642000a0780c642000b06a0c642000c06e0c642000d0690c642000e0630c642000f05e0c64200000620c642000105d0c64200020610c642000305c0c64200040600c642000505b0c642000605f0c642000705a0c64200080310c642000904a0c642000a0300c642000b0490c642000c02f0c642000d0480c642000e02e0c642000f0470c642000002d0c64200010460c64200020ca0c642000303b0c64200040cb0c642000503a0c64200060cc0c64200070390c64200080cd0c64200090380c642000a0ce0c642000b02c0c642000c0d00c642000d02b0c642000e0d10c642000f02a0c64200000d20c64200010290c64200020d30c64200030280c64200040d60c642000501c0c64200060d70c642000701b0c64200080d80c642000901a0c642000a0d90c642000b0190c642000c0da0c642000d0150c642000e0df0c642000f0140c64200000e00c64200010130c64200020e10c64200030120c64200040e20c64200050110c64200060e40c642000700e0c64200080e50c642000900d0c642000a0e60c642000b00c0c642000c0e70c642000d00b0c642000e0e80c642000f00a0c64200000ea0c64200010070c64200020eb0c64200030060c64200040ec0c64200050050c64200060ed0c64200070040c64200080ee0c64200090030c642000a0ef0c642000b0020c642000c0f00c642000d0010c642000e0f10c642000f0000c', '32000c000000008068110100641126003400180200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007e007e0102a13102a13102a120100000620102d0101000007c8078c060b5d00005e00004f80005080006d030059940b07010000240308a1089f08a2089e08a3089d08a4089c08a6089b08a7089a08a8089908a90898c0102c0308af089508b0089408b1089308b2089208b3088b08b7088a08b8088908b90888c0100308ba088708bb088108bf088008c0087f08c1087e08c2087d08c5087208c60871c010062807010308c7087008c8086f08c9086d087a086c0879086b0878086a086e08690863085ec010030862085d0861085c0860085b085f085a0831084a08300849082f0848082e0847c01003082d084608ca083b08cb083a08cc083908cd083808ce082c08d0082b08d1082ac010063007010308d2082908d3082808d6081c08d7081b08d8081a08d9081908da081508df0814c01059940b0308e0081308e1081208e2081108e4080e08e5080d08e6080c08e7080b08e8080ac010240308ea080708eb080608ec080508ed080408ee080308ef080208f0080108f10800c0100c0720070c2003040200004200080002089000000000002f00040038000000290004009000000035000400a0000000']),
SensorCaptureProg(major=0x6, minor=0x14, build=0x0, u1=0x0, dev_type=0xb4b, a0=0x18, a1=0x19, blobs=['2300000020000800002000800000010032005c00000000802020040024200000382000002820df0b2c20df0b302000003420000050200a015c200000602000004c2003006c20660070206600742001007820010084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a00', '330064030000008064200000a10c642000109f0c64200020a20c642000309e0c64200040a30c642000509d0c64200060a40c642000709c0c64200080a60c642000909b0c642000a0a70c642000b09a0c642000c0a80c642000d0990c642000e0a90c642000f0980c64200000af0c64200010950c64200020b00c64200030940c64200040b10c64200050930c64200060b20c64200070920c64200080b30c642000908b0c642000a0b70c642000b08a0c642000c0b80c642000d0890c642000e0b90c642000f0880c64200000ba0c64200010870c64200020bb0c64200030810c64200040bf0c64200050800c64200060c00c642000707f0c64200080c10c642000907e0c642000a0c20c642000b07d0c642000c0c50c642000d0720c642000e0c60c642000f0710c64200000c70c64200010700c64200020c80c642000306f0c64200040c90c642000506d0c642000607a0c642000706c0c64200080790c642000906b0c642000a0780c642000b06a0c642000c06e0c642000d0690c642000e0630c642000f05e0c64200000620c642000105d0c64200020610c642000305c0c64200040600c642000505b0c642000605f0c642000705a0c64200080310c642000904a0c642000a0300c642000b0490c642000c02f0c642000d0480c642000e02e0c642000f0470c642000002d0c64200010460c64200020ca0c642000303b0c64200040cb0c642000503a0c64200060cc0c64200070390c64200080cd0c64200090380c642000a0ce0c642000b02c0c642000c0d00c642000d02b0c642000e0d10c642000f02a0c64200000d20c64200010290c64200020d30c64200030280c64200040d60c642000501c0c64200060d70c642000701b0c64200080d80c642000901a0c642000a0d90c642000b0190c642000c0da0c642000d0150c642000e0df0c642000f0140c64200000e00c64200010130c64200020e10c64200030120c64200040e20c64200050110c64200060e40c642000700e0c64200080e50c642000900d0c642000a0e60c642000b00c0c642000c0e70c642000d00b0c642000e0e80c642000f00a0c64200000ea0c64200010070c64200020eb0c64200030060c64200040ec0c64200050050c64200060ed0c64200070040c64200080ee0c64200090030c642000a0ef0c642000b0020c642000c0f00c642000d0010c642000e0f10c642000f0000c', '32000c000000008068110100641126003400180200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007e007e0102a13102a13102a12010000061e102d0101000007c8078c060b5d00005e00004f80005080006d030059940b07010000240308a1089f08a2089e08a3089d08a4089c08a6089b08a7089a08a8089908a90898c0102c0308af089508b0089408b1089308b2089208b3088b08b7088a08b8088908b90888c0100308ba088708bb088108bf088008c0087f08c1087e08c2087d08c5087208c60871c010062807010308c7087008c8086f08c9086d087a086c0879086b0878086a086e08690863085ec010030862085d0861085c0860085b085f085a0831084a08300849082f0848082e0847c01003082d084608ca083b08cb083a08cc083908cd083808ce082c08d0082b08d1082ac010063207010308d2082908d3082808d6081c08d7081b08d8081a08d9081908da081508df0814c01059940b0308e0081308e1081208e2081108e4080e08e5080d08e6080c08e7080b08e8080ac010240308ea080708eb080608ec080508ed080408ee080308ef080208f0080108f10800c0100c0720070c2003040200004200080002089000000000002f00040038000000290004009000000035000400a0000000']),
SensorCaptureProg(major=0x6, minor=0x15, build=0x0, u1=0x0, dev_type=0xb4b, a0=0x18, a1=0x19, blobs=['2300000020000800002000800000010032005c00000000802020040024200000382000002820df0b2c20df0b302000003420000050200a015c200000602000004c2003006c20660070206600742001007820010084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a00', '330064030000008064200000a10c642000109f0c64200020a20c642000309e0c64200040a30c642000509d0c64200060a40c642000709c0c64200080a60c642000909b0c642000a0a70c642000b09a0c642000c0a80c642000d0990c642000e0a90c642000f0980c64200000af0c64200010950c64200020b00c64200030940c64200040b10c64200050930c64200060b20c64200070920c64200080b30c642000908b0c642000a0b70c642000b08a0c642000c0b80c642000d0890c642000e0b90c642000f0880c64200000ba0c64200010870c64200020bb0c64200030810c64200040bf0c64200050800c64200060c00c642000707f0c64200080c10c642000907e0c642000a0c20c642000b07d0c642000c0c50c642000d0720c642000e0c60c642000f0710c64200000c70c64200010700c64200020c80c642000306f0c64200040c90c642000506d0c642000607a0c642000706c0c64200080790c642000906b0c642000a0780c642000b06a0c642000c06e0c642000d0690c642000e0630c642000f05e0c64200000620c642000105d0c64200020610c642000305c0c64200040600c642000505b0c642000605f0c642000705a0c64200080310c642000904a0c642000a0300c642000b0490c642000c02f0c642000d0480c642000e02e0c642000f0470c642000002d0c64200010460c64200020ca0c642000303b0c64200040cb0c642000503a0c64200060cc0c64200070390c64200080cd0c64200090380c642000a0ce0c642000b02c0c642000c0d00c642000d02b0c642000e0d10c642000f02a0c64200000d20c64200010290c64200020d30c64200030280c64200040d60c642000501c0c64200060d70c642000701b0c64200080d80c642000901a0c642000a0d90c642000b0190c642000c0da0c642000d0150c642000e0df0c642000f0140c64200000e00c64200010130c64200020e10c64200030120c64200040e20c64200050110c64200060e40c642000700e0c64200080e50c642000900d0c642000a0e60c642000b00c0c642000c0e70c642000d00b0c642000e0e80c642000f00a0c64200000ea0c64200010070c64200020eb0c64200030060c64200040ec0c64200050050c64200060ed0c64200070040c64200080ee0c64200090030c642000a0ef0c642000b0020c642000c0f00c642000d0010c642000e0f10c642000f0000c', '32000c000000008068110100641126003400180200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007e007e0102a13102a13102a12010000061e102d0101000007c8078c060b5d00005e00004f80005080006d030059940b07010000240308a1089f08a2089e08a3089d08a4089c08a6089b08a7089a08a8089908a90898c0102c0308af089508b0089408b1089308b2089208b3088b08b7088a08b8088908b90888c0100308ba088708bb088108bf088008c0087f08c1087e08c2087d08c5087208c60871c010062807010308c7087008c8086f08c9086d087a086c0879086b0878086a086e08690863085ec010030862085d0861085c0860085b085f085a0831084a08300849082f0848082e0847c01003082d084608ca083b08cb083a08cc083908cd083808ce082c08d0082b08d1082ac010063207010308d2082908d3082808d6081c08d7081b08d8081a08d9081908da081508df0814c01059940b0308e0081308e1081208e2081108e4080e08e5080d08e6080c08e7080b08e8080ac010240308ea080708eb080608ec080508ed080408ee080308ef080208f0080108f10800c0100c0720070c2003040200004200080002089000000000002f00040038000000290004009000000035000400a0000000']),
SensorCaptureProg(major=0x6, minor=0x14, build=0x0, u1=0x0, dev_type=0xb4b, a0=0x18, a1=0x19, blobs=['2300000020000800002000800000010032005c00000000802020040024200000382000002820df0b2c20df0b302000003420000050201f015c200000602000004c2003006c20720070207200742004007820040084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a00', '330064030000008064200000a10c642000109f0c64200020a20c642000309e0c64200040a30c642000509d0c64200060a40c642000709c0c64200080a60c642000909b0c642000a0a70c642000b09a0c642000c0a80c642000d0990c642000e0a90c642000f0980c64200000af0c64200010950c64200020b00c64200030940c64200040b10c64200050930c64200060b20c64200070920c64200080b30c642000908b0c642000a0b70c642000b08a0c642000c0b80c642000d0890c642000e0b90c642000f0880c64200000ba0c64200010870c64200020bb0c64200030810c64200040bf0c64200050800c64200060c00c642000707f0c64200080c10c642000907e0c642000a0c20c642000b07d0c642000c0c50c642000d0720c642000e0c60c642000f0710c64200000c70c64200010700c64200020c80c642000306f0c64200040c90c642000506d0c642000607a0c642000706c0c64200080790c642000906b0c642000a0780c642000b06a0c642000c06e0c642000d0690c642000e0630c642000f05e0c64200000620c642000105d0c64200020610c642000305c0c64200040600c642000505b0c642000605f0c642000705a0c64200080310c642000904a0c642000a0300c642000b0490c642000c02f0c642000d0480c642000e02e0c642000f0470c642000002d0c64200010460c64200020ca0c642000303b0c64200040cb0c642000503a0c64200060cc0c64200070390c64200080cd0c64200090380c642000a0ce0c642000b02c0c642000c0d00c642000d02b0c642000e0d10c642000f02a0c64200000d20c64200010290c64200020d30c64200030280c64200040d60c642000501c0c64200060d70c642000701b0c64200080d80c642000901a0c642000a0d90c642000b0190c642000c0da0c642000d0150c642000e0df0c642000f0140c64200000e00c64200010130c64200020e10c64200030120c64200040e20c64200050110c64200060e40c642000700e0c64200080e50c642000900d0c642000a0e60c642000b00c0c642000c0e70c642000d00b0c642000e0e80c642000f00a0c64200000ea0c64200010070c64200020eb0c64200030060c64200040ec0c64200050050c64200060ed0c64200070040c64200080ee0c64200090030c642000a0ef0c642000b0020c642000c0f00c642000d0010c642000e0f10c642000f0000c', '32000c000000008068110100641126003400180200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007e007e0102a13102a13102a12010000061e102d0101000007c8078c060b5d03005e03004f80005080006d030059940b07010000240308a1089f08a2089e08a3089d08a4089c08a6089b08a7089a08a8089908a90898c0102c0308af089508b0089408b1089308b2089208b3088b08b7088a08b8088908b90888c0100308ba088708bb088108bf088008c0087f08c1087e08c2087d08c5087208c60871c010062807010308c7087008c8086f08c9086d087a086c0879086b0878086a086e08690863085ec010030862085d0861085c0860085b085f085a0831084a08300849082f0848082e0847c01003082d084608ca083b08cb083a08cc083908cd083808ce082c08d0082b08d1082ac010063207010308d2082908d3082808d6081c08d7081b08d8081a08d9081908da081508df0814c01059940b0308e0081308e1081208e2081108e4080e08e5080d08e6080c08e7080b08e8080ac010240308ea080708eb080608ec080508ed080408ee080308ef080208f0080108f10800c0100c0720070c2003040200004200080002089000000000002f00040038000000290004009000000035000400a0000000']),
SensorCaptureProg(major=0x6, minor=0x15, build=0x0, u1=0x0, dev_type=0xb4b, a0=0x18, a1=0x19, blobs=['2300000020000800002000800000010032005c00000000802020040024200000382000002820df0b2c20df0b302000003420000050201f015c200000602000004c2003006c20720070207200742004007820040084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a00', '330064030000008064200000a10c642000109f0c64200020a20c642000309e0c64200040a30c642000509d0c64200060a40c642000709c0c64200080a60c642000909b0c642000a0a70c642000b09a0c642000c0a80c642000d0990c642000e0a90c642000f0980c64200000af0c64200010950c64200020b00c64200030940c64200040b10c64200050930c64200060b20c64200070920c64200080b30c642000908b0c642000a0b70c642000b08a0c642000c0b80c642000d0890c642000e0b90c642000f0880c64200000ba0c64200010870c64200020bb0c64200030810c64200040bf0c64200050800c64200060c00c642000707f0c64200080c10c642000907e0c642000a0c20c642000b07d0c642000c0c50c642000d0720c642000e0c60c642000f0710c64200000c70c64200010700c64200020c80c642000306f0c64200040c90c642000506d0c642000607a0c642000706c0c64200080790c642000906b0c642000a0780c642000b06a0c642000c06e0c642000d0690c642000e0630c642000f05e0c64200000620c642000105d0c64200020610c642000305c0c64200040600c642000505b0c642000605f0c642000705a0c64200080310c642000904a0c642000a0300c642000b0490c642000c02f0c642000d0480c642000e02e0c642000f0470c642000002d0c64200010460c64200020ca0c642000303b0c64200040cb0c642000503a0c64200060cc0c64200070390c64200080cd0c64200090380c642000a0ce0c642000b02c0c642000c0d00c642000d02b0c642000e0d10c642000f02a0c64200000d20c64200010290c64200020d30c64200030280c64200040d60c642000501c0c64200060d70c642000701b0c64200080d80c642000901a0c642000a0d90c642000b0190c642000c0da0c642000d0150c642000e0df0c642000f0140c64200000e00c64200010130c64200020e10c64200030120c64200040e20c64200050110c64200060e40c642000700e0c64200080e50c642000900d0c642000a0e60c642000b00c0c642000c0e70c642000d00b0c642000e0e80c642000f00a0c64200000ea0c64200010070c64200020eb0c64200030060c64200040ec0c64200050050c64200060ed0c64200070040c64200080ee0c64200090030c642000a0ef0c642000b0020c642000c0f00c642000d0010c642000e0f10c642000f0000c', '32000c000000008068110100641126003400180200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007e007e0102a13102a13102a12010000061e102d0101000007c8078c060b5d03005e03004f80005080006d030059940b07010000240308a1089f08a2089e08a3089d08a4089c08a6089b08a7089a08a8089908a90898c0102c0308af089508b0089408b1089308b2089208b3088b08b7088a08b8088908b90888c0100308ba088708bb088108bf088008c0087f08c1087e08c2087d08c5087208c60871c010062807010308c7087008c8086f08c9086d087a086c0879086b0878086a086e08690863085ec010030862085d0861085c0860085b085f085a0831084a08300849082f0848082e0847c01003082d084608ca083b08cb083a08cc083908cd083808ce082c08d0082b08d1082ac010063207010308d2082908d3082808d6081c08d7081b08d8081a08d9081908da081508df0814c01059940b0308e0081308e1081208e2081108e4080e08e5080d08e6080c08e7080b08e8080ac010240308ea080708eb080608ec080508ed080408ee080308ef080208f0080108f10800c0100c0720070c2003040200004200080002089000000000002f00040038000000290004009000000035000400a0000000']),
SensorCaptureProg(major=0x6, minor=0x14, build=0x0, u1=0x0, dev_type=0xb4d, a0=0x18, a1=0x19, blobs=['2300000020000800002000800000010032005c00000000802020040024200000382000002820df0b2c20df0b302000003420000050200a015c200000602000004c2003006c20600070206000742002007820020084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a00', '330064030000008064200000a10c642000109f0c64200020a20c642000309e0c64200040a30c642000509d0c64200060a40c642000709c0c64200080a60c642000909b0c642000a0a70c642000b09a0c642000c0a80c642000d0990c642000e0a90c642000f0980c64200000af0c64200010950c64200020b00c64200030940c64200040b10c64200050930c64200060b20c64200070920c64200080b30c642000908b0c642000a0b70c642000b08a0c642000c0b80c642000d0890c642000e0b90c642000f0880c64200000ba0c64200010870c64200020bb0c64200030810c64200040bf0c64200050800c64200060c00c642000707f0c64200080c10c642000907e0c642000a0c20c642000b07d0c642000c0c50c642000d0720c642000e0c60c642000f0710c64200000c70c64200010700c64200020c80c642000306f0c64200040c90c642000506d0c642000607a0c642000706c0c64200080790c642000906b0c642000a0780c642000b06a0c642000c06e0c642000d0690c642000e0630c642000f05e0c64200000620c642000105d0c64200020610c642000305c0c64200040600c642000505b0c642000605f0c642000705a0c64200080310c642000904a0c642000a0300c642000b0490c642000c02f0c642000d0480c642000e02e0c642000f0470c642000002d0c64200010460c64200020ca0c642000303b0c64200040cb0c642000503a0c64200060cc0c64200070390c64200080cd0c64200090380c642000a0ce0c642000b02c0c642000c0d00c642000d02b0c642000e0d10c642000f02a0c64200000d20c64200010290c64200020d30c64200030280c64200040d60c642000501c0c64200060d70c642000701b0c64200080d80c642000901a0c642000a0d90c642000b0190c642000c0da0c642000d0150c642000e0df0c642000f0140c64200000e00c64200010130c64200020e10c64200030120c64200040e20c64200050110c64200060e40c642000700e0c64200080e50c642000900d0c642000a0e60c642000b00c0c642000c0e70c642000d00b0c642000e0e80c642000f00a0c64200000ea0c64200010070c64200020eb0c64200030060c64200040ec0c64200050050c64200060ed0c64200070040c64200080ee0c64200090030c642000a0ef0c642000b0020c642000c0f00c642000d0010c642000e0f10c642000f0000c', '32000c000000008068110100641126003400180200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007e007e0102a13102a13102a12010000061e102d0101000007c8078c060b5d01005e01004f80005080006d030059940b07010000240308a1089f08a2089e08a3089d08a4089c08a6089b08a7089a08a8089908a90898c0102c0308af089508b0089408b1089308b2089208b3088b08b7088a08b8088908b90888c0100308ba088708bb088108bf088008c0087f08c1087e08c2087d08c5087208c60871c010062807010308c7087008c8086f08c9086d087a086c0879086b0878086a086e08690863085ec010030862085d0861085c0860085b085f085a0831084a08300849082f0848082e0847c01003082d084608ca083b08cb083a08cc083908cd083808ce082c08d0082b08d1082ac010063207010308d2082908d3082808d6081c08d7081b08d8081a08d9081908da081508df0814c01059940b0308e0081308e1081208e2081108e4080e08e5080d08e6080c08e7080b08e8080ac010240308ea080708eb080608ec080508ed080408ee080308ef080208f0080108f10800c0100c0720070c2003040200004200080002089000000000002f00040038000000290004009000000035000400a0000000']),
SensorCaptureProg(major=0x6, minor=0x15, build=0x0, u1=0x0, dev_type=0xb4d, a0=0x18, a1=0x19, blobs=['2300000020000800002000800000010032005c00000000802020040024200000382000002820df0b2c20df0b302000003420000050200a015c200000602000004c2003006c20600070206000742002007820020084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a00', '330064030000008064200000a10c642000109f0c64200020a20c642000309e0c64200040a30c642000509d0c64200060a40c642000709c0c64200080a60c642000909b0c642000a0a70c642000b09a0c642000c0a80c642000d0990c642000e0a90c642000f0980c64200000af0c64200010950c64200020b00c64200030940c64200040b10c64200050930c64200060b20c64200070920c64200080b30c642000908b0c642000a0b70c642000b08a0c642000c0b80c642000d0890c642000e0b90c642000f0880c64200000ba0c64200010870c64200020bb0c64200030810c64200040bf0c64200050800c64200060c00c642000707f0c64200080c10c642000907e0c642000a0c20c642000b07d0c642000c0c50c642000d0720c642000e0c60c642000f0710c64200000c70c64200010700c64200020c80c642000306f0c64200040c90c642000506d0c642000607a0c642000706c0c64200080790c642000906b0c642000a0780c642000b06a0c642000c06e0c642000d0690c642000e0630c642000f05e0c64200000620c642000105d0c64200020610c642000305c0c64200040600c642000505b0c642000605f0c642000705a0c64200080310c642000904a0c642000a0300c642000b0490c642000c02f0c642000d0480c642000e02e0c642000f0470c642000002d0c64200010460c64200020ca0c642000303b0c64200040cb0c642000503a0c64200060cc0c64200070390c64200080cd0c64200090380c642000a0ce0c642000b02c0c642000c0d00c642000d02b0c642000e0d10c642000f02a0c64200000d20c64200010290c64200020d30c64200030280c64200040d60c642000501c0c64200060d70c642000701b0c64200080d80c642000901a0c642000a0d90c642000b0190c642000c0da0c642000d0150c642000e0df0c642000f0140c64200000e00c64200010130c64200020e10c64200030120c64200040e20c64200050110c64200060e40c642000700e0c64200080e50c642000900d0c642000a0e60c642000b00c0c642000c0e70c642000d00b0c642000e0e80c642000f00a0c64200000ea0c64200010070c64200020eb0c64200030060c64200040ec0c64200050050c64200060ed0c64200070040c64200080ee0c64200090030c642000a0ef0c642000b0020c642000c0f00c642000d0010c642000e0f10c642000f0000c', '32000c000000008068110100641126003400180200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007e007e0102a13102a13102a12010000061e102d0101000007c8078c060b5d01005e01004f80005080006d030059940b07010000240308a1089f08a2089e08a3089d08a4089c08a6089b08a7089a08a8089908a90898c0102c0308af089508b0089408b1089308b2089208b3088b08b7088a08b8088908b90888c0100308ba088708bb088108bf088008c0087f08c1087e08c2087d08c5087208c60871c010062807010308c7087008c8086f08c9086d087a086c0879086b0878086a086e08690863085ec010030862085d0861085c0860085b085f085a0831084a08300849082f0848082e0847c01003082d084608ca083b08cb083a08cc083908cd083808ce082c08d0082b08d1082ac010063207010308d2082908d3082808d6081c08d7081b08d8081a08d9081908da081508df0814c01059940b0308e0081308e1081208e2081108e4080e08e5080d08e6080c08e7080b08e8080ac010240308ea080708eb080608ec080508ed080408ee080308ef080208f0080108f10800c0100c0720070c2003040200004200080002089000000000002f00040038000000290004009000000035000400a0000000']),
SensorCaptureProg(major=0x6, minor=0x15, build=0x0, u1=0x0, dev_type=0x130, a0=0x18, a1=0x19, blobs=['2300000020000800002000800000010032005c00000000802020040024200000382000002820df0b2c20df0b302000003420000050200a015c200000602000004c2003006c20400070204000742001007820010084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a003200b4020000008074030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030005740300077403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030015740300177403000174030003', '330064030000008064200000e40c64200010050c64200020e60c64200030040c64200040e70c64200050020c64200060eb0c64200070000c64200080ec0c64200090010c642000a0ed0c642000b0030c642000c0f10c642000d0060c642000e0f00c642000f0070c64200000ef0c64200010080c64200020ee0c642000300a0c64200040ea0c642000500b0c64200060e80c642000700c0c64200080e50c642000900d0c642000a0e10c642000b0100c642000c0e00c642000d0140c642000e0df0c642000f0160c64200000de0c64200010190c64200020dc0c642000301d0c64200040db0c642000501e0c64200060da0c64200070220c64200080d30c64200090250c642000a0d10c642000b0270c642000c0cb0c642000d02b0c642000e0ca0c642000f02d0c642000003a0c64200010310c642000203b0c64200030320c642000403d0c64200050370c642000603e0c64200070390c64200080460c642000903c0c642000a0470c642000b03f0c642000c0490c642000d0400c642000e04a0c642000f0450c642000004c0c64200010480c642000204d0c642000304b0c642000405c0c642000504e0c642000605d0c642000704f0c642000805e0c64200090500c642000a0610c642000b0550c642000c0620c642000d05a0c642000e0630c642000f05b0c64200000680c642000105f0c64200020690c64200030600c642000406a0c64200050640c642000606d0c64200070650c642000806e0c642000906b0c642000a06f0c642000b06c0c642000c0700c642000d0710c642000e0c90c642000f0720c64200000c80c64200010770c64200020c60c64200030780c64200040c20c642000507c0c64200060c10c642000707f0c64200080c00c64200090820c642000a0bd0c642000b0840c642000c0bc0c642000d0870c642000e0b80c642000f08b0c64200000b50c642000108f0c64200020b20c64200030910c64200040af0c64200050940c64200060ae0c64200070980c64200080ad0c642000909a0c642000a0ac0c642000b09e0c642000c0ab0c642000d09f0c642000e0a90c642000f09d0c64200000a80c642000109c0c64200020a70c642000309b0c64200040a60c64200050990c64200060a40c64200070960c64200080a30c64200090950c642000a0a20c642000b0930c642000c0a10c642000d0920c642000e0a90c642000f09d0c', '32000c0000000080681101006411260034000c0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007e007e0102a0d102a0d102a0e0100000628102c0101000007c8078c061400004f80005080006d030059940b07010000240308e4080508e6080408e7080208eb080008ec080108ed080308f1080608f00807c0102c0308ef080808ee080a08ea080b08e8080c08e5080d08e1081008e0081408df0816c0100308de081908dc081d08db081e08da082208d3082508d1082708cb082b08ca082dc01003083a0831083b0832083d0837083e08390846083c0847083f08490840084a0845c01003084c0848084d084b085c084e085d084f085e0850086108550862085a0863085bc010030868085f08690860086a0864086d0865086e086b086f086c0870087108c90872c0100308c8087708c6087808c2087c08c1087f08c0088208bd088408bc088708b8088bc0100308b5088f08b2089108af089408ae089808ad089a08ac089e08ab089f08a9089dc010240308a9089d08a8089c08a7089b08a6089908a4089608a3089508a2089308a10892c0100c072c20030703070304020000004200080002089000000000002f00040028000000290004009000000035000400a0000000']),
SensorCaptureProg(major=0x6, minor=0x15, build=0x0, u1=0x0, dev_type=0x518, a0=0x18, a1=0x19, blobs=['2300000020000800002000800000010032005c00000000802020040024200000382000002820df0b2c20df0b302000003420000050200a015c200000602000004c2003006c20640070206400742001007820010084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a003200b4020000008074030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030005740300077403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030015740300177403000174030003', '330064030000008064200000e40c64200010050c64200020e60c64200030040c64200040e70c64200050020c64200060eb0c64200070000c64200080ec0c64200090010c642000a0ed0c642000b0030c642000c0f10c642000d0060c642000e0f00c642000f0070c64200000ef0c64200010080c64200020ee0c642000300a0c64200040ea0c642000500b0c64200060e80c642000700c0c64200080e50c642000900d0c642000a0e10c642000b0100c642000c0e00c642000d0140c642000e0df0c642000f0160c64200000de0c64200010190c64200020dc0c642000301d0c64200040db0c642000501e0c64200060da0c64200070220c64200080d30c64200090250c642000a0d10c642000b0270c642000c0cb0c642000d02b0c642000e0ca0c642000f02d0c642000003a0c64200010310c642000203b0c64200030320c642000403d0c64200050370c642000603e0c64200070390c64200080460c642000903c0c642000a0470c642000b03f0c642000c0490c642000d0400c642000e04a0c642000f0450c642000004c0c64200010480c642000204d0c642000304b0c642000405c0c642000504e0c642000605d0c642000704f0c642000805e0c64200090500c642000a0610c642000b0550c642000c0620c642000d05a0c642000e0630c642000f05b0c64200000680c642000105f0c64200020690c64200030600c642000406a0c64200050640c642000606d0c64200070650c642000806e0c642000906b0c642000a06f0c642000b06c0c642000c0700c642000d0710c642000e0c90c642000f0720c64200000c80c64200010770c64200020c60c64200030780c64200040c20c642000507c0c64200060c10c642000707f0c64200080c00c64200090820c642000a0bd0c642000b0840c642000c0bc0c642000d0870c642000e0b80c642000f08b0c64200000b50c642000108f0c64200020b20c64200030910c64200040af0c64200050940c64200060ae0c64200070980c64200080ad0c642000909a0c642000a0ac0c642000b09e0c642000c0ab0c642000d09f0c642000e0a90c642000f09d0c64200000a80c642000109c0c64200020a70c642000309b0c64200040a60c64200050990c64200060a40c64200070960c64200080a30c64200090950c642000a0a20c642000b0930c642000c0a10c642000d0920c642000e0a90c642000f09d0c', '32000c0000000080681101006411260034000c0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007e007e0102a0d102a0d102a0e0100000628102c0101000007c8078c061400004f80005080006d030059940b07010000240308e4080508e6080408e7080208eb080008ec080108ed080308f1080608f00807c0102c0308ef080808ee080a08ea080b08e8080c08e5080d08e1081008e0081408df0816c0100308de081908dc081d08db081e08da082208d3082508d1082708cb082b08ca082dc01003083a0831083b0832083d0837083e08390846083c0847083f08490840084a0845c01003084c0848084d084b085c084e085d084f085e0850086108550862085a0863085bc010030868085f08690860086a0864086d0865086e086b086f086c0870087108c90872c0100308c8087708c6087808c2087c08c1087f08c0088208bd088408bc088708b8088bc0100308b5088f08b2089108af089408ae089808ad089a08ac089e08ab089f08a9089dc010240308a9089d08a8089c08a7089b08a6089908a4089608a3089508a2089308a10892c0100c072c20030703070304020000004200080002089000000000002f00040028000000290004009000000035000400a0000000']),
SensorCaptureProg(major=0x6, minor=0x15, build=0x0, u1=0x0, dev_type=0xbe1, a0=0x18, a1=0x19, blobs=['2300000020000800002000800000010032005c00000000802020040024200000382000002820df0b2c20df0b302000003420000050200a015c200000602000004c2003006c20550070205500742001007820010084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a003200b4020000008074030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030005740300077403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030015740300177403000174030003', '330064030000008064200000e40c64200010050c64200020e60c64200030040c64200040e70c64200050020c64200060eb0c64200070000c64200080ec0c64200090010c642000a0ed0c642000b0030c642000c0f10c642000d0060c642000e0f00c642000f0070c64200000ef0c64200010080c64200020ee0c642000300a0c64200040ea0c642000500b0c64200060e80c642000700c0c64200080e50c642000900d0c642000a0e10c642000b0100c642000c0e00c642000d0140c642000e0df0c642000f0160c64200000de0c64200010190c64200020dc0c642000301d0c64200040db0c642000501e0c64200060da0c64200070220c64200080d30c64200090250c642000a0d10c642000b0270c642000c0cb0c642000d02b0c642000e0ca0c642000f02d0c642000003a0c64200010310c642000203b0c64200030320c642000403d0c64200050370c642000603e0c64200070390c64200080460c642000903c0c642000a0470c642000b03f0c642000c0490c642000d0400c642000e04a0c642000f0450c642000004c0c64200010480c642000204d0c642000304b0c642000405c0c642000504e0c642000605d0c642000704f0c642000805e0c64200090500c642000a0610c642000b0550c642000c0620c642000d05a0c642000e0630c642000f05b0c64200000680c642000105f0c64200020690c64200030600c642000406a0c64200050640c642000606d0c64200070650c642000806e0c642000906b0c642000a06f0c642000b06c0c642000c0700c642000d0710c642000e0c90c642000f0720c64200000c80c64200010770c64200020c60c64200030780c64200040c20c642000507c0c64200060c10c642000707f0c64200080c00c64200090820c642000a0bd0c642000b0840c642000c0bc0c642000d0870c642000e0b80c642000f08b0c64200000b50c642000108f0c64200020b20c64200030910c64200040af0c64200050940c64200060ae0c64200070980c64200080ad0c642000909a0c642000a0ac0c642000b09e0c642000c0ab0c642000d09f0c642000e0a90c642000f09d0c64200000a80c642000109c0c64200020a70c642000309b0c64200040a60c64200050990c64200060a40c64200070960c64200080a30c64200090950c642000a0a20c642000b0930c642000c0a10c642000d0920c642000e0a90c642000f09d0c', '32000c0000000080681101006411260034000c0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007e007e0102a0d102a0d102a0e0100000628102c0101000007c8078c061400004f80005080006d030059940b07010000240308e4080508e6080408e7080208eb080008ec080108ed080308f1080608f00807c0102c0308ef080808ee080a08ea080b08e8080c08e5080d08e1081008e0081408df0816c0100308de081908dc081d08db081e08da082208d3082508d1082708cb082b08ca082dc01003083a0831083b0832083d0837083e08390846083c0847083f08490840084a0845c01003084c0848084d084b085c084e085d084f085e0850086108550862085a0863085bc010030868085f08690860086a0864086d0865086e086b086f086c0870087108c90872c0100308c8087708c6087808c2087c08c1087f08c0088208bd088408bc088708b8088bc0100308b5088f08b2089108af089408ae089808ad089a08ac089e08ab089f08a9089dc010240308a9089d08a8089c08a7089b08a6089908a4089608a3089508a2089308a10892c0100c072c20030703070304020000004200080002089000000000002f00040028000000290004009000000035000400a0000000']),
SensorCaptureProg(major=0x6, minor=0x15, build=0x0, u1=0x0, dev_type=0xbe2, a0=0x18, a1=0x19, blobs=['2300000020000800002000800000010032005c00000000802020040024200000382000002820df0b2c20df0b302000003420000050200a015c200000602000004c2003006c20500070205000742001007820010084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a003200b4020000008074030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030005740300077403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030015740300177403000174030003', '330064030000008064200000e40c64200010050c64200020e60c64200030040c64200040e70c64200050020c64200060eb0c64200070000c64200080ec0c64200090010c642000a0ed0c642000b0030c642000c0f10c642000d0060c642000e0f00c642000f0070c64200000ef0c64200010080c64200020ee0c642000300a0c64200040ea0c642000500b0c64200060e80c642000700c0c64200080e50c642000900d0c642000a0e10c642000b0100c642000c0e00c642000d0140c642000e0df0c642000f0160c64200000de0c64200010190c64200020dc0c642000301d0c64200040db0c642000501e0c64200060da0c64200070220c64200080d30c64200090250c642000a0d10c642000b0270c642000c0cb0c642000d02b0c642000e0ca0c642000f02d0c642000003a0c64200010310c642000203b0c64200030320c642000403d0c64200050370c642000603e0c64200070390c64200080460c642000903c0c642000a0470c642000b03f0c642000c0490c642000d0400c642000e04a0c642000f0450c642000004c0c64200010480c642000204d0c642000304b0c642000405c0c642000504e0c642000605d0c642000704f0c642000805e0c64200090500c642000a0610c642000b0550c642000c0620c642000d05a0c642000e0630c642000f05b0c64200000680c642000105f0c64200020690c64200030600c642000406a0c64200050640c642000606d0c64200070650c642000806e0c642000906b0c642000a06f0c642000b06c0c642000c0700c642000d0710c642000e0c90c642000f0720c64200000c80c64200010770c64200020c60c64200030780c64200040c20c642000507c0c64200060c10c642000707f0c64200080c00c64200090820c642000a0bd0c642000b0840c642000c0bc0c642000d0870c642000e0b80c642000f08b0c64200000b50c642000108f0c64200020b20c64200030910c64200040af0c64200050940c64200060ae0c64200070980c64200080ad0c642000909a0c642000a0ac0c642000b09e0c642000c0ab0c642000d09f0c642000e0a90c642000f09d0c64200000a80c642000109c0c64200020a70c642000309b0c64200040a60c64200050990c64200060a40c64200070960c64200080a30c64200090950c642000a0a20c642000b0930c642000c0a10c642000d0920c642000e0a90c642000f09d0c', '32000c0000000080681101006411260034000c0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007e007e0102a0d102a0d102a0e0100000628102c0101000007c8078c061400004f80005080006d030059940b07010000240308e4080508e6080408e7080208eb080008ec080108ed080308f1080608f00807c0102c0308ef080808ee080a08ea080b08e8080c08e5080d08e1081008e0081408df0816c0100308de081908dc081d08db081e08da082208d3082508d1082708cb082b08ca082dc01003083a0831083b0832083d0837083e08390846083c0847083f08490840084a0845c01003084c0848084d084b085c084e085d084f085e0850086108550862085a0863085bc010030868085f08690860086a0864086d0865086e086b086f086c0870087108c90872c0100308c8087708c6087808c2087c08c1087f08c0088208bd088408bc088708b8088bc0100308b5088f08b2089108af089408ae089808ad089a08ac089e08ab089f08a9089dc010240308a9089d08a8089c08a7089b08a6089908a4089608a3089508a2089308a10892c0100c072c20030703070304020000004200080002089000000000002f00040028000000290004009000000035000400a0000000']),
SensorCaptureProg(major=0x6, minor=0xb, build=0x0, u1=0x0, dev_type=0x194, a0=0x18, a1=0x19, blobs=['2300000020000800002000800000010032005c0000000080202004002820ff0b2c20f60b6c202f007020000074201000782000005c2000006020000064200000502000005420151d84202000942001809c200902a0200b19b4200000b8203a00bc201400c0200200c4200200c82008003300100000000080cc2000004900d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0201400f8200500fc200000b8203b00002804001428000008280000082810001428180008281100142819001c281a00', '32001400000000806811010064111f007c1700007017010033001c00000000809c1701000000ac1700900100b01754000000b417007200003400500010061110061110061110061110061001068010080101000007c80764060000002003070107010c07840a640863c91e2cc9159107010a9dc9110701030a3208330701c90f20c91e070304020000000000', '2f0004005400000029000400000000003500040010000000']),
SensorCaptureProg(major=0x6, minor=0x0, build=0x0, u1=0x0, dev_type=0x179, a0=0x18, a1=0x19, blobs=['2300000020000800002000800000010032007800000000802020040024200000382000002820df0b2c20df0b30200000342000003c20000040200000442000004820000050200a005c20000060200000642000004c200300002100006c2030007020300040210000742006007820060084202000b4200000b8203a00bc201400c0200200c4200100c820020033001c000000008054202f27030058202f270300cc200000ef03d0200000ef033200440000000080dc20e803e020e803e420d002e820d002f0200500f8200500fc200000b8203a00002804001428000008280000082800001428300008280000142831001c281a00', '320014000000008068110100641126007c1700007017010033001c00000000809c1701000000ac1700900100b01738000000b417009000003400040310060b10060b10060b10060b10060c01064e10080101000007c80764060000002003070107010c2c078408a180089f800aa108a2800a9f089e800aa208a3800a9e089d800aa308a4800a9d089c800aa408a6800a9c089b800aa608a7800a9b089a800aa708a8800a9a0899800aa808a9800a990898800aa908af800a980895800aaf08b0800a950894800ab008b1800a940893800ab108b2800a930892800ab208b3800a92088b800ab308b7800a8b088a800ab708b8800a8a0889800ab808b9800a890888800ab908ba800a880887800aba08bb800a870881800abb08bf800a810880800abf08c0800a80087f800ac008c1800a7f087e800ac108c2800a7e087d800ac208c5800a7d0872800ac508c6800a720871800ac608c7800a710870800ac708c8800a70086f800ac808c9800a6f0863800ac9086c800a630862800a6c086b800a620861800a6b086a800a610860800a6a0869800a60085f800a69085e800a5f084f800a5e085d800a4f084e800a5d085c800a4e084d800a5c085b800a4d084c800a5b085a800a4c084b800a5a0831800a4b084a800a310830800a4a0849800a30082f800a490848800a2f082e800a480847800a2e082d800a470846800a2d08ca800a46083b800aca08cb800a3b083a800acb08cc800a3a0839800acc08cd800a390838800acd08ce800a38082c800ace08d1800a2c082b800ad108d2800a2b082a800ad208d3800a2a0829800ad308d6800a290828800ad608d7800a28081d800ad708d8800a1d081c800ad808d9800a1c081b800ad908da800a1b081a800ada08de800a1a0819800ade08df800a190815800adf08e0800a150814800ae008e1800a140813800ae108e2800a130812800ae208e4800a120811800ae408e5800a11080d800ae508e6800a0d080c800ae608e7800a0c080b800ae708ea800a0b080a800aea08eb800a0a0807800aeb08ec800a070806800aec08ed800a060805800aed08ee800a050804800aee08ef800a040803800aef08f0800a030802800af008f1800a020801800af108f2800a010800802007032003070307030402000000', '2f0004003800000029000400000000003500040010000000']),
SensorCaptureProg(major=0x6, minor=0xa, build=0x0, u1=0x0, dev_type=0x117, a0=0x18, a1=0x19, blobs=['2300000020000800002000800000010032006400000000802020040024200000382000002820df0b2c20df0b30200000342000003c2080004020800050200a005c200000602000004c2003006c20680070206800742001007820010084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a00', '32000c000000008068110100641126003400ac0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000102b0e102b0e102b0e102b0e01000000061e10301001000007c80764060b4f80005080006d030007010000006d0300200307010007032408a180089f800aa108a2800a9f089e800aa208a3800a9e089d800aa308a4800a9d089c800aa408a6800a9c089b802c0aa608a7800a9b089a800aa708a8800a9a0899800aa808a9800a990898800aa908af800a980895800aaf08b0800a950894800ab008b1800a940893800ab108b2800a930892800ab208b3800a92088b800ab308b7800a8b088a800ab708b8800a8a0889800ab808b9800a890888800ab908ba800a880887800aba08bb800a870881800abb08bf800a810880800abf08c0800a80087f800ac008c1800a7f087e800ac108c2800a7e087d800ac208c5800a7d0872800ac508c6800a72087180062807010ac608c7800a710870800ac708c8800a70086f800ac808c9800a6f0863800ac9086c800a630862800a6c086b800a620861800a6b086a800a610860800a6a0869800a60085f800a69085e800a5f084f800a5e085d800a4f084e800a5d085c800a4e084d800a5c085b800a4d084c800a5b085a800a4c084b800a5a0831800a4b084a800a310830800a4a0849800a30082f800a490848800a2f082e800a480847800a2e082d800a470846800a2d08ca800a46083b800aca08cb800a3b083a800acb08cc800a3a0839800acc08cd800a390838800acd08ce800a38082c800ace08d1800a2c082b800ad108d2800a2b082a80063207010ad208d3800a2a0829800ad308d6800a290828800ad608d7800a28081d800ad708d8800a1d081c800ad808d9800a1c081b800ad908da800a1b081a800ada08de800a1a0819800ade08df800a190815800adf08e0800a150814800ae008e1800a140813800ae108e2800a130812800ae208e4800a120811800ae408e5800a11080d800ae508e6800a0d080c800ae608e7800a0c080b800ae708ea800a0b080a800aea08eb800a0a0807800aeb08ec800a070806800aec08ed800a06080580240aed08ee800a050804800aee08ef800a040803800aef08f0800a030802800af008f1800a020801800af108f2800c0a01080080070103040200000000002f00040038000000', '290004009400000035000400a4000000']),
SensorCaptureProg(major=0x6, minor=0xb, build=0x0, u1=0x0, dev_type=0x117, a0=0x18, a1=0x19, blobs=['2300000020000800002000800000010032006400000000802020040024200000382000002820df0b2c20df0b30200000342000003c2080004020800050200a005c200000602000004c2003006c20680070206800742001007820010084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a00', '32000c000000008068110100641126003400ac0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000102b0e102b0e102b0e102b0e01000000061e10301001000007c80764060b4f80005080006d030007010000006d0300200307010007032408a180089f800aa108a2800a9f089e800aa208a3800a9e089d800aa308a4800a9d089c800aa408a6800a9c089b802c0aa608a7800a9b089a800aa708a8800a9a0899800aa808a9800a990898800aa908af800a980895800aaf08b0800a950894800ab008b1800a940893800ab108b2800a930892800ab208b3800a92088b800ab308b7800a8b088a800ab708b8800a8a0889800ab808b9800a890888800ab908ba800a880887800aba08bb800a870881800abb08bf800a810880800abf08c0800a80087f800ac008c1800a7f087e800ac108c2800a7e087d800ac208c5800a7d0872800ac508c6800a72087180062807010ac608c7800a710870800ac708c8800a70086f800ac808c9800a6f0863800ac9086c800a630862800a6c086b800a620861800a6b086a800a610860800a6a0869800a60085f800a69085e800a5f084f800a5e085d800a4f084e800a5d085c800a4e084d800a5c085b800a4d084c800a5b085a800a4c084b800a5a0831800a4b084a800a310830800a4a0849800a30082f800a490848800a2f082e800a480847800a2e082d800a470846800a2d08ca800a46083b800aca08cb800a3b083a800acb08cc800a3a0839800acc08cd800a390838800acd08ce800a38082c800ace08d1800a2c082b800ad108d2800a2b082a80063207010ad208d3800a2a0829800ad308d6800a290828800ad608d7800a28081d800ad708d8800a1d081c800ad808d9800a1c081b800ad908da800a1b081a800ada08de800a1a0819800ade08df800a190815800adf08e0800a150814800ae008e1800a140813800ae108e2800a130812800ae208e4800a120811800ae408e5800a11080d800ae508e6800a0d080c800ae608e7800a0c080b800ae708ea800a0b080a800aea08eb800a0a0807800aeb08ec800a070806800aec08ed800a06080580240aed08ee800a050804800aee08ef800a040803800aef08f0800a030802800af008f1800a020801800af108f2800c0a01080080070103040200000000002f00040038000000', '290004009400000035000400a4000000']),
SensorCaptureProg(major=0x6, minor=0xb, build=0x0, u1=0x0, dev_type=0x126, a0=0x18, a1=0x19, blobs=['2300000020000800002000800000010032007000000000802020040024200000382000002820df0b2c20df0b30200000342000003c2080004020800050200a005c200000602000004c2003006c2068007020680074200100782001006420000084202000b4200000b8203a00bc201400c0200200c4200100c820020074030000a0030f00330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a00', '32000c000000008068110100641126003400ac0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000102b0e102b0e102b0e102b0e01000000061e10301001000007c80764060b4f80005080006d030007010000006d0300200307010007032408a180089f800aa108a2800a9f089e800aa208a3800a9e089d800aa308a4800a9d089c800aa408a6800a9c089b802c0aa608a7800a9b089a800aa708a8800a9a0899800aa808a9800a990898800aa908af800a980895800aaf08b0800a950894800ab008b1800a940893800ab108b2800a930892800ab208b3800a92088b800ab308b7800a8b088a800ab708b8800a8a0889800ab808b9800a890888800ab908ba800a880887800aba08bb800a870881800abb08bf800a810880800abf08c0800a80087f800ac008c1800a7f087e800ac108c2800a7e087d800ac208c5800a7d0872800ac508c6800a72087180062807010ac608c7800a710870800ac708c8800a70086f800ac808c9800a6f0863800ac9086c800a630862800a6c086b800a620861800a6b086a800a610860800a6a0869800a60085f800a69085e800a5f084f800a5e085d800a4f084e800a5d085c800a4e084d800a5c085b800a4d084c800a5b085a800a4c084b800a5a0831800a4b084a800a310830800a4a0849800a30082f800a490848800a2f082e800a480847800a2e082d800a470846800a2d08ca800a46083b800aca08cb800a3b083a800acb08cc800a3a0839800acc08cd800a390838800acd08ce800a38082c800ace08d0800a2c082b800ad008d1800a2b082a80063207010ad108d2800a2a0829800ad208d3800a290828800ad308d6800a28081c800ad608d7800a1c081b800ad708d8800a1b081a800ad808d9800a1a0819800ad908da800a190815800ada08df800a150814800adf08e0800a140813800ae008e1800a130812800ae108e2800a120811800ae208e4800a11080e800ae408e5800a0e080d800ae508e6800a0d080c800ae608e7800a0c080b800ae708e8800a0b080a800ae808ea800a0a0807800aea08eb800a070806800aeb08ec800a06080580240aec08ed800a050804800aed08ee800a040803800aee08ef800a030802800aef08f0800a020801800af008f1800c0a01080080070c03040200000000002f00040038000000290004009400000035000400a4000000']),
SensorCaptureProg(major=0x6, minor=0x0, build=0x0, u1=0x0, dev_type=0xdb, a0=0x18, a1=0x19, blobs=['2300000020000800002000800000010032007000000000802020050024200000502077362820010030200100082170000c210000482102004c210000582000005c20000060200000682005006c20012970200121742001887820018084202000942001809c200902a0200b19b4200000b8203b04bc201400c0200200c4200100c82002003300100000000080cc200000f503d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203b00000804001408000008080000080800001408300008080000140831001c081a00', '32000c0000000080501101004c1126003400080310061d10061d10061d10061d10061c01065810080101000007c8078c06100000204f80007f000003070107010c07032c08fc80095a800afc08fb800b5a095b800afb08fa800b5b095c800afa08f9800b5c095d800af908f8800b5d095e800af808f7800b5e095f800af708f6800b5f0960800af608f5800b600961800af508f4800b610962800af408f3800b620963800af308f2800b630964800af208f1800b640965800af108f0800b650966800af008ef800b660967800aef08ee800b670968800aee08ed800b68096c800aed08ec800b6c096d800aec08eb800b6d096e800aeb08ea800b6e096f800aea08e9800b6f0970800ae908e8800b700971800ae808e7800b710972800ae708e6800b720973800ae608e5800b730974800ae508e4800b740975800ae408e3800b750976800ae308e2800b760977800ae208e1800b770978800ae108e0800b780979800ae008df800b79097a800adf08de800b7a097b800ade08dd800b7b097c800add08dc800b7c097d800adc08db800b7d097e800adb08da800b7e097f800ada08d9800b7f0980800ad908d8800b800981800ad808d7800b810982800ad708d6800b820983800ad608d5800b830984800ad508d4800b840985800ad408d3800b850986800ad308d2800b860987800ad208d1800b870988800ad108d0800b880989800ad008cf800b89098a800acf08ce800b8a098b800ace08cd800b8b098c800acd08cc800b8c098d800acc08cb800b8d098e800acb08ca800b8e098f800aca08c9800b8f0990800ac908c8800b900991800ac808c7800b910992800ac708c6800b920993800ac608c5800b930994800ac508c4800b940995800ac408c3800b950996800ac308c2800b960997800ac208c1800b970998800ac108c0800b980999800ac008bf800b99099a800abf08be800b9a099b800abe08bd800b9b099c800abd08bc800b9c099d800abc08bb800b9d099e800abb08ba800b9e099f800aba08b9800b9f09a0800ab908b8800ba00801800ab808b7800a010802800ab708b6800a020803800ab608b5800a030804802003070404020000000000002f0004009000000029000400000000003500040010000000']),
SensorCaptureProg.table = [
SensorCaptureProg(
major=0x6,
minor=0x0,
build=0x0,
u1=0x0,
dev_type=0x0,
a0=0x0,
a1=0x0,
blobs=[
'23000000320074000000008000200000502077322820020030200000082110000c211000482105004c2105002020000024200000582000005c20000060204300682014006c2001247020012c842020008c20900190202c01942001809c200902a0200b19b4200000b8203a00bc201400c0200200c4200200c82008003300100000000080cc200000a101d0200000a10132004c0000000080dc20e803e0206401e420d002e8200001ec201400f0200500fc200000b8203a00140800000008040008080000080802001408300008080300140831001c081a004c11240050110000',
'2a00080020010100100100002c002800802080200000000000013f4000000000080f080f00000000279c1000279c10000000000000000000340040000300000007160000240a59085a0701c9500aaa07010ada08db0701c9460b2107010800800a0088c9590a5a07010aa908aa0701c91f0ac900000c040100000000',
'29000400000000003500040000000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x6,
build=0x0,
u1=0x0,
dev_type=0x0,
a0=0x0,
a1=0x0,
blobs=[
'23000000320074000000008000200000502077322820020030200000082110000c211000482105004c2105002020000024200000582000005c20000060204300682014006c2001247020012c842020008c20900190202c01942001809c200902a0200b19b4200000b8203a00bc201400c0200200c4200200c82008003300100000000080cc200000a101d0200000a10132004c0000000080dc20e803e0206401e420d002e8200001ec201400f0200500fc200000b8203a00140800000008040008080000080802001408300008080300140831001c081a004c11240050110000',
'2a00080020010100100100002c002800802080200000000000013f4000000000080f080f00000000279c1000279c10000000000000000000340040000300000007160000240a59085a0701c9500aaa07010ada08db0701c9460b2107010800800a0088c9590a5a07010aa908aa0701c91f0ac900000c040100000000',
'29000400000000003500040000000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x7,
build=0x0,
u1=0x0,
dev_type=0x0,
a0=0x0,
a1=0x0,
blobs=[
'23000000320074000000008000200000502077322820020030200000082110000c211000482105004c2105002020000024200000582000005c20000060204300682014006c2001247020012c842020008c20900190202c01942001809c200902a0200b19b4200000b8203a00bc201400c0200200c4200200c82008003300100000000080cc200000a101d0200000a10132004c0000000080dc20e803e0206401e420d002e8200001ec201400f0200500fc200000b8203a00140800000008040008080000080802001408300008080300140831001c081a004c11240050110000',
'2a00080020010100100100002c002800802080200000000000013f4000000000080f080f00000000279c1000279c10000000000000000000340040000300000007160000240a59085a0701c9500aaa07010ada08db0701c9460b2107010800800a0088c9590a5a07010aa908aa0701c91f0ac900000c040100000000',
'29000400000000003500040000000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x8,
build=0x0,
u1=0x0,
dev_type=0x0,
a0=0x0,
a1=0x0,
blobs=[
'23000000320074000000008000200000502077322820020030200000082110000c211000482105004c2105002020000024200000582000005c20000060204300682014006c2001247020012c842020008c20900190202c01942001809c200902a0200b19b4200000b8203a00bc201400c0200200c4200200c82008003300100000000080cc200000a101d0200000a10132004c0000000080dc20e803e0206401e420d002e8200001ec201400f0200500fc200000b8203a00140800000008040008080000080802001408300008080300140831001c081a004c11240050110000',
'2a00080020010100100100002c002800802080200000000000013f4000000000080f080f00000000279c1000279c10000000000000000000340040000300000007160000240a59085a0701c9500aaa07010ada08db0701c9460b2107010800800a0088c9590a5a07010aa908aa0701c91f0ac900000c040100000000',
'29000400000000003500040000000000'
]),
SensorCaptureProg(
major=0x6,
minor=0xa,
build=0x0,
u1=0x0,
dev_type=0x0,
a0=0x0,
a1=0x0,
blobs=[
'230000003200680000000080002000002020000024200000382000002820df0b2c20df0b302000003420000050200a005c20000064204300602000004c2000006c20100070201000742005007820050084202000b4200000b8203b00bc201400c0200200c4200100c82002007403000233001c000000008054202a2203005820272f0300cc200000ef03d0200000ef033200480000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203b00002804001428000008280000082800001428300008280000142831001c281a006411240068110000',
'2a00080020010100100100002c002800802080200000000000013f4000000000080f080f00000000279c1000279c10000000000000000000340040000300000007160000240a59085a0701c9500aaa07010ada08db0701c9460b2107010800800a0088c9590a5a07010aa908aa0701c91f0ac900000c040100000000',
'29000400000000003500040000000000'
]),
SensorCaptureProg(
major=0x6,
minor=0xb,
build=0x0,
u1=0x0,
dev_type=0x0,
a0=0x0,
a1=0x0,
blobs=[
'230000003200680000000080002000002020000024200000382000002820df0b2c20df0b302000003420000050200a005c20000064204300602000004c2000006c20100070201000742005007820050084202000b4200000b8203b00bc201400c0200200c4200100c82002007403000233001c000000008054202a2203005820272f0300cc200000ef03d0200000ef033200480000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203b00002804001428000008280000082800001428300008280000142831001c281a006411240068110000',
'2a00080020010100100100002c002800802080200000000000013f4000000000080f080f00000000279c1000279c10000000000000000000340040000300000007160000240a59085a0701c9500aaa07010ada08db0701c9460b2107010800800a0088c9590a5a07010aa908aa0701c91f0ac900000c040100000000',
'29000400000000003500040000000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x14,
build=0x0,
u1=0x0,
dev_type=0x0,
a0=0x0,
a1=0x0,
blobs=[
'230000003200680000000080002000002020000024200000382000002820df0b2c20df0b302000003420000050200a005c20000064204300602000004c2000006c20100070201000742005007820050084202000b4200000b8203b00bc201400c0200200c4200100c82002007403000233001c000000008054202a2203005820272f0300cc200000ef03d0200000ef033200480000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203b00002804001428000008280000082800001428300008280000142831001c281a006411240068110000',
'2a00080020010100100100002c002800802080200000000000013f4000000000080f080f00000000279c1000279c10000000000000000000340040000300000007160000240a59085a0701c9500aaa07010ada08db0701c9460b2107010800800a0088c9590a5a07010aa908aa0701c91f0ac900000c040100000000',
'29000400000000003500040000000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x6,
build=0x0,
u1=0x0,
dev_type=0x885,
a0=0x18,
a1=0x19,
blobs=[
'23000000200008000020008000000100320074000000008020200400242000005020773628200100302001003c208000082150000c210000482105004c210000582000005c2000006020000068200a006c20014970200141742001887820018084202000942001809c200902a0200b19b4200300b8203b04bc201400c0200200c4200100c82002003300100000000080cc200000f503d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203a00000804001408000008080000080800001408300008080000140831001c081a00',
'32000c0000000080501101004c111e00340070010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010221710221710221610221610221601066310250101000007c8078c06ff4f80006d0300200307030b90098db08d099186890b9108c180910ac190ba2c928f099382890b938889898908c881910ac8888a9189099a82890b9a8889898908d081910ad0888a9189080282890a02095a80890b5a888908d981890ad98891898a095e81890b5e8889898908e181890ae18891898a096481890b64888989096e8108e9810b6e880ae9889191ba096f828f0b6f8889918908f082890af08891898a097681890b7690b9928f08f882910af8908a8a91097c818a0b7c88090181890b018889892491097f818a0b7f900908818a0b0890898a910c0703030720040200002f0004007000000029000400700000003500040080000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x7,
build=0x0,
u1=0x0,
dev_type=0x885,
a0=0x18,
a1=0x19,
blobs=[
'23000000200008000020008000000100320074000000008020200400242000005020773628200100302001003c208000082150000c210000482105004c210000582000005c2000006020000068200a006c20014970200141742001887820018084202000942001809c200902a0200b19b4200300b8203b04bc201400c0200200c4200100c82002003300100000000080cc200000f503d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203a00000804001408000008080000080800001408300008080000140831001c081a00',
'32000c0000000080501101004c111e00340070010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010221710221710221610221610221601066310250101000007c8078c06ff4f80006d0300200307030b90098db08d099186890b9108c180910ac190ba2c928f099382890b938889898908c881910ac8888a9189099a82890b9a8889898908d081910ad0888a9189080282890a02095a80890b5a888908d981890ad98891898a095e81890b5e8889898908e181890ae18891898a096481890b64888989096e8108e9810b6e880ae9889191ba096f828f0b6f8889918908f082890af08891898a097681890b7690b9928f08f882910af8908a8a91097c818a0b7c88090181890b018889892491097f818a0b7f900908818a0b0890898a910c0703030720040200002f0004007000000029000400700000003500040080000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x0,
build=0x0,
u1=0x0,
dev_type=0x1055,
a0=0x18,
a1=0x19,
blobs=[
'23000000200008000020008000000100320074000000008020200400242000005020773628200100302001003c208000082138000c210000482103004c210000582000005c20000060200000682005006c20014970200141742001887820018084202000942001809c200902a0200b19b4200300b8203b04bc201400c0200200c4200100c82002003300100000000080cc200000f503d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203a00000804001408000008080000080800001408300008080000140831001c081a00',
'32000c0000000080501101004c111e00340070010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010221710221710221610221610221601066310250101000007c8078c06ff4f80006d0300200307030b90098db08d099186890b9108c180910ac190ba2c928f099382890b938889898908c881910ac8888a9189099a82890b9a8889898908d081910ad0888a9189080282890a02095a80890b5a888908d981890ad98891898a095e81890b5e8889898908e181890ae18891898a096481890b64888989096e8108e9810b6e880ae9889191ba096f828f0b6f8889918908f082890af08891898a097681890b7690b9928f08f882910af8908a8a91097c818a0b7c88090181890b018889892491097f818a0b7f900908818a0b0890898a910c0703030720040200002f0004007000000029000400700000003500040080000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x0,
build=0x0,
u1=0x0,
dev_type=0x1825,
a0=0x18,
a1=0x19,
blobs=[
'23000000200008000020008000000100320074000000008020200400242000005020773628200100302001003c208000082138000c210000482108004c210000582000005c20000060200000682005006c20014970200141742001887820018084202000942001809c200902a0200b19b4200300b8203b04bc201400c0200200c4200100c82002003300100000000080cc200000f503d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203a00000804001408000008080000080800001408300008080000140831001c081a00',
'32000c0000000080501101004c111e00340074010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010221710221710221610221610221601062810250101000007c8078c06ff4f80006d0300200307030990098db00b90880991858e08c1810b9190910ac1b828928a0993878a890b9388898908c88191890ac8889289099a818a890b9a88898908d08191890ad08892890802818a095a810a0288890b5a8808d98189890ad9908989095e8289890b5e88898908e18189890ae190898909648289890b648889096e8108e981890b6e880ae99091b9096f828a8f0b6f88918908f0818a890af090898909768289910b76b8918a08f88792910af8888a92097c81898a0b7c09018089890b01888991097f812089920b7f09088089920b088889920c07030307200402000000002f0004007000000029000400700000003500040080000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x0,
build=0x0,
u1=0x0,
dev_type=0xb5,
a0=0x18,
a1=0x19,
blobs=[
'23000000200008000020008000000100320074000000008020200400242000005020773628200100302001003c208000082138000c210000482106004c210000582000005c20000060200000682005006c20014970200141742001887820018084202000942001809c200902a0200b19b4200300b8203b04bc201400c0200200c4200100c82002003300100000000080cc200000f503d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203a00000804001408000008080000080800001408300008080000140831001c081a00',
'32000c0000000080501101004c111e0034007801000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001023171023171023161023161023160106635205001025010100000007c8078c06ff00004f80006d0300280307030990098db00b90880991858e08c1810b9190910ac1b8928a0993878a890b9388898908c88191890ac8889289099a818a890b9a88898908d08191890ad08892890802818a095a810a0288890b5a8808d98189890ad9908989095e8289890b5e88898908e18189890ae190898909648289890b648889096e8108e981890b6e880ae99091b9096f828a8f0b6f88918908f0818a890af090898909768289910b76b8918a08f88792910af8888a92097c81898a0b7c09018089890b01888991097f8189920b7f09088089920b088889920c07030307200402000000002f0004007000000029000400700000003500040080000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x0,
build=0x0,
u1=0x0,
dev_type=0x1ff5,
a0=0x18,
a1=0x19,
blobs=[
'23000000200008000020008000000100320074000000008020200400242000005020773628200100302001003c208000082138000c210000482106004c210000582000005c20000060200000682005006c20014970200141742001887820018084202000942001809c200902a0200b19b4200300b8203b04bc201400c0200200c4200100c82002003300100000000080cc200000f503d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203a00000804001408000008080000080800001408300008080000140831001c081a00',
'32000c0000000080501101004c111e00340074010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010221710221710221610221610221601062810250101000007c8078c06ff4f80006d0300200307030990098db00b90880991858e08c1810b9190910ac1b828928a0993878a890b9388898908c88191890ac8889289099a818a890b9a88898908d08191890ad08892890802818a095a810a0288890b5a8808d98189890ad9908989095e8289890b5e88898908e18189890ae190898909648289890b648889096e8108e981890b6e880ae99091b9096f828a8f0b6f88918908f0818a890af090898909768289910b76b8918a08f88792910af8888a92097c81898a0b7c09018089890b01888991097f812089920b7f09088089920b088889920c07030307200402000000002f0004007000000029000400700000003500040080000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x7,
build=0x0,
u1=0x0,
dev_type=0x1825,
a0=0x18,
a1=0x19,
blobs=[
'23000000200008000020008000000100320074000000008020200400242000005020773628200100302001003c208000082138000c210000482108004c210000582000005c20000060200000682005006c20014970200141742001887820018084202000942001809c200902a0200b19b4200300b8203b04bc201400c0200200c4200100c82002003300100000000080cc200000f503d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203a00000804001408000008080000080800001408300008080000140831001c081a00',
'32000c0000000080501101004c111e00340074010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010221710221710221610221610221601065010240101000007c8078c06ff00004f80006d0300280307030990098db00b90880991858e08c1810b9190910ac1b8928a0993878a890b9388898908c88191890ac8889289099a818a890b9a88898908d08191890ad08892890802818a095a810a0288890b5a8808d98189890ad9908989095e8289890b5e88898908e18189890ae190898909648289890b648889096e8108e981890b6e880ae99091b9096f828a8f0b6f88918908f0818a890af090898909768289910b76b8918a08f88792910af8888a92097c81898a0b7c09018089890b01888991097f8189920b7f09088089920b088889920c07030307200402000000002f0004007000000029000400700000003500040080000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x0,
build=0x0,
u1=0x0,
dev_type=0xe4,
a0=0x18,
a1=0x19,
blobs=[
'23000000200008000020008000000100320070000000008020200400242000005020773628200100302001003c208000082138000c210000482108004c210000582000005c20000060200000682005006c20014970200141742001887820018084202000942001809c200902a0200b19b4200300bc201400c0200200c4200100c82002003300100000000080cc200000f503d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203a00000804001408000008080000080800001408300008080000140831001c081a00',
'32000c0000000080501101004c111e00340070010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010221410221410221410221410221401066510250101000007c8078c06ff4f80006d0300280307030990098db00b90880991858e08c1810b9190910ac1b8928a0993878a890b9388898908c88191890ac8889289099a818a890b9a88898908d08191890ad08892890802818a095a810a0288890b5a8808d98189890ad9908989095e8289890b5e88898908e18189890ae190898909648289890b648889096e8108e981890b6e880ae99091b9096f828a8f0b6f88918908f0818a890af090898909768289910b76b8918a08f88792910af8888a92097c81898a0b7c09018089890b01888991097f8189920b7f09088089920b088889920c0703030720040200002f0004006400000029000400700000003500040080000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x0,
build=0x0,
u1=0x0,
dev_type=0xed,
a0=0x18,
a1=0x19,
blobs=[
'23000000200008000020008000000100320074000000008020200400242000005020773628200100302001003c208000082138000c210000482104004c210000582000005c20000060200000682005006c20014970200141742001887820018084202000942001809c200902a0200b19b4200300b8203b04bc201400c0200200c4200100c82002003300100000000080cc200000f503d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203a00000804001408000008080000080800001408300008080000140831001c081a00',
'32000c0000000080501101004c111e00340074010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010221710221710221610221610221601065010240101000007c8078c06ff00004f80006d0300280307030990098db00b90880991858e08c1810b9190910ac1b8928a0993878a890b9388898908c88191890ac8889289099a818a890b9a88898908d08191890ad08892890802818a095a810a0288890b5a8808d98189890ad9908989095e8289890b5e88898908e18189890ae190898909648289890b648889096e8108e981890b6e880ae99091b9096f828a8f0b6f88918908f0818a890af090898909768289910b76b8918a08f88792910af8888a92097c81898a0b7c09018089890b01888991097f8189920b7f09088089920b088889920c07030307200402000000002f0004007000000029000400700000003500040080000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x7,
build=0x0,
u1=0x0,
dev_type=0x143b,
a0=0x18,
a1=0x19,
blobs=[
'23000000200008000020008000000100320070000000008020200400242000005020773628200100302001003c208000082138000c210000482108004c210000582000005c2000006020000068200a006c20014970200141742001887820018084202000942001809c200902a0200b19b4200300bc201400c0200200c4200100c82002003300100000000080cc200000d600d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203a00000804001408000008080000080800001408300008080000140831001c081a00',
'32000c0000000080501101004c1117003400340200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101c11101c11101c11101c11101c10010657101e0101000007c8078c06ff00004f80006d03002c03070308c608c709930703800ac60994800ac70995800b930996800b940997800b950998800b9608c8800b9708ca800b9808cb800ac808cc800aca08ce800acb08cf800acc099a800ace099b800acf099c800b9a099d800b9b099e800b9c099f800b9d08d0800b9e08d2800b9f08d3800ad008d4800ad208d6800ad308d7800ad40802800ad60803800ad7095a800a02095b800a03095c800b5a095d800b5b08d9800b5c08da800b5d08db800ad908dd800ada08de800adb08df800add095e800ade095f800adf0960800b5e0961800b5f0962800b600963800b6108e1800b6208e2800b6308e3800ae108e5800ae208e6800ae308e7800ae50964800ae60965800ae70966800b640967800b650968800b66096e800b6708e9800b6808ea800b6e08eb800ae908ed800aea08ef800aeb08ee800aed096f800aef0970800aee0971800b6f0972800b700974800b710975800b7208f0800b7408f1800b7508f2800af008f4800af108f5800af208f6800af40976800af50977800af60979800b760978800b77097a800b79097b800b7808f8800b7a08fa800b7b08fc800af808fd800afa08fe800afc0900800c2007030307200402002f0004005400000029000400580000003500040068000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x7,
build=0x0,
u1=0x0,
dev_type=0xb3,
a0=0x18,
a1=0x19,
blobs=[
'23000000200008000020008000000100320070000000008020200400242000005020773628200100302001003c208000082140000c210000482106004c210000582000005c2000006020000068200a006c20012970200121742001887820018084202000942001809c200902a0200b19b4200300bc201400c0200100c4200100c82002003300100000000080cc2000002c01d0200000a1013200440000000080dc205302e0206401e420a901e8200001f0200500f8200500fc200000b8203a00000804001408000008080000080800001408300008080000140831001c081a00',
'32000c0000000080501101004c11180034003c0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101c11101c11101c11101c11101c10010657101e0101000007c8078c06ff00004f80006d03002c0308c608c70703800ac60993800ac70994800b930995800b940996800b950997800b960998800b9708c8800b9808ca800ac808cb800aca08cc800acb08ce800acc08cf800ace099a800acf099b800b9a099c800b9b099d800b9c099e800b9d099f800b9e08d0800b9f08d2800ad008d3800ad208d4800ad308d6800ad408d7800ad60802800ad70803800a02095a800a03095b800b5a095c800b5b095d800b5c08d9800b5d08da800ad908db800ada08dd800adb08de800add08df800ade095e800adf095f800b5e0960800b5f0961800b600962800b610963800b6208e1800b6308e2800ae108e3800ae208e5800ae308e6800ae508e7800ae60964800ae70965800b640966800b650967800b660968800b67096e800b6808e9800b6e08ea800ae908eb800aea08ed800aeb08ef800aed08ee800aef096f800aee0970800b6f0971800b700972800b710974800b720975800b7408f0800b7508f1800af008f2800af108f4800af208f5800af408f6800af50976800af60977800b760979800b770978800b79097a800b78097b800b7a08f8800b7b08fa800af808fc800afa08fd800afc08fe800afd090080808080240c0703030720040200000000002f0004005400000029000400580000003500040068000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x0,
build=0x0,
u1=0x0,
dev_type=0xe1,
a0=0x18,
a1=0x19,
blobs=[
'2300000020000800002000800000010032006c000000008020200400242000005020773628200100302001003c208000082138000c210000482105004c210000582000005c2000006020000068200a006c20014970200141742001887820018084203000942001809c200902a0200b19bc201400c0200200c4200100c82002003300100000000080cc2000006401d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203b00000804001408000008080000080800001408300008080000140831001c081a00',
'32000c0000000080501101004c11160034001402000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101b10101b10101b10101b0f101b0f010656101e0101000007c8078c06ff4f80006d03002c03070308c108bf098f0703800ac10990800abf098d800b8f0991800b900992800b8d08c5800b9108c3800b9208c6800ac508c4800ac308cb800ac608c7800ac40993800acb0994800ac70995800b930997800b940996800b950998800b9708ce800b9608cc800b9808cf800ace08d0800acc08d2800acf08dd800ad0099a800ad2099b800add099c800b9a0803800b9b095a800b9c095b800a0308de800b5a08df800b5b08e1800ade08eb800adf08ed800ae108f1800aeb095c800aed0962800af10963800b5c096f800b620970800b630971800b6f08f2800b7008f5800b7108f6800af208fa800af508f8800af608fc800afa0974800af80976800afc097b800b74097a800b76097f800b7b097e800b7a08fd800b7f08fe800b7e090b800afd090c800afe090d800b0b090f800b0c0980800b0d0982800b0f0983800b80097d800b820978800b83097c800b7d0914800b780908800b7c0909800b140907800b080905800b090904800b070979800b050977800b040975800b790972800b77096c800b750936800b7209348080800c20070303072004020000002f0004004e00000029000400540000003500040064000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x0,
build=0x0,
u1=0x0,
dev_type=0x8b1,
a0=0x18,
a1=0x19,
blobs=[
'2300000020000800002000800000010032006c000000008020200400242000005020773628200100302001003c208000082138000c210000482107004c210000582000005c2000006020000068200a006c20014970200141742001887820018084203000942001809c200902a0200b19bc201400c0200200c4200100c82002003300100000000080cc2000002c00d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203a00000804001408000008080000080800001408300008080000140831001c081a00',
'32000c0000000080501101004c11160034001402000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101b10101b10101b10101b0f101b0f010656101e0101000007c8078c06ff4f80006d03002c03070308c108bf098f0703800ac10990800abf098d800b8f0991800b900992800b8d08c5800b9108c3800b9208c6800ac508c4800ac308cb800ac608c7800ac40993800acb0994800ac70995800b930997800b940996800b950998800b9708ce800b9608cc800b9808cf800ace08d0800acc08d2800acf08dd800ad0099a800ad2099b800add099c800b9a0803800b9b095a800b9c095b800a0308de800b5a08df800b5b08e1800ade08eb800adf08ed800ae108f1800aeb095c800aed0962800af10963800b5c096f800b620970800b630971800b6f08f2800b7008f5800b7108f6800af208fa800af508f8800af608fc800afa0974800af80976800afc097b800b74097a800b76097f800b7b097e800b7a08fd800b7f08fe800b7e090b800afd090c800afe090d800b0b090f800b0c0980800b0d0982800b0f0983800b80097d800b820978800b83097c800b7d0914800b780908800b7c0909800b140907800b080905800b090904800b070979800b050977800b040975800b790972800b77096c800b750936800b7209348080800c20070303072004020000002f0004004e00000029000400540000003500040064000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x0,
build=0x0,
u1=0x0,
dev_type=0xea,
a0=0x18,
a1=0x19,
blobs=[
'23000000200008000020008000000100320070000000008020200400242000005020773628200100302001003c208000082138000c210000482106004c210000582000005c2000006020000068200a006c20014970200141742001887820018084202000942001809c200902a0200b19b4200300bc201400c0200200c4200100c82002003300100000000080cc200000d600d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203b00000804001408000008080000080800001408300008080000140831001c081a00',
'32000c0000000080501101004c11170034003002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101b11101b11101b11101b11101b1001064d101d0101000007c8078c06ff00004f80006d03002c03070308c608c709930703800ac60994800ac70995800b930996800b940997800b950998800b9608c8800b9708ca800b9808cb800ac808cc800aca08ce800acb08cf800acc099a800ace099b800acf099c800b9a099d800b9b099e800b9c099f800b9d08d0800b9e08d2800b9f08d3800ad008d4800ad208d6800ad308d7800ad40802800ad60803800ad7095a800a02095b800a03095c800b5a095d800b5b08d9800b5c08da800b5d08db800ad908dd800ada08de800adb08df800add095e800ade095f800adf0960800b5e0961800b5f0962800b600963800b6108e1800b6208e2800b6308e3800ae108e5800ae208e6800ae308e7800ae50964800ae60965800ae70966800b640967800b650968800b66096e800b6708e9800b6808ea800b6e08eb800ae908ed800aea08ef800aeb08ee800aed096f800aef0970800aee0971800b6f0972800b700974800b710975800b7208f0800b7408f1800b7508f2800af008f4800af108f5800af208f6800af40976800af50977800af60979800b760978800b77097a800b79097b800b7808f8800b7a08fa800b7b08fc800af808fd800afa08fe800afc0900800c2007030307200402002f0004005400000029000400540000003500040064000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x0,
build=0x0,
u1=0x0,
dev_type=0x199,
a0=0x18,
a1=0x19,
blobs=[
'23000000200008000020008000000100320074000000008020200400242000005020773628200100302001003c208000082138000c210000482107004c210000582000005c20000060200000682005006c20014970200141742001887820018084202000942001809c200902a0200b19b4200300b8203b04bc201400c0200200c4200100c82002003300100000000080cc200000f503d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203a00000804001408000008080000080800001408300008080000140831001c081a00',
'32000c0000000080501101004c111e00340078010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010221710221710221610221610221601065010250101000007c8078c06ff0000000000004f80006d0300280307030990098db00b90880991858e08c1810b9190910ac1b8928a0993878a890b9388898908c88191890ac8889289099a818a890b9a88898908d08191890ad08892890802818a095a810a0288890b5a8808d98189890ad9908989095e8289890b5e88898908e18189890ae190898909648289890b648889096e8108e981890b6e880ae99091b9096f828a8f0b6f88918908f0818a890af090898909768289910b76b8918a08f88792910af8888a92097c81898a0b7c09018089890b01888991097f8189920b7f09088089920b088889920c07030307200402000000002f0004007000000029000400700000003500040080000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x14,
build=0x0,
u1=0x0,
dev_type=0x8f3,
a0=0x18,
a1=0x19,
blobs=[
'2300000020000800002000800000010032006000000000802020040024200000382000002820df0b2c20df0b302000003420000050200a015c200000602000004c2003006c20700070207000742001007820010084202000b4200000bc201400c0200200c4200100c820020074030002a0030000330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a00',
'330064030000008064200000a10c642000109f0c64200020a20c642000309e0c64200040a30c642000509d0c64200060a40c642000709c0c64200080a60c642000909b0c642000a0a70c642000b09a0c642000c0a80c642000d0990c642000e0a90c642000f0980c64200000af0c64200010950c64200020b00c64200030940c64200040b10c64200050930c64200060b20c64200070920c64200080b30c642000908b0c642000a0b70c642000b08a0c642000c0b80c642000d0890c642000e0b90c642000f0880c64200000ba0c64200010870c64200020bb0c64200030810c64200040bf0c64200050800c64200060c00c642000707f0c64200080c10c642000907e0c642000a0c20c642000b07d0c642000c0c50c642000d0720c642000e0c60c642000f0710c64200000c70c64200010700c64200020c80c642000306f0c64200040c90c64200050630c642000606c0c64200070620c642000806b0c64200090610c642000a06a0c642000b0600c642000c0690c642000d05f0c642000e05e0c642000f04f0c642000005d0c642000104e0c642000205c0c642000304d0c642000405b0c642000504c0c642000605a0c642000704b0c64200080310c642000904a0c642000a0300c642000b0490c642000c02f0c642000d0480c642000e02e0c642000f0470c642000002d0c64200010460c64200020ca0c642000303b0c64200040cb0c642000503a0c64200060cc0c64200070390c64200080cd0c64200090380c642000a0ce0c642000b02c0c642000c0d10c642000d02b0c642000e0d20c642000f02a0c64200000d30c64200010290c64200020d60c64200030280c64200040d70c642000501d0c64200060d80c642000701c0c64200080d90c642000901b0c642000a0da0c642000b01a0c642000c0de0c642000d0190c642000e0df0c642000f0150c64200000e00c64200010140c64200020e10c64200030130c64200040e20c64200050120c64200060e40c64200070110c64200080e50c642000900d0c642000a0e60c642000b00c0c642000c0e70c642000d00b0c642000e0e80c642000f00a0c64200000ea0c64200010070c64200020eb0c64200030060c64200040ec0c64200050050c64200060ed0c64200070040c64200080ee0c64200090030c642000a0ef0c642000b0020c642000c0f00c642000d0010c642000e0f10c642000f0000c',
'32000c000000008068110100641126003400180200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007e007e0102a13102a13102a12010000061e102d0101000007c8078c060b5d00005e00004f80005080006d030059940b070100002403089808a9089908a8089a08a7089b08a6089c08a4089d08a3089e08a2089f08a1c0102c03088808b9088908b8088a08b7088b08b3089208b2089308b1089408b0089508afc01003087108c6087208c5087d08c2087e08c1087f08c0088008bf088108bb088708bac0100628070103084f085e085f08690860086a0861086b0862086c086308c9086f08c8087008c7c010030847082e0848082f08490830084a0831084b085a084c085b084d085c084e085dc01003082a08d2082b08d1082c08ce083808cd083908cc083a08cb083b08ca0846082dc0100632070103081508df081908de081a08da081b08d9081c08d8081d08d7082808d6082908d3c01059940b03080a08e8080b08e7080c08e6080d08e5081108e4081208e2081308e1081408e0c0102403080008f1080108f0080208ef080308ee080408ed080508ec080608eb080708eac0100c0720070c2003040200004200080002089000000000002f00040038000000290004009000000035000400a0000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x14,
build=0x0,
u1=0x0,
dev_type=0x8f6,
a0=0x18,
a1=0x19,
blobs=[
'2300000020000800002000800000010032005c00000000802020040024200000382000002820df0b2c20df0b302000003420000050200a015c200000602000004c2003006c20500070205000742000007820000084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a00330064030000008064200000a10c642000109f0c64200020a20c642000309e0c64200040a30c642000509d0c64200060a40c642000709c0c64200080a60c642000909b0c642000a0a70c642000b09a0c642000c0a80c642000d0990c642000e0a90c642000f0980c64200000af0c64200010950c64200020b00c64200030940c64200040b10c64200050930c64200060b20c64200070920c64200080b30c642000908b0c642000a0b70c642000b08a0c642000c0b80c642000d0890c642000e0b90c642000f0880c64200000ba0c64200010870c64200020bb0c64200030810c64200040bf0c64200050800c64200060c00c642000707f0c64200080c10c642000907e0c642000a0c20c642000b07d0c642000c0c50c642000d0720c642000e0c60c642000f0710c64200000c70c64200010700c64200020c80c642000306f0c64200040c90c64200050630c642000606c0c64200070620c642000806b0c64200090610c642000a06a0c642000b0600c642000c0690c642000d05f0c642000e05e0c642000f04f0c642000005d0c642000104e0c642000205c0c642000304d0c642000405b0c642000504c0c642000605a0c642000704b0c64200080310c642000904a0c642000a0300c642000b0490c642000c02f0c642000d0480c642000e02e0c642000f0470c642000002d0c64200010460c64200020ca0c642000303b0c64200040cb0c642000503a0c64200060cc0c64200070390c64200080cd0c64200090380c642000a0ce0c642000b02c0c642000c0d00c642000d02b0c642000e0d10c642000f02a0c64200000d20c64200010290c64200020d30c64200030280c64200040d60c642000501c0c64200060d70c642000701b0c64200080d80c642000901a0c642000a0d90c642000b0190c642000c0da0c642000d0150c642000e0df0c642000f0140c64200000e00c64200010130c64200020e10c64200030120c64200040e20c64200050110c64200060e40c642000700e0c64200080e50c642000900d0c642000a0e60c642000b00c0c642000c0e70c642000d00b0c642000e0e80c642000f00a0c64200000ea0c64200010070c64200020eb0c64200030060c64200040ec0c64200050050c64200060ed0c64200070040c64200080ee0c64200090030c642000a0ef0c642000b0020c642000c0f00c642000d0010c642000e0f10c642000f0000c',
'32000c0000000080681101006411260034001c0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007e007e0102a13102a13102a12010000061e102d0101000007c8078c060b5d00005e00004f80005080006d030059940b070100000720240308a1089f08a2089e08a3089d08a4089c08a6089b08a7089a08a8089908a90898c0102c0308af089508b0089408b1089308b2089208b3088b08b7088a08b8088908b90888c0100308ba088708bb088108bf088008c0087f08c1087e08c2087d08c5087208c60871c010062807010308c7087008c8086f08c90863086c0862086b0861086a08600869085f085e084fc01003085d084e085c084d085b084c085a084b0831084a08300849082f0848082e0847c01003082d084608ca083b08cb083a08cc083908cd083808ce082c08d0082b08d1082ac010063207010308d2082908d3082808d6081c08d7081b08d8081a08d9081908da081508df0814c0100308e0081308e1081208e2081108e4080e08e5080d08e6080c08e7080b08e8080ac010240308ea080708eb080608ec080508ed080408ee080308ef080208f0080108f10800c010070320030c07030703072004020000004200080002089000000000002f00040038000000',
'2f00040038000000290004009000000035000400a0000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x14,
build=0x0,
u1=0x0,
dev_type=0x121,
a0=0x18,
a1=0x19,
blobs=[
'2300000020000800002000800000010032005c00000000802020040024200000382000002820df0b2c20df0b302000003420000050200a015c200000602000004c2003006c20720070207200742001007820010084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a00',
'330064030000008064200000a10c642000109f0c64200020a20c642000309e0c64200040a30c642000509d0c64200060a40c642000709c0c64200080a60c642000909b0c642000a0a70c642000b09a0c642000c0a80c642000d0990c642000e0a90c642000f0980c64200000af0c64200010950c64200020b00c64200030940c64200040b10c64200050930c64200060b20c64200070920c64200080b30c642000908b0c642000a0b70c642000b08a0c642000c0b80c642000d0890c642000e0b90c642000f0880c64200000ba0c64200010870c64200020bb0c64200030810c64200040bf0c64200050800c64200060c00c642000707f0c64200080c10c642000907e0c642000a0c20c642000b07d0c642000c0c50c642000d0720c642000e0c60c642000f0710c64200000c70c64200010700c64200020c80c642000306f0c64200040c90c642000506d0c642000607a0c642000706c0c64200080790c642000906b0c642000a0780c642000b06a0c642000c06e0c642000d0690c642000e0630c642000f05e0c64200000620c642000105d0c64200020610c642000305c0c64200040600c642000505b0c642000605f0c642000705a0c64200080310c642000904a0c642000a0300c642000b0490c642000c02f0c642000d0480c642000e02e0c642000f0470c642000002d0c64200010460c64200020ca0c642000303b0c64200040cb0c642000503a0c64200060cc0c64200070390c64200080cd0c64200090380c642000a0ce0c642000b02c0c642000c0d00c642000d02b0c642000e0d10c642000f02a0c64200000d20c64200010290c64200020d30c64200030280c64200040d60c642000501c0c64200060d70c642000701b0c64200080d80c642000901a0c642000a0d90c642000b0190c642000c0da0c642000d0150c642000e0df0c642000f0140c64200000e00c64200010130c64200020e10c64200030120c64200040e20c64200050110c64200060e40c642000700e0c64200080e50c642000900d0c642000a0e60c642000b00c0c642000c0e70c642000d00b0c642000e0e80c642000f00a0c64200000ea0c64200010070c64200020eb0c64200030060c64200040ec0c64200050050c64200060ed0c64200070040c64200080ee0c64200090030c642000a0ef0c642000b0020c642000c0f00c642000d0010c642000e0f10c642000f0000c',
'32000c000000008068110100641126003400180200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007e007e0102a13102a13102a120100000620102d0101000007c8078c060b5d00005e00004f80005080006d030059940b07010000240308a1089f08a2089e08a3089d08a4089c08a6089b08a7089a08a8089908a90898c0102c0308af089508b0089408b1089308b2089208b3088b08b7088a08b8088908b90888c0100308ba088708bb088108bf088008c0087f08c1087e08c2087d08c5087208c60871c010062807010308c7087008c8086f08c9086d087a086c0879086b0878086a086e08690863085ec010030862085d0861085c0860085b085f085a0831084a08300849082f0848082e0847c01003082d084608ca083b08cb083a08cc083908cd083808ce082c08d0082b08d1082ac010063007010308d2082908d3082808d6081c08d7081b08d8081a08d9081908da081508df0814c01059940b0308e0081308e1081208e2081108e4080e08e5080d08e6080c08e7080b08e8080ac010240308ea080708eb080608ec080508ed080408ee080308ef080208f0080108f10800c0100c0720070c2003040200004200080002089000000000002f00040038000000290004009000000035000400a0000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x15,
build=0x0,
u1=0x0,
dev_type=0x121,
a0=0x18,
a1=0x19,
blobs=[
'2300000020000800002000800000010032005c00000000802020040024200000382000002820df0b2c20df0b302000003420000050200a015c200000602000004c2003006c20720070207200742001007820010084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a00',
'330064030000008064200000a10c642000109f0c64200020a20c642000309e0c64200040a30c642000509d0c64200060a40c642000709c0c64200080a60c642000909b0c642000a0a70c642000b09a0c642000c0a80c642000d0990c642000e0a90c642000f0980c64200000af0c64200010950c64200020b00c64200030940c64200040b10c64200050930c64200060b20c64200070920c64200080b30c642000908b0c642000a0b70c642000b08a0c642000c0b80c642000d0890c642000e0b90c642000f0880c64200000ba0c64200010870c64200020bb0c64200030810c64200040bf0c64200050800c64200060c00c642000707f0c64200080c10c642000907e0c642000a0c20c642000b07d0c642000c0c50c642000d0720c642000e0c60c642000f0710c64200000c70c64200010700c64200020c80c642000306f0c64200040c90c642000506d0c642000607a0c642000706c0c64200080790c642000906b0c642000a0780c642000b06a0c642000c06e0c642000d0690c642000e0630c642000f05e0c64200000620c642000105d0c64200020610c642000305c0c64200040600c642000505b0c642000605f0c642000705a0c64200080310c642000904a0c642000a0300c642000b0490c642000c02f0c642000d0480c642000e02e0c642000f0470c642000002d0c64200010460c64200020ca0c642000303b0c64200040cb0c642000503a0c64200060cc0c64200070390c64200080cd0c64200090380c642000a0ce0c642000b02c0c642000c0d00c642000d02b0c642000e0d10c642000f02a0c64200000d20c64200010290c64200020d30c64200030280c64200040d60c642000501c0c64200060d70c642000701b0c64200080d80c642000901a0c642000a0d90c642000b0190c642000c0da0c642000d0150c642000e0df0c642000f0140c64200000e00c64200010130c64200020e10c64200030120c64200040e20c64200050110c64200060e40c642000700e0c64200080e50c642000900d0c642000a0e60c642000b00c0c642000c0e70c642000d00b0c642000e0e80c642000f00a0c64200000ea0c64200010070c64200020eb0c64200030060c64200040ec0c64200050050c64200060ed0c64200070040c64200080ee0c64200090030c642000a0ef0c642000b0020c642000c0f00c642000d0010c642000e0f10c642000f0000c',
'32000c000000008068110100641126003400180200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007e007e0102a13102a13102a120100000620102d0101000007c8078c060b5d00005e00004f80005080006d030059940b07010000240308a1089f08a2089e08a3089d08a4089c08a6089b08a7089a08a8089908a90898c0102c0308af089508b0089408b1089308b2089208b3088b08b7088a08b8088908b90888c0100308ba088708bb088108bf088008c0087f08c1087e08c2087d08c5087208c60871c010062807010308c7087008c8086f08c9086d087a086c0879086b0878086a086e08690863085ec010030862085d0861085c0860085b085f085a0831084a08300849082f0848082e0847c01003082d084608ca083b08cb083a08cc083908cd083808ce082c08d0082b08d1082ac010063007010308d2082908d3082808d6081c08d7081b08d8081a08d9081908da081508df0814c01059940b0308e0081308e1081208e2081108e4080e08e5080d08e6080c08e7080b08e8080ac010240308ea080708eb080608ec080508ed080408ee080308ef080208f0080108f10800c0100c0720070c2003040200004200080002089000000000002f00040038000000290004009000000035000400a0000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x14,
build=0x0,
u1=0x0,
dev_type=0xb4b,
a0=0x18,
a1=0x19,
blobs=[
'2300000020000800002000800000010032005c00000000802020040024200000382000002820df0b2c20df0b302000003420000050200a015c200000602000004c2003006c20660070206600742001007820010084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a00',
'330064030000008064200000a10c642000109f0c64200020a20c642000309e0c64200040a30c642000509d0c64200060a40c642000709c0c64200080a60c642000909b0c642000a0a70c642000b09a0c642000c0a80c642000d0990c642000e0a90c642000f0980c64200000af0c64200010950c64200020b00c64200030940c64200040b10c64200050930c64200060b20c64200070920c64200080b30c642000908b0c642000a0b70c642000b08a0c642000c0b80c642000d0890c642000e0b90c642000f0880c64200000ba0c64200010870c64200020bb0c64200030810c64200040bf0c64200050800c64200060c00c642000707f0c64200080c10c642000907e0c642000a0c20c642000b07d0c642000c0c50c642000d0720c642000e0c60c642000f0710c64200000c70c64200010700c64200020c80c642000306f0c64200040c90c642000506d0c642000607a0c642000706c0c64200080790c642000906b0c642000a0780c642000b06a0c642000c06e0c642000d0690c642000e0630c642000f05e0c64200000620c642000105d0c64200020610c642000305c0c64200040600c642000505b0c642000605f0c642000705a0c64200080310c642000904a0c642000a0300c642000b0490c642000c02f0c642000d0480c642000e02e0c642000f0470c642000002d0c64200010460c64200020ca0c642000303b0c64200040cb0c642000503a0c64200060cc0c64200070390c64200080cd0c64200090380c642000a0ce0c642000b02c0c642000c0d00c642000d02b0c642000e0d10c642000f02a0c64200000d20c64200010290c64200020d30c64200030280c64200040d60c642000501c0c64200060d70c642000701b0c64200080d80c642000901a0c642000a0d90c642000b0190c642000c0da0c642000d0150c642000e0df0c642000f0140c64200000e00c64200010130c64200020e10c64200030120c64200040e20c64200050110c64200060e40c642000700e0c64200080e50c642000900d0c642000a0e60c642000b00c0c642000c0e70c642000d00b0c642000e0e80c642000f00a0c64200000ea0c64200010070c64200020eb0c64200030060c64200040ec0c64200050050c64200060ed0c64200070040c64200080ee0c64200090030c642000a0ef0c642000b0020c642000c0f00c642000d0010c642000e0f10c642000f0000c',
'32000c000000008068110100641126003400180200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007e007e0102a13102a13102a12010000061e102d0101000007c8078c060b5d00005e00004f80005080006d030059940b07010000240308a1089f08a2089e08a3089d08a4089c08a6089b08a7089a08a8089908a90898c0102c0308af089508b0089408b1089308b2089208b3088b08b7088a08b8088908b90888c0100308ba088708bb088108bf088008c0087f08c1087e08c2087d08c5087208c60871c010062807010308c7087008c8086f08c9086d087a086c0879086b0878086a086e08690863085ec010030862085d0861085c0860085b085f085a0831084a08300849082f0848082e0847c01003082d084608ca083b08cb083a08cc083908cd083808ce082c08d0082b08d1082ac010063207010308d2082908d3082808d6081c08d7081b08d8081a08d9081908da081508df0814c01059940b0308e0081308e1081208e2081108e4080e08e5080d08e6080c08e7080b08e8080ac010240308ea080708eb080608ec080508ed080408ee080308ef080208f0080108f10800c0100c0720070c2003040200004200080002089000000000002f00040038000000290004009000000035000400a0000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x15,
build=0x0,
u1=0x0,
dev_type=0xb4b,
a0=0x18,
a1=0x19,
blobs=[
'2300000020000800002000800000010032005c00000000802020040024200000382000002820df0b2c20df0b302000003420000050200a015c200000602000004c2003006c20660070206600742001007820010084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a00',
'330064030000008064200000a10c642000109f0c64200020a20c642000309e0c64200040a30c642000509d0c64200060a40c642000709c0c64200080a60c642000909b0c642000a0a70c642000b09a0c642000c0a80c642000d0990c642000e0a90c642000f0980c64200000af0c64200010950c64200020b00c64200030940c64200040b10c64200050930c64200060b20c64200070920c64200080b30c642000908b0c642000a0b70c642000b08a0c642000c0b80c642000d0890c642000e0b90c642000f0880c64200000ba0c64200010870c64200020bb0c64200030810c64200040bf0c64200050800c64200060c00c642000707f0c64200080c10c642000907e0c642000a0c20c642000b07d0c642000c0c50c642000d0720c642000e0c60c642000f0710c64200000c70c64200010700c64200020c80c642000306f0c64200040c90c642000506d0c642000607a0c642000706c0c64200080790c642000906b0c642000a0780c642000b06a0c642000c06e0c642000d0690c642000e0630c642000f05e0c64200000620c642000105d0c64200020610c642000305c0c64200040600c642000505b0c642000605f0c642000705a0c64200080310c642000904a0c642000a0300c642000b0490c642000c02f0c642000d0480c642000e02e0c642000f0470c642000002d0c64200010460c64200020ca0c642000303b0c64200040cb0c642000503a0c64200060cc0c64200070390c64200080cd0c64200090380c642000a0ce0c642000b02c0c642000c0d00c642000d02b0c642000e0d10c642000f02a0c64200000d20c64200010290c64200020d30c64200030280c64200040d60c642000501c0c64200060d70c642000701b0c64200080d80c642000901a0c642000a0d90c642000b0190c642000c0da0c642000d0150c642000e0df0c642000f0140c64200000e00c64200010130c64200020e10c64200030120c64200040e20c64200050110c64200060e40c642000700e0c64200080e50c642000900d0c642000a0e60c642000b00c0c642000c0e70c642000d00b0c642000e0e80c642000f00a0c64200000ea0c64200010070c64200020eb0c64200030060c64200040ec0c64200050050c64200060ed0c64200070040c64200080ee0c64200090030c642000a0ef0c642000b0020c642000c0f00c642000d0010c642000e0f10c642000f0000c',
'32000c000000008068110100641126003400180200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007e007e0102a13102a13102a12010000061e102d0101000007c8078c060b5d00005e00004f80005080006d030059940b07010000240308a1089f08a2089e08a3089d08a4089c08a6089b08a7089a08a8089908a90898c0102c0308af089508b0089408b1089308b2089208b3088b08b7088a08b8088908b90888c0100308ba088708bb088108bf088008c0087f08c1087e08c2087d08c5087208c60871c010062807010308c7087008c8086f08c9086d087a086c0879086b0878086a086e08690863085ec010030862085d0861085c0860085b085f085a0831084a08300849082f0848082e0847c01003082d084608ca083b08cb083a08cc083908cd083808ce082c08d0082b08d1082ac010063207010308d2082908d3082808d6081c08d7081b08d8081a08d9081908da081508df0814c01059940b0308e0081308e1081208e2081108e4080e08e5080d08e6080c08e7080b08e8080ac010240308ea080708eb080608ec080508ed080408ee080308ef080208f0080108f10800c0100c0720070c2003040200004200080002089000000000002f00040038000000290004009000000035000400a0000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x14,
build=0x0,
u1=0x0,
dev_type=0xb4b,
a0=0x18,
a1=0x19,
blobs=[
'2300000020000800002000800000010032005c00000000802020040024200000382000002820df0b2c20df0b302000003420000050201f015c200000602000004c2003006c20720070207200742004007820040084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a00',
'330064030000008064200000a10c642000109f0c64200020a20c642000309e0c64200040a30c642000509d0c64200060a40c642000709c0c64200080a60c642000909b0c642000a0a70c642000b09a0c642000c0a80c642000d0990c642000e0a90c642000f0980c64200000af0c64200010950c64200020b00c64200030940c64200040b10c64200050930c64200060b20c64200070920c64200080b30c642000908b0c642000a0b70c642000b08a0c642000c0b80c642000d0890c642000e0b90c642000f0880c64200000ba0c64200010870c64200020bb0c64200030810c64200040bf0c64200050800c64200060c00c642000707f0c64200080c10c642000907e0c642000a0c20c642000b07d0c642000c0c50c642000d0720c642000e0c60c642000f0710c64200000c70c64200010700c64200020c80c642000306f0c64200040c90c642000506d0c642000607a0c642000706c0c64200080790c642000906b0c642000a0780c642000b06a0c642000c06e0c642000d0690c642000e0630c642000f05e0c64200000620c642000105d0c64200020610c642000305c0c64200040600c642000505b0c642000605f0c642000705a0c64200080310c642000904a0c642000a0300c642000b0490c642000c02f0c642000d0480c642000e02e0c642000f0470c642000002d0c64200010460c64200020ca0c642000303b0c64200040cb0c642000503a0c64200060cc0c64200070390c64200080cd0c64200090380c642000a0ce0c642000b02c0c642000c0d00c642000d02b0c642000e0d10c642000f02a0c64200000d20c64200010290c64200020d30c64200030280c64200040d60c642000501c0c64200060d70c642000701b0c64200080d80c642000901a0c642000a0d90c642000b0190c642000c0da0c642000d0150c642000e0df0c642000f0140c64200000e00c64200010130c64200020e10c64200030120c64200040e20c64200050110c64200060e40c642000700e0c64200080e50c642000900d0c642000a0e60c642000b00c0c642000c0e70c642000d00b0c642000e0e80c642000f00a0c64200000ea0c64200010070c64200020eb0c64200030060c64200040ec0c64200050050c64200060ed0c64200070040c64200080ee0c64200090030c642000a0ef0c642000b0020c642000c0f00c642000d0010c642000e0f10c642000f0000c',
'32000c000000008068110100641126003400180200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007e007e0102a13102a13102a12010000061e102d0101000007c8078c060b5d03005e03004f80005080006d030059940b07010000240308a1089f08a2089e08a3089d08a4089c08a6089b08a7089a08a8089908a90898c0102c0308af089508b0089408b1089308b2089208b3088b08b7088a08b8088908b90888c0100308ba088708bb088108bf088008c0087f08c1087e08c2087d08c5087208c60871c010062807010308c7087008c8086f08c9086d087a086c0879086b0878086a086e08690863085ec010030862085d0861085c0860085b085f085a0831084a08300849082f0848082e0847c01003082d084608ca083b08cb083a08cc083908cd083808ce082c08d0082b08d1082ac010063207010308d2082908d3082808d6081c08d7081b08d8081a08d9081908da081508df0814c01059940b0308e0081308e1081208e2081108e4080e08e5080d08e6080c08e7080b08e8080ac010240308ea080708eb080608ec080508ed080408ee080308ef080208f0080108f10800c0100c0720070c2003040200004200080002089000000000002f00040038000000290004009000000035000400a0000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x15,
build=0x0,
u1=0x0,
dev_type=0xb4b,
a0=0x18,
a1=0x19,
blobs=[
'2300000020000800002000800000010032005c00000000802020040024200000382000002820df0b2c20df0b302000003420000050201f015c200000602000004c2003006c20720070207200742004007820040084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a00',
'330064030000008064200000a10c642000109f0c64200020a20c642000309e0c64200040a30c642000509d0c64200060a40c642000709c0c64200080a60c642000909b0c642000a0a70c642000b09a0c642000c0a80c642000d0990c642000e0a90c642000f0980c64200000af0c64200010950c64200020b00c64200030940c64200040b10c64200050930c64200060b20c64200070920c64200080b30c642000908b0c642000a0b70c642000b08a0c642000c0b80c642000d0890c642000e0b90c642000f0880c64200000ba0c64200010870c64200020bb0c64200030810c64200040bf0c64200050800c64200060c00c642000707f0c64200080c10c642000907e0c642000a0c20c642000b07d0c642000c0c50c642000d0720c642000e0c60c642000f0710c64200000c70c64200010700c64200020c80c642000306f0c64200040c90c642000506d0c642000607a0c642000706c0c64200080790c642000906b0c642000a0780c642000b06a0c642000c06e0c642000d0690c642000e0630c642000f05e0c64200000620c642000105d0c64200020610c642000305c0c64200040600c642000505b0c642000605f0c642000705a0c64200080310c642000904a0c642000a0300c642000b0490c642000c02f0c642000d0480c642000e02e0c642000f0470c642000002d0c64200010460c64200020ca0c642000303b0c64200040cb0c642000503a0c64200060cc0c64200070390c64200080cd0c64200090380c642000a0ce0c642000b02c0c642000c0d00c642000d02b0c642000e0d10c642000f02a0c64200000d20c64200010290c64200020d30c64200030280c64200040d60c642000501c0c64200060d70c642000701b0c64200080d80c642000901a0c642000a0d90c642000b0190c642000c0da0c642000d0150c642000e0df0c642000f0140c64200000e00c64200010130c64200020e10c64200030120c64200040e20c64200050110c64200060e40c642000700e0c64200080e50c642000900d0c642000a0e60c642000b00c0c642000c0e70c642000d00b0c642000e0e80c642000f00a0c64200000ea0c64200010070c64200020eb0c64200030060c64200040ec0c64200050050c64200060ed0c64200070040c64200080ee0c64200090030c642000a0ef0c642000b0020c642000c0f00c642000d0010c642000e0f10c642000f0000c',
'32000c000000008068110100641126003400180200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007e007e0102a13102a13102a12010000061e102d0101000007c8078c060b5d03005e03004f80005080006d030059940b07010000240308a1089f08a2089e08a3089d08a4089c08a6089b08a7089a08a8089908a90898c0102c0308af089508b0089408b1089308b2089208b3088b08b7088a08b8088908b90888c0100308ba088708bb088108bf088008c0087f08c1087e08c2087d08c5087208c60871c010062807010308c7087008c8086f08c9086d087a086c0879086b0878086a086e08690863085ec010030862085d0861085c0860085b085f085a0831084a08300849082f0848082e0847c01003082d084608ca083b08cb083a08cc083908cd083808ce082c08d0082b08d1082ac010063207010308d2082908d3082808d6081c08d7081b08d8081a08d9081908da081508df0814c01059940b0308e0081308e1081208e2081108e4080e08e5080d08e6080c08e7080b08e8080ac010240308ea080708eb080608ec080508ed080408ee080308ef080208f0080108f10800c0100c0720070c2003040200004200080002089000000000002f00040038000000290004009000000035000400a0000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x14,
build=0x0,
u1=0x0,
dev_type=0xb4d,
a0=0x18,
a1=0x19,
blobs=[
'2300000020000800002000800000010032005c00000000802020040024200000382000002820df0b2c20df0b302000003420000050200a015c200000602000004c2003006c20600070206000742002007820020084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a00',
'330064030000008064200000a10c642000109f0c64200020a20c642000309e0c64200040a30c642000509d0c64200060a40c642000709c0c64200080a60c642000909b0c642000a0a70c642000b09a0c642000c0a80c642000d0990c642000e0a90c642000f0980c64200000af0c64200010950c64200020b00c64200030940c64200040b10c64200050930c64200060b20c64200070920c64200080b30c642000908b0c642000a0b70c642000b08a0c642000c0b80c642000d0890c642000e0b90c642000f0880c64200000ba0c64200010870c64200020bb0c64200030810c64200040bf0c64200050800c64200060c00c642000707f0c64200080c10c642000907e0c642000a0c20c642000b07d0c642000c0c50c642000d0720c642000e0c60c642000f0710c64200000c70c64200010700c64200020c80c642000306f0c64200040c90c642000506d0c642000607a0c642000706c0c64200080790c642000906b0c642000a0780c642000b06a0c642000c06e0c642000d0690c642000e0630c642000f05e0c64200000620c642000105d0c64200020610c642000305c0c64200040600c642000505b0c642000605f0c642000705a0c64200080310c642000904a0c642000a0300c642000b0490c642000c02f0c642000d0480c642000e02e0c642000f0470c642000002d0c64200010460c64200020ca0c642000303b0c64200040cb0c642000503a0c64200060cc0c64200070390c64200080cd0c64200090380c642000a0ce0c642000b02c0c642000c0d00c642000d02b0c642000e0d10c642000f02a0c64200000d20c64200010290c64200020d30c64200030280c64200040d60c642000501c0c64200060d70c642000701b0c64200080d80c642000901a0c642000a0d90c642000b0190c642000c0da0c642000d0150c642000e0df0c642000f0140c64200000e00c64200010130c64200020e10c64200030120c64200040e20c64200050110c64200060e40c642000700e0c64200080e50c642000900d0c642000a0e60c642000b00c0c642000c0e70c642000d00b0c642000e0e80c642000f00a0c64200000ea0c64200010070c64200020eb0c64200030060c64200040ec0c64200050050c64200060ed0c64200070040c64200080ee0c64200090030c642000a0ef0c642000b0020c642000c0f00c642000d0010c642000e0f10c642000f0000c',
'32000c000000008068110100641126003400180200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007e007e0102a13102a13102a12010000061e102d0101000007c8078c060b5d01005e01004f80005080006d030059940b07010000240308a1089f08a2089e08a3089d08a4089c08a6089b08a7089a08a8089908a90898c0102c0308af089508b0089408b1089308b2089208b3088b08b7088a08b8088908b90888c0100308ba088708bb088108bf088008c0087f08c1087e08c2087d08c5087208c60871c010062807010308c7087008c8086f08c9086d087a086c0879086b0878086a086e08690863085ec010030862085d0861085c0860085b085f085a0831084a08300849082f0848082e0847c01003082d084608ca083b08cb083a08cc083908cd083808ce082c08d0082b08d1082ac010063207010308d2082908d3082808d6081c08d7081b08d8081a08d9081908da081508df0814c01059940b0308e0081308e1081208e2081108e4080e08e5080d08e6080c08e7080b08e8080ac010240308ea080708eb080608ec080508ed080408ee080308ef080208f0080108f10800c0100c0720070c2003040200004200080002089000000000002f00040038000000290004009000000035000400a0000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x15,
build=0x0,
u1=0x0,
dev_type=0xb4d,
a0=0x18,
a1=0x19,
blobs=[
'2300000020000800002000800000010032005c00000000802020040024200000382000002820df0b2c20df0b302000003420000050200a015c200000602000004c2003006c20600070206000742002007820020084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a00',
'330064030000008064200000a10c642000109f0c64200020a20c642000309e0c64200040a30c642000509d0c64200060a40c642000709c0c64200080a60c642000909b0c642000a0a70c642000b09a0c642000c0a80c642000d0990c642000e0a90c642000f0980c64200000af0c64200010950c64200020b00c64200030940c64200040b10c64200050930c64200060b20c64200070920c64200080b30c642000908b0c642000a0b70c642000b08a0c642000c0b80c642000d0890c642000e0b90c642000f0880c64200000ba0c64200010870c64200020bb0c64200030810c64200040bf0c64200050800c64200060c00c642000707f0c64200080c10c642000907e0c642000a0c20c642000b07d0c642000c0c50c642000d0720c642000e0c60c642000f0710c64200000c70c64200010700c64200020c80c642000306f0c64200040c90c642000506d0c642000607a0c642000706c0c64200080790c642000906b0c642000a0780c642000b06a0c642000c06e0c642000d0690c642000e0630c642000f05e0c64200000620c642000105d0c64200020610c642000305c0c64200040600c642000505b0c642000605f0c642000705a0c64200080310c642000904a0c642000a0300c642000b0490c642000c02f0c642000d0480c642000e02e0c642000f0470c642000002d0c64200010460c64200020ca0c642000303b0c64200040cb0c642000503a0c64200060cc0c64200070390c64200080cd0c64200090380c642000a0ce0c642000b02c0c642000c0d00c642000d02b0c642000e0d10c642000f02a0c64200000d20c64200010290c64200020d30c64200030280c64200040d60c642000501c0c64200060d70c642000701b0c64200080d80c642000901a0c642000a0d90c642000b0190c642000c0da0c642000d0150c642000e0df0c642000f0140c64200000e00c64200010130c64200020e10c64200030120c64200040e20c64200050110c64200060e40c642000700e0c64200080e50c642000900d0c642000a0e60c642000b00c0c642000c0e70c642000d00b0c642000e0e80c642000f00a0c64200000ea0c64200010070c64200020eb0c64200030060c64200040ec0c64200050050c64200060ed0c64200070040c64200080ee0c64200090030c642000a0ef0c642000b0020c642000c0f00c642000d0010c642000e0f10c642000f0000c',
'32000c000000008068110100641126003400180200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007e007e0102a13102a13102a12010000061e102d0101000007c8078c060b5d01005e01004f80005080006d030059940b07010000240308a1089f08a2089e08a3089d08a4089c08a6089b08a7089a08a8089908a90898c0102c0308af089508b0089408b1089308b2089208b3088b08b7088a08b8088908b90888c0100308ba088708bb088108bf088008c0087f08c1087e08c2087d08c5087208c60871c010062807010308c7087008c8086f08c9086d087a086c0879086b0878086a086e08690863085ec010030862085d0861085c0860085b085f085a0831084a08300849082f0848082e0847c01003082d084608ca083b08cb083a08cc083908cd083808ce082c08d0082b08d1082ac010063207010308d2082908d3082808d6081c08d7081b08d8081a08d9081908da081508df0814c01059940b0308e0081308e1081208e2081108e4080e08e5080d08e6080c08e7080b08e8080ac010240308ea080708eb080608ec080508ed080408ee080308ef080208f0080108f10800c0100c0720070c2003040200004200080002089000000000002f00040038000000290004009000000035000400a0000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x15,
build=0x0,
u1=0x0,
dev_type=0x130,
a0=0x18,
a1=0x19,
blobs=[
'2300000020000800002000800000010032005c00000000802020040024200000382000002820df0b2c20df0b302000003420000050200a015c200000602000004c2003006c20400070204000742001007820010084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a003200b4020000008074030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030005740300077403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030015740300177403000174030003',
'330064030000008064200000e40c64200010050c64200020e60c64200030040c64200040e70c64200050020c64200060eb0c64200070000c64200080ec0c64200090010c642000a0ed0c642000b0030c642000c0f10c642000d0060c642000e0f00c642000f0070c64200000ef0c64200010080c64200020ee0c642000300a0c64200040ea0c642000500b0c64200060e80c642000700c0c64200080e50c642000900d0c642000a0e10c642000b0100c642000c0e00c642000d0140c642000e0df0c642000f0160c64200000de0c64200010190c64200020dc0c642000301d0c64200040db0c642000501e0c64200060da0c64200070220c64200080d30c64200090250c642000a0d10c642000b0270c642000c0cb0c642000d02b0c642000e0ca0c642000f02d0c642000003a0c64200010310c642000203b0c64200030320c642000403d0c64200050370c642000603e0c64200070390c64200080460c642000903c0c642000a0470c642000b03f0c642000c0490c642000d0400c642000e04a0c642000f0450c642000004c0c64200010480c642000204d0c642000304b0c642000405c0c642000504e0c642000605d0c642000704f0c642000805e0c64200090500c642000a0610c642000b0550c642000c0620c642000d05a0c642000e0630c642000f05b0c64200000680c642000105f0c64200020690c64200030600c642000406a0c64200050640c642000606d0c64200070650c642000806e0c642000906b0c642000a06f0c642000b06c0c642000c0700c642000d0710c642000e0c90c642000f0720c64200000c80c64200010770c64200020c60c64200030780c64200040c20c642000507c0c64200060c10c642000707f0c64200080c00c64200090820c642000a0bd0c642000b0840c642000c0bc0c642000d0870c642000e0b80c642000f08b0c64200000b50c642000108f0c64200020b20c64200030910c64200040af0c64200050940c64200060ae0c64200070980c64200080ad0c642000909a0c642000a0ac0c642000b09e0c642000c0ab0c642000d09f0c642000e0a90c642000f09d0c64200000a80c642000109c0c64200020a70c642000309b0c64200040a60c64200050990c64200060a40c64200070960c64200080a30c64200090950c642000a0a20c642000b0930c642000c0a10c642000d0920c642000e0a90c642000f09d0c',
'32000c0000000080681101006411260034000c0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007e007e0102a0d102a0d102a0e0100000628102c0101000007c8078c061400004f80005080006d030059940b07010000240308e4080508e6080408e7080208eb080008ec080108ed080308f1080608f00807c0102c0308ef080808ee080a08ea080b08e8080c08e5080d08e1081008e0081408df0816c0100308de081908dc081d08db081e08da082208d3082508d1082708cb082b08ca082dc01003083a0831083b0832083d0837083e08390846083c0847083f08490840084a0845c01003084c0848084d084b085c084e085d084f085e0850086108550862085a0863085bc010030868085f08690860086a0864086d0865086e086b086f086c0870087108c90872c0100308c8087708c6087808c2087c08c1087f08c0088208bd088408bc088708b8088bc0100308b5088f08b2089108af089408ae089808ad089a08ac089e08ab089f08a9089dc010240308a9089d08a8089c08a7089b08a6089908a4089608a3089508a2089308a10892c0100c072c20030703070304020000004200080002089000000000002f00040028000000290004009000000035000400a0000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x15,
build=0x0,
u1=0x0,
dev_type=0x518,
a0=0x18,
a1=0x19,
blobs=[
'2300000020000800002000800000010032005c00000000802020040024200000382000002820df0b2c20df0b302000003420000050200a015c200000602000004c2003006c20640070206400742001007820010084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a003200b4020000008074030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030005740300077403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030015740300177403000174030003',
'330064030000008064200000e40c64200010050c64200020e60c64200030040c64200040e70c64200050020c64200060eb0c64200070000c64200080ec0c64200090010c642000a0ed0c642000b0030c642000c0f10c642000d0060c642000e0f00c642000f0070c64200000ef0c64200010080c64200020ee0c642000300a0c64200040ea0c642000500b0c64200060e80c642000700c0c64200080e50c642000900d0c642000a0e10c642000b0100c642000c0e00c642000d0140c642000e0df0c642000f0160c64200000de0c64200010190c64200020dc0c642000301d0c64200040db0c642000501e0c64200060da0c64200070220c64200080d30c64200090250c642000a0d10c642000b0270c642000c0cb0c642000d02b0c642000e0ca0c642000f02d0c642000003a0c64200010310c642000203b0c64200030320c642000403d0c64200050370c642000603e0c64200070390c64200080460c642000903c0c642000a0470c642000b03f0c642000c0490c642000d0400c642000e04a0c642000f0450c642000004c0c64200010480c642000204d0c642000304b0c642000405c0c642000504e0c642000605d0c642000704f0c642000805e0c64200090500c642000a0610c642000b0550c642000c0620c642000d05a0c642000e0630c642000f05b0c64200000680c642000105f0c64200020690c64200030600c642000406a0c64200050640c642000606d0c64200070650c642000806e0c642000906b0c642000a06f0c642000b06c0c642000c0700c642000d0710c642000e0c90c642000f0720c64200000c80c64200010770c64200020c60c64200030780c64200040c20c642000507c0c64200060c10c642000707f0c64200080c00c64200090820c642000a0bd0c642000b0840c642000c0bc0c642000d0870c642000e0b80c642000f08b0c64200000b50c642000108f0c64200020b20c64200030910c64200040af0c64200050940c64200060ae0c64200070980c64200080ad0c642000909a0c642000a0ac0c642000b09e0c642000c0ab0c642000d09f0c642000e0a90c642000f09d0c64200000a80c642000109c0c64200020a70c642000309b0c64200040a60c64200050990c64200060a40c64200070960c64200080a30c64200090950c642000a0a20c642000b0930c642000c0a10c642000d0920c642000e0a90c642000f09d0c',
'32000c0000000080681101006411260034000c0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007e007e0102a0d102a0d102a0e0100000628102c0101000007c8078c061400004f80005080006d030059940b07010000240308e4080508e6080408e7080208eb080008ec080108ed080308f1080608f00807c0102c0308ef080808ee080a08ea080b08e8080c08e5080d08e1081008e0081408df0816c0100308de081908dc081d08db081e08da082208d3082508d1082708cb082b08ca082dc01003083a0831083b0832083d0837083e08390846083c0847083f08490840084a0845c01003084c0848084d084b085c084e085d084f085e0850086108550862085a0863085bc010030868085f08690860086a0864086d0865086e086b086f086c0870087108c90872c0100308c8087708c6087808c2087c08c1087f08c0088208bd088408bc088708b8088bc0100308b5088f08b2089108af089408ae089808ad089a08ac089e08ab089f08a9089dc010240308a9089d08a8089c08a7089b08a6089908a4089608a3089508a2089308a10892c0100c072c20030703070304020000004200080002089000000000002f00040028000000290004009000000035000400a0000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x15,
build=0x0,
u1=0x0,
dev_type=0xbe1,
a0=0x18,
a1=0x19,
blobs=[
'2300000020000800002000800000010032005c00000000802020040024200000382000002820df0b2c20df0b302000003420000050200a015c200000602000004c2003006c20550070205500742001007820010084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a003200b4020000008074030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030005740300077403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030015740300177403000174030003',
'330064030000008064200000e40c64200010050c64200020e60c64200030040c64200040e70c64200050020c64200060eb0c64200070000c64200080ec0c64200090010c642000a0ed0c642000b0030c642000c0f10c642000d0060c642000e0f00c642000f0070c64200000ef0c64200010080c64200020ee0c642000300a0c64200040ea0c642000500b0c64200060e80c642000700c0c64200080e50c642000900d0c642000a0e10c642000b0100c642000c0e00c642000d0140c642000e0df0c642000f0160c64200000de0c64200010190c64200020dc0c642000301d0c64200040db0c642000501e0c64200060da0c64200070220c64200080d30c64200090250c642000a0d10c642000b0270c642000c0cb0c642000d02b0c642000e0ca0c642000f02d0c642000003a0c64200010310c642000203b0c64200030320c642000403d0c64200050370c642000603e0c64200070390c64200080460c642000903c0c642000a0470c642000b03f0c642000c0490c642000d0400c642000e04a0c642000f0450c642000004c0c64200010480c642000204d0c642000304b0c642000405c0c642000504e0c642000605d0c642000704f0c642000805e0c64200090500c642000a0610c642000b0550c642000c0620c642000d05a0c642000e0630c642000f05b0c64200000680c642000105f0c64200020690c64200030600c642000406a0c64200050640c642000606d0c64200070650c642000806e0c642000906b0c642000a06f0c642000b06c0c642000c0700c642000d0710c642000e0c90c642000f0720c64200000c80c64200010770c64200020c60c64200030780c64200040c20c642000507c0c64200060c10c642000707f0c64200080c00c64200090820c642000a0bd0c642000b0840c642000c0bc0c642000d0870c642000e0b80c642000f08b0c64200000b50c642000108f0c64200020b20c64200030910c64200040af0c64200050940c64200060ae0c64200070980c64200080ad0c642000909a0c642000a0ac0c642000b09e0c642000c0ab0c642000d09f0c642000e0a90c642000f09d0c64200000a80c642000109c0c64200020a70c642000309b0c64200040a60c64200050990c64200060a40c64200070960c64200080a30c64200090950c642000a0a20c642000b0930c642000c0a10c642000d0920c642000e0a90c642000f09d0c',
'32000c0000000080681101006411260034000c0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007e007e0102a0d102a0d102a0e0100000628102c0101000007c8078c061400004f80005080006d030059940b07010000240308e4080508e6080408e7080208eb080008ec080108ed080308f1080608f00807c0102c0308ef080808ee080a08ea080b08e8080c08e5080d08e1081008e0081408df0816c0100308de081908dc081d08db081e08da082208d3082508d1082708cb082b08ca082dc01003083a0831083b0832083d0837083e08390846083c0847083f08490840084a0845c01003084c0848084d084b085c084e085d084f085e0850086108550862085a0863085bc010030868085f08690860086a0864086d0865086e086b086f086c0870087108c90872c0100308c8087708c6087808c2087c08c1087f08c0088208bd088408bc088708b8088bc0100308b5088f08b2089108af089408ae089808ad089a08ac089e08ab089f08a9089dc010240308a9089d08a8089c08a7089b08a6089908a4089608a3089508a2089308a10892c0100c072c20030703070304020000004200080002089000000000002f00040028000000290004009000000035000400a0000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x15,
build=0x0,
u1=0x0,
dev_type=0xbe2,
a0=0x18,
a1=0x19,
blobs=[
'2300000020000800002000800000010032005c00000000802020040024200000382000002820df0b2c20df0b302000003420000050200a015c200000602000004c2003006c20500070205000742001007820010084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a003200b4020000008074030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030001740300037403000174030003740300017403000374030005740300077403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030001740300037403001574030017740300017403000374030015740300177403000174030003740300157403001774030015740300177403000174030003',
'330064030000008064200000e40c64200010050c64200020e60c64200030040c64200040e70c64200050020c64200060eb0c64200070000c64200080ec0c64200090010c642000a0ed0c642000b0030c642000c0f10c642000d0060c642000e0f00c642000f0070c64200000ef0c64200010080c64200020ee0c642000300a0c64200040ea0c642000500b0c64200060e80c642000700c0c64200080e50c642000900d0c642000a0e10c642000b0100c642000c0e00c642000d0140c642000e0df0c642000f0160c64200000de0c64200010190c64200020dc0c642000301d0c64200040db0c642000501e0c64200060da0c64200070220c64200080d30c64200090250c642000a0d10c642000b0270c642000c0cb0c642000d02b0c642000e0ca0c642000f02d0c642000003a0c64200010310c642000203b0c64200030320c642000403d0c64200050370c642000603e0c64200070390c64200080460c642000903c0c642000a0470c642000b03f0c642000c0490c642000d0400c642000e04a0c642000f0450c642000004c0c64200010480c642000204d0c642000304b0c642000405c0c642000504e0c642000605d0c642000704f0c642000805e0c64200090500c642000a0610c642000b0550c642000c0620c642000d05a0c642000e0630c642000f05b0c64200000680c642000105f0c64200020690c64200030600c642000406a0c64200050640c642000606d0c64200070650c642000806e0c642000906b0c642000a06f0c642000b06c0c642000c0700c642000d0710c642000e0c90c642000f0720c64200000c80c64200010770c64200020c60c64200030780c64200040c20c642000507c0c64200060c10c642000707f0c64200080c00c64200090820c642000a0bd0c642000b0840c642000c0bc0c642000d0870c642000e0b80c642000f08b0c64200000b50c642000108f0c64200020b20c64200030910c64200040af0c64200050940c64200060ae0c64200070980c64200080ad0c642000909a0c642000a0ac0c642000b09e0c642000c0ab0c642000d09f0c642000e0a90c642000f09d0c64200000a80c642000109c0c64200020a70c642000309b0c64200040a60c64200050990c64200060a40c64200070960c64200080a30c64200090950c642000a0a20c642000b0930c642000c0a10c642000d0920c642000e0a90c642000f09d0c',
'32000c0000000080681101006411260034000c0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007e007e0102a0d102a0d102a0e0100000628102c0101000007c8078c061400004f80005080006d030059940b07010000240308e4080508e6080408e7080208eb080008ec080108ed080308f1080608f00807c0102c0308ef080808ee080a08ea080b08e8080c08e5080d08e1081008e0081408df0816c0100308de081908dc081d08db081e08da082208d3082508d1082708cb082b08ca082dc01003083a0831083b0832083d0837083e08390846083c0847083f08490840084a0845c01003084c0848084d084b085c084e085d084f085e0850086108550862085a0863085bc010030868085f08690860086a0864086d0865086e086b086f086c0870087108c90872c0100308c8087708c6087808c2087c08c1087f08c0088208bd088408bc088708b8088bc0100308b5088f08b2089108af089408ae089808ad089a08ac089e08ab089f08a9089dc010240308a9089d08a8089c08a7089b08a6089908a4089608a3089508a2089308a10892c0100c072c20030703070304020000004200080002089000000000002f00040028000000290004009000000035000400a0000000'
]),
SensorCaptureProg(
major=0x6,
minor=0xb,
build=0x0,
u1=0x0,
dev_type=0x194,
a0=0x18,
a1=0x19,
blobs=[
'2300000020000800002000800000010032005c0000000080202004002820ff0b2c20f60b6c202f007020000074201000782000005c2000006020000064200000502000005420151d84202000942001809c200902a0200b19b4200000b8203a00bc201400c0200200c4200200c82008003300100000000080cc2000004900d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0201400f8200500fc200000b8203b00002804001428000008280000082810001428180008281100142819001c281a00',
'32001400000000806811010064111f007c1700007017010033001c00000000809c1701000000ac1700900100b01754000000b417007200003400500010061110061110061110061110061001068010080101000007c80764060000002003070107010c07840a640863c91e2cc9159107010a9dc9110701030a3208330701c90f20c91e070304020000000000',
'2f0004005400000029000400000000003500040010000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x0,
build=0x0,
u1=0x0,
dev_type=0x179,
a0=0x18,
a1=0x19,
blobs=[
'2300000020000800002000800000010032007800000000802020040024200000382000002820df0b2c20df0b30200000342000003c20000040200000442000004820000050200a005c20000060200000642000004c200300002100006c2030007020300040210000742006007820060084202000b4200000b8203a00bc201400c0200200c4200100c820020033001c000000008054202f27030058202f270300cc200000ef03d0200000ef033200440000000080dc20e803e020e803e420d002e820d002f0200500f8200500fc200000b8203a00002804001428000008280000082800001428300008280000142831001c281a00',
'320014000000008068110100641126007c1700007017010033001c00000000809c1701000000ac1700900100b01738000000b417009000003400040310060b10060b10060b10060b10060c01064e10080101000007c80764060000002003070107010c2c078408a180089f800aa108a2800a9f089e800aa208a3800a9e089d800aa308a4800a9d089c800aa408a6800a9c089b800aa608a7800a9b089a800aa708a8800a9a0899800aa808a9800a990898800aa908af800a980895800aaf08b0800a950894800ab008b1800a940893800ab108b2800a930892800ab208b3800a92088b800ab308b7800a8b088a800ab708b8800a8a0889800ab808b9800a890888800ab908ba800a880887800aba08bb800a870881800abb08bf800a810880800abf08c0800a80087f800ac008c1800a7f087e800ac108c2800a7e087d800ac208c5800a7d0872800ac508c6800a720871800ac608c7800a710870800ac708c8800a70086f800ac808c9800a6f0863800ac9086c800a630862800a6c086b800a620861800a6b086a800a610860800a6a0869800a60085f800a69085e800a5f084f800a5e085d800a4f084e800a5d085c800a4e084d800a5c085b800a4d084c800a5b085a800a4c084b800a5a0831800a4b084a800a310830800a4a0849800a30082f800a490848800a2f082e800a480847800a2e082d800a470846800a2d08ca800a46083b800aca08cb800a3b083a800acb08cc800a3a0839800acc08cd800a390838800acd08ce800a38082c800ace08d1800a2c082b800ad108d2800a2b082a800ad208d3800a2a0829800ad308d6800a290828800ad608d7800a28081d800ad708d8800a1d081c800ad808d9800a1c081b800ad908da800a1b081a800ada08de800a1a0819800ade08df800a190815800adf08e0800a150814800ae008e1800a140813800ae108e2800a130812800ae208e4800a120811800ae408e5800a11080d800ae508e6800a0d080c800ae608e7800a0c080b800ae708ea800a0b080a800aea08eb800a0a0807800aeb08ec800a070806800aec08ed800a060805800aed08ee800a050804800aee08ef800a040803800aef08f0800a030802800af008f1800a020801800af108f2800a010800802007032003070307030402000000',
'2f0004003800000029000400000000003500040010000000'
]),
SensorCaptureProg(
major=0x6,
minor=0xa,
build=0x0,
u1=0x0,
dev_type=0x117,
a0=0x18,
a1=0x19,
blobs=[
'2300000020000800002000800000010032006400000000802020040024200000382000002820df0b2c20df0b30200000342000003c2080004020800050200a005c200000602000004c2003006c20680070206800742001007820010084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a00',
'32000c000000008068110100641126003400ac0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000102b0e102b0e102b0e102b0e01000000061e10301001000007c80764060b4f80005080006d030007010000006d0300200307010007032408a180089f800aa108a2800a9f089e800aa208a3800a9e089d800aa308a4800a9d089c800aa408a6800a9c089b802c0aa608a7800a9b089a800aa708a8800a9a0899800aa808a9800a990898800aa908af800a980895800aaf08b0800a950894800ab008b1800a940893800ab108b2800a930892800ab208b3800a92088b800ab308b7800a8b088a800ab708b8800a8a0889800ab808b9800a890888800ab908ba800a880887800aba08bb800a870881800abb08bf800a810880800abf08c0800a80087f800ac008c1800a7f087e800ac108c2800a7e087d800ac208c5800a7d0872800ac508c6800a72087180062807010ac608c7800a710870800ac708c8800a70086f800ac808c9800a6f0863800ac9086c800a630862800a6c086b800a620861800a6b086a800a610860800a6a0869800a60085f800a69085e800a5f084f800a5e085d800a4f084e800a5d085c800a4e084d800a5c085b800a4d084c800a5b085a800a4c084b800a5a0831800a4b084a800a310830800a4a0849800a30082f800a490848800a2f082e800a480847800a2e082d800a470846800a2d08ca800a46083b800aca08cb800a3b083a800acb08cc800a3a0839800acc08cd800a390838800acd08ce800a38082c800ace08d1800a2c082b800ad108d2800a2b082a80063207010ad208d3800a2a0829800ad308d6800a290828800ad608d7800a28081d800ad708d8800a1d081c800ad808d9800a1c081b800ad908da800a1b081a800ada08de800a1a0819800ade08df800a190815800adf08e0800a150814800ae008e1800a140813800ae108e2800a130812800ae208e4800a120811800ae408e5800a11080d800ae508e6800a0d080c800ae608e7800a0c080b800ae708ea800a0b080a800aea08eb800a0a0807800aeb08ec800a070806800aec08ed800a06080580240aed08ee800a050804800aee08ef800a040803800aef08f0800a030802800af008f1800a020801800af108f2800c0a01080080070103040200000000002f00040038000000',
'290004009400000035000400a4000000'
]),
SensorCaptureProg(
major=0x6,
minor=0xb,
build=0x0,
u1=0x0,
dev_type=0x117,
a0=0x18,
a1=0x19,
blobs=[
'2300000020000800002000800000010032006400000000802020040024200000382000002820df0b2c20df0b30200000342000003c2080004020800050200a005c200000602000004c2003006c20680070206800742001007820010084202000b4200000bc201400c0200200c4200100c820020074030002330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a00',
'32000c000000008068110100641126003400ac0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000102b0e102b0e102b0e102b0e01000000061e10301001000007c80764060b4f80005080006d030007010000006d0300200307010007032408a180089f800aa108a2800a9f089e800aa208a3800a9e089d800aa308a4800a9d089c800aa408a6800a9c089b802c0aa608a7800a9b089a800aa708a8800a9a0899800aa808a9800a990898800aa908af800a980895800aaf08b0800a950894800ab008b1800a940893800ab108b2800a930892800ab208b3800a92088b800ab308b7800a8b088a800ab708b8800a8a0889800ab808b9800a890888800ab908ba800a880887800aba08bb800a870881800abb08bf800a810880800abf08c0800a80087f800ac008c1800a7f087e800ac108c2800a7e087d800ac208c5800a7d0872800ac508c6800a72087180062807010ac608c7800a710870800ac708c8800a70086f800ac808c9800a6f0863800ac9086c800a630862800a6c086b800a620861800a6b086a800a610860800a6a0869800a60085f800a69085e800a5f084f800a5e085d800a4f084e800a5d085c800a4e084d800a5c085b800a4d084c800a5b085a800a4c084b800a5a0831800a4b084a800a310830800a4a0849800a30082f800a490848800a2f082e800a480847800a2e082d800a470846800a2d08ca800a46083b800aca08cb800a3b083a800acb08cc800a3a0839800acc08cd800a390838800acd08ce800a38082c800ace08d1800a2c082b800ad108d2800a2b082a80063207010ad208d3800a2a0829800ad308d6800a290828800ad608d7800a28081d800ad708d8800a1d081c800ad808d9800a1c081b800ad908da800a1b081a800ada08de800a1a0819800ade08df800a190815800adf08e0800a150814800ae008e1800a140813800ae108e2800a130812800ae208e4800a120811800ae408e5800a11080d800ae508e6800a0d080c800ae608e7800a0c080b800ae708ea800a0b080a800aea08eb800a0a0807800aeb08ec800a070806800aec08ed800a06080580240aed08ee800a050804800aee08ef800a040803800aef08f0800a030802800af008f1800a020801800af108f2800c0a01080080070103040200000000002f00040038000000',
'290004009400000035000400a4000000'
]),
SensorCaptureProg(
major=0x6,
minor=0xb,
build=0x0,
u1=0x0,
dev_type=0x126,
a0=0x18,
a1=0x19,
blobs=[
'2300000020000800002000800000010032007000000000802020040024200000382000002820df0b2c20df0b30200000342000003c2080004020800050200a005c200000602000004c2003006c2068007020680074200100782001006420000084202000b4200000b8203a00bc201400c0200200c4200100c820020074030000a0030f00330028000000008054202a2203005820272f03004420898103004820868e0300cc200000ef03d0200000ef033200400000000080dc20fa00e020fa00e420b400e820b400f0200500f8200500b8203a00002804001428000008280000082800001428300008280000142831001c281a00',
'32000c000000008068110100641126003400ac0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000102b0e102b0e102b0e102b0e01000000061e10301001000007c80764060b4f80005080006d030007010000006d0300200307010007032408a180089f800aa108a2800a9f089e800aa208a3800a9e089d800aa308a4800a9d089c800aa408a6800a9c089b802c0aa608a7800a9b089a800aa708a8800a9a0899800aa808a9800a990898800aa908af800a980895800aaf08b0800a950894800ab008b1800a940893800ab108b2800a930892800ab208b3800a92088b800ab308b7800a8b088a800ab708b8800a8a0889800ab808b9800a890888800ab908ba800a880887800aba08bb800a870881800abb08bf800a810880800abf08c0800a80087f800ac008c1800a7f087e800ac108c2800a7e087d800ac208c5800a7d0872800ac508c6800a72087180062807010ac608c7800a710870800ac708c8800a70086f800ac808c9800a6f0863800ac9086c800a630862800a6c086b800a620861800a6b086a800a610860800a6a0869800a60085f800a69085e800a5f084f800a5e085d800a4f084e800a5d085c800a4e084d800a5c085b800a4d084c800a5b085a800a4c084b800a5a0831800a4b084a800a310830800a4a0849800a30082f800a490848800a2f082e800a480847800a2e082d800a470846800a2d08ca800a46083b800aca08cb800a3b083a800acb08cc800a3a0839800acc08cd800a390838800acd08ce800a38082c800ace08d0800a2c082b800ad008d1800a2b082a80063207010ad108d2800a2a0829800ad208d3800a290828800ad308d6800a28081c800ad608d7800a1c081b800ad708d8800a1b081a800ad808d9800a1a0819800ad908da800a190815800ada08df800a150814800adf08e0800a140813800ae008e1800a130812800ae108e2800a120811800ae208e4800a11080e800ae408e5800a0e080d800ae508e6800a0d080c800ae608e7800a0c080b800ae708e8800a0b080a800ae808ea800a0a0807800aea08eb800a070806800aeb08ec800a06080580240aec08ed800a050804800aed08ee800a040803800aee08ef800a030802800aef08f0800a020801800af008f1800c0a01080080070c03040200000000002f00040038000000290004009400000035000400a4000000'
]),
SensorCaptureProg(
major=0x6,
minor=0x0,
build=0x0,
u1=0x0,
dev_type=0xdb,
a0=0x18,
a1=0x19,
blobs=[
'2300000020000800002000800000010032007000000000802020050024200000502077362820010030200100082170000c210000482102004c210000582000005c20000060200000682005006c20012970200121742001887820018084202000942001809c200902a0200b19b4200000b8203b04bc201400c0200200c4200100c82002003300100000000080cc200000f503d0200000a1013200440000000080dc20e803e0206401e420d002e8200001f0200500f8200500fc200000b8203b00000804001408000008080000080800001408300008080000140831001c081a00',
'32000c0000000080501101004c1126003400080310061d10061d10061d10061d10061c01065810080101000007c8078c06100000204f80007f000003070107010c07032c08fc80095a800afc08fb800b5a095b800afb08fa800b5b095c800afa08f9800b5c095d800af908f8800b5d095e800af808f7800b5e095f800af708f6800b5f0960800af608f5800b600961800af508f4800b610962800af408f3800b620963800af308f2800b630964800af208f1800b640965800af108f0800b650966800af008ef800b660967800aef08ee800b670968800aee08ed800b68096c800aed08ec800b6c096d800aec08eb800b6d096e800aeb08ea800b6e096f800aea08e9800b6f0970800ae908e8800b700971800ae808e7800b710972800ae708e6800b720973800ae608e5800b730974800ae508e4800b740975800ae408e3800b750976800ae308e2800b760977800ae208e1800b770978800ae108e0800b780979800ae008df800b79097a800adf08de800b7a097b800ade08dd800b7b097c800add08dc800b7c097d800adc08db800b7d097e800adb08da800b7e097f800ada08d9800b7f0980800ad908d8800b800981800ad808d7800b810982800ad708d6800b820983800ad608d5800b830984800ad508d4800b840985800ad408d3800b850986800ad308d2800b860987800ad208d1800b870988800ad108d0800b880989800ad008cf800b89098a800acf08ce800b8a098b800ace08cd800b8b098c800acd08cc800b8c098d800acc08cb800b8d098e800acb08ca800b8e098f800aca08c9800b8f0990800ac908c8800b900991800ac808c7800b910992800ac708c6800b920993800ac608c5800b930994800ac508c4800b940995800ac408c3800b950996800ac308c2800b960997800ac208c1800b970998800ac108c0800b980999800ac008bf800b99099a800abf08be800b9a099b800abe08bd800b9b099c800abd08bc800b9c099d800abc08bb800b9d099e800abb08ba800b9e099f800aba08b9800b9f09a0800ab908b8800ba00801800ab808b7800a010802800ab708b6800a020803800ab608b5800a030804802003070404020000000000002f0004009000000029000400000000003500040010000000'
]),
]

View file

@ -1,14 +1,13 @@
class DeviceInfo():
def __init__(self, major, type, version, version_mask, name):
class DeviceInfo:
def __init__(self, major: int, type: int, version: int, version_mask: int, name: str):
self.major, self.type, self.version, self.version_mask, self.name = major, type, version, version_mask, name
def __repr__(self):
return "DeviceInfo(0x%04x, 0x%04x, 0x%02x, 0x%02x, '%s')" % (
self.major, self.type, self.version, self.version_mask, self.name
)
self.major, self.type, self.version, self.version_mask, self.name)
dev_info_table=[
dev_info_table = [
DeviceInfo(0x0000, 0x0080, 0x00, 0x00, 'VSI 15A '),
DeviceInfo(0x0000, 0x0080, 0x00, 0x00, 'VSI 15A '),
DeviceInfo(0x0000, 0x0080, 0x00, 0x00, 'VSI 15A '),
@ -428,7 +427,8 @@ dev_info_table=[
DeviceInfo(0x0190, 0x2449, 0xa3, 0xff, '86C TM-P3569-001 '),
]
def dev_info_lookup(major, ver):
def dev_info_lookup(major: int, ver: int):
fuzzy_match = None
for i in dev_info_table:
@ -444,16 +444,19 @@ def dev_info_lookup(major, ver):
return fuzzy_match
class FlashIcInfo():
def __init__(self, name, size, f18, jid0, jid1, f1b, f1c, f1e, secror_size, sector_erase_cmd, f25, f26):
class FlashIcInfo:
def __init__(self, name: str, size: int, f18: int, jid0: int, jid1: int, f1b: int, f1c: int,
f1e: int, secror_size: int, sector_erase_cmd: int, f25: int, f26: int):
self.name, self.size, self.f18, self.jid0, self.jid1, self.f1b, self.f1c, self.f1e, self.secror_size, self.sector_erase_cmd, self.f25, self.f26 = name, size, f18, jid0, jid1, f1b, f1c, f1e, secror_size, sector_erase_cmd, f25, f26
def __repr__(self):
return "FlashIcInfo('%s', %d, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)" % (
self.name, self.size, self.f18, self.jid0, self.jid1, self.f1b, self.f1c, self.f1e, self.secror_size, self.sector_erase_cmd, self.f25, self.f26)
self.name, self.size, self.f18, self.jid0, self.jid1, self.f1b, self.f1c, self.f1e,
self.secror_size, self.sector_erase_cmd, self.f25, self.f26)
flash_ic_table=[
flash_ic_table = [
FlashIcInfo('M25P05-A', 65536, 0x5, 0x20, 0x20, 0x10, 0x8000, 0x0, 0x8000, 0xd8, 0x0, 0x4),
FlashIcInfo('M25P10-A', 131072, 0x10, 0x20, 0x20, 0x11, 0x8000, 0x0, 0x8000, 0xd8, 0x0, 0x4),
FlashIcInfo('M25P20', 262144, 0x11, 0x20, 0x20, 0x12, 0x0, 0x1, 0x10000, 0xd8, 0x0, 0x4),
@ -476,10 +479,10 @@ flash_ic_table=[
FlashIcInfo('GD25Q80C', 1048576, 0x13, 0xc8, 0x40, 0x14, 0x0, 0x1, 0x1000, 0x20, 0x0, 0x4),
]
def flash_ic_table_lookup(jedec_id0, jedec_id1, size):
def flash_ic_table_lookup(jedec_id0: int, jedec_id1: int, size: int):
for i in flash_ic_table:
if i.jid0 == jedec_id0 and i.jid1 == jedec_id1 and i.size == size:
return i
return None

View file

@ -1,14 +1,14 @@
import atexit
import logging
from validitysensor.usb import usb
from validitysensor.tls import tls
from validitysensor.sensor import sensor, reboot, RebootException
from validitysensor.flash import read_tls_flash
from validitysensor.init_flash import init_flash
from validitysensor.upload_fwext import upload_fwext
from validitysensor.init_db import init_db
from validitysensor.init_flash import init_flash
from validitysensor.sensor import sensor, reboot, RebootException
from validitysensor.tls import tls
from validitysensor.upload_fwext import upload_fwext
from validitysensor.usb import usb
def close():
logging.debug('In atexit handler')
@ -24,16 +24,17 @@ def close():
finally:
usb.close()
def open_common():
init_flash()
usb.send_init()
tls.parseTlsFlash(read_tls_flash())
tls.parse_tls_flash(read_tls_flash())
tls.open()
upload_fwext()
sensor.open()
init_db()
# We must register atexit only after we opened usb device,
# We must register atexit only after we opened usb device,
# so that our atexit handler is called before pyusb's one and we can still talk to the device
#
# Don't attempt to autoreboot unless we finished initializing the sensor successfully.
@ -41,10 +42,12 @@ def open_common():
atexit.register(close)
logging.debug('atexit registered')
def open():
usb.open()
open_common()
def open_devpath(busnum, address):
def open_devpath(busnum: int, address: int):
usb.open_devpath(busnum, address)
open_common()

View file

@ -1,13 +1,14 @@
from struct import pack, unpack
import logging
from struct import pack, unpack
from .db import db
def machine_id_rec_value(b):
def machine_id_rec_value(b: str):
b = b.encode('utf-16le')
b = b + b'\0' * (0x94 - len(b))
return pack('<HH', 0x102, len(b)) + b # 0x102 = Machine ID/GUID?
return pack('<HH', 0x102, len(b)) + b # 0x102 = Machine ID/GUID?
# This function is unused. It simply describes the Windows driver behavior.
# TODO: make this GUID unique!
@ -24,15 +25,15 @@ def init_machine_guid(machine_guid='e7260876-58db-4d27-8c40-8d13110d6a71'):
if rc != machine_id_rec_value(machine_guid):
u0, l = unpack('<HH', rc[:4])
b=rc[4:4+l]
b=b.decode('utf-16le')
b = rc[4:4 + l]
b = b.decode('utf-16le')
raise Exception('Machine GUID does not match the DB flash ownership record (%s).' % b)
def init_db():
stg = db.get_user_storage(name='StgWindsor')
if stg == None:
if stg is None:
logging.info('Creating a new user storage object')
db.new_user_storate()
#init_machine_guid()
# init_machine_guid()

View file

@ -1,61 +1,64 @@
import os
from struct import pack, unpack
from binascii import unhexlify
import logging
from hashlib import sha256
import hmac
import logging
import os
import typing
from binascii import unhexlify
from hashlib import sha256
from struct import pack, unpack
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
from .blobs import reset_blob
from .flash import write_flash, erase_flash, call_cleanups, PartitionInfo, get_flash_info, FlashInfo
from .hw_tables import FlashIcInfo
from .sensor import reboot, RomInfo
from .tls import tls, hs_key, crt_hardcoded
from .usb import usb
from .flash import write_flash, erase_flash, call_cleanups, PartitionInfo, get_flash_info
from .sensor import reboot, RomInfo
from .util import assert_status, unhex
from .blobs import reset_blob
flash_layout_hardcoded=[
flash_layout_hardcoded = [
# id type access offset size
# lvl
PartitionInfo(1, 4, 7, 0x00001000, 0x00001000), # cert store
PartitionInfo(2, 1, 2, 0x00002000, 0x0003e000), # xpfwext
PartitionInfo(5, 5, 3, 0x00040000, 0x00008000), # ???
PartitionInfo(6, 6, 3, 0x00048000, 0x00008000), # calibration data
PartitionInfo(4, 3, 5, 0x00050000, 0x00080000), # template database
# lvl
PartitionInfo(1, 4, 7, 0x00001000, 0x00001000), # cert store
PartitionInfo(2, 1, 2, 0x00002000, 0x0003e000), # xpfwext
PartitionInfo(5, 5, 3, 0x00040000, 0x00008000), # ???
PartitionInfo(6, 6, 3, 0x00048000, 0x00008000), # calibration data
PartitionInfo(4, 3, 5, 0x00050000, 0x00080000), # template database
]
partition_signature=unhex('''
partition_signature = unhex('''
1db02a886b007e2b47263bb8fe30bd64a1f58bea7b25f1e1ba9ae09add7ecff36333f8198339cdd713f043633710a17bc7b3f418f1d8ff435a1bf47f065dffca
727109152217fce73bf2bf8e01a1641f6a24b0c492a6a3f10114057275846842b1c8b66bd6700738524d4471bca3315ba23bb832743220ad195b60558aa79a3e
deb2604834e2bb62e890b0ce405b3b8ef2fec2aab3e22bff23f89a58ff0dc015fece5d3ed3f5496ace879a92980aec9d85eb7e9df245eae03a41acfd4e7d1cb1
dbd0df42d534904de00b6389f68867646e9d7c3d0b1dffd74070b2d0f2049b9f1dc7b0c9651c59be3ea891674725e1f2f7a484a941615b80211105978369cf71
''')
crypto_backend=default_backend()
crypto_backend = default_backend()
def get_partition_signature():
if usb.usb_dev().idVendor == 0x138a:
if usb.usb_dev().idProduct == 0x0090:
return b''
return partition_signature
def with_hdr(id, buf):
def with_hdr(id: int, buf: bytes):
return pack('<HH', id, len(buf)) + buf
def encrypt_key(client_private, client_public):
x = unhexlify('%064x' % client_public.x)[::-1]
y = unhexlify('%064x' % client_public.y)[::-1]
d = unhexlify('%064x' % client_private)[::-1]
m = x+y+d
m = x + y + d
l = 16 - (len(m) % 16)
m = m + bytes([l])*l
m = m + bytes([l]) * l
iv = os.urandom(0x10)
cipher = Cipher(algorithms.AES(tls.psk_encryption_key), modes.CBC(iv), backend=crypto_backend)
@ -64,45 +67,48 @@ def encrypt_key(client_private, client_public):
sig = hmac.new(tls.psk_validation_key, c, sha256).digest()
return b'\x02' + c + sig
def make_cert(client_public):
msg=(pack('<LL', 0x17, 0x20) +
unhexlify('%064x' % client_public.x)[::-1] +
(b'\0'*0x24) +
unhexlify('%064x' % client_public.y)[::-1] +
(b'\0'*0x4c))
msg = (pack('<LL', 0x17, 0x20) + unhexlify('%064x' % client_public.x)[::-1] + (b'\0' * 0x24) +
unhexlify('%064x' % client_public.y)[::-1] + (b'\0' * 0x4c))
pk = ec.derive_private_key(hs_key(), ec.SECP256R1(), backend=crypto_backend)
s=pk.sign(msg, ec.ECDSA(hashes.SHA256()))
s=pack('<L', len(s)) + s
s = pk.sign(msg, ec.ECDSA(hashes.SHA256()))
s = pack('<L', len(s)) + s
msg = msg + s
msg += b'\0'*(444 - len(msg)) # FIXME not sure this math is right
msg += b'\0' * (444 - len(msg)) # FIXME not sure this math is right
return msg
def serialize_flash_params(ic):
def serialize_flash_params(ic: FlashIcInfo):
return pack('<LLxxBx', ic.size, ic.secror_size, ic.sector_erase_cmd)
def serialize_partition(p):
def serialize_partition(p: PartitionInfo):
b = pack('<BBHLL', p.id, p.type, p.access_lvl, p.offset, p.size)
b = b + b'\0'*4 + sha256(b).digest()
b = b + b'\0' * 4 + sha256(b).digest()
return b
def partition_flash(info, layout, client_public):
def partition_flash(info: FlashInfo, layout: typing.List[PartitionInfo], client_public):
logging.info('Detected Flash IC: %s, %d bytes' % (info.ic.name, info.ic.size))
cmd = unhex('4f 0000 0000')
cmd += with_hdr(0, serialize_flash_params(info.ic))
cmd += with_hdr(1, b''.join([serialize_partition(p) for p in layout]) + get_partition_signature())
cmd += with_hdr(0, serialize_flash_params(info.ic))
cmd += with_hdr(1,
b''.join([serialize_partition(p) for p in layout]) + get_partition_signature())
cmd += with_hdr(5, make_cert(client_public))
cmd += with_hdr(3, crt_hardcoded)
rsp = tls.cmd(cmd)
assert_status(rsp)
rsp = rsp[2:]
crt_len, rsp=rsp[:4], rsp[4:]
crt_len, rsp = rsp[:4], rsp[4:]
crt_len, = unpack('<L', crt_len)
tls.handle_cert(rsp[:crt_len])
rsp = rsp[crt_len:]
# ^ TODO - figure out what the rest of rsp means
def init_flash():
info = get_flash_info()
@ -125,13 +131,13 @@ def init_flash():
# ^ TODO: use the firmware version which to lookup pubkey for server cert validation
try:
rsp=usb.cmd(unhex('50'))
rsp = usb.cmd(unhex('50'))
assert_status(rsp)
finally:
call_cleanups()
rsp=rsp[2:]
l,=unpack('<L', rsp[:4])
rsp = rsp[2:]
l, = unpack('<L', rsp[:4])
if len(rsp) != l:
raise Exception('Length mismatch')
@ -153,8 +159,8 @@ def init_flash():
erase_flash(4)
# Persist certs and keys on cert partition.
write_flash(1, 0, tls.makeTlsFlash())
write_flash(1, 0, tls.make_tls_flash())
# Reboot.
# Reboot.
# The device will disconnect and our service will be started by udev as soon as it is connected again.
reboot()

View file

@ -1,83 +1,101 @@
import logging
import os.path
import typing
from binascii import hexlify, unhexlify
from enum import Enum
from hashlib import sha256
import os.path
import logging
from struct import pack, unpack
from time import sleep
from usb import core as usb_core
from .tls import tls
from .usb import usb, CancelledException
from . import timeslot as prg
from .blobs import reset_blob
from .db import db, SidIdentity
from .flash import write_enable, call_cleanups, read_flash, erase_flash, write_flash_all, read_flash_all
from time import sleep
from struct import pack, unpack
from .table_types import SensorTypeInfo, SensorCaptureProg
from binascii import hexlify, unhexlify
from .util import assert_status, unhex
from .hw_tables import dev_info_lookup
from .blobs import reset_blob
from . import timeslot as prg
from .table_types import SensorTypeInfo, SensorCaptureProg
from .tls import tls
from .usb import usb, CancelledException
from .util import assert_status, unhex
# TODO: this should be specific to an individual device (system may have more than one sensor)
calib_data_path='/usr/share/python-validity/calib-data.bin'
calib_data_path = '/usr/share/python-validity/calib-data.bin'
line_update_type1_devices = [
0xB5, 0x885, 0xB3, 0x143B, 0x1055, 0xE1, 0x8B1, 0xEA, 0xE4, 0xED, 0x1825, 0x1FF5, 0x199
]
line_update_type1_devices = [ 0xB5, 0x885, 0xB3, 0x143B, 0x1055, 0xE1, 0x8B1, 0xEA, 0xE4, 0xED, 0x1825, 0x1FF5, 0x199 ]
# TODO use more sophisticated glow patters in different cases
def glow_start_scan():
cmd=unhexlify('3920bf0200ffff0000019900200000000099990000000000000000000000000020000000000000000000000000ffff000000990020000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000')
cmd = unhexlify(
'3920bf0200ffff0000019900200000000099990000000000000000000000000020000000000000000000000000ffff000000990020000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
)
assert_status(tls.app(cmd))
def glow_end_scan():
cmd=unhexlify('39f4010000f401000001ff002000000000ffff0000000000000000000000000020000000000000000000000000f401000000ff0020000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000')
cmd = unhexlify(
'39f4010000f401000001ff002000000000ffff0000000000000000000000000020000000000000000000000000f401000000ff0020000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
)
assert_status(tls.app(cmd))
def get_prg_status():
return tls.app(unhexlify('5100000000'))
def wait_till_finished():
while True:
status = get_prg_status()
if status[0] in [0, 7]:
break
sleep(0.2)
def get_prg_status2():
return tls.app(unhexlify('5100200000'))
def read_hw_reg32(addr):
rsp=tls.cmd(pack('<BLB', 7, addr, 4))
def read_hw_reg32(addr: int):
rsp = tls.cmd(pack('<BLB', 7, addr, 4))
assert_status(rsp)
rsp, = unpack('<L', rsp[2:])
return rsp
def write_hw_reg32(addr, val):
rsp=tls.cmd(pack('<BLLB', 8, addr, val, 4))
def write_hw_reg32(addr: int, val: int):
rsp = tls.cmd(pack('<BLLB', 8, addr, val, 4))
assert_status(rsp)
class RebootException(Exception):
pass
def reboot():
assert_status(tls.cmd(unhex('050200')))
raise RebootException()
def factory_reset():
assert_status(usb.cmd(reset_blob))
assert_status(usb.cmd(b'\x10' + b'\0'*0x61))
assert_status(usb.cmd(b'\x10' + b'\0' * 0x61))
reboot()
class RomInfo():
class RomInfo:
@classmethod
def get(cls):
rsp=tls.cmd(b'\x01')
rsp = tls.cmd(b'\x01')
assert_status(rsp)
rsp=rsp[2:]
rsp = rsp[2:]
return cls(*unpack('<LLBBxBxxxB', rsp[0:0x10]))
def __init__(self, timestamp, build, major, minor, product, u1):
def __init__(self, timestamp: int, build: int, major: int, minor: int, product: int, u1: int):
self.timestamp, self.build, self.major, self.minor, self.product, self.u1 = timestamp, build, major, minor, product, u1
def __repr__(self):
@ -86,9 +104,9 @@ class RomInfo():
def identify_sensor():
rsp=tls.cmd(b'\x75')
rsp = tls.cmd(b'\x75')
assert_status(rsp)
rsp=rsp[2:]
rsp = rsp[2:]
zeroes, minor, major = unpack('<LHH', rsp)
@ -97,6 +115,7 @@ def identify_sensor():
return dev_info_lookup(major, minor)
# <<< 0000 880d 0000 07000000
# 08000000 9400 0e00 0300 0080 07000000 7e7f807f808080808080808080808080808080808080818081808180818080808080818081808080818081808180
# a4000000 0800 0e00 0200 0000 00000000 0d007100
@ -105,15 +124,15 @@ def identify_sensor():
# d0000000 9400 0e00 0700 0080 07000000 2b23203c2d182e1e30182e1c321d341d341e321c301e1e241e201f201d1c321a301e1c211e21341f1e202024201f
# 6c010000 1400 0e00 0f00 0080 05550007 7701002805720000080100020811e107
# 88010000 0c00 0e00 1200 0080 07000000 7002 7800 7002 7800
def get_factory_bits(tag):
rsp=tls.cmd(pack('<B H HL', 0x6f, tag, 0, 0))
def get_factory_bits(tag: int):
rsp = tls.cmd(pack('<B H HL', 0x6f, tag, 0, 0))
assert_status(rsp)
rsp=rsp[2:]
rsp = rsp[2:]
wtf, entries = unpack('<LL', rsp[:8])
rsp = rsp[8:]
rc={}
rc = {}
for x in range(0, entries):
hdr, rsp = rsp[:12], rsp[12:]
ptr, l, tag, subtag, flags = unpack('<LHHHH', hdr)
@ -121,7 +140,7 @@ def get_factory_bits(tag):
if len(value) != l:
raise Exception('Truncated response %d != %d' % (len(value), l))
rc[subtag] = value
rsp = rsp[l:]
@ -132,95 +151,106 @@ def get_factory_bits(tag):
def bitpack(b):
l=len(b)
m=min(b)
x=max(b)
l = len(b)
m = min(b)
x = max(b)
# maximum delta which we must encode
x-=m
x -= m
# count useful bits
u=0
u = 0
while x > 0:
x>>=1
u+=1
x >>= 1
u += 1
# convert to array of binary strings with each element exactly u characters long
b=[bin(i-m+0x100)[-u:] for i in b]
b = [bin(i - m + 0x100)[-u:] for i in b]
# combine chunks into one long text number with u*l binary digits and parse it as integer
b=int(''.join(b[::-1]), 2)
b = int(''.join(b[::-1]), 2)
# convert back to bytes
b=b.to_bytes((u*l+7)//8, 'little')
b = b.to_bytes((u * l + 7) // 8, 'little')
return (u, m, b)
return u, m, b
class Line():
mask=None
flags=None
data=None
v0=0
v1=0
v2=0
def clip(x):
class Line:
def __init__(self):
self.mask: typing.Optional[int] = None
self.flags: typing.Optional[int] = None
self.data: typing.Optional[bytes] = None
self.v0 = 0
self.v1 = 0
self.v2 = 0
def clip(x: int):
if x < -128:
x=-128
x = -128
if x > 127:
x=127
x = 127
return x & 0xff
def scale(x):
def scale(x: int):
x -= 0x80
x = int(x*10/0x22) # TODO: scaling factor depends on a device
x = int(x * 10 / 0x22) # TODO: scaling factor depends on a device
return clip(x)
def add(l, r):
def add(l: int, r: int):
# Make signed
l, r = unpack('bb', pack('BB', l, r))
return clip(l+r)
return clip(l + r)
def chunks(b: bytes, l: int):
return [b[i:i + l] for i in range(0, len(b), l)]
def chunks(b, l):
return [b[i:i+l] for i in range(0, len(b), l)]
class CaptureMode(Enum):
CALIBRATE=1
IDENTIFY=2
ENROLL=3
CALIBRATE = 1
IDENTIFY = 2
ENROLL = 3
class Sensor():
calib_data=b''
class Sensor:
calib_data = b''
def open(self):
self.device_info = identify_sensor()
logging.info('Opening sensor: %s' % self.device_info.name)
self.type_info = SensorTypeInfo.get_by_type(self.device_info.type)
if self.device_info.type == 0x199:
self.key_calibration_line = 0x38 # (lines_per_calibration_data/2), but hardcoded for sensor type 0x199
self.calibration_frames = 3 # TODO: workout where it's really comming from
self.calibration_iterations = 3 # hardcoded for type
self.key_calibration_line = 0x38 # (lines_per_calibration_data/2), but hardcoded for sensor type 0x199
self.calibration_frames = 3 # TODO: workout where it's really comming from
self.calibration_iterations = 3 # hardcoded for type
elif self.device_info.type == 0xdb:
self.key_calibration_line = 0x48 # TODO 48 is just a guess -- find it
self.calibration_frames = 6 # TODO: workout where it's really comming from
self.key_calibration_line = 0x48 # TODO 48 is just a guess -- find it
self.calibration_frames = 6 # TODO: workout where it's really comming from
self.calibration_iterations = 0
else:
raise Exception('Device %s is not supported (sensor type 0x%x)' % (self.device_info.name, self.device_info.type))
raise Exception('Device %s is not supported (sensor type 0x%x)' %
(self.device_info.name, self.device_info.type))
self.rom_info = RomInfo.get()
self.hardcoded_prog = SensorCaptureProg.get(self.rom_info, self.device_info.type, 0x18, 0x19) # TODO: find where 0x18, 0x19 coming from
self.hardcoded_prog = SensorCaptureProg.get(self.rom_info, self.device_info.type, 0x18,
0x19) # TODO: find where 0x18, 0x19 coming from
if self.hardcoded_prog is None:
raise Exception('Can\'t find initial capture program for rom %s and sensor type %x' % (repr(self.rom_info), self.device_info.type))
raise Exception('Can\'t find initial capture program for rom %s and sensor type %x' %
(repr(self.rom_info), self.device_info.type))
# Look for a "2D" chunk. It must have a 32 bit integer which represent the number of lines per frame
lines_2d = [unpack('<L', v)[0] for [k, v] in prg.split_chunks(self.hardcoded_prog) if k == 0x2f][0]
self.lines_per_frame = lines_2d*self.type_info.repeat_multiplier
lines_2d = [
unpack('<L', v)[0] for [k, v] in prg.split_chunks(self.hardcoded_prog) if k == 0x2f
][0]
self.lines_per_frame = lines_2d * self.type_info.repeat_multiplier
self.bytes_per_line = self.type_info.bytes_per_line
factory_bits = get_factory_bits(0x0e00)
@ -235,37 +265,37 @@ class Sensor():
with open(calib_data_path, 'wb') as f:
f.write(self.calib_data)
# This is the exact logic from the DLL.
# This is the exact logic from the DLL.
# If it looks broken that was probably intended.
def patch_timeslot_table(self, b, inc_address, mult):
b=bytearray(b)
i=0
while i+3 < len(b):
def patch_timeslot_table(self, b: bytes, inc_address: bool, mult: int):
b = bytearray(b)
i = 0
while i + 3 < len(b):
if b[i] & 0xf8 == 0x10:
if b[i+2] > 1:
b[i+2] *= mult
if b[i + 2] > 1:
b[i + 2] *= mult
if inc_address:
b[i+1] += 1
i+=3
b[i + 1] += 1
i += 3
continue
if b[i] == 0:
i+=1
i += 1
continue
if b[i] == 7:
i+=2
i += 2
continue
break
return bytes(b)
def patch_timeslot_again(self, b):
b=bytearray(b)
def patch_timeslot_again(self, b: bytes):
b = bytearray(b)
pc = 0
match=None
match = None
# Look for the last Call in the script
while pc < len(b):
opcode, l, *operands = prg.decode_insn(b[pc:])
@ -276,7 +306,7 @@ class Sensor():
# Call
if opcode == 11:
match = operands[1] # destination address
match = operands[1] # destination address
pc += l
@ -303,88 +333,93 @@ class Sensor():
return bytes(b)
# Hack the value to be taken from the factory calibration table right in the middle of a sensor
b[match+1] = self.factory_calibration_values[self.key_calibration_line]
b[match + 1] = self.factory_calibration_values[self.key_calibration_line]
return bytes(b)
def average(self, raw_calib_data):
def average(self, raw_calib_data: bytes):
frame_size = self.lines_per_frame * self.bytes_per_line
interleave_lines = self.lines_per_frame // self.type_info.lines_per_calibration_data # 2, TODO: algo is quite different when it is 1
interleave_lines = self.lines_per_frame // self.type_info.lines_per_calibration_data # 2, TODO: algo is quite different when it is 1
input_frames = self.calibration_frames
if interleave_lines > 1:
if input_frames > 1:
# skip the first frame
input_frames -= 1
base_address = frame_size
frame=raw_calib_data[base_address:base_address+frame_size]
frame = raw_calib_data[base_address:base_address + frame_size]
# split into groups of lines
frame=chunks(frame, interleave_lines*self.bytes_per_line)
frame = chunks(frame, interleave_lines * self.bytes_per_line)
# split group of lines into lines
frame=[chunks(f, self.bytes_per_line) for f in frame]
frame = [chunks(f, self.bytes_per_line) for f in frame]
# calculate averages across interleaved lines
frame=[bytes([sum(i)//len(f) for i in zip(*f)]) for f in frame]
frame=b''.join(frame)
frame = [bytes([sum(i) // len(f) for i in zip(*f)]) for f in frame]
frame = b''.join(frame)
else:
if input_frames > 1:
# skip the first frame
input_frames -= 2
base_address = frame_size*2
base_address = frame_size * 2
frames=raw_calib_data[base_address:base_address+frame_size*input_frames]
frames=chunks(frames, frame_size)
frame=[int(sum(i)/input_frames) for i in zip(*frames)]
frame=bytes(frame)
frames = raw_calib_data[base_address:base_address + frame_size * input_frames]
frames = chunks(frames, frame_size)
frame = [int(sum(i) / input_frames) for i in zip(*frames)]
frame = bytes(frame)
return frame
def process_calibration_results(self, cooked_data):
frame=chunks(cooked_data, self.bytes_per_line)
def process_calibration_results(self, cooked_data: bytes):
frame = chunks(cooked_data, self.bytes_per_line)
# apply scaling factors
frame=[f[:8] + bytes(map(scale, f[8:])) for f in frame]
frame=b''.join(frame)
frame = [f[:8] + bytes(map(scale, f[8:])) for f in frame]
frame = b''.join(frame)
if len(self.calib_data) > 0:
# Not the first calibration run. Combine results
# split previous calibration info into lines
lll=chunks(self.calib_data, self.bytes_per_line)
lll = chunks(self.calib_data, self.bytes_per_line)
# split next calibration info into lines
rrr=chunks(frame, self.bytes_per_line)
rrr = chunks(frame, self.bytes_per_line)
# Don't touch the first 8 bytes of each line, add everything else as signed characters, clipping the values
combined=[ll[:8] + bytes([add(l, r) for l, r in zip(ll[8:],rr[8:])]) for ll, rr in zip(lll, rrr)]
combined = [
ll[:8] + bytes([add(l, r) for l, r in zip(ll[8:], rr[8:])])
for ll, rr in zip(lll, rrr)
]
self.calib_data = bytes(b''.join(combined))
else:
self.calib_data = frame
def get_key_line(self):
if len(self.calib_data) > 0:
bytes_per_calibration_line=len(self.calib_data) // self.type_info.lines_per_calibration_data
key_line_offset=8+bytes_per_calibration_line*self.key_calibration_line
key_line=self.calib_data[key_line_offset:key_line_offset+self.type_info.line_width]
key_line=bytes([i-1 if i == 5 else i for i in key_line])
bytes_per_calibration_line = len(
self.calib_data) // self.type_info.lines_per_calibration_data
key_line_offset = 8 + bytes_per_calibration_line * self.key_calibration_line
key_line = self.calib_data[key_line_offset:key_line_offset + self.type_info.line_width]
key_line = bytes([i - 1 if i == 5 else i for i in key_line])
else:
key_line=b'\0'*self.type_info.line_width
key_line = b'\0' * self.type_info.line_width
return key_line
def line_update_type_1(self, mode, chunks):
def line_update_type_1(self, mode: CaptureMode,
chunks: typing.List[typing.List[typing.Union[int, bytes]]]):
for c in chunks:
# Timeslot Table 2D
if c[0] == 0x34:
# TODO: figure out when to use address increment
tst = self.patch_timeslot_table(c[1], True, self.type_info.repeat_multiplier)
if mode != CaptureMode.CALIBRATE:
tst=self.patch_timeslot_again(tst)
tst = self.patch_timeslot_again(tst)
c[1] = self.get_key_line() + tst[self.type_info.line_width:]
#---------------- Reply Configuration ---------------
# ---------------- Reply Configuration ---------------
chunks += [[0x17, b'']]
if mode == CaptureMode.IDENTIFY:
@ -392,53 +427,68 @@ class Sensor():
# It seems to be only used for identification and it looks almost identical to Finger Detect (0x26)
# Seems to be the same all the time for a given sensor and mostly hardcoded
# TODO: analyse construct_wtf_4e @0000000180090BF0
chunks += [[0x4e, unhexlify('fbb20f0000000f00300000008700020067000a00018000000a0200000b1900008813b80b01091000')]]
chunks += [[
0x4e,
unhexlify(
'fbb20f0000000f00300000008700020067000a00018000000a0200000b1900008813b80b01091000'
)
]]
# Image Reconstruction.
# TODO: analyse add_image_reconstruction_cmd_02_buff_list_item @000000018008EA70
chunks += [[0x2e, unhexlify('0200180002000000700070004d010000a0008c003c32321e3c0a0202')]]
chunks += [[
0x2e, unhexlify('0200180002000000700070004d010000a0008c003c32321e3c0a0202')
]]
elif mode == CaptureMode.ENROLL:
chunks += [[0x26, unhexlify('fbb20f0000000f00300000008700020067000a00018000000a0200000b19000050c360ea01091000')]]
chunks += [[
0x26,
unhexlify(
'fbb20f0000000f00300000008700020067000a00018000000a0200000b19000050c360ea01091000'
)
]]
# Image Reconstruction. There is only one byte difference with the "identify" version. (same is true for 0097)
chunks += [[0x2e, unhexlify('0200180023000000700070004d010000a0008c003c32321e3c0a0202')]]
chunks += [[
0x2e, unhexlify('0200180023000000700070004d010000a0008c003c32321e3c0a0202')
]]
#---------------- Interleave ---------------
# ---------------- Interleave ---------------
chunks += [[0x44, pack('<L', 1)]]
lines=[]
cnt=2 # TODO figure out why 2
lines: typing.List[Line] = []
cnt = 2 # TODO figure out why 2
l=Line()
l = Line()
lines += [l]
l.mask = 0xff
# Find 2nd "Enable Rx" instruction
pc, _ = prg.find_nth_insn(tst, 6, 2)
pc, _ = prg.find_nth_insn(tst, 6, 2)
l.flags = (pc + 1) | (cnt << 0x14) | 0x7000000
l.data = self.type_info.calibration_blob
l.v0 = 0xf
cnt += 1
l=Line()
l = Line()
lines += [l]
l.mask = 0xff
# Find 1st "Write Register" instruction to the 0x8000203C port
pc, _ = prg.find_nth_regwrite(tst, 0x8000203C, 1)
pc, _ = prg.find_nth_regwrite(tst, 0x8000203C, 1)
l.flags = (pc + 1) | (cnt << 0x14) | 0x7000000
l.v0, l.v1, l.data = bitpack(self.factory_calibration_values)
l.v0 = (l.v0-1) | 8
l.v0 = (l.v0 - 1) | 8
cnt += 1
if len(self.calib_data) > 0:
bytes_per_calibration_line=len(self.calib_data) // self.type_info.lines_per_calibration_data
bytes_per_calibration_line = len(
self.calib_data) // self.type_info.lines_per_calibration_data
for i in range(0, 112, 4):
l=Line()
l = Line()
lines += [l]
l.mask=0xffffffff
l.flags=i | (0x85 << 24)
l.data=b''
l.mask = 0xffffffff
l.flags = i | (0x85 << 24)
l.data = b''
for j in range(0, 112):
p=8+j*bytes_per_calibration_line+i
l.data += self.calib_data[p:p+4]
p = 8 + j * bytes_per_calibration_line + i
l.data += self.calib_data[p:p + 4]
# Align to dwords, as the sensor demands it
for l in lines:
@ -446,25 +496,28 @@ class Sensor():
if pad > 0:
l.data += b'\0' * (4 - pad)
#---------------- Line Update ---------------
# ---------------- Line Update ---------------
line_update = pack('<L', len(lines))
line_update += b''.join([pack('<LL', l.mask, l.flags) for l in lines])
line_update += b''.join([l.data for l in lines if ((l.flags & 0x00f00000) >> 0x14) <= 1])
chunks += [[0x30, line_update]]
#---------------- Line Update Transform ---------------
update_transform = b''.join([pack('<BBH', l.v0, l.v1, l.v2) + l.data for l in lines if ((l.flags & 0x00f00000) >> 0x14) > 1])
# ---------------- Line Update Transform ---------------
update_transform = b''.join([
pack('<BBH', l.v0, l.v1, l.v2) + l.data for l in lines
if ((l.flags & 0x00f00000) >> 0x14) > 1
])
chunks += [[0x43, update_transform]]
return chunks
def line_update_type_2(self, mode, chunks):
def line_update_type_2(self, mode: CaptureMode,
chunks: typing.List[typing.List[typing.Union[int, bytes]]]):
for c in chunks:
# patch the 2D params.
# patch the 2D params.
# The following is only needed on some rom versions below 6.5 as reported by cmd_01
#if c[0] == 0x2f:
# if c[0] == 0x2f:
# c[1] = pack('<L', unpack('<L', c[1])[0]*mult)
# Timeslot Table 2D
@ -472,10 +525,10 @@ class Sensor():
# TODO: figure out when to use address increment
tst = self.patch_timeslot_table(c[1], True, self.type_info.repeat_multiplier)
if mode != CaptureMode.CALIBRATE:
tst=self.patch_timeslot_again(tst)
tst = self.patch_timeslot_again(tst)
c[1] = tst
#---------------- Reply Configuration ---------------
# ---------------- Reply Configuration ---------------
chunks += [[0x17, b'']]
if mode == CaptureMode.IDENTIFY:
@ -483,38 +536,52 @@ class Sensor():
# It seems to be only used for identification and it looks almost identical to Finger Detect (0x26)
# Seems to be the same all the time for a given sensor and mostly hardcoded
# TODO: analyse construct_wtf_4e @0000000180090BF0
chunks += [[0x4e, unhexlify('fbb20f0000000f00300000006001020040010a00018000000a0200000b1900008813b80b01091000')]]
chunks += [[
0x4e,
unhexlify(
'fbb20f0000000f00300000006001020040010a00018000000a0200000b1900008813b80b01091000'
)
]]
# Image Reconstruction.
# TODO: analyse add_image_reconstruction_cmd_02_buff_list_item @000000018008EA70
chunks += [[0x2e, unhexlify('0200180002000000900090004d01000090017c013c323232640a0201')]]
chunks += [[
0x2e, unhexlify('0200180002000000900090004d01000090017c013c323232640a0201')
]]
elif mode == CaptureMode.ENROLL:
chunks += [[0x26, unhexlify('fbb20f0000000f00300000006001020040010a00018000000a0200000b19000050c360ea01091000')]]
chunks += [[
0x26,
unhexlify(
'fbb20f0000000f00300000006001020040010a00018000000a0200000b19000050c360ea01091000'
)
]]
# Image Reconstruction. There is only one byte difference with the "identify" version. (same is true for 0097)
chunks += [[0x2e, unhexlify('0200180023000000900090004d01000090017c013c323232640a0201')]]
chunks += [[
0x2e, unhexlify('0200180023000000900090004d01000090017c013c323232640a0201')
]]
lines = []
l=Line()
l = Line()
lines += [l]
l.mask = 0xff
# Find 2nd "Enable Rx" instruction
pc, _ = prg.find_nth_insn(tst, 6, 2)
pc, _ = prg.find_nth_insn(tst, 6, 2)
l.flags = (pc + 1) | 0x3000000
l.data = self.type_info.calibration_blob
l=Line()
l = Line()
lines += [l]
l.mask = 0xff
# Find 1st "Write Register" instruction to the 0x8000203C port
pc, _ = prg.find_nth_regwrite(tst, 0x800020fc, 1)
pc, _ = prg.find_nth_regwrite(tst, 0x800020fc, 1)
l.flags = (pc + 1) | 0x3000000
l.data = self.factory_calib_data
l=Line()
l = Line()
lines += [l]
l.mask = 0xff
# Find 1st "Write Register" instruction to the 0x8000203C port
pc, _ = prg.find_nth_regwrite(tst, 0x8000203c, 1)
pc, _ = prg.find_nth_regwrite(tst, 0x8000203c, 1)
l.flags = (pc + 1) | 0x3000000
l.data = self.factory_calibration_values
@ -524,8 +591,7 @@ class Sensor():
if pad > 0:
l.data += b'\0' * (4 - pad)
#---------------- Line Update ---------------
# ---------------- Line Update ---------------
line_update = pack('<L', len(lines))
line_update += b''.join([pack('<LL', l.mask, l.flags) for l in lines])
@ -534,25 +600,25 @@ class Sensor():
return chunks
def build_cmd_02(self, mode):
chunks=list(prg.split_chunks(self.hardcoded_prog))
def build_cmd_02(self, mode: CaptureMode):
chunks = list(prg.split_chunks(self.hardcoded_prog))
if self.rom_info.product != 0x30:
raise Exception('Not implemented')
if self.device_info.type in line_update_type1_devices:
chunks=self.line_update_type_1(mode, chunks)
chunks = self.line_update_type_1(mode, chunks)
else:
chunks=self.line_update_type_2(mode, chunks)
chunks = self.line_update_type_2(mode, chunks)
if mode == CaptureMode.CALIBRATE:
req_lines = self.calibration_frames*self.lines_per_frame+1 # TODO: figure out how this is actually calculated
req_lines = self.calibration_frames * self.lines_per_frame + 1 # TODO: figure out how this is actually calculated
else:
req_lines = 0
return pack('<BHH', 2, self.bytes_per_line, req_lines) + prg.merge_chunks(chunks)
def persist_clean_slate(self, clean_slate):
def persist_clean_slate(self, clean_slate: bytes):
start = read_flash(6, 0, 0x44)
if start != b'\xff' * 0x44:
@ -574,8 +640,8 @@ class Sensor():
return False
hs, zeroes = start[0:0x20], start[0x20:0x40]
if zeroes != b'\0'*0x20:
if zeroes != b'\0' * 0x20:
logging.warning('Unexpected contents in calibration flash partition')
return False
@ -586,7 +652,6 @@ class Sensor():
return True
def calibrate(self):
if os.path.isfile(calib_data_path):
with open(calib_data_path, 'rb') as f:
@ -615,8 +680,9 @@ class Sensor():
clean_slate = self.average(usb.read_82())
clean_slate = pack('<H', len(clean_slate)) + clean_slate
clean_slate = clean_slate + pack('<H', 0) # TODO: still don't know what this zero is for
clean_slate = pack('<H', len(clean_slate)) + sha256(clean_slate).digest() + b'\0'*0x20 + clean_slate
clean_slate = clean_slate + pack('<H', 0) # TODO: still don't know what this zero is for
clean_slate = pack(
'<H', len(clean_slate)) + sha256(clean_slate).digest() + b'\0' * 0x20 + clean_slate
clean_slate = pack('<H', 0x5002) + clean_slate
self.persist_clean_slate(clean_slate)
@ -625,7 +691,7 @@ class Sensor():
def cancel(self):
usb.cancel = True
def capture(self, mode):
def capture(self, mode: CaptureMode) -> typing.Tuple[int, int, int, int]:
try:
assert_status(tls.app(self.build_cmd_02(mode)))
@ -638,8 +704,8 @@ class Sensor():
while True:
b = usb.wait_int()
if b[0] == 2:
break;
break
# wait capture complete
while True:
b = usb.wait_int()
@ -648,12 +714,12 @@ class Sensor():
if b[2] & 4:
break
res = get_prg_status2()
assert_status(res)
res = res[2:]
l, res = res[:4], res[4:]
l, = unpack('<L', l)
@ -665,14 +731,13 @@ class Sensor():
if error != 0:
raise Exception('Scanning problem: %04x' % error)
return (x, y, w1, w2)
return x, y, w1, w2
finally:
tls.app(unhexlify('04')) # capture stop if still running, cleanup
tls.app(unhexlify('04')) # capture stop if still running, cleanup
def enrollment_update_start(self, key):
rsp=tls.app(pack('<BLL', 0x68, key, 0))
def enrollment_update_start(self, key: int) -> int:
rsp = tls.app(pack('<BLL', 0x68, key, 0))
assert_status(rsp)
new_key, = unpack('<L', rsp[2:])
@ -687,19 +752,19 @@ class Sensor():
assert_status(tls.app(pack('<BL', 0x69, 0)))
# Generates interrupt
def enrollment_update(self, prev):
def enrollment_update(self, prev: bytes):
write_enable()
try:
rsp=tls.app(b'\x6b' + prev)
rsp = tls.app(b'\x6b' + prev)
assert_status(rsp)
finally:
call_cleanups()
return rsp[2:]
def append_new_image(self, prev):
def append_new_image(self, prev: bytes):
self.enrollment_update(prev)
usb.wait_int()
res = self.enrollment_update(prev)
@ -709,27 +774,26 @@ class Sensor():
if l != len(res):
raise Exception('Response size does not match %d != %d', l, len(res))
magic_len = 0x38 # hardcoded in the DLL
magic_len = 0x38 # hardcoded in the DLL
template = header = tid = None
while len(res) > 0:
tag, l = unpack('<HH', res[:4])
if tag == 0:
template = res[:magic_len+l]
template = res[:magic_len + l]
elif tag == 1:
header = res[magic_len:magic_len+l]
header = res[magic_len:magic_len + l]
elif tag == 3:
tid = res[magic_len:magic_len+l]
tid = res[magic_len:magic_len + l]
else:
logging.warning('Ignoring unknown tag %x' % tag)
res=res[magic_len+l:]
return (header, template, tid)
res = res[magic_len + l:]
def make_finger_data(self, subtype, template, tid):
return header, template, tid
def make_finger_data(self, subtype: int, template: bytes, tid: bytes):
template = pack('<HH', 1, len(template)) + template
tid = pack('<HH', 2, len(tid)) + tid
@ -743,15 +807,15 @@ class Sensor():
# TODO: Better typing information needed.
def enroll(self, identity: SidIdentity, subtype: int,
update_cb: typing.Callable[[typing.Any, typing.Optional[Exception]], None]):
def do_create_finger(final_template, tid):
def do_create_finger(final_template: bytes, tid: bytes):
tinfo = self.make_finger_data(subtype, final_template, tid)
usr=db.lookup_user(identity)
if usr == None:
usr = db.lookup_user(identity)
if usr is None:
usr = db.new_user(identity)
else:
usr = usr.dbid
recid = db.new_finger(usr, tinfo)
usb.wait_int()
@ -759,8 +823,8 @@ class Sensor():
return recid
key=0
template=b''
key = 0
template = b''
self.create_enrollment()
while True:
try:
@ -785,11 +849,11 @@ class Sensor():
finally:
self.enrollment_update_end()
self.enrollment_update_end() # done twice for some reason
self.enrollment_update_end() # done twice for some reason
return do_create_finger(template, tid)
def parse_dict(self, x):
rc={}
def parse_dict(self, x: bytes):
rc = {}
while len(x) > 0:
(t, l), x = unpack('<HH', x[:4]), x[4:]
@ -799,10 +863,10 @@ class Sensor():
def match_finger(self) -> typing.Tuple[int, int, bytes]:
try:
stg_id=0 # match against any storage
usr_id=0 # match against any user
cmd=pack('<BBBHHHHH', 0x5e, 2, 0xff, stg_id, usr_id, 1, 0,0)
rsp=tls.app(cmd)
stg_id = 0 # match against any storage
usr_id = 0 # match against any user
cmd = pack('<BBBHHHHH', 0x5e, 2, 0xff, stg_id, usr_id, 1, 0, 0)
rsp = tls.app(cmd)
assert_status(rsp)
b = usb.wait_int()
@ -814,23 +878,22 @@ class Sensor():
assert_status(rsp)
rsp = rsp[2:]
(l,), rsp = unpack('<H', rsp[:2]), rsp[2:]
(l, ), rsp = unpack('<H', rsp[:2]), rsp[2:]
if l != len(rsp):
raise Exception('Response size does not match')
rsp=self.parse_dict(rsp)
rsp = self.parse_dict(rsp)
usrid, subtype, hsh = rsp[1], rsp[3], rsp[4]
usrid, = unpack('<L', usrid)
subtype, = unpack('<H', subtype)
return (usrid, subtype, hsh)
return usrid, subtype, hsh
finally:
# cleanup, ignore any errors
tls.app(unhexlify('6200000000'))
def identify(self, update_cb):
def identify(self, update_cb: typing.Callable[[Exception], None]):
while True:
try:
glow_start_scan()
@ -848,17 +911,17 @@ class Sensor():
return self.match_finger()
def get_finger_blobs(self, usrid, subtype):
def get_finger_blobs(self, usrid: int, subtype: int):
usr = db.get_user(usrid)
fingerids = [f['dbid'] for f in usr.fingers if f['subtype'] == subtype]
if len(fingerids) != 1:
raise Exception('Unexpected matching finger count')
finger_record = db.get_record_children(fingerids[0])
ids=[r['dbid'] for r in finger_record.children if r['type'] == 8]
ids = [r['dbid'] for r in finger_record.children if r['type'] == 8]
return [db.get_record_value(id).value for id in ids]
sensor = Sensor()
sensor = Sensor()

View file

@ -1,15 +1,15 @@
from struct import unpack, pack
import typing
from struct import unpack, pack
class SidIdentity():
class SidIdentity:
def __init__(self, revision: int, auth: int, subauth: typing.Sequence[int]):
self.revision = revision
self.auth = auth
self.subauth = subauth
def to_bytes(self):
b=pack('>BBHL', self.revision, len(self.subauth), self.auth >> 32, self.auth & 0xffffffff)
b = pack('>BBHL', self.revision, len(self.subauth), self.auth >> 32, self.auth & 0xffffffff)
for i in self.subauth:
b += pack('<L', i)
@ -18,6 +18,7 @@ class SidIdentity():
def __repr__(self):
return 'S-%d-%d-%s' % (self.revision, self.auth, '-'.join(map(str, self.subauth)))
def sid_from_bytes(b: bytes):
revision = b[0]
subcnt = b[1]
@ -26,11 +27,12 @@ def sid_from_bytes(b: bytes):
for i in b[2:8]:
auth <<= 8
auth |= i
subauth=unpack('<%dL' % subcnt, b[8:])
subauth = unpack('<%dL' % subcnt, b[8:])
return SidIdentity(revision, auth, subauth)
def sid_from_string(s: str):
parts = s.split('-')

View file

@ -1,28 +1,33 @@
import typing
from binascii import hexlify, unhexlify
class SensorTypeInfo:
table=[]
table: typing.List["SensorTypeInfo"] = []
@classmethod
def get_by_type(cls, sensor_type):
def get_by_type(cls, sensor_type: int) -> typing.Optional["SensorTypeInfo"]:
# noinspection PyUnresolvedReferences
from . import generated_tables
for i in cls.table:
if i.sensor_type == sensor_type:
return i
def __init__(self, sensor_type, bytes_per_line, repeat_multiplier, lines_per_calibration_data, line_width, calibration_blob):
self.sensor_type=sensor_type
self.repeat_multiplier=repeat_multiplier
self.lines_per_calibration_data=lines_per_calibration_data
self.line_width=line_width
self.bytes_per_line=bytes_per_line
self.calibration_blob=unhexlify(calibration_blob)
def __init__(self, sensor_type: int, bytes_per_line: int, repeat_multiplier: int,
lines_per_calibration_data: int, line_width: int, calibration_blob: str):
self.sensor_type = sensor_type
self.repeat_multiplier = repeat_multiplier
self.lines_per_calibration_data = lines_per_calibration_data
self.line_width = line_width
self.bytes_per_line = bytes_per_line
self.calibration_blob = unhexlify(calibration_blob)
def __repr__(self):
calibration_blob=hexlify(self.calibration_blob).decode()
calibration_blob = hexlify(self.calibration_blob).decode()
return 'SensorTypeInfo(sensor_type=0x%04x, bytes_per_line=0x%x, repeat_multiplier=%d, lines_per_calibration_data=%d, line_width=%d, calibration_blob=%s)' % (
self.sensor_type, self.bytes_per_line, self.repeat_multiplier, self.lines_per_calibration_data, self.line_width, repr(calibration_blob))
self.sensor_type, self.bytes_per_line, self.repeat_multiplier,
self.lines_per_calibration_data, self.line_width, repr(calibration_blob))
def fuzzy(expected, actual):
if expected == actual:
@ -32,6 +37,7 @@ def fuzzy(expected, actual):
else:
return 0
def metric(i, rominfo):
metric = 0
metric |= fuzzy(i.major, rominfo.major)
@ -42,13 +48,15 @@ def metric(i, rominfo):
metric <<= 2
metric |= fuzzy(i.u1, rominfo.u1)
return metric
return metric
class SensorCaptureProg:
table=[]
table: typing.List["SensorCaptureProg"] = []
@classmethod
def get(cls, rominfo, sensor_type, a0, a1):
def get(cls, rominfo, sensor_type: int, a0: int, a1: int):
# noinspection PyUnresolvedReferences
from . import generated_tables
maximum = 0
@ -74,20 +82,20 @@ class SensorCaptureProg:
if found is not None:
return b''.join(found.blobs)
def __init__(self, major, minor, build, u1, dev_type, a0, a1, blobs):
self.major=major
self.minor=minor
self.build=build
self.u1=u1
self.dev_type=dev_type
self.a0=a0
self.a1=a1
blobs=[unhexlify(b) for b in blobs]
self.blobs=blobs
def __init__(self, major: int, minor: int, build: int, u1: int, dev_type: int, a0: int, a1: int,
blobs: typing.Sequence[str]):
self.major = major
self.minor = minor
self.build = build
self.u1 = u1
self.dev_type = dev_type
self.a0 = a0
self.a1 = a1
self.blobs = [unhexlify(b) for b in blobs]
def __repr__(self):
blobs=[hexlify(b).decode() for b in self.blobs]
blobs = [hexlify(b).decode() for b in self.blobs]
return 'SensorCaptureProg(major=0x%x, minor=0x%x, build=0x%x, u1=0x%x, dev_type=0x%x, a0=0x%x, a1=0x%x, blobs=%s)' % (
self.major, self.minor, self.build, self.u1, self.dev_type, self.a0, self.a1,

View file

@ -1,151 +1,155 @@
import typing
from binascii import hexlify
from struct import unpack, pack
codes={}
codes[0x0] = "No Operation"
codes[0x1] = "Swipe"
codes[0x2] = "Timeslot Configuration"
codes[0x3] = "Register"
codes[0x4] = "Register Set 32"
codes[0x5] = "Register Operation 32"
codes[0x6] = "Security"
codes[0x7] = "WOE"
codes[0x8] = "Motion 1"
codes[0xa] = "CPUCLK"
codes[0xb] = "Motion 2"
codes[0xc] = "Calibration Block"
codes[0xd] = "Sweep"
codes[0xe] = "Zone Configuration"
codes[0xf] = "Zones Per Sweep"
codes[0x10] = "Lines Per Sweep Iteration"
codes[0x11] = "Lines Per Sweep"
codes[0x12] = "Total Zones"
codes[0x13] = "CAL WOE Ctrl"
codes[0x14] = "Cal WOE Mask"
codes[0x15] = "BW Reduciton"
codes[0x16] = "AGC"
codes[0x17] = "Reply Configuration"
codes[0x18] = "Motion 3"
codes[0x19] = "WOVAR"
codes[0x1a] = "Block MOde"
codes[0x1b] = "Bit Reduction"
codes[0x1c] = "Motion 4"
codes[0x1d] = "Calibration WOENF"
codes[0x1e] = "Calibration"
codes[0x1f] = "Zone Configuration A"
codes[0x20] = "Set Register 32"
codes[0x21] = "Register Operation 32A"
codes[0x22] = "Fingerprint Buffering"
codes[0x23] = "Reply Config + Timeslot Table"
codes[0x24] = "Baseline"
codes[0x25] = "SO Alternate"
codes[0x26] = "Finger Detect"
codes[0x27] = "Finger Detect Sample Register"
codes[0x28] = "Finger Detect Scan Registers"
codes[0x29] = "Timeslot Table Offset"
codes[0x2a] = "ACM Config"
codes[0x2b] = "ACM Control"
codes[0x2c] = "CEM Config"
codes[0x2d] = "CEM Control"
codes[0x2e] = "Image Reconstruction"
codes[0x2f] = "2D"
codes[0x30] = "Line Update"
codes[0x31] = "FDetect Timeslot Table"
codes[0x32] = "Register List 16"
codes[0x33] = "Register list 32"
codes[0x34] = "Timeslot Table 2D"
codes[0x35] = "Timeslot Table Offset for Finger Detect"
codes[0x36] = "Security Aligned"
codes[0x37] = "WOF2"
codes[0x38] = "WOE WOF"
codes[0x39] = "Navigation"
codes[0x3a] = "WOE WOF2 Version2"
codes[0x3b] = "Cal WOE WOF2"
codes[0x3c] = "Event Signal"
codes[0x3d] = "IFS Frame Stats"
codes[0x3e] = "SNR Method 4"
codes[0x3f] = "WOE WOF2 Version 3"
codes[0x40] = "Calibrate WOE WOF2 Version 3"
codes[0x41] = "Finger Detect Ratchet"
codes[0x42] = "Data Encoder"
codes[0x43] = "Line Update Transform"
codes[0x44] = "Line Update InterLeave"
codes[0x45] = "SO Table Values for Macros"
codes[0x46] = "Timeslot Macro Definitions"
codes[0x47] = "Enable ASP Feature"
codes[0x48] = "Baseline Frame"
codes[0x49] = "Rx Select"
codes[0x4e] = "WTF"
codes[0xffff] = "Unknown"
codes = {}
codes[0x0] = "No Operation"
codes[0x1] = "Swipe"
codes[0x2] = "Timeslot Configuration"
codes[0x3] = "Register"
codes[0x4] = "Register Set 32"
codes[0x5] = "Register Operation 32"
codes[0x6] = "Security"
codes[0x7] = "WOE"
codes[0x8] = "Motion 1"
codes[0xa] = "CPUCLK"
codes[0xb] = "Motion 2"
codes[0xc] = "Calibration Block"
codes[0xd] = "Sweep"
codes[0xe] = "Zone Configuration"
codes[0xf] = "Zones Per Sweep"
codes[0x10] = "Lines Per Sweep Iteration"
codes[0x11] = "Lines Per Sweep"
codes[0x12] = "Total Zones"
codes[0x13] = "CAL WOE Ctrl"
codes[0x14] = "Cal WOE Mask"
codes[0x15] = "BW Reduciton"
codes[0x16] = "AGC"
codes[0x17] = "Reply Configuration"
codes[0x18] = "Motion 3"
codes[0x19] = "WOVAR"
codes[0x1a] = "Block MOde"
codes[0x1b] = "Bit Reduction"
codes[0x1c] = "Motion 4"
codes[0x1d] = "Calibration WOENF"
codes[0x1e] = "Calibration"
codes[0x1f] = "Zone Configuration A"
codes[0x20] = "Set Register 32"
codes[0x21] = "Register Operation 32A"
codes[0x22] = "Fingerprint Buffering"
codes[0x23] = "Reply Config + Timeslot Table"
codes[0x24] = "Baseline"
codes[0x25] = "SO Alternate"
codes[0x26] = "Finger Detect"
codes[0x27] = "Finger Detect Sample Register"
codes[0x28] = "Finger Detect Scan Registers"
codes[0x29] = "Timeslot Table Offset"
codes[0x2a] = "ACM Config"
codes[0x2b] = "ACM Control"
codes[0x2c] = "CEM Config"
codes[0x2d] = "CEM Control"
codes[0x2e] = "Image Reconstruction"
codes[0x2f] = "2D"
codes[0x30] = "Line Update"
codes[0x31] = "FDetect Timeslot Table"
codes[0x32] = "Register List 16"
codes[0x33] = "Register list 32"
codes[0x34] = "Timeslot Table 2D"
codes[0x35] = "Timeslot Table Offset for Finger Detect"
codes[0x36] = "Security Aligned"
codes[0x37] = "WOF2"
codes[0x38] = "WOE WOF"
codes[0x39] = "Navigation"
codes[0x3a] = "WOE WOF2 Version2"
codes[0x3b] = "Cal WOE WOF2"
codes[0x3c] = "Event Signal"
codes[0x3d] = "IFS Frame Stats"
codes[0x3e] = "SNR Method 4"
codes[0x3f] = "WOE WOF2 Version 3"
codes[0x40] = "Calibrate WOE WOF2 Version 3"
codes[0x41] = "Finger Detect Ratchet"
codes[0x42] = "Data Encoder"
codes[0x43] = "Line Update Transform"
codes[0x44] = "Line Update InterLeave"
codes[0x45] = "SO Table Values for Macros"
codes[0x46] = "Timeslot Macro Definitions"
codes[0x47] = "Enable ASP Feature"
codes[0x48] = "Baseline Frame"
codes[0x49] = "Rx Select"
codes[0x4e] = "WTF"
codes[0xffff] = "Unknown"
insn_to_string=[
'NOOP', # 0
'End of Table', # 1
'Return', # 2
'Clear SO', # 3
'End of Data', # 4
'Marco %02x', # 5
'Enable Rx 0x%02x', # 6
'Idle Rx 0x%03x', # 7
'Enable SO 0x%03x', # 8
'Disable SO 0x%03x', # 9
'Interrupt %x', # 10
'Call rx_inc=%d, addr=%x, repeat=%d', # 11
'Features %02x', # 12
'Register Write *0x%08x = 0x%04x', # 13
'Sample %x, %x', # 14
'Sample Repeat %x, %x, repeat=%x', # 15
insn_to_string = [
'NOOP', # 0
'End of Table', # 1
'Return', # 2
'Clear SO', # 3
'End of Data', # 4
'Marco %02x', # 5
'Enable Rx 0x%02x', # 6
'Idle Rx 0x%03x', # 7
'Enable SO 0x%03x', # 8
'Disable SO 0x%03x', # 9
'Interrupt %x', # 10
'Call rx_inc=%d, addr=%x, repeat=%d', # 11
'Features %02x', # 12
'Register Write *0x%08x = 0x%04x', # 13
'Sample %x, %x', # 14
'Sample Repeat %x, %x, repeat=%x', # 15
]
def decode_insn(b):
def decode_insn(b: bytes):
if b[0] == 0:
return (0, 1)
return 0, 1
elif b[0] == 1:
return (1, 1)
return 1, 1
elif b[0] == 2:
return (2, 1)
return 2, 1
elif b[0] == 3:
return (3, 1)
return 3, 1
elif b[0] == 4:
return (4, 1)
return 4, 1
elif b[0] == 5:
return (5, 2, b[1])
return 5, 2, b[1]
elif b[0] == 6:
return (6, 2, b[1])
return 6, 2, b[1]
elif b[0] == 7:
return (7, 2, 0x100 if b[1] == 0 else b[1])
return 7, 2, 0x100 if b[1] == 0 else b[1]
elif b[0] & 0xfe == 8:
return (8, 2, (b[0] & 1) << 8 | b[1])
return 8, 2, (b[0] & 1) << 8 | b[1]
elif b[0] & 0xfe == 0xa:
return (9, 2, (b[0] & 1) << 8 | b[1])
return 9, 2, (b[0] & 1) << 8 | b[1]
elif b[0] & 0xfc == 0xc:
return (10, 1, b[0] & 3)
return 10, 1, b[0] & 3
elif b[0] & 0xf8 == 0x10:
return (11, 3, b[0] & 7, b[1] << 2, 0x100 if b[2] == 0 else b[2])
return 11, 3, b[0] & 7, b[1] << 2, 0x100 if b[2] == 0 else b[2]
elif b[0] & 0xe0 == 0x20:
return (12, 1, b[0] & 0x1f) # TODO check how features are converted to op args
return 12, 1, b[0] & 0x1f # TODO check how features are converted to op args
elif b[0] & 0xc0 == 0x40:
return (13, 3, (b[0] & 0x3f)*4+0x80002000, b[1] | (b[2] << 8))
return 13, 3, (b[0] & 0x3f) * 4 + 0x80002000, b[1] | (b[2] << 8)
elif b[0] & 0xc0 == 0x80:
return (14, 1, (b[0] & 0x38) >> 3, b[0] & 7)
return 14, 1, (b[0] & 0x38) >> 3, b[0] & 7
elif b[0] & 0xc0 == 0xc0:
return (15, 2, (b[0] & 0x38) >> 3, b[0] & 7, 0x100 if b[1] == 0 else b[1])
return 15, 2, (b[0] & 0x38) >> 3, b[0] & 7, 0x100 if b[1] == 0 else b[1]
else:
raise Exception('Unhandled instruction %02x' % b)
def disassm_timeslot_table(b, off):
pc=off
def disassm_timeslot_table(b: bytes, off: int):
pc = off
while len(b) > 0:
op, sz, *operands = decode_insn(b)
if sz > len(b):
raise Exception('Truncated instruction')
print(' %04x: %-6s %s' % (pc, hexlify(b[:sz]).decode(), insn_to_string[op] % tuple(operands)))
print(' %04x: %-6s %s' %
(pc, hexlify(b[:sz]).decode(), insn_to_string[op] % tuple(operands)))
b = b[sz:]
pc += sz
def find_nth_insn(b, opcode, n):
pc=0
def find_nth_insn(b: bytes, opcode: int, n: int):
pc = 0
while len(b) > 0:
op, sz, *_ = decode_insn(b)
@ -153,15 +157,16 @@ def find_nth_insn(b, opcode, n):
raise Exception('Truncated instruction')
if op == opcode:
n-=1
n -= 1
if n == 0:
return (pc, b[:sz])
return pc, b[:sz]
b = b[sz:]
pc += sz
def find_nth_regwrite(b, reg_addr, n):
pc=0
def find_nth_regwrite(b: bytes, reg_addr: int, n: int):
pc = 0
while len(b) > 0:
op, sz, *operands = decode_insn(b)
@ -171,24 +176,28 @@ def find_nth_regwrite(b, reg_addr, n):
if op == 13:
addr, value = operands
if addr == reg_addr:
n-=1
n -= 1
if n == 0:
return (pc, b[:sz])
return pc, b[:sz]
b = b[sz:]
pc += sz
def split_chunks(b):
def split_chunks(b: bytes) -> typing.Generator[typing.List[typing.Union[int, bytes]], None, None]:
while len(b) > 0:
(typ, sz), b = unpack('<HH', b[:4]), b[4:]
p, b = b[:sz], b[sz:]
yield [typ, p]
def merge_chunks(cs):
def merge_chunks(cs: typing.List[typing.List[typing.Union[int, bytes]]]):
return b''.join([pack('<HH', key, len(val)) + val for key, val in cs])
def dump_all(b):
def dump_all(b: bytes):
ts: typing.Optional[bytes] = None
ts_off: typing.Optional[int] = None
while len(b) > 0:
(typ, sz), b = unpack('<HH', b[:4]), b[4:]
p, b = b[:sz], b[sz:]
@ -198,19 +207,19 @@ def dump_all(b):
print(' *0x%08x = 0x%08x' % (addr, val))
elif typ == 0x32:
print('Set Registers 16:')
(base,), p = unpack('<L', p[:4]), p[4:]
(base, ), p = unpack('<L', p[:4]), p[4:]
while len(p) > 0:
(off, val), p = unpack('<HH', p[:4]), p[4:]
print(' *0x%08x = 0x%04x' % (off + base, val))
elif typ == 0x33:
print('Set Registers 32:')
(base,), p = unpack('<L', p[:4]), p[4:]
(base, ), p = unpack('<L', p[:4]), p[4:]
while len(p) > 0:
(off, val), p = unpack('<HL', p[:6]), p[6:]
print(' *0x%08x = 0x%08x' % (off + base, val))
elif typ == 0x34:
print('%04x (%20s): (0x%x bytes) %s' % (typ, codes[typ], len(p), hexlify(p).decode()))
ts=p
ts = p
elif typ == 0x29:
ts_off, = unpack('<L', p)
print('%04x (%20s): 0x%x' % (typ, codes[typ], ts_off))
@ -220,4 +229,3 @@ def dump_all(b):
if ts is not None:
print('Timeslot table, starting at 0x%x:' % ts_off)
disassm_timeslot_table(ts[ts_off:], ts_off)

View file

@ -1,25 +1,25 @@
import hmac
import logging
import os
import pickle
import logging
import typing
from binascii import hexlify, unhexlify
from hashlib import sha256
from struct import pack, unpack
from binascii import *
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.asymmetric.utils import Prehashed
from cryptography.hazmat.primitives import hashes
from hashlib import sha256
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from .usb import usb, Usb
from .util import unhex
from .usb import usb
password_hardcoded = unhexlify('717cd72d0962bc4a2846138dbb2c24192512a76407065f383846139d4bec2033')
gwk_sign_hardcoded = unhexlify('3a4c76b76a97981d1274247e166610e77f4d9c9d07d3c728e532916bdd28b454')
password_hardcoded=unhexlify('717cd72d0962bc4a2846138dbb2c24192512a76407065f383846139d4bec2033')
gwk_sign_hardcoded=unhexlify('3a4c76b76a97981d1274247e166610e77f4d9c9d07d3c728e532916bdd28b454')
crt_hardcoded=unhex('''
crt_hardcoded = unhex('''
170000000001000001000000fcffffffffffffffffffffff00000000000000000000000001000000fffff
fff0000000000000000000000000000000000000000000000000000000000000000000000004b60d2273e
3cce3bf6b053ccb0061d65bc86987655bdebb3e7933aaad835c65a0000000000000000000000000000000
@ -32,56 +32,63 @@ ae6bcffffffffffffffff00000000ffffffff0000000000000000000000000000000000000000000
fff000000000000000000000000000000000000000000000000000000000000000000000000
''')
crypto_backend=default_backend()
crypto_backend = default_backend()
def prf(secret, seed, length):
def prf(secret: bytes, seed: bytes, length: int):
n = (length + 0x20 - 1) // 0x20
res = b''
a = hmac.new(secret, seed, sha256).digest()
while n > 0:
res += hmac.new(secret, a+seed, sha256).digest()
res += hmac.new(secret, a + seed, sha256).digest()
a = hmac.new(secret, a, sha256).digest()
n -= 1
return res[:length]
def hs_key():
key=password_hardcoded[:0x10]
seed=password_hardcoded[0x10:] + b'\xaa'*2
hs_key=prf(key, b'HS_KEY_PAIR_GEN' + seed, 0x20)
key = password_hardcoded[:0x10]
seed = password_hardcoded[0x10:] + b'\xaa' * 2
hs_key = prf(key, b'HS_KEY_PAIR_GEN' + seed, 0x20)
return int(hs_key[::-1].hex(), 16)
def with_2bytes_size(chunk):
def with_2bytes_size(chunk: bytes):
return pack('>H', len(chunk)) + chunk
def with_3bytes_size(chunk):
def with_3bytes_size(chunk: bytes):
return pack('>BH', len(chunk) >> 16, len(chunk)) + chunk
def with_1byte_size(chunk):
def with_1byte_size(chunk: bytes):
return pack('>B', len(chunk)) + chunk
def to_bytes(n):
b=b''
b = b''
while n:
b += (n & 0xff).to_bytes(1, 'big')
n >>= 8
return b
def pad(b):
l = 16 - (len(b) % 16)
return b + bytes([l-1])*l
def unpad(b):
return b[:-1-b[-1]]
def pad(b: bytes):
l = 16 - (len(b) % 16)
return b + bytes([l - 1]) * l
def unpad(b: bytes):
return b[:-1 - b[-1]]
# TODO assert the right state transitions
class Tls():
def __init__(self, usb):
class Tls:
def __init__(self, usb: Usb):
self.usb = usb
self.reset()
try:
@ -101,20 +108,20 @@ class Tls():
self.secure_tx = False
# Info about the host computer
def set_hwkey(self, product_name, serial_number):
def set_hwkey(self, product_name: str, serial_number: str):
hw_key = bytes(product_name, 'ascii') + b'\0' + \
bytes(serial_number, 'ascii') + b'\0'
# pre-TLS keys
self.psk_encryption_key = prf(password_hardcoded, b'GWK' + hw_key, 0x20)
self.psk_validation_key = prf(self.psk_encryption_key,
b'GWK_SIGN' + gwk_sign_hardcoded, 0x20)
self.psk_validation_key = prf(self.psk_encryption_key, b'GWK_SIGN' + gwk_sign_hardcoded,
0x20)
def cmd(self, cmd):
def cmd(self, cmd: typing.Union[bytes, typing.Callable[[], bytes]]):
if self.secure_rx and self.secure_tx:
rsp=self.app(cmd)
rsp = self.app(cmd)
else:
rsp=self.usb.cmd(cmd)
rsp = self.usb.cmd(cmd)
return rsp
@ -124,31 +131,27 @@ class Tls():
self.handshake_hash = sha256()
rsp=self.usb.cmd(unhexlify('44000000') + self.make_handshake(self.make_client_hello()))
rsp = self.usb.cmd(unhexlify('44000000') + self.make_handshake(self.make_client_hello()))
self.parse_tls_response(rsp)
self.make_keys()
rsp=self.usb.cmd(
unhexlify('44000000') +
self.make_handshake(
self.make_certs() +
self.make_client_kex() +
self.make_cert_verify()) +
self.make_change_cipher_spec() +
self.make_handshake(self.make_finish()))
rsp = self.usb.cmd(
unhexlify('44000000') + self.make_handshake(self.make_certs() + self.make_client_kex() +
self.make_cert_verify()) +
self.make_change_cipher_spec() + self.make_handshake(self.make_finish()))
self.parse_tls_response(rsp)
def trace(self, s):
def trace(self, s: str):
if self.trace_enabled:
logging.debug(s)
def app(self, b):
def app(self, b: typing.Union[bytes, typing.Callable[[], bytes]]):
b = b() if callable(b) else b
return self.parse_tls_response(self.usb.cmd(self.make_app_data(b)))
def update_neg(self, b):
def update_neg(self, b: bytes):
self.handshake_hash.update(b)
def make_keys(self):
@ -156,27 +159,28 @@ class Tls():
self.session_public = skey.private_numbers().public_numbers
pre_master_secret = skey.exchange(ec.ECDH(), self.ecdh_q)
seed = self.client_random + self.server_random
self.master_secret = prf(pre_master_secret, b'master secret'+seed, 0x30)
key_block = prf(self.master_secret, b'key expansion'+seed, 0x120)
self.master_secret = prf(pre_master_secret, b'master secret' + seed, 0x30)
key_block = prf(self.master_secret, b'key expansion' + seed, 0x120)
self.sign_key = key_block[0x00:0x20]
self.validation_key = key_block[0x20:0x20+0x20]
self.encryption_key = key_block[0x40:0x40+0x20]
self.decryption_key = key_block[0x60:0x60+0x20]
self.validation_key = key_block[0x20:0x20 + 0x20]
self.encryption_key = key_block[0x40:0x40 + 0x20]
self.decryption_key = key_block[0x60:0x60 + 0x20]
def save(self):
with open('tls.dict', 'wb') as f:
pickle.dump({
'sign_key': self.sign_key,
'validation_key': self.validation_key,
'encryption_key': self.encryption_key,
'decryption_key': self.decryption_key,
'secure_rx': self.secure_rx,
'secure_tx': self.secure_tx
}, f)
pickle.dump(
{
'sign_key': self.sign_key,
'validation_key': self.validation_key,
'encryption_key': self.encryption_key,
'decryption_key': self.decryption_key,
'secure_rx': self.secure_rx,
'secure_tx': self.secure_tx
}, f)
def load(self):
with open('tls.dict', 'rb') as f:
d=pickle.load(f)
d = pickle.load(f)
self.sign_key = d['sign_key']
self.validation_key = d['validation_key']
self.encryption_key = d['encryption_key']
@ -184,46 +188,46 @@ class Tls():
self.secure_rx = d['secure_rx']
self.secure_tx = d['secure_tx']
def decrypt(self, c):
def decrypt(self, c: bytes):
iv, c = c[:0x10], c[0x10:]
cipher = Cipher(algorithms.AES(self.decryption_key), modes.CBC(iv), backend=crypto_backend)
decryptor = cipher.decryptor()
m = decryptor.update(c) + decryptor.finalize()
m=unpad(m)
m = unpad(m)
return m
def encrypt(self, b):
#iv = unhexlify('454849acdd075174d6b9e713a957c2e7')
def encrypt(self, b: bytes):
# iv = unhexlify('454849acdd075174d6b9e713a957c2e7')
iv = os.urandom(0x10)
cipher = Cipher(algorithms.AES(self.encryption_key), modes.CBC(iv), backend=crypto_backend)
encryptor = cipher.encryptor()
b=pad(b)
c=encryptor.update(b) + encryptor.finalize()
b = pad(b)
c = encryptor.update(b) + encryptor.finalize()
return iv + c
def validate(self, t, b):
def validate(self, t: int, b: bytes):
b, hs = b[:-0x20], b[-0x20:]
hdr = pack('>BBBH', t, 3, 3, len(b))
sig=hmac.new(self.validation_key, hdr+b, sha256).digest()
sig = hmac.new(self.validation_key, hdr + b, sha256).digest()
if sig != hs:
raise Exception('Packet signature validation check failed')
self.trace('<tls< %02x: %s' % (t, hexlify(b).decode()))
return b
def sign(self, t, b):
def sign(self, t: int, b: bytes):
self.trace('>tls> %02x: %s' % (t, hexlify(b).decode()))
hdr = pack('>BBBH', t, 3, 3, len(b))
sig=hmac.new(self.sign_key, hdr+b, sha256).digest()
sig = hmac.new(self.sign_key, hdr + b, sha256).digest()
return b + sig
def make_finish(self):
self.secure_tx = True
hs_hash = self.handshake_hash.copy().digest()
verify_data = prf(self.master_secret, b'client finished'+hs_hash, 0xc)
verify_data = prf(self.master_secret, b'client finished' + hs_hash, 0xc)
return b'\x14' + with_3bytes_size(verify_data)
def make_change_cipher_spec(self):
@ -231,12 +235,13 @@ class Tls():
def make_certs(self):
cert = self.tls_cert
cert = unhexlify('ac16') + cert # what's this?
cert = pack('>BH', 0, len(self.tls_cert)) + cert # this seems to violate the standard (should be len(cert))
cert = pack('>BH', 0, len(self.tls_cert)) + cert # same
cert = unhexlify('ac16') + cert # what's this?
cert = pack('>BH', 0, len(
self.tls_cert)) + cert # this seems to violate the standard (should be len(cert))
cert = pack('>BH', 0, len(self.tls_cert)) + cert # same
return self.with_neg_hdr(0x0b, cert)
def with_neg_hdr(self, t, b):
def with_neg_hdr(self, t: int, b: bytes):
b = pack('>B', t) + with_3bytes_size(b)
self.update_neg(b)
return b
@ -246,11 +251,11 @@ class Tls():
return self.with_neg_hdr(0x10, b)
def make_cert_verify(self):
buf=self.handshake_hash.copy().digest()
b=self.priv_key.sign(buf, ec.ECDSA(Prehashed(hashes.SHA256())))
buf = self.handshake_hash.copy().digest()
b = self.priv_key.sign(buf, ec.ECDSA(Prehashed(hashes.SHA256())))
return self.with_neg_hdr(0x0f, b)
def handle_server_hello(self, p):
def handle_server_hello(self, p: bytes):
if p[:2] != unhexlify('0303'):
raise Exception('unexpected TLS version %s' % hexlify(p[:2]).decode())
@ -258,50 +263,54 @@ class Tls():
self.server_random, p = p[:0x20], p[0x20:]
l = p[0]
self.server_sessid, p = p[1:1+l], p[1+l:]
self.server_sessid, p = p[1:1 + l], p[1 + l:]
(suite,), p = unpack('>H', p[:2]), p[2:]
(suite, ), p = unpack('>H', p[:2]), p[2:]
if suite != 0xc005:
raise Exception('Server accepted unsupported cipher suite %04x' % suite)
if p[0] != 0:
raise Exception('Server selected to enable compression, which we don''t support %02x' % p[0])
raise Exception('Server selected to enable compression, which we don'
't support %02x' % p[0])
p = p[1:]
if p != b'':
raise Exception('Not expecting any more data')
def handle_cert_req(self, p):
(sign_and_hash_algo,), p = unpack('>H', p[:2]), p[2:]
def handle_cert_req(self, p: bytes):
(sign_and_hash_algo, ), p = unpack('>H', p[:2]), p[2:]
if sign_and_hash_algo != 0x140:
raise Exception('Server requested a cert with an unsupported sign and hash algo combination %04x' % sign_and_hash_algo)
raise Exception(
'Server requested a cert with an unsupported sign and hash algo combination %04x' %
sign_and_hash_algo)
(l,), p = unpack('>H', p[:2]), p[2:]
(l, ), p = unpack('>H', p[:2]), p[2:]
if l != 0:
raise Exception('Server requested a cert with non-empty list of CAs')
if p != b'':
raise Exception('Not expecting any more data')
def handle_server_hello_done(self, p):
def handle_server_hello_done(self, p: bytes):
if p != b'':
raise Exception('Not expecting any body for "server hello done" pkt: %s' % hexlify(p).decode())
raise Exception('Not expecting any body for "server hello done" pkt: %s' %
hexlify(p).decode())
def handle_finish(self, b):
def handle_finish(self, b: bytes):
hs_hash = self.handshake_hash.copy().digest()
verify_data = prf(self.master_secret, b'server finished'+hs_hash, 0xc)
verify_data = prf(self.master_secret, b'server finished' + hs_hash, 0xc)
if verify_data != b:
raise Exception('Final handshake check failed')
def handle_app_data(self, b):
def handle_app_data(self, b: bytes):
if not self.secure_rx:
raise Exception('App payload before secure connection established')
return self.validate(0x17, self.decrypt(b))
def handle_handshake(self, handshake):
def handle_handshake(self, handshake: bytes) -> None:
if self.secure_rx:
handshake = self.validate(0x16, self.decrypt(handshake))
@ -325,10 +334,10 @@ class Tls():
else:
raise Exception('Unknown handshake packet %02x' % t)
self.update_neg(hdr+p)
self.update_neg(hdr + p)
def parse_tls_response(self, rsp):
app_data=b''
def parse_tls_response(self, rsp: bytes):
app_data = b''
while len(rsp) > 0:
while len(rsp) < 5:
@ -347,7 +356,7 @@ class Tls():
elif t == 0x14:
if pkt != unhexlify('01'):
raise Exception('Unexpected ChangeCipherSpec payload')
self.secure_rx = True
elif t == 0x17:
@ -358,47 +367,48 @@ class Tls():
return app_data
def make_app_data(self, b):
def make_app_data(self, b: bytes):
if not self.secure_tx:
raise Exception('App payload before secure connection established')
b=self.encrypt(self.sign(0x17, b))
b = self.encrypt(self.sign(0x17, b))
return unhexlify('170303') + with_2bytes_size(b)
def make_handshake(self, b):
def make_handshake(self, b: bytes):
if self.secure_tx:
b=self.encrypt(self.sign(0x16, b))
b = self.encrypt(self.sign(0x16, b))
return unhexlify('160303') + with_2bytes_size(b)
def make_client_hello(self):
h = unhexlify('0303') # TLS 1.2
#self.client_random = unhexlify('bc349559ac16c8f8362191395b4d04a435d870315f519eed8777488bc2b9600c')
h = unhexlify('0303') # TLS 1.2
# self.client_random = unhexlify('bc349559ac16c8f8362191395b4d04a435d870315f519eed8777488bc2b9600c')
self.client_random = os.urandom(0x20)
h += self.client_random # client's random
h += with_1byte_size(unhexlify('00000000000000')) # session ID
h += self.client_random # client's random
h += with_1byte_size(unhexlify('00000000000000')) # session ID
suits = b''
suits += pack('>H', 0xc005) # TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
suits += pack('>H', 0x003d) # TLS_RSA_WITH_AES_256_CBC_SHA256
suits += pack('>H', 0x008d) # TLS_RSA_WITH_AES_256_CBC_SHA256
suits += pack('>H', 0xc005) # TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
suits += pack('>H', 0x003d) # TLS_RSA_WITH_AES_256_CBC_SHA256
suits += pack('>H', 0x008d) # TLS_RSA_WITH_AES_256_CBC_SHA256
h += with_2bytes_size(suits)
h += with_1byte_size(b'') # no compression options
h += with_1byte_size(b'') # no compression options
exts = b''
exts += self.make_ext(0x004, pack('>H', 0x0017)) # truncated_hmac = 0x17
exts += self.make_ext(0x00b, with_1byte_size(unhexlify('00'))) # EC points format = uncompressed
exts += self.make_ext(0x004, pack('>H', 0x0017)) # truncated_hmac = 0x17
exts += self.make_ext(0x00b,
with_1byte_size(unhexlify('00'))) # EC points format = uncompressed
# h += with_2bytes_size(exts)
h += pack('>H', len(exts)-2) + exts # -2? WHY?!...
h += pack('>H', len(exts) - 2) + exts # -2? WHY?!...
return self.with_neg_hdr(0x01, h)
def make_ext(self, id, b):
def make_ext(self, id: int, b: bytes):
return pack('>H', id) + with_2bytes_size(b)
def parseTlsFlash(self, reply):
def parse_tls_flash(self, reply: bytes):
while len(reply) > 0:
hdr, reply = reply[:4], reply[4:]
hs, reply = reply[:0x20], reply[0x20:]
@ -410,7 +420,7 @@ class Tls():
self.trace('block id %04x (%d bytes)' % (id, sz))
m=sha256()
m = sha256()
m.update(body)
if m.digest() != hs:
@ -431,37 +441,37 @@ class Tls():
else:
self.trace('unhandled block id %04x (%d bytes): %s' % (id, sz, hexlify(body)))
def makeTlsFlashBlock(self, id, body):
m=sha256()
def make_tls_flash_block(self, id: int, body: bytes):
m = sha256()
m.update(body)
hdr = pack('<HH', id, len(body))
return hdr+m.digest()+body
return hdr + m.digest() + body
def makeTlsFlash(self):
b = self.makeTlsFlashBlock(0, b'\0')
b+= self.makeTlsFlashBlock(4, self.priv_blob)
b+= self.makeTlsFlashBlock(3, self.tls_cert)
b+= self.makeTlsFlashBlock(5, crt_hardcoded)
b+= self.makeTlsFlashBlock(1, b'\0' * 0x100)
b+= self.makeTlsFlashBlock(2, b'\0' * 0x100)
b+= self.makeTlsFlashBlock(6, self.ecdh_blob)
b+= b'\xff' * (0x1000 - len(b))
def make_tls_flash(self):
b = self.make_tls_flash_block(0, b'\0')
b += self.make_tls_flash_block(4, self.priv_blob)
b += self.make_tls_flash_block(3, self.tls_cert)
b += self.make_tls_flash_block(5, crt_hardcoded)
b += self.make_tls_flash_block(1, b'\0' * 0x100)
b += self.make_tls_flash_block(2, b'\0' * 0x100)
b += self.make_tls_flash_block(6, self.ecdh_blob)
b += b'\xff' * (0x1000 - len(b))
return b
def handle_empty(self, body):
def handle_empty(self, body: bytes):
if body != b'\0' * len(body):
raise Exception('Expected empty block')
def handle_cert(self, body):
def handle_cert(self, body: bytes):
# TODO validate cert, check if pub keys match
self.tls_cert = body
self.trace('TLS cert blob: %s' % hexlify(self.tls_cert))
def handle_ecdh(self, body):
def handle_ecdh(self, body: bytes):
self.ecdh_blob = body
key, signature = body[:0x90], body[0x90:]
x = key[0x8:0x8+0x20]
y = key[0x4c:0x4c+0x20]
x = key[0x8:0x8 + 0x20]
y = key[0x4c:0x4c + 0x20]
x, y = [int(hexlify(i[::-1]), 0x10) for i in [x, y]]
@ -477,35 +487,39 @@ class Tls():
l, = unpack('<L', l)
signature, zeroes = signature[:l], signature[l:]
if zeroes != b'\0'*len(zeroes):
if zeroes != b'\0' * len(zeroes):
raise Exception('Zeroes expected')
# The following pub key is hardcoded for each fw revision in the synaWudfBioUsb.dll.
# Corresponding private key should only be known to a genuine Synaptic device.
fwpub = ec.EllipticCurvePublicNumbers(
0xf727653b4e16ce0665a6894d7f3a30d7d0a0be310d1292a743671fdf69f6a8d3,
0xa85538f8b6bec50d6eef8bd5f4d07a886243c58b2393948df761a84721a6ca94, ec.SECP256R1()).public_key(crypto_backend)
0xf727653b4e16ce0665a6894d7f3a30d7d0a0be310d1292a743671fdf69f6a8d3,
0xa85538f8b6bec50d6eef8bd5f4d07a886243c58b2393948df761a84721a6ca94,
ec.SECP256R1()).public_key(crypto_backend)
# throws InvalidSignature
fwpub.verify(signature, key, ec.ECDSA(hashes.SHA256()))
def handle_priv(self, body):
def handle_priv(self, body: bytes):
self.priv_blob = body
prefix, body = body[0], body[1:]
if prefix != 2:
raise Exception('Unknown private key prefix %02x' % prefix)
c, hs = body[:-0x20], body[-0x20:]
sig=hmac.new(self.psk_validation_key, c, sha256).digest()
sig = hmac.new(self.psk_validation_key, c, sha256).digest()
if hs != sig:
raise Exception('Signature verification failed. This device was probably paired with another computer.')
raise Exception(
'Signature verification failed. This device was probably paired with another computer.'
)
iv, c = c[:0x10], c[0x10:]
cipher = Cipher(algorithms.AES(self.psk_encryption_key), modes.CBC(iv), backend=crypto_backend)
cipher = Cipher(algorithms.AES(self.psk_encryption_key),
modes.CBC(iv),
backend=crypto_backend)
decryptor = cipher.decryptor()
m = decryptor.update(c) + decryptor.finalize()
m=m[:-m[-1]] # unpad (standard this time)
m = m[:-m[-1]] # unpad (standard this time)
x, m = m[:0x20], m[0x20:]
y, m = m[:0x20], m[0x20:]
@ -519,8 +533,8 @@ class Tls():
self.trace('d=0x%x' % d)
# Someone has reported that x and y are 0 after pairing with the latest windows driver.
#pub_key = ec.EllipticCurvePublicNumbers(x, y, ec.SECP256R1())
#self.priv_key = ec.EllipticCurvePrivateNumbers(d, pub_key).private_key(crypto_backend)
# pub_key = ec.EllipticCurvePublicNumbers(x, y, ec.SECP256R1())
# self.priv_key = ec.EllipticCurvePrivateNumbers(d, pub_key).private_key(crypto_backend)
self.priv_key = ec.derive_private_key(d, ec.SECP256R1(), backend=crypto_backend)

View file

@ -1,12 +1,14 @@
from time import ctime
import logging
import typing
from os.path import basename
from time import ctime
from .usb import usb
from .sensor import reboot, write_hw_reg32, read_hw_reg32, identify_sensor
from .flash import write_flash_all, write_fw_signature, get_fw_info
from .sensor import reboot, write_hw_reg32, read_hw_reg32, identify_sensor
from .usb import usb
firmware_home = '/usr/share/python-validity'
firmware_home='/usr/share/python-validity'
def default_fwext_name():
if usb.usb_dev().idVendor == 0x138a:
@ -14,15 +16,17 @@ def default_fwext_name():
return '6_07f_Lenovo.xpfwext'
# It looks like the firmware file must match DLL, not the hardware.
# Both DLL and xpfwext are universal.
# Both DLL and xpfwext are universal.
# The device dependant code seems to be loaded dynamically (via encrypted blobs).
# So, it is important that xpfwext file is matching the blobs contents.
return '6_07f_lenovo_mis_qm.xpfwext'
def upload_fwext(fw_path=None):
fwi=get_fw_info(2)
if fwi != None:
logging.info('Detected firmware version %d.%d (%s))' % (fwi.major, fwi.minor, ctime(fwi.buildtime)))
def upload_fwext(fw_path: typing.Optional[str] = None):
fwi = get_fw_info(2)
if fwi is not None:
logging.info('Detected firmware version %d.%d (%s))' %
(fwi.major, fwi.minor, ctime(fwi.buildtime)))
return
else:
logging.info('No firmware detected. Uploading...')
@ -32,33 +36,32 @@ def upload_fwext(fw_path=None):
if read_hw_reg32(0x80002080) not in [2, 3]:
raise Exception('Unexpected register value')
dev=identify_sensor()
dev = identify_sensor()
logging.debug('Sensor: %s' % dev.name)
# ^ TODO -- what is the real reason to detect HW at this stage?
# just a guess: perhaps it is used to construct fwext filename
default_name = firmware_home + '/' + default_fwext_name()
if not fw_path:
fw_path = default_name
elif basename(fw_path) != default_name:
logging.warning('WARNING: Your device fw is supposed to be called {}'.format(
default_name))
logging.warning('WARNING: Your device fw is supposed to be called {}'.format(default_name))
with open(fw_path, 'rb') as f:
fwext=f.read()
fwext = f.read()
fwext=fwext[fwext.index(b'\x1a')+1:]
fwext = fwext[fwext.index(b'\x1a') + 1:]
fwext, signature = fwext[:-0x100], fwext[-0x100:]
write_flash_all(2, 0, fwext)
write_fw_signature(2, signature)
fwi=get_fw_info(2)
if fwi == None:
fwi = get_fw_info(2)
if fwi is None:
raise Exception('No firmware detected')
logging.info('Loaded FWExt version %d.%d (%s), %d modules' % (fwi.major, fwi.minor, ctime(fwi.buildtime), len(fwi.modules)))
logging.info('Loaded FWExt version %d.%d (%s), %d modules' %
(fwi.major, fwi.minor, ctime(fwi.buildtime), len(fwi.modules)))
# Reboot
reboot()

View file

@ -1,33 +1,37 @@
import logging
import errno
import usb.core as ucore
from binascii import *
from .util import assert_status
import logging
import typing
from binascii import hexlify, unhexlify
from struct import unpack
from usb.core import USBError
from .blobs import init_hardcoded, init_hardcoded_clean_slate
supported_devices=[
import usb.core as ucore
from usb.core import USBError
from .blobs import init_hardcoded, init_hardcoded_clean_slate
from .util import assert_status
supported_devices = [
(0x138a, 0x0090),
(0x138a, 0x0097),
(0x06cb, 0x009a),
]
class CancelledException(Exception):
pass
class Usb():
class Usb:
def __init__(self):
self.interrupt_cb = None
self.trace_enabled = False
self.dev = None
self.dev: typing.Optional[ucore.Device] = None
self.cancel = False
def open(self, vendor=None, product=None):
if vendor is not None and product is not None:
dev = ucore.find(idVendor=vendor, idProduct=product)
else:
def match(d):
return (d.idVendor, d.idProduct) in supported_devices
@ -35,15 +39,15 @@ class Usb():
self.open_dev(dev)
def open_devpath(self, busnum, address):
def open_devpath(self, busnum: int, address: int):
def match(d):
return d.bus == busnum and d.address == address
dev = ucore.find(custom_match=match)
self.open_dev(dev)
def open_dev(self, dev):
def open_dev(self, dev: ucore.Device):
if dev is None:
raise Exception('No matching devices found')
@ -62,39 +66,39 @@ class Usb():
return self.dev
def send_init(self):
#self.dev.set_configuration()
# self.dev.set_configuration()
# TODO analyse responses, detect hardware type
assert_status(self.cmd(unhexlify('01'))) # RomInfo.get()
assert_status(self.cmd(unhexlify('01'))) # RomInfo.get()
assert_status(self.cmd(unhexlify('19')))
# 43 -- get partition header(?) (02 -- fwext partition)
# c28c745a in response is a FwextBuildtime = 0x5A748CC2
rsp=self.cmd(unhexlify('4302')) # get_fw_info()
rsp = self.cmd(unhexlify('4302')) # get_fw_info()
assert_status(self.cmd(init_hardcoded))
(err,), rsp = unpack('<H', rsp[:2]), rsp[2:]
(err, ), rsp = unpack('<H', rsp[:2]), rsp[2:]
if err != 0:
# fwext is not loaded
logging.info('Clean slate')
self.cmd(init_hardcoded_clean_slate)
def cmd(self, out):
def cmd(self, out: typing.Union[bytes, typing.Callable[[], bytes]]):
if callable(out):
out = out()
if not out:
return 0
self.trace('>cmd> %s' % hexlify(out).decode())
self.dev.write(1, out)
resp = self.dev.read(129, 100*1024)
resp = self.dev.read(129, 100 * 1024)
resp = bytes(resp)
self.trace('<cmd< %s' % hexlify(resp).decode())
return resp
def read_82(self):
try:
resp = self.dev.read(130, 1024*1024, timeout=10000)
resp = self.dev.read(130, 1024 * 1024, timeout=10000)
resp = bytes(resp)
self.trace('<130< %s' % hexlify(resp).decode())
return resp
@ -122,8 +126,9 @@ class Usb():
else:
raise e
def trace(self, s):
def trace(self, s: str):
if self.trace_enabled:
logging.debug(s)
usb=Usb()
usb = Usb()

View file

@ -1,10 +1,10 @@
import re
from struct import unpack
from binascii import unhexlify
from struct import unpack
def assert_status(b):
s,=unpack('<H', b[:2])
def assert_status(b: bytes):
s, = unpack('<H', b[:2])
if s != 0:
if s == 0x44f:
raise Exception('Signature validation failed: %04x' % s)
@ -12,6 +12,5 @@ def assert_status(b):
raise Exception('Failed: %04x' % s)
def unhex(x):
return unhexlify(re.sub('\W', '', x))
def unhex(x: str):
return unhexlify(re.sub(r'\W', '', x))

View file

@ -1,36 +1,34 @@
finger_ids = {
# https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/shared/winbio_types.h#L864-L878
"WINBIO_ANSI_381_POS_UNKNOWN": 0,
"WINBIO_ANSI_381_POS_RH_THUMB": 1,
"WINBIO_ANSI_381_POS_RH_INDEX_FINGER": 2,
"WINBIO_ANSI_381_POS_RH_MIDDLE_FINGER": 3,
"WINBIO_ANSI_381_POS_RH_RING_FINGER": 4,
"WINBIO_ANSI_381_POS_RH_LITTLE_FINGER": 5,
"WINBIO_ANSI_381_POS_LH_THUMB": 6,
"WINBIO_ANSI_381_POS_LH_INDEX_FINGER": 7,
"WINBIO_ANSI_381_POS_LH_MIDDLE_FINGER": 8,
"WINBIO_ANSI_381_POS_LH_RING_FINGER": 9,
"WINBIO_ANSI_381_POS_LH_LITTLE_FINGER": 10,
# https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/shared/winbio_types.h#L864-L878
"WINBIO_ANSI_381_POS_UNKNOWN": 0,
"WINBIO_ANSI_381_POS_RH_THUMB": 1,
"WINBIO_ANSI_381_POS_RH_INDEX_FINGER": 2,
"WINBIO_ANSI_381_POS_RH_MIDDLE_FINGER": 3,
"WINBIO_ANSI_381_POS_RH_RING_FINGER": 4,
"WINBIO_ANSI_381_POS_RH_LITTLE_FINGER": 5,
"WINBIO_ANSI_381_POS_LH_THUMB": 6,
"WINBIO_ANSI_381_POS_LH_INDEX_FINGER": 7,
"WINBIO_ANSI_381_POS_LH_MIDDLE_FINGER": 8,
"WINBIO_ANSI_381_POS_LH_RING_FINGER": 9,
"WINBIO_ANSI_381_POS_LH_LITTLE_FINGER": 10,
"WINBIO_ANSI_381_POS_RH_FOUR_FINGERS": 13,
"WINBIO_ANSI_381_POS_LH_FOUR_FINGERS": 14,
"WINBIO_ANSI_381_POS_TWO_THUMBS": 15,
"WINBIO_ANSI_381_POS_RH_FOUR_FINGERS": 13,
"WINBIO_ANSI_381_POS_LH_FOUR_FINGERS": 14,
"WINBIO_ANSI_381_POS_TWO_THUMBS": 15,
# https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/shared/winbio_types.h#L920-L929
"WINBIO_FINGER_UNSPECIFIED_POS_01": 0xf5,
"WINBIO_FINGER_UNSPECIFIED_POS_02": 0xf6,
"WINBIO_FINGER_UNSPECIFIED_POS_03": 0xf7,
"WINBIO_FINGER_UNSPECIFIED_POS_04": 0xf8,
"WINBIO_FINGER_UNSPECIFIED_POS_05": 0xf9,
"WINBIO_FINGER_UNSPECIFIED_POS_06": 0xfa,
"WINBIO_FINGER_UNSPECIFIED_POS_07": 0xfb,
"WINBIO_FINGER_UNSPECIFIED_POS_08": 0xfc,
"WINBIO_FINGER_UNSPECIFIED_POS_09": 0xfd,
"WINBIO_FINGER_UNSPECIFIED_POS_10": 0xfe
# https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/shared/winbio_types.h#L920-L929
"WINBIO_FINGER_UNSPECIFIED_POS_01": 0xf5,
"WINBIO_FINGER_UNSPECIFIED_POS_02": 0xf6,
"WINBIO_FINGER_UNSPECIFIED_POS_03": 0xf7,
"WINBIO_FINGER_UNSPECIFIED_POS_04": 0xf8,
"WINBIO_FINGER_UNSPECIFIED_POS_05": 0xf9,
"WINBIO_FINGER_UNSPECIFIED_POS_06": 0xfa,
"WINBIO_FINGER_UNSPECIFIED_POS_07": 0xfb,
"WINBIO_FINGER_UNSPECIFIED_POS_08": 0xfc,
"WINBIO_FINGER_UNSPECIFIED_POS_09": 0xfd,
"WINBIO_FINGER_UNSPECIFIED_POS_10": 0xfe
}
# Store the keys in the reverse order for faster lookups
finger_names = {}
for name, index in finger_ids.items():
finger_names[index] = name
finger_names[index] = name