1077 lines
52 KiB
Python
1077 lines
52 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# This python script was built hacking 'pydfu.py', available at https://github.com/dhylands/stm32-test:
|
|
#
|
|
# This file is part of the OpenMV project.
|
|
# Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com>
|
|
# This work is licensed under the MIT license, see the file LICENSE for
|
|
# details.
|
|
#
|
|
#
|
|
# And python code available on the Travis Goodspeed's md380tools, available at https://github.com/travisgoodspeed/md380tools.git
|
|
#
|
|
# Copyright 2010, 2011 Michael Ossmann
|
|
# Copyright 2015 Travis Goodspeed
|
|
#
|
|
#
|
|
# Adapted & hacked for the OpenGD77 (for STM32) project by:
|
|
#
|
|
# Copyright (C) 2023-2025 Daniel Caujolle-Bert, F1RMB
|
|
# Roger Clark, VK3KYY / G4KYF
|
|
#
|
|
#################################################################################################################################
|
|
#
|
|
######################### Error codes #########################
|
|
# 0: No error
|
|
# -1: Missing firmware file
|
|
# -2: Wrong SGL file format
|
|
# -3: Unsupported Firmware file format
|
|
# -4: Firmware file is too large
|
|
# -5: Unknown device model type
|
|
# -6: Unable to connect the device
|
|
# -7: Command line parsing error
|
|
# -8: Unable to patch the firmware
|
|
###############################################################
|
|
|
|
|
|
from __future__ import print_function
|
|
|
|
import argparse
|
|
import collections
|
|
import inspect
|
|
import re
|
|
import struct
|
|
import sys
|
|
import usb.core
|
|
import usb.util
|
|
import zlib
|
|
import os.path
|
|
from pathlib import Path
|
|
import configparser
|
|
import hashlib
|
|
from typing import Final
|
|
import enum
|
|
import time
|
|
|
|
|
|
# USB request __TIMEOUT
|
|
__TIMEOUT = 4000
|
|
|
|
# DFU commands
|
|
__DFU_DETACH = 0
|
|
__DFU_DNLOAD = 1
|
|
__DFU_UPLOAD = 2
|
|
__DFU_GETSTATUS = 3
|
|
__DFU_CLRSTATUS = 4
|
|
__DFU_GETSTATE = 5
|
|
__DFU_ABORT = 6
|
|
|
|
# DFU status
|
|
__DFU_STATE_APP_IDLE = 0x00
|
|
__DFU_STATE_APP_DETACH = 0x01
|
|
__DFU_STATE_DFU_IDLE = 0x02
|
|
__DFU_STATE_DFU_DOWNLOAD_SYNC = 0x03
|
|
__DFU_STATE_DFU_DOWNLOAD_BUSY = 0x04
|
|
__DFU_STATE_DFU_DOWNLOAD_IDLE = 0x05
|
|
__DFU_STATE_DFU_MANIFEST_SYNC = 0x06
|
|
__DFU_STATE_DFU_MANIFEST = 0x07
|
|
__DFU_STATE_DFU_MANIFEST_WAIT_RESET = 0x08
|
|
__DFU_STATE_DFU_UPLOAD_IDLE = 0x09
|
|
__DFU_STATE_DFU_ERROR = 0x0A
|
|
|
|
_DFU_DESCRIPTOR_TYPE = 0x21
|
|
|
|
__DFU_STATUS_STR = {
|
|
__DFU_STATE_APP_IDLE: "STATE_APP_IDLE",
|
|
__DFU_STATE_APP_DETACH: "STATE_APP_DETACH",
|
|
__DFU_STATE_DFU_IDLE: "STATE_DFU_IDLE",
|
|
__DFU_STATE_DFU_DOWNLOAD_SYNC: "STATE_DFU_DOWNLOAD_SYNC",
|
|
__DFU_STATE_DFU_DOWNLOAD_BUSY: "STATE_DFU_DOWNLOAD_BUSY",
|
|
__DFU_STATE_DFU_DOWNLOAD_IDLE: "STATE_DFU_DOWNLOAD_IDLE",
|
|
__DFU_STATE_DFU_MANIFEST_SYNC: "STATE_DFU_MANIFEST_SYNC",
|
|
__DFU_STATE_DFU_MANIFEST: "STATE_DFU_MANIFEST",
|
|
__DFU_STATE_DFU_MANIFEST_WAIT_RESET: "STATE_DFU_MANIFEST_WAIT_RESET",
|
|
__DFU_STATE_DFU_UPLOAD_IDLE: "STATE_DFU_UPLOAD_IDLE",
|
|
__DFU_STATE_DFU_ERROR: "STATE_DFU_ERROR",
|
|
}
|
|
|
|
# USB device handle
|
|
__dev = None
|
|
|
|
# Configuration descriptor of the device
|
|
__cfg_descr = None
|
|
|
|
__verbose = None
|
|
|
|
# USB DFU interface
|
|
__DFU_INTERFACE = 0
|
|
|
|
defaultVID = 0x0483
|
|
defaultPID = 0xDF11
|
|
version:Final = "1.1.1"
|
|
|
|
class FWPlatformOutput(enum.Enum):
|
|
MD_9600 = 0
|
|
MD_UV380 = 1
|
|
DM_1701 = 2
|
|
MD_2017 = 3
|
|
MD_380 = 4
|
|
UNKNOWN = 5
|
|
|
|
def __int__(self):
|
|
return self.value
|
|
|
|
|
|
config = []
|
|
FWOutputPlatforms = ["MD-9600", "MD-UV380", "DM-1701", "MD-2017", "MD-380", "Unknown"]
|
|
FWPlatformFormat = FWPlatformOutput.UNKNOWN
|
|
FW2645_SHA256_Checksum: Final = "d8a653307222e576ee416ab6d4704d14758fa71c1b0e826ffd840f26266cf11f"
|
|
BLOCK_WRITE_SIZE:Final = 1024
|
|
|
|
MD9600_ENCODE_CIPHER:Final = [
|
|
0xA2, 0xFA, 0xBB, 0x4B, 0x90, 0x8F, 0x17, 0x20, 0x96, 0x36, 0x43, 0x84, 0xF7, 0xAC, 0x4E, 0x55,
|
|
0xEA, 0xE5, 0xB4, 0x36, 0x55, 0xB9, 0x39, 0xE2, 0xD8, 0xDA, 0x18, 0xC0, 0x0D, 0x09, 0x5D, 0xB8,
|
|
0x0E, 0x89, 0x90, 0x46, 0x38, 0xD4, 0x93, 0xCC, 0x2F, 0x8E, 0xCD, 0x2D, 0x22, 0xB7, 0x89, 0x97,
|
|
0x51, 0x24, 0x98, 0xA0, 0xCC, 0x30, 0x3E, 0x95, 0x7D, 0xAF, 0x4C, 0x0E, 0x68, 0x23, 0x89, 0xC6,
|
|
0x32, 0x33, 0x56, 0xAA, 0xE0, 0x58, 0x92, 0x30, 0xE2, 0xDA, 0xBC, 0xEA, 0x50, 0xFB, 0x57, 0x5B,
|
|
0x73, 0x71, 0x93, 0x09, 0x87, 0x1A, 0x29, 0xD3, 0xBF, 0xEC, 0x87, 0x85, 0x8A, 0x2B, 0x2D, 0xAA,
|
|
0x15, 0xDE, 0x57, 0xA2, 0x11, 0x83, 0xDC, 0xF4, 0xB6, 0x02, 0x56, 0xE5, 0x08, 0xE0, 0x83, 0x49,
|
|
0x59, 0xB5, 0xEB, 0x99, 0x0F, 0xE0, 0xC3, 0x46, 0xA7, 0x79, 0x12, 0x4D, 0xFA, 0x87, 0x12, 0x0C,
|
|
0xBF, 0x73, 0xD9, 0x53, 0x52, 0xBD, 0x38, 0xBF, 0xB4, 0xEE, 0xE4, 0x43, 0xD2, 0xCE, 0xD3, 0x08,
|
|
0x0A, 0xD6, 0xE9, 0x77, 0xEB, 0xE8, 0xD4, 0x94, 0x3C, 0x3E, 0x35, 0x8D, 0x40, 0xA1, 0x00, 0x92,
|
|
0x39, 0xDB, 0x25, 0xE8, 0x2B, 0x6E, 0x70, 0x39, 0xE2, 0x86, 0xAD, 0x2F, 0x36, 0x2D, 0x11, 0x41,
|
|
0x8E, 0xBE, 0xD5, 0xCC, 0xA3, 0x9C, 0x24, 0x65, 0x87, 0x23, 0x37, 0x6E, 0xE5, 0xDF, 0xBF, 0xE7,
|
|
0x8A, 0xFC, 0x83, 0x87, 0x24, 0xFE, 0x4A, 0x0B, 0x4A, 0xB3, 0xFB, 0xCF, 0xBD, 0x65, 0x03, 0x9B,
|
|
0xEE, 0x53, 0xF7, 0xBF, 0xC0, 0x63, 0x7A, 0x62, 0x8E, 0x11, 0x62, 0x17, 0x70, 0xAB, 0x16, 0xB1,
|
|
0xBA, 0xC0, 0x3A, 0x59, 0xC6, 0xD6, 0x8F, 0xDD, 0xF4, 0x5B, 0x14, 0x4B, 0xEE, 0xDE, 0x72, 0xBF,
|
|
0x31, 0x7F, 0x96, 0x79, 0xC9, 0xA4, 0xA0, 0x32, 0x5B, 0xEE, 0xFC, 0xB0, 0x69, 0x6C, 0xCE, 0x99,
|
|
0xD2, 0x0E, 0x94, 0x85, 0x98, 0x5C, 0x07, 0x56, 0xE6, 0x67, 0x41, 0xCC, 0x52, 0x00, 0x25, 0x54,
|
|
0x5F, 0x29, 0xFC, 0x21, 0x46, 0xC9, 0x5C, 0x7E, 0xF6, 0xA4, 0x4E, 0x63, 0x59, 0x89, 0xAF, 0x46,
|
|
0xD9, 0xCD, 0xD7, 0x33, 0x23, 0xF9, 0x79, 0x1F, 0x2A, 0xC0, 0xCA, 0x7A, 0x6F, 0x34, 0xE6, 0x03,
|
|
0x81, 0x39, 0x6F, 0xE0, 0xBF, 0x39, 0x77, 0xEE, 0x65, 0x19, 0xA0, 0x56, 0xC7, 0x6C, 0x81, 0x61,
|
|
0xD7, 0xE7, 0x4C, 0x8D, 0xED, 0x15, 0xAE, 0xE0, 0xC8, 0x4C, 0xF7, 0x7C, 0xD0, 0xE0, 0x7B, 0x74,
|
|
0x9D, 0x96, 0x38, 0xDE, 0xBD, 0x5C, 0xB9, 0x29, 0xB2, 0x37, 0x3A, 0xB1, 0x3B, 0x7C, 0x0C, 0x91,
|
|
0xD5, 0x43, 0x3B, 0xB8, 0x80, 0x19, 0x6F, 0x40, 0xC6, 0xF5, 0x10, 0xFB, 0xFA, 0x6E, 0xAD, 0x4E,
|
|
0xBE, 0x2A, 0x9F, 0x42, 0xC7, 0x9A, 0xE9, 0xD8, 0xE5, 0xE4, 0x63, 0x9D, 0x3D, 0x21, 0x18, 0x7F,
|
|
0xD9, 0xC9, 0xEC, 0xDF, 0x64, 0x6B, 0x82, 0xE7, 0x2E, 0xA2, 0x5C, 0x1E, 0x77, 0x44, 0x44, 0x39,
|
|
0xE9, 0xDC, 0xEB, 0x35, 0x66, 0x5B, 0xD1, 0xA2, 0x04, 0x0A, 0x64, 0x42, 0x56, 0xC3, 0x6C, 0xD2,
|
|
0xEE, 0x61, 0xA6, 0x28, 0x1F, 0x75, 0xAF, 0x7E, 0x08, 0x3B, 0x24, 0x0E, 0xCD, 0xCC, 0x08, 0xDF,
|
|
0x28, 0x94, 0x66, 0xDE, 0x21, 0x07, 0x37, 0x30, 0x19, 0x90, 0x85, 0xC7, 0x0D, 0xCA, 0xD1, 0x33,
|
|
0x19, 0xF3, 0xB3, 0xBB, 0x3B, 0x9E, 0xC0, 0xAD, 0x5A, 0xA7, 0xB0, 0xF2, 0x87, 0x6C, 0xC1, 0xE5,
|
|
0x82, 0x3A, 0x56, 0x66, 0x80, 0x06, 0xE4, 0x29, 0x2B, 0x5E, 0x0E, 0x54, 0xEB, 0x9F, 0x0F, 0x4A,
|
|
0x64, 0x67, 0x59, 0xC1, 0x40, 0x4D, 0x7B, 0x1B, 0x2E, 0xD0, 0x48, 0xF3, 0x2A, 0x8E, 0x36, 0xF6,
|
|
0x00, 0xB7, 0x04, 0xF4, 0x0B, 0xC0, 0xA0, 0x36, 0x43, 0x5C, 0x47, 0x13, 0x77, 0xA8, 0xEE, 0xBE,
|
|
0xD6, 0xA5, 0xE1, 0x62, 0xB4, 0xEC, 0xAA, 0x71, 0x8B, 0x9D, 0x34, 0x39, 0x40, 0x99, 0x30, 0xB8,
|
|
0xA8, 0xF1, 0xB8, 0xB1, 0x4B, 0x9E, 0x32, 0xFF, 0x68, 0x72, 0x78, 0x2A, 0x39, 0x4E, 0x36, 0x38,
|
|
0x77, 0x96, 0x93, 0xC5, 0x21, 0xE2, 0x13, 0x56, 0x7A, 0xF6, 0xBB, 0xEB, 0x51, 0xF5, 0x77, 0xD3,
|
|
0x84, 0xD1, 0xBA, 0xC4, 0xC7, 0x06, 0x64, 0x2B, 0xA2, 0x88, 0xE8, 0xC1, 0xB9, 0xF9, 0xAE, 0x5F,
|
|
0x50, 0x20, 0xB6, 0x13, 0x0E, 0x97, 0x7F, 0x73, 0x01, 0xC3, 0x27, 0x31, 0xE3, 0x09, 0xD3, 0xF0,
|
|
0x9C, 0x3F, 0x51, 0x56, 0x07, 0x61, 0xFC, 0x63, 0xF9, 0x86, 0xE0, 0x01, 0x80, 0x12, 0x1F, 0xDC,
|
|
0x68, 0x2C, 0x94, 0x73, 0x04, 0x73, 0xB5, 0x70, 0x2B, 0xEC, 0xBE, 0x34, 0x80, 0x3F, 0x0C, 0xB7,
|
|
0xF6, 0x24, 0xC6, 0x8F, 0x94, 0x18, 0xC3, 0x4E, 0x76, 0x54, 0xA8, 0x11, 0x15, 0xFF, 0x51, 0x56,
|
|
0xC8, 0xA3, 0x73, 0x0E, 0x8A, 0xDE, 0x7F, 0xF4, 0xFD, 0x5A, 0xC9, 0x1C, 0xAF, 0xFE, 0xE9, 0xCF,
|
|
0x9C, 0x66, 0x61, 0x96, 0xF5, 0x91, 0x81, 0x95, 0x20, 0xDA, 0x88, 0x1A, 0x00, 0x2A, 0x0C, 0x76,
|
|
0x76, 0x6B, 0x9C, 0x0C, 0x28, 0x40, 0xA3, 0xA7, 0x81, 0xF3, 0x8F, 0x11, 0xF9, 0xAF, 0x33, 0xE1,
|
|
0x96, 0xEF, 0x6A, 0x94, 0xB2, 0x36, 0xFE, 0xDF, 0x00, 0x01, 0xC8, 0x44, 0xCA, 0xF9, 0x18, 0xE4,
|
|
0x7C, 0x6E, 0x57, 0x94, 0x66, 0x01, 0xEA, 0x32, 0xBE, 0xA0, 0x5A, 0x3A, 0xE4, 0xB8, 0xB2, 0x94,
|
|
0xEA, 0xA5, 0x29, 0xB0, 0x54, 0x6E, 0x01, 0xD5, 0x1C, 0xAF, 0xAF, 0xB6, 0xFA, 0xD6, 0x3C, 0x47,
|
|
0xE2, 0x92, 0xEB, 0xCE, 0xCD, 0x89, 0x1C, 0x3D, 0xBC, 0x4A, 0x70, 0xBF, 0xFA, 0x82, 0x2E, 0x91,
|
|
0xA2, 0x72, 0xE6, 0x13, 0x62, 0xA0, 0x54, 0x1F, 0x7E, 0xCD, 0x86, 0x99, 0x18, 0x28, 0x41, 0x47,
|
|
0xAE, 0xC1, 0xA2, 0xE3, 0xE4, 0x40, 0x01, 0x6F, 0x84, 0xD7, 0x1A, 0xC9, 0xC3, 0x75, 0x6F, 0x7F,
|
|
0xC6, 0x3D, 0xE8, 0xE4, 0x64, 0x36, 0xBD, 0x64, 0x2E, 0x44, 0x95, 0x14, 0xAC, 0x57, 0xF0, 0x8D,
|
|
0xEA, 0xE2, 0xC2, 0xFB, 0x33, 0x8F, 0x60, 0x71, 0x1D, 0x31, 0xA0, 0x80, 0xC6, 0xF9, 0x3C, 0x07,
|
|
0x5C, 0xEE, 0x78, 0x4C, 0xE3, 0x97, 0x05, 0x4C, 0x32, 0xFA, 0x24, 0x50, 0x3F, 0xCB, 0x0F, 0xC1,
|
|
0x9D, 0xDD, 0x94, 0x3D, 0x43, 0xDC, 0x03, 0xEA, 0x8F, 0x3E, 0x4A, 0x0B, 0x8B, 0x77, 0x5F, 0xD1,
|
|
0x6E, 0x6C, 0xDE, 0x73, 0x66, 0x2B, 0xF4, 0x81, 0x94, 0xD9, 0x7B, 0x75, 0x58, 0xEB, 0x66, 0x8B,
|
|
0xD0, 0x9A, 0x60, 0xD2, 0x9B, 0x90, 0xB0, 0x83, 0xE3, 0xE8, 0x60, 0x92, 0x9A, 0x55, 0x9E, 0x84,
|
|
0x03, 0xA1, 0x62, 0x80, 0x75, 0x5A, 0x51, 0xA8, 0x5C, 0xC8, 0xE2, 0xAA, 0x80, 0x21, 0xBF, 0x91,
|
|
0x8A, 0x00, 0x6E, 0xE2, 0xC4, 0x14, 0x30, 0xE4, 0x20, 0x15, 0x29, 0x3F, 0x7C, 0xFD, 0xC2, 0xC8,
|
|
0x24, 0x74, 0x4C, 0x9C, 0x98, 0x8C, 0xE6, 0x6C, 0x90, 0xAE, 0xA0, 0x17, 0x3E, 0xD5, 0xE0, 0x7E,
|
|
0xD3, 0xF9, 0x05, 0x94, 0x44, 0xCF, 0x4B, 0xB4, 0x4E, 0xAF, 0xEE, 0x38, 0xB8, 0xD5, 0x93, 0x47,
|
|
0xD8, 0xCD, 0xE3, 0xEE, 0x58, 0x29, 0x79, 0x72, 0x3A, 0x75, 0xFE, 0xE5, 0x1A, 0x6D, 0x92, 0xF8,
|
|
0xB3, 0x6D, 0x6E, 0x10, 0xA5, 0x28, 0xC8, 0x9C, 0x76, 0x9D, 0xF7, 0xA5, 0xD6, 0x47, 0xD8, 0xA6,
|
|
0x27, 0x94, 0x70, 0x9F, 0x3C, 0x99, 0xD3, 0x65, 0x61, 0x04, 0x44, 0x3C, 0x9C, 0x52, 0x9D, 0xA7,
|
|
0x33, 0x42, 0xF2, 0x7F, 0x6E, 0x89, 0x71, 0x43, 0x9E, 0xC7, 0x8C, 0xAF, 0x5E, 0xBA, 0x5B, 0x90,
|
|
0x19, 0xB1, 0x3B, 0xD6, 0xCD, 0x44, 0xBC, 0xEB, 0x0E, 0x43, 0xBA, 0x43, 0x4D, 0xEC, 0xC9, 0x35
|
|
]
|
|
|
|
MDUV380_ENCODE_CIPHER:Final = [
|
|
0x00, 0xaa, 0x89, 0x89, 0x1f, 0x4b, 0xec, 0xcf, 0x42, 0x45, 0x14, 0x54, 0x00, 0x65, 0xeb, 0x66,
|
|
0x41, 0x7d, 0x4c, 0x88, 0x49, 0x5a, 0x21, 0x0d, 0xf2, 0xf5, 0xc8, 0xe6, 0x38, 0xed, 0xbc, 0xb9,
|
|
0xfb, 0x35, 0x71, 0x33, 0x01, 0x0a, 0x7f, 0x9e, 0x3b, 0x29, 0x03, 0xb6, 0x49, 0x3e, 0x42, 0xb8,
|
|
0x3f, 0x9f, 0x90, 0xbd, 0xaa, 0x3a, 0x71, 0x46, 0xce, 0xcd, 0xfd, 0x18, 0x32, 0x55, 0x89, 0x4a,
|
|
0x5f, 0xc8, 0x83, 0x9c, 0xe4, 0x06, 0x9e, 0x0a, 0x9d, 0x0d, 0x2f, 0xa1, 0x35, 0x6d, 0xd7, 0x92,
|
|
0xea, 0xfd, 0x63, 0x85, 0x90, 0xcb, 0xf0, 0x2f, 0xd9, 0x59, 0x53, 0x27, 0xd3, 0x06, 0xb8, 0xf5,
|
|
0xb2, 0xca, 0x88, 0x6c, 0xd0, 0x26, 0x91, 0x3b, 0xf2, 0x5b, 0x61, 0xbe, 0xcd, 0xdb, 0xf2, 0x1a,
|
|
0xc9, 0xfd, 0x8d, 0x88, 0x04, 0xf4, 0xe8, 0xf1, 0x9a, 0x02, 0x92, 0xbc, 0x24, 0xe9, 0x90, 0xe4,
|
|
0x7e, 0xa3, 0x49, 0x4d, 0xce, 0x52, 0x9f, 0x58, 0xc1, 0x7a, 0x5f, 0xb5, 0x18, 0x6e, 0xdb, 0x78,
|
|
0x64, 0x08, 0xd5, 0x6f, 0x0d, 0x9d, 0x9f, 0xb3, 0x99, 0x30, 0x81, 0x7e, 0x2b, 0xe6, 0x5b, 0x3c,
|
|
0x4a, 0xba, 0x8b, 0xe5, 0xe4, 0x72, 0x11, 0x89, 0x93, 0xd2, 0xf1, 0x2d, 0x1e, 0x0f, 0xd9, 0xd5,
|
|
0x43, 0x87, 0x04, 0xe2, 0xb4, 0xae, 0x5e, 0x9e, 0x5f, 0x4c, 0xe9, 0x16, 0xf2, 0xe6, 0x5f, 0x28,
|
|
0x9f, 0x79, 0x19, 0xdc, 0x1d, 0x6f, 0x2f, 0xf8, 0xef, 0xcb, 0xe1, 0xce, 0xe8, 0xa7, 0x36, 0x59,
|
|
0xef, 0xe0, 0xe2, 0x88, 0x00, 0x10, 0x6d, 0xda, 0x73, 0xbc, 0x92, 0x2b, 0x81, 0xcf, 0xe6, 0xce,
|
|
0x04, 0x47, 0xba, 0xdb, 0x7e, 0x2f, 0x41, 0xca, 0x5d, 0xcd, 0xf6, 0x41, 0x7d, 0x1c, 0x38, 0x2b,
|
|
0xef, 0x7d, 0x37, 0x0a, 0xf9, 0xa9, 0x14, 0x8e, 0x5d, 0xea, 0x44, 0x66, 0xde, 0x8b, 0x36, 0x56,
|
|
0x01, 0x8c, 0x35, 0x8a, 0x11, 0x9b, 0x8f, 0x2a, 0x65, 0x40, 0xf7, 0x2e, 0xe6, 0x58, 0x28, 0x74,
|
|
0xcb, 0xc4, 0xcb, 0x0f, 0xa7, 0x62, 0x9b, 0xe3, 0xa6, 0x3c, 0xc7, 0x6f, 0x13, 0x00, 0x97, 0xe9,
|
|
0x1e, 0xb1, 0x53, 0x90, 0xdd, 0x9b, 0x61, 0x3e, 0x90, 0x8c, 0xad, 0x3c, 0x29, 0x41, 0x4e, 0x5b,
|
|
0x0c, 0x1f, 0x66, 0x40, 0x13, 0x24, 0x49, 0x00, 0xd5, 0x1c, 0xe2, 0xed, 0x28, 0x18, 0x53, 0xaf,
|
|
0xe4, 0x1c, 0xdc, 0x96, 0xea, 0x18, 0xfe, 0x2e, 0x65, 0x19, 0xe0, 0x14, 0x50, 0xc1, 0xf1, 0x09,
|
|
0x39, 0xf5, 0xcf, 0x45, 0x44, 0xd5, 0x68, 0x0d, 0x72, 0xf1, 0x5f, 0x88, 0x23, 0xb9, 0xb1, 0xcf,
|
|
0xda, 0x36, 0x98, 0x43, 0x41, 0xf8, 0xaf, 0x23, 0x6d, 0x50, 0x57, 0x5e, 0x62, 0xbf, 0x5a, 0xa5,
|
|
0xda, 0xad, 0xcf, 0xc5, 0x42, 0x5e, 0x3e, 0x34, 0x06, 0x23, 0x04, 0xe9, 0x0e, 0xcd, 0xf8, 0x71,
|
|
0x89, 0x67, 0x4e, 0x40, 0xe9, 0x25, 0xbc, 0x45, 0x2e, 0x97, 0xdc, 0xc1, 0x68, 0x22, 0xd2, 0x58,
|
|
0x77, 0xb1, 0x2e, 0x69, 0x16, 0xa8, 0x14, 0x9b, 0x18, 0x1a, 0x9a, 0xb8, 0xf0, 0x3b, 0x71, 0xbf,
|
|
0x77, 0x18, 0xc8, 0x34, 0xea, 0x85, 0x6d, 0xbb, 0x32, 0x57, 0x35, 0xe5, 0x69, 0xd4, 0x9f, 0x4a,
|
|
0x99, 0x68, 0xb4, 0xd8, 0xc7, 0x9a, 0x31, 0x6a, 0x30, 0x3d, 0xe8, 0x9c, 0xd2, 0xeb, 0x64, 0xde,
|
|
0x2e, 0xaf, 0xcc, 0xc8, 0x4d, 0x02, 0x09, 0xae, 0x01, 0xf9, 0x2b, 0x73, 0x6d, 0xbc, 0x09, 0xa2,
|
|
0xc7, 0x3a, 0x28, 0xba, 0x5d, 0x1b, 0xdf, 0xca, 0xd6, 0xf6, 0xb8, 0x3e, 0xbb, 0xc5, 0x18, 0xf9,
|
|
0x36, 0x96, 0x23, 0xa4, 0x19, 0x83, 0xda, 0x45, 0x21, 0xe3, 0x86, 0x13, 0x7d, 0xc2, 0x5a, 0x89,
|
|
0x8a, 0x8f, 0x54, 0xb9, 0xe1, 0x15, 0x64, 0xe3, 0x93, 0xad, 0xd0, 0x46, 0xb3, 0xb1, 0xd7, 0x36,
|
|
0x15, 0x33, 0x95, 0x6f, 0x56, 0xef, 0x26, 0xa9, 0x1c, 0x7f, 0x0e, 0x6c, 0x9f, 0xce, 0xd8, 0x26,
|
|
0x69, 0xcf, 0xfe, 0x7b, 0x5a, 0x6f, 0x09, 0xdc, 0xee, 0xc8, 0xf9, 0x5b, 0xc3, 0x97, 0xe7, 0xbd,
|
|
0x55, 0xf0, 0xe9, 0xd1, 0x0c, 0x30, 0x36, 0x01, 0x7a, 0x34, 0x8b, 0x27, 0xdd, 0xc8, 0xcd, 0xa2,
|
|
0xec, 0x62, 0xef, 0xa8, 0xd0, 0x11, 0x16, 0xdd, 0x70, 0xb0, 0xfb, 0x25, 0xf1, 0x5f, 0x91, 0xb7,
|
|
0x7d, 0x34, 0xe9, 0x74, 0x44, 0x2d, 0x52, 0x76, 0xc1, 0x69, 0xc4, 0xeb, 0x3f, 0x98, 0x7f, 0x24,
|
|
0x9b, 0xb1, 0xef, 0xe9, 0x4b, 0xe3, 0xd3, 0x10, 0x9f, 0xcd, 0x9e, 0x4e, 0x47, 0xf1, 0x1d, 0x4c,
|
|
0x16, 0x66, 0x5b, 0xfd, 0x06, 0xce, 0xc2, 0x30, 0x7b, 0x88, 0x82, 0x61, 0xcc, 0x27, 0x37, 0xd5,
|
|
0xff, 0x22, 0xc6, 0xe6, 0xd4, 0xcc, 0x87, 0x9b, 0x06, 0x87, 0xaa, 0x7b, 0xcd, 0x35, 0xd3, 0xa3,
|
|
0xa7, 0xf0, 0x08, 0x17, 0x58, 0xfb, 0xcd, 0x56, 0x2f, 0xf8, 0x8d, 0x31, 0x8c, 0x5b, 0x3c, 0xdc,
|
|
0x9f, 0x1e, 0x3b, 0x46, 0x72, 0xb7, 0x7c, 0xa6, 0x2a, 0x47, 0xe6, 0x56, 0x8a, 0x14, 0xfb, 0xe5,
|
|
0xb8, 0x39, 0xb8, 0x68, 0x44, 0x9c, 0xbc, 0x10, 0x66, 0x21, 0xad, 0x02, 0x87, 0x1d, 0xd8, 0x62,
|
|
0x03, 0x0e, 0x17, 0xb1, 0x2e, 0x89, 0xf8, 0x5a, 0x95, 0x73, 0x1b, 0x87, 0x86, 0x74, 0xdc, 0x39,
|
|
0xd2, 0xa9, 0x32, 0x98, 0xd1, 0x99, 0xd7, 0x88, 0xa7, 0x6b, 0xaa, 0x7c, 0xc6, 0x56, 0x51, 0x8f,
|
|
0xb4, 0x58, 0x22, 0xd1, 0x0f, 0x2b, 0x44, 0xde, 0xce, 0x75, 0x11, 0xb6, 0xc9, 0x3f, 0xbf, 0xc8,
|
|
0x7c, 0xa8, 0x40, 0x50, 0x07, 0xda, 0x66, 0xe3, 0x7a, 0x3e, 0x4b, 0x48, 0x50, 0xec, 0xf0, 0x8a,
|
|
0x39, 0x66, 0x24, 0x4b, 0x1d, 0x85, 0xa8, 0x5b, 0x5d, 0xb3, 0x90, 0x8a, 0x5c, 0x5b, 0xec, 0xba,
|
|
0x3e, 0x9e, 0xa8, 0x38, 0xef, 0x48, 0xb1, 0x4c, 0x67, 0x02, 0x59, 0x0e, 0x2d, 0xc9, 0xfd, 0x7c,
|
|
0x1a, 0x9e, 0xe5, 0xca, 0x60, 0x7f, 0x6b, 0xf9, 0xcb, 0x97, 0x60, 0xab, 0x46, 0xb2, 0xab, 0x36,
|
|
0xa0, 0xf3, 0x33, 0xf7, 0x90, 0xc9, 0x00, 0xe9, 0xf7, 0x1f, 0x9d, 0x75, 0x66, 0xd3, 0xc0, 0x8c,
|
|
0xe0, 0x6a, 0x2c, 0xf4, 0xe1, 0x02, 0xd7, 0xdf, 0x9e, 0x87, 0x48, 0xc2, 0x8f, 0x2a, 0x44, 0x64,
|
|
0x2b, 0x0f, 0xa9, 0x36, 0xf3, 0x46, 0x9a, 0xe2, 0xb1, 0xfd, 0xdc, 0x26, 0x02, 0xf4, 0x80, 0xe3,
|
|
0x12, 0x31, 0xc3, 0x71, 0xa7, 0xf4, 0x32, 0x36, 0x61, 0xed, 0x12, 0x77, 0x40, 0xad, 0xfe, 0x6d,
|
|
0x66, 0x5b, 0xd2, 0x9c, 0x1e, 0xa8, 0xc8, 0x60, 0x1e, 0x04, 0xe1, 0xc9, 0x09, 0x13, 0x87, 0xa8,
|
|
0x38, 0x5a, 0x70, 0xea, 0xba, 0x3f, 0xc5, 0x25, 0x99, 0x30, 0x84, 0x71, 0x5f, 0x22, 0x23, 0x79,
|
|
0xd9, 0x3d, 0x76, 0xd2, 0x1b, 0xd5, 0xd2, 0x8b, 0xc4, 0x9d, 0x73, 0x05, 0x84, 0x17, 0x1b, 0x04,
|
|
0xdb, 0x4f, 0xfc, 0x07, 0x23, 0xc9, 0xd8, 0xd5, 0xd0, 0xb8, 0x67, 0x59, 0xf7, 0x70, 0xf9, 0xaf,
|
|
0x0d, 0x1e, 0x5c, 0x7f, 0xf2, 0xb7, 0x00, 0x8a, 0x2d, 0x2e, 0x59, 0x82, 0x7a, 0xea, 0x85, 0x1f,
|
|
0x82, 0x77, 0x2f, 0x6f, 0xe9, 0x7c, 0xb3, 0x6e, 0x8d, 0xed, 0x82, 0xd6, 0x0d, 0x81, 0xc9, 0x38,
|
|
0x89, 0x67, 0x4d, 0x4c, 0xa9, 0x35, 0x99, 0x86, 0xe1, 0x21, 0x5c, 0xe9, 0xf3, 0x73, 0x0d, 0x20,
|
|
0xb5, 0x3a, 0xd0, 0xcb, 0x14, 0x3e, 0x9d, 0x17, 0x59, 0x37, 0x9f, 0x91, 0xab, 0x3c, 0xda, 0x3c,
|
|
0xd5, 0x7e, 0x11, 0xe0, 0x4a, 0x36, 0xe7, 0xa6, 0x66, 0xdc, 0x44, 0xe2, 0xf7, 0x9a, 0xfa, 0x30,
|
|
0xfc, 0x00, 0xa9, 0xc2, 0xad, 0xf9, 0xe0, 0xf8, 0xbb, 0xfe, 0x84, 0x31, 0xd8, 0x89, 0x76, 0xe2
|
|
]
|
|
|
|
MD380_ENCODE_CIPHER:Final = [
|
|
0x2e, 0xdf, 0x40, 0xb5, 0xbd, 0xda, 0x91, 0x35, 0x21, 0x42, 0xe3, 0xe2, 0x6d, 0xa9, 0x0b, 0x90,
|
|
0x31, 0x30, 0x3a, 0xfa, 0x4f, 0x05, 0x74, 0x64, 0x0a, 0x29, 0x44, 0x7e, 0x60, 0x77, 0xad, 0x8c,
|
|
0x9a, 0xe2, 0x63, 0xc4, 0x21, 0xfe, 0x3c, 0xf7, 0x93, 0xc2, 0xe1, 0x74, 0x16, 0x8c, 0xc9, 0x2a,
|
|
0xed, 0x65, 0x68, 0x0c, 0x49, 0x86, 0xa3, 0xba, 0x61, 0x1c, 0x88, 0x5d, 0xc4, 0x49, 0x3c, 0xd2,
|
|
0xee, 0x6b, 0x34, 0x0c, 0x1a, 0xa0, 0xa8, 0xb3, 0x58, 0x8a, 0x45, 0x11, 0xdf, 0x4f, 0x23, 0x2f,
|
|
0xa4, 0xe4, 0xf6, 0x3b, 0x2c, 0x8c, 0x88, 0x2d, 0x9e, 0x9b, 0x67, 0xab, 0x1c, 0x80, 0xda, 0x29,
|
|
0x53, 0x02, 0x1a, 0x54, 0x51, 0xca, 0xbf, 0xb1, 0x97, 0x22, 0x79, 0x81, 0x70, 0xfc, 0x00, 0xe9,
|
|
0x81, 0x36, 0x4e, 0x4f, 0xa0, 0x1c, 0x0b, 0x07, 0xea, 0x2f, 0x49, 0x2f, 0x0f, 0x25, 0x71, 0xd7,
|
|
0xf1, 0x30, 0x7d, 0x66, 0x6e, 0x83, 0x68, 0x38, 0x79, 0x13, 0xe3, 0x8c, 0x70, 0x9a, 0x4a, 0x9e,
|
|
0xa9, 0xe2, 0xd6, 0x10, 0x4f, 0x40, 0x14, 0x8e, 0x6c, 0x5e, 0x96, 0xb2, 0x46, 0x3e, 0xe8, 0x25,
|
|
0xef, 0x7c, 0xc5, 0x08, 0x18, 0xd4, 0x8b, 0x92, 0x26, 0xe3, 0xed, 0xfa, 0x88, 0x32, 0xe8, 0x97,
|
|
0x47, 0x70, 0xf8, 0x46, 0xde, 0xff, 0x8b, 0x0c, 0x4d, 0xb3, 0xb6, 0xfc, 0x69, 0xd6, 0x27, 0x5b,
|
|
0x76, 0x6f, 0x5b, 0x03, 0xf7, 0xc3, 0x11, 0x05, 0xc5, 0x1d, 0xfe, 0x92, 0x5f, 0xcb, 0xc2, 0x1c,
|
|
0x81, 0x69, 0x1b, 0xb8, 0xf8, 0x62, 0x58, 0xc7, 0xb4, 0xb3, 0x11, 0xd5, 0x1f, 0xf2, 0x16, 0xc1,
|
|
0xad, 0x8f, 0xa5, 0x1e, 0xb4, 0x5b, 0xe0, 0xda, 0x7f, 0x46, 0x7d, 0x1d, 0x9e, 0x6d, 0xc0, 0x74,
|
|
0x7f, 0x54, 0xa6, 0x2f, 0x43, 0x6f, 0x64, 0x08, 0xca, 0xe8, 0x0f, 0x05, 0x10, 0x9c, 0x9d, 0x9f,
|
|
0xbd, 0x67, 0x0c, 0x23, 0xf7, 0xa1, 0xe1, 0x59, 0x7b, 0xe8, 0xd4, 0x64, 0xec, 0x20, 0xca, 0xe9,
|
|
0x6a, 0xb9, 0x03, 0x73, 0x67, 0x30, 0x95, 0x16, 0xb6, 0xd9, 0x19, 0x53, 0xe5, 0xdb, 0xa4, 0x3c,
|
|
0xcd, 0x7c, 0xf9, 0xd8, 0x67, 0x9f, 0xfc, 0xc9, 0xe2, 0x8a, 0x6a, 0x2c, 0xf2, 0xed, 0xc8, 0xc1,
|
|
0x6a, 0x20, 0x99, 0x4c, 0x0d, 0xad, 0xd4, 0x3b, 0xa1, 0x0e, 0x95, 0x88, 0x46, 0xb8, 0x13, 0xe1,
|
|
0x06, 0x58, 0xd2, 0x07, 0xad, 0x5c, 0x1a, 0x74, 0xdb, 0xb5, 0xa7, 0x40, 0x57, 0xdb, 0xa2, 0x45,
|
|
0xa6, 0x12, 0xd0, 0x82, 0xdd, 0xed, 0x0a, 0xbd, 0xb3, 0x10, 0xed, 0x6c, 0xda, 0x39, 0xd2, 0xd6,
|
|
0x90, 0x82, 0x00, 0x76, 0x71, 0xe0, 0x21, 0xa0, 0x8f, 0xf0, 0xf3, 0x67, 0xc4, 0xf3, 0x40, 0xbd,
|
|
0x47, 0x16, 0x10, 0xdc, 0x7e, 0xf8, 0x1d, 0xe5, 0x13, 0x66, 0x87, 0xc7, 0x4a, 0x69, 0xc9, 0x63,
|
|
0x92, 0x82, 0xec, 0xee, 0x5a, 0x34, 0xfb, 0x96, 0x25, 0xc3, 0xb6, 0x68, 0xe1, 0x3c, 0x8a, 0x71,
|
|
0x74, 0xb5, 0xc1, 0x23, 0x99, 0xd6, 0xf7, 0xfb, 0xea, 0x98, 0xcd, 0x61, 0x3d, 0x4d, 0xe1, 0xd0,
|
|
0x34, 0xe1, 0xfd, 0x36, 0x10, 0x5f, 0x8e, 0x9e, 0xc6, 0xb6, 0x58, 0x0c, 0x55, 0xbe, 0x69, 0xa8,
|
|
0x56, 0x76, 0x4b, 0x1f, 0xd5, 0x90, 0x7e, 0x47, 0x5f, 0x2f, 0x25, 0x02, 0x5c, 0xef, 0x00, 0x64,
|
|
0xa0, 0x26, 0x9a, 0x18, 0x3c, 0x69, 0xc4, 0xff, 0x9a, 0x52, 0x41, 0x1b, 0xc9, 0x81, 0xc3, 0xac,
|
|
0x15, 0xe1, 0x17, 0x98, 0xdb, 0x2c, 0x9c, 0x10, 0x9b, 0xb2, 0xf9, 0x71, 0x4f, 0x56, 0x0f, 0x68,
|
|
0xfb, 0xd9, 0x2d, 0x5a, 0x86, 0x5b, 0x83, 0x03, 0xc8, 0x1e, 0xda, 0x5d, 0xe4, 0x8e, 0x82, 0xc3,
|
|
0xd8, 0x7e, 0x8b, 0x56, 0x52, 0xb5, 0x38, 0xa0, 0xc6, 0xa9, 0xb0, 0x77, 0xbd, 0x8a, 0xf7, 0x24,
|
|
0x70, 0x82, 0x1d, 0xc5, 0x95, 0x3c, 0xb5, 0xf0, 0x79, 0xa3, 0x89, 0x99, 0x4f, 0xec, 0x8c, 0x36,
|
|
0xc7, 0xd6, 0x10, 0x20, 0xe3, 0x30, 0x39, 0x3d, 0x07, 0x9c, 0xb2, 0xdc, 0x4f, 0x94, 0x9e, 0xe0,
|
|
0x24, 0xaa, 0xd2, 0x21, 0x12, 0x14, 0x41, 0x0f, 0xd4, 0x67, 0xb7, 0x99, 0xb1, 0xa3, 0xcb, 0x4d,
|
|
0x0c, 0x70, 0x0f, 0xc0, 0x36, 0xa7, 0x89, 0x30, 0x86, 0x14, 0x67, 0x68, 0xac, 0x7b, 0xee, 0xe4,
|
|
0x42, 0xd8, 0xb4, 0x36, 0xa4, 0xeb, 0x0f, 0xa8, 0x02, 0xf4, 0xcd, 0x23, 0xb3, 0xbc, 0x25, 0x4f,
|
|
0xcc, 0xd4, 0xee, 0xfc, 0xf2, 0x21, 0x0f, 0xc1, 0x6c, 0x99, 0x37, 0xe2, 0x7c, 0x47, 0xce, 0x77,
|
|
0xf0, 0x95, 0x2b, 0xcb, 0xf4, 0xca, 0x07, 0x03, 0x2a, 0xd2, 0x31, 0x00, 0xfd, 0x3e, 0x84, 0x86,
|
|
0x32, 0x8b, 0x17, 0x9d, 0xbf, 0xa7, 0xb3, 0x37, 0xe1, 0xb1, 0x8a, 0x14, 0x69, 0x00, 0x25, 0xe3,
|
|
0x56, 0x68, 0x9f, 0xaa, 0xa9, 0xb8, 0x11, 0x67, 0x75, 0x87, 0x4d, 0xf8, 0x36, 0x31, 0xcf, 0x38,
|
|
0x63, 0x1c, 0xf0, 0x6b, 0x47, 0x40, 0x5d, 0xdc, 0x0c, 0xe6, 0xc8, 0xc4, 0x19, 0xaf, 0xdd, 0x6e,
|
|
0x9e, 0xd9, 0x78, 0x99, 0x6c, 0xbe, 0x15, 0x1e, 0x0b, 0x9d, 0x88, 0xd2, 0x06, 0x9d, 0xee, 0xae,
|
|
0x8a, 0x0f, 0xe3, 0x2d, 0x2f, 0xf4, 0xf5, 0xf6, 0x16, 0xbf, 0x59, 0xbb, 0x34, 0x5c, 0xdd, 0x61,
|
|
0xed, 0x70, 0x1e, 0x61, 0xe5, 0xe3, 0xfb, 0x6e, 0x13, 0x9c, 0x49, 0x58, 0x17, 0x8b, 0xc8, 0x30,
|
|
0xcd, 0xed, 0x56, 0xad, 0x22, 0xcb, 0x63, 0xce, 0x26, 0xc4, 0xa5, 0xc1, 0x63, 0x0d, 0x0d, 0x04,
|
|
0x6e, 0xb6, 0xf9, 0xca, 0xbb, 0x2f, 0xab, 0xa0, 0xb5, 0x0a, 0xfa, 0x50, 0x0e, 0x02, 0x47, 0x05,
|
|
0x54, 0x3d, 0xb3, 0xb1, 0xc6, 0xce, 0x8f, 0xac, 0x65, 0x7e, 0x15, 0x9e, 0x4e, 0xcc, 0x55, 0x9e,
|
|
0x46, 0x32, 0x71, 0x9b, 0x97, 0xaa, 0x0d, 0xfb, 0x1b, 0x71, 0x02, 0x83, 0x96, 0x0b, 0x52, 0x77,
|
|
0x48, 0x87, 0x61, 0x02, 0xc3, 0x04, 0x62, 0xd7, 0xfb, 0x74, 0x0f, 0x19, 0x9c, 0xa0, 0x9d, 0x79,
|
|
0xa0, 0x6d, 0xef, 0x9e, 0x20, 0x5d, 0x0a, 0xc9, 0x6a, 0x58, 0xc9, 0xb9, 0x55, 0xad, 0xd1, 0xcc,
|
|
0xd1, 0x54, 0xc8, 0x68, 0xc2, 0x76, 0xc2, 0x99, 0x0f, 0x2e, 0xfc, 0xfb, 0xf5, 0x92, 0xcd, 0xdb,
|
|
0xa2, 0xed, 0xd9, 0x99, 0xff, 0x4f, 0x88, 0x50, 0xcd, 0x48, 0xb7, 0xb9, 0xf3, 0xf0, 0xad, 0x4d,
|
|
0x16, 0x2a, 0x50, 0xaa, 0x6b, 0x2a, 0x98, 0x38, 0xc9, 0x35, 0x45, 0x0c, 0x03, 0xa8, 0xcd, 0x0d,
|
|
0x74, 0x3c, 0x99, 0x55, 0xdb, 0x88, 0x70, 0xda, 0x6a, 0xc8, 0x34, 0x4d, 0x19, 0xdc, 0xcc, 0x42,
|
|
0x40, 0x94, 0x61, 0x92, 0x65, 0x2a, 0xcd, 0xfd, 0x52, 0x10, 0x50, 0x14, 0x6b, 0xec, 0x85, 0x57,
|
|
0x3f, 0xe2, 0x95, 0x9a, 0x5d, 0x11, 0xab, 0xad, 0x69, 0x60, 0xa8, 0x3b, 0x6f, 0x7a, 0x17, 0xf3,
|
|
0x76, 0x17, 0x63, 0xe6, 0x59, 0x7e, 0x47, 0x30, 0xd2, 0x47, 0x87, 0xdb, 0xd8, 0x66, 0xde, 0x00,
|
|
0x2b, 0x65, 0x37, 0x2f, 0x2d, 0xf1, 0x20, 0x11, 0xf3, 0x98, 0x7b, 0x4c, 0x9c, 0xd1, 0x76, 0xa7,
|
|
0xe1, 0x3d, 0xbe, 0x6f, 0xee, 0x2c, 0xf0, 0x19, 0x70, 0x63, 0x51, 0x28, 0xf0, 0x1d, 0xbe, 0x52,
|
|
0x5f, 0x4f, 0xe6, 0xde, 0xf2, 0x30, 0xb6, 0x50, 0x30, 0xf9, 0x15, 0x48, 0x49, 0xe9, 0xd2, 0xa8,
|
|
0xa9, 0x8d, 0xda, 0xf5, 0xcd, 0x3e, 0xaf, 0x00, 0x55, 0xeb, 0x15, 0xc5, 0x5b, 0x19, 0x0f, 0x93,
|
|
0x04, 0x27, 0x09, 0x6d, 0x54, 0xd7, 0x57, 0xb1, 0x47, 0x0a, 0xde, 0xf7, 0x1d, 0xcb, 0x11, 0x3c,
|
|
0xf5, 0x8f, 0x20, 0x40, 0x9d, 0xbb, 0x6b, 0x2c, 0xa9, 0x67, 0x3d, 0x78, 0xc2, 0x62, 0xb7, 0x0c
|
|
]
|
|
|
|
DM1701_ENCODE_CIPHER:Final = [
|
|
0x3a, 0x04, 0x74, 0xad, 0x90, 0xae, 0xb3, 0x78, 0xde, 0xfa, 0x73, 0x8d, 0xdc, 0x8c, 0x53, 0x67,
|
|
0x27, 0x61, 0xf3, 0x6f, 0x95, 0xc8, 0xf1, 0x1f, 0xc5, 0xad, 0x17, 0x68, 0xfb, 0x1d, 0xd2, 0x51,
|
|
0x2b, 0x07, 0xe6, 0xe2, 0x54, 0x40, 0x61, 0x40, 0x10, 0xca, 0xcd, 0x19, 0x68, 0x56, 0xaa, 0x42,
|
|
0xec, 0x07, 0x1c, 0x9f, 0x04, 0x79, 0xe0, 0x44, 0x81, 0x02, 0x84, 0xd9, 0x77, 0x38, 0xd8, 0x43,
|
|
0x4f, 0xb3, 0xa0, 0x81, 0x18, 0x14, 0x8b, 0xd3, 0x1e, 0x45, 0x69, 0x22, 0xbe, 0x03, 0x98, 0x9c,
|
|
0x78, 0x9a, 0xbf, 0x9f, 0x46, 0xf0, 0xbf, 0xd8, 0x2c, 0xc5, 0xe7, 0xac, 0x11, 0x39, 0x68, 0xd6,
|
|
0xcd, 0x8f, 0x08, 0x52, 0x83, 0x30, 0x1a, 0x7a, 0x31, 0xf3, 0xad, 0x70, 0x85, 0x9b, 0x04, 0xbb,
|
|
0xf3, 0xa2, 0x46, 0x35, 0x04, 0x35, 0x77, 0x24, 0xf1, 0x7f, 0xa7, 0xa7, 0x70, 0x2a, 0x69, 0x54,
|
|
0xce, 0x23, 0x87, 0x1f, 0x3e, 0x9e, 0xf4, 0x7d, 0x71, 0x5b, 0x02, 0xca, 0x66, 0x27, 0xd5, 0xe8,
|
|
0x84, 0xa5, 0x18, 0x2a, 0xe6, 0x4e, 0xee, 0x70, 0xf6, 0xb7, 0x2c, 0x93, 0x3d, 0x12, 0xc5, 0x03,
|
|
0x79, 0xf8, 0x86, 0xae, 0xf0, 0x66, 0x03, 0x24, 0x05, 0x05, 0xd1, 0xf9, 0x09, 0xae, 0xf5, 0x6b,
|
|
0x53, 0x2d, 0x9d, 0x45, 0x93, 0x45, 0x0e, 0x04, 0x63, 0xf5, 0xde, 0x37, 0x1f, 0xfa, 0x63, 0x2c,
|
|
0xf7, 0x95, 0x6b, 0xc8, 0x42, 0x8e, 0x2d, 0xb7, 0x15, 0x79, 0x80, 0xc6, 0x15, 0x38, 0x4b, 0x8c,
|
|
0x89, 0xc1, 0x3d, 0x50, 0xb4, 0x22, 0xbe, 0x27, 0x61, 0xc2, 0x25, 0x5d, 0xbf, 0xe9, 0x2b, 0x16,
|
|
0x6f, 0x82, 0x9f, 0x35, 0xdc, 0x20, 0x5c, 0x7d, 0xcb, 0x40, 0x79, 0xf6, 0x33, 0xce, 0xbf, 0x93,
|
|
0x4e, 0xea, 0x60, 0x11, 0xf0, 0xeb, 0xe5, 0x22, 0x18, 0xa4, 0x69, 0xcb, 0xc4, 0xe7, 0x05, 0x0b,
|
|
0x0a, 0x48, 0x8b, 0xbd, 0x65, 0x23, 0x77, 0xbf, 0x4d, 0xe1, 0x22, 0x54, 0x0a, 0x76, 0x39, 0xc7,
|
|
0xc9, 0x2e, 0x6e, 0x52, 0xf0, 0xaa, 0x6d, 0x3d, 0xaf, 0x25, 0x12, 0x4a, 0xd7, 0xfd, 0xd9, 0x51,
|
|
0xf0, 0x6e, 0x96, 0x28, 0x86, 0xa0, 0x66, 0xc5, 0xc3, 0xe4, 0xe5, 0xa7, 0x43, 0x3a, 0xa1, 0x72,
|
|
0x23, 0x18, 0xcf, 0xd9, 0x5b, 0x66, 0x3d, 0xc0, 0x4e, 0xcd, 0x88, 0xa2, 0xa0, 0x31, 0x8f, 0x31,
|
|
0x48, 0x7c, 0x27, 0x3d, 0xe6, 0x9e, 0x11, 0xd7, 0x56, 0xd2, 0x29, 0xb6, 0x85, 0x22, 0xdf, 0xda,
|
|
0x83, 0x2d, 0xeb, 0x6e, 0xda, 0x28, 0x3d, 0xf3, 0x1f, 0x23, 0x33, 0x9b, 0xc6, 0x8d, 0x0f, 0xf3,
|
|
0x3a, 0xfb, 0xa8, 0xc5, 0x2e, 0x25, 0x60, 0x3d, 0x2d, 0x31, 0x55, 0x4a, 0x79, 0x35, 0xdc, 0x47,
|
|
0x12, 0xf7, 0x2b, 0xdb, 0x15, 0xf7, 0x55, 0x1e, 0x47, 0xaf, 0x7c, 0xfd, 0xf2, 0x19, 0x41, 0xdf,
|
|
0xf0, 0x72, 0x80, 0x89, 0x05, 0x3e, 0x3b, 0x3e, 0x72, 0x8c, 0xd3, 0x2b, 0xc6, 0x7b, 0x7e, 0x03,
|
|
0xf8, 0xfd, 0xf5, 0xe7, 0xb3, 0xdb, 0x6d, 0x88, 0xf1, 0xf9, 0xc9, 0x8f, 0xcb, 0xdc, 0x0e, 0x3d,
|
|
0x8f, 0x69, 0x17, 0x4e, 0x14, 0xef, 0x8a, 0x24, 0x4a, 0x68, 0x0a, 0x21, 0x15, 0xfc, 0xae, 0x55,
|
|
0x5c, 0xc7, 0xb2, 0x59, 0x5d, 0xdc, 0x6d, 0x7a, 0x43, 0x8a, 0x83, 0x1a, 0xfa, 0xde, 0x5c, 0x54,
|
|
0x42, 0x68, 0xd5, 0xdf, 0x02, 0x42, 0x35, 0x35, 0xdf, 0x4f, 0x62, 0xf4, 0x0e, 0xc1, 0x55, 0x84,
|
|
0x66, 0xde, 0xcb, 0xfa, 0xba, 0x03, 0x3d, 0x3c, 0x65, 0xe9, 0x13, 0x66, 0x26, 0x27, 0x15, 0x6d,
|
|
0x2f, 0xf8, 0x22, 0x03, 0x78, 0x3f, 0x24, 0xba, 0x59, 0xc8, 0x43, 0x6b, 0x58, 0xd1, 0x59, 0xd9,
|
|
0x40, 0xc9, 0xa6, 0x92, 0x73, 0x57, 0xc6, 0x16, 0x80, 0x9e, 0xdf, 0x3b, 0xf8, 0xc0, 0x1f, 0xd0,
|
|
0x7e, 0xa0, 0x66, 0x81, 0x1e, 0xed, 0x3f, 0xfa, 0xe0, 0x5c, 0x15, 0x50, 0x9c, 0x34, 0xa4, 0x9c,
|
|
0x0f, 0x10, 0xad, 0xe9, 0x2f, 0xe0, 0xee, 0x50, 0xbc, 0x32, 0x51, 0x61, 0x18, 0xb0, 0x64, 0xc5,
|
|
0x58, 0xe9, 0x09, 0x22, 0x9b, 0x54, 0x6f, 0x3f, 0x9a, 0x91, 0x40, 0x69, 0x81, 0xf3, 0x1c, 0x15,
|
|
0xfe, 0x3c, 0x47, 0xc6, 0x97, 0xa7, 0x9e, 0x31, 0x40, 0x2c, 0xd0, 0x9f, 0x2d, 0xff, 0xca, 0x94,
|
|
0xe5, 0x5a, 0x73, 0xae, 0x98, 0x7c, 0x9a, 0xcf, 0xb2, 0xf2, 0x2c, 0x7f, 0xb0, 0x15, 0xab, 0x8b,
|
|
0x32, 0xd4, 0xdb, 0xf2, 0x52, 0xb3, 0xbf, 0x02, 0x35, 0x14, 0xc3, 0xbf, 0xdf, 0xb5, 0x3b, 0x84,
|
|
0x4c, 0x7b, 0x0c, 0xed, 0xbc, 0x6e, 0xa9, 0xf3, 0x4e, 0x04, 0x42, 0x59, 0xd0, 0xa2, 0x38, 0x48,
|
|
0xd6, 0x60, 0xd3, 0x36, 0x09, 0x0d, 0x37, 0x0c, 0xc2, 0x73, 0x94, 0x87, 0xd8, 0xdb, 0x9e, 0xde,
|
|
0xb6, 0xd4, 0x3d, 0xa6, 0xb0, 0x31, 0x85, 0xf3, 0x97, 0x51, 0xe8, 0xc1, 0x8a, 0xa3, 0xaa, 0x92,
|
|
0x10, 0x68, 0x96, 0x58, 0x64, 0xbb, 0xf0, 0x94, 0x10, 0xcf, 0xaa, 0xc0, 0xbd, 0x79, 0xda, 0xeb,
|
|
0x4a, 0xee, 0x6c, 0xa3, 0x1b, 0xcd, 0x14, 0x17, 0xb4, 0x60, 0x87, 0x7d, 0x86, 0x1f, 0xeb, 0xb2,
|
|
0x08, 0x75, 0x8c, 0x20, 0x0a, 0xc7, 0xd0, 0xe5, 0x47, 0xb3, 0x6d, 0x32, 0x39, 0x95, 0xd9, 0xf0,
|
|
0x31, 0x50, 0x03, 0xaa, 0xa6, 0x4b, 0x40, 0xa7, 0xcd, 0xb9, 0x88, 0x56, 0x6b, 0x1e, 0xe2, 0xf0,
|
|
0xe8, 0x0e, 0x1d, 0x58, 0xa4, 0x38, 0xc1, 0x46, 0x8e, 0xa4, 0x45, 0xa4, 0xf2, 0x39, 0x82, 0x38,
|
|
0x92, 0x82, 0x68, 0x84, 0xf9, 0xb2, 0xf0, 0xea, 0x0c, 0xe5, 0x51, 0x14, 0xe2, 0xa8, 0x77, 0x93,
|
|
0xd5, 0xbc, 0xb1, 0xc6, 0xd9, 0x17, 0xaa, 0xfe, 0x0d, 0x2c, 0x9a, 0xdf, 0x90, 0x6c, 0xbd, 0x0a,
|
|
0x96, 0x0d, 0x05, 0xf9, 0xbb, 0x0a, 0x0c, 0x29, 0x97, 0x6b, 0x4c, 0x7f, 0x92, 0xc6, 0x92, 0xe5,
|
|
0xf9, 0x06, 0xb0, 0x34, 0x52, 0x6b, 0x72, 0x56, 0xed, 0xd2, 0xd4, 0xac, 0xbc, 0x37, 0x72, 0xad,
|
|
0x64, 0x78, 0x40, 0xd0, 0x94, 0x5b, 0x7b, 0xac, 0x96, 0xd3, 0xe0, 0x5e, 0x24, 0x7f, 0x1b, 0x2c,
|
|
0x7c, 0x74, 0x82, 0x68, 0xb7, 0x3c, 0x03, 0x96, 0x56, 0x1e, 0x5b, 0xd1, 0x1e, 0xa0, 0x89, 0x6a,
|
|
0x26, 0x4b, 0x83, 0xd3, 0x2e, 0xae, 0x27, 0xbb, 0x32, 0xa6, 0x74, 0x7b, 0x3f, 0xdc, 0xfa, 0xb1,
|
|
0x86, 0x8e, 0x8f, 0x2a, 0xaf, 0x93, 0x44, 0x06, 0x6f, 0x99, 0x98, 0x16, 0x5d, 0xb2, 0xeb, 0x89,
|
|
0x01, 0x0f, 0x35, 0xc8, 0x2e, 0x0a, 0xf7, 0x9e, 0x92, 0x6a, 0x72, 0x9c, 0x8c, 0xe3, 0x18, 0xbc,
|
|
0x3d, 0xdd, 0x40, 0x44, 0xe2, 0x77, 0x1d, 0xed, 0x61, 0xca, 0xf1, 0x45, 0x21, 0x72, 0x7e, 0x52,
|
|
0x1f, 0x4b, 0xbd, 0x78, 0x3f, 0x78, 0xd3, 0x9c, 0xe0, 0xaa, 0x41, 0x8a, 0xb2, 0x9e, 0x5b, 0x94,
|
|
0xcc, 0xe8, 0xfb, 0x7c, 0xf9, 0xf0, 0x76, 0x95, 0x53, 0x3a, 0xcf, 0x24, 0x14, 0xea, 0x2b, 0x0c,
|
|
0xa8, 0x87, 0x85, 0xab, 0x07, 0xff, 0xa3, 0xff, 0x41, 0xeb, 0x49, 0x0d, 0x5a, 0x15, 0xac, 0x83,
|
|
0x59, 0x37, 0x29, 0x9c, 0x9c, 0x06, 0x37, 0x44, 0x6e, 0x6f, 0x9b, 0x7d, 0xdc, 0x21, 0xdb, 0x01,
|
|
0xc4, 0x4b, 0xf4, 0x28, 0x2e, 0xa7, 0x4f, 0x0d, 0xdf, 0xb7, 0xf2, 0xec, 0x2c, 0x4f, 0xf4, 0xcf,
|
|
0x0d, 0x53, 0x33, 0x6a, 0x72, 0xc2, 0x49, 0x43, 0xda, 0xf3, 0xbb, 0x16, 0x21, 0x1f, 0x74, 0x77,
|
|
0x99, 0x20, 0x72, 0xb9, 0x5d, 0x78, 0xc0, 0x0f, 0xe2, 0x95, 0xa4, 0xf1, 0xcf, 0x54, 0x19, 0xc1,
|
|
0x0f, 0xc3, 0x7f, 0xaf, 0x24, 0x2b, 0x92, 0xda, 0xbe, 0x4e, 0x99, 0xb7, 0x8c, 0xed, 0xdf, 0xb7
|
|
]
|
|
|
|
|
|
# Python 3 deprecated getargspec in favour of getfullargspec, but
|
|
# Python 2 doesn't have the latter, so detect which one to use
|
|
# F1RMB: make it work with Python >= 3.11
|
|
try:
|
|
getargspec = getattr(inspect, "getfullargspec", inspect.getargspec)
|
|
except AttributeError:
|
|
getargspec = getattr(inspect, "getfullargspec", inspect.getfullargspec)
|
|
|
|
if "length" in getargspec(usb.util.get_string).args:
|
|
# PyUSB 1.0.0.b1 has the length argument
|
|
def get_string(dev, index):
|
|
return usb.util.get_string(dev, 255, index)
|
|
else:
|
|
# PyUSB 1.0.0.b2 dropped the length argument
|
|
def get_string(dev, index):
|
|
return usb.util.get_string(dev, index)
|
|
|
|
|
|
def GetSHA256Checksum(filename):
|
|
fHash = ''
|
|
|
|
try:
|
|
with open(filename,"rb") as f:
|
|
bytes = f.read()
|
|
|
|
fHash = hashlib.sha256(bytes).hexdigest()
|
|
except:
|
|
return ''
|
|
|
|
return fHash
|
|
|
|
|
|
def dfu_get_string(i=0):
|
|
try:
|
|
# Mac calling convention.
|
|
return usb.util.get_string(__dev, 255, i, None)
|
|
except:
|
|
# Linux calling convention.
|
|
return usb.util.get_string(__dev, i, None)
|
|
|
|
|
|
def check_if_in_bootloader():
|
|
bootl = dfu_get_string(1)
|
|
return (bootl == u'AnyRoad Technology')
|
|
|
|
|
|
def find_dfu_cfg_descr(descr):
|
|
if len(descr) == 9 and descr[0] == 9 and descr[1] == _DFU_DESCRIPTOR_TYPE:
|
|
nt = collections.namedtuple(
|
|
"CfgDescr",
|
|
[
|
|
"bLength",
|
|
"bDescriptorType",
|
|
"bmAttributes",
|
|
"wDetachTimeOut",
|
|
"wTransferSize",
|
|
"bcdDFUVersion",
|
|
],
|
|
)
|
|
return nt(*struct.unpack("<BBBHHH", bytearray(descr)))
|
|
return None
|
|
|
|
|
|
def init(**kwargs):
|
|
"""Initializes the found DFU device so that we can program it."""
|
|
global __dev, __cfg_descr
|
|
devices = get_dfu_devices(**kwargs)
|
|
if not devices:
|
|
raise ValueError(" !!! " + "No DFU device found")
|
|
if len(devices) > 1:
|
|
raise ValueError(" !!! " + "Multiple DFU devices found")
|
|
__dev = devices[0]
|
|
__dev.set_configuration()
|
|
|
|
# Claim DFU interface
|
|
usb.util.claim_interface(__dev, __DFU_INTERFACE)
|
|
|
|
# Find the DFU configuration descriptor, either in the device or interfaces
|
|
__cfg_descr = None
|
|
for cfg in __dev.configurations():
|
|
__cfg_descr = find_dfu_cfg_descr(cfg.extra_descriptors)
|
|
if __cfg_descr:
|
|
break
|
|
for itf in cfg.interfaces():
|
|
__cfg_descr = find_dfu_cfg_descr(itf.extra_descriptors)
|
|
if __cfg_descr:
|
|
break
|
|
|
|
# Get device into idle state
|
|
for attempt in range(4):
|
|
status = get_status()
|
|
if status == __DFU_STATE_DFU_IDLE:
|
|
break
|
|
elif status == __DFU_STATE_DFU_DOWNLOAD_IDLE or status == __DFU_STATE_DFU_UPLOAD_IDLE:
|
|
abort_request()
|
|
else:
|
|
clr_status()
|
|
|
|
|
|
def abort_request():
|
|
"""Sends an abort request."""
|
|
__dev.ctrl_transfer(0x21, __DFU_ABORT, 0, __DFU_INTERFACE, None, __TIMEOUT)
|
|
|
|
|
|
def clr_status():
|
|
"""Clears any error status (perhaps left over from a previous session)."""
|
|
__dev.ctrl_transfer(0x21, __DFU_CLRSTATUS, 0, __DFU_INTERFACE, None, __TIMEOUT)
|
|
|
|
|
|
def get_status():
|
|
"""Get the status of the last operation."""
|
|
try:
|
|
stat = __dev.ctrl_transfer(0xA1, __DFU_GETSTATUS, 0, __DFU_INTERFACE, 6, 20000)
|
|
except:
|
|
return
|
|
# firmware can provide an optional string for any error
|
|
if stat[5]:
|
|
message = get_string(__dev, stat[5])
|
|
if message:
|
|
print(message)
|
|
|
|
return stat[4]
|
|
|
|
|
|
def check_status(stage, expected):
|
|
status = get_status()
|
|
if status != expected:
|
|
raise SystemExit(" !!! DFU: %s failed (%s)" % (stage, __DFU_STATUS_STR.get(status, status)))
|
|
|
|
def wait_for_idle():
|
|
# Seems to be something strange with the GetStatus command that effects the internal logic state of the bootloader
|
|
# These commands can't be optimised to not pre-read the GetStatus, possibly if the status is Idle it should not be cleared.
|
|
##STDFU_GetStatus(ref hDevice, ref status);
|
|
status = get_status()
|
|
while (status != __DFU_STATE_DFU_IDLE):
|
|
clr_status()
|
|
status = get_status()
|
|
|
|
|
|
def page_erase(addr):
|
|
"""Erases a single page."""
|
|
if __verbose:
|
|
print("Erasing page: 0x%x..." % (addr))
|
|
|
|
# Send DNLOAD with first byte=0x41 and page address
|
|
buf = struct.pack("<BI", 0x41, addr)
|
|
__dev.ctrl_transfer(0x21, __DFU_DNLOAD, 0, __DFU_INTERFACE, buf, __TIMEOUT)
|
|
|
|
# Execute last command
|
|
check_status("erase", __DFU_STATE_DFU_DOWNLOAD_BUSY)
|
|
|
|
# Check command state
|
|
check_status("erase", __DFU_STATE_DFU_DOWNLOAD_IDLE)
|
|
|
|
|
|
def set_address(addr):
|
|
"""Sets the address for the next operation."""
|
|
# Send DNLOAD with first byte=0x21 and page address
|
|
buf = struct.pack("<BI", 0x21, addr)
|
|
__dev.ctrl_transfer(0x21, __DFU_DNLOAD, 0, __DFU_INTERFACE, buf, __TIMEOUT)
|
|
|
|
# Execute last command
|
|
check_status("set address", __DFU_STATE_DFU_DOWNLOAD_BUSY)
|
|
|
|
# Check command state
|
|
check_status("set address", __DFU_STATE_DFU_DOWNLOAD_IDLE)
|
|
|
|
|
|
def send_custom_command(a, b):
|
|
a &= 0xFF
|
|
b &= 0xFF
|
|
__dev.ctrl_transfer(0x21, __DFU_DNLOAD, 0, 0, [a, b])
|
|
status = get_status() # this changes state
|
|
time.sleep(0.1)
|
|
status = get_status() # this gets the status
|
|
wait_for_idle()
|
|
|
|
|
|
def write_firmware_data(blockNumber, chunk):
|
|
"""Download a chunk of bytes, for block number. This routine assumes that memory has
|
|
already been erased.
|
|
"""
|
|
__dev.ctrl_transfer(0x21, __DFU_DNLOAD, blockNumber, __DFU_INTERFACE, chunk, __TIMEOUT)
|
|
|
|
# Execute last command
|
|
check_status("write memory", __DFU_STATE_DFU_DOWNLOAD_BUSY)
|
|
|
|
# Check command state
|
|
check_status("write memory", __DFU_STATE_DFU_DOWNLOAD_IDLE)
|
|
|
|
|
|
def exit_dfu(bootloaderHT=False):
|
|
"""Exit DFU mode, and start running the program."""
|
|
# Set jump address
|
|
set_address(0x08000000)
|
|
|
|
# Send DNLOAD with 0 length to exit DFU
|
|
__dev.ctrl_transfer(0x21, __DFU_DNLOAD, 0, __DFU_INTERFACE, None, __TIMEOUT)
|
|
|
|
try:
|
|
# Execute last command
|
|
status = get_status()
|
|
if (((bootloaderHT == False) and (status != __DFU_STATE_DFU_MANIFEST)) or (status != None)):
|
|
print("Failed to reset device {}".format(status))
|
|
|
|
# Release device
|
|
usb.util.dispose_resources(__dev)
|
|
except:
|
|
pass
|
|
|
|
|
|
class FilterDFU(object):
|
|
"""Class for filtering USB devices to identify devices which are in DFU
|
|
mode.
|
|
"""
|
|
|
|
def __call__(self, device):
|
|
for cfg in device:
|
|
for intf in cfg:
|
|
return intf.bInterfaceClass == 0xFE and intf.bInterfaceSubClass == 1
|
|
|
|
|
|
def get_dfu_devices(*args, **kwargs):
|
|
"""Returns a list of USB devices which are currently in DFU mode.
|
|
Additional filters (like idProduct and idVendor) can be passed in
|
|
to refine the search.
|
|
"""
|
|
|
|
# Convert to list for compatibility with newer PyUSB
|
|
return list(usb.core.find(*args, find_all=True, custom_match=FilterDFU(), **kwargs))
|
|
|
|
|
|
def named(values, names):
|
|
"""Creates a dict with `names` as fields, and `values` as values."""
|
|
return dict(zip(names.split(), values))
|
|
|
|
|
|
def get_memory_layout(device):
|
|
"""Returns an array which identifies the memory layout. Each entry
|
|
of the array will contain a dictionary with the following keys:
|
|
addr - Address of this memory segment.
|
|
last_addr - Last address contained within the memory segment.
|
|
size - Size of the segment, in bytes.
|
|
num_pages - Number of pages in the segment.
|
|
page_size - Size of each page, in bytes.
|
|
"""
|
|
|
|
cfg = device[0]
|
|
intf = cfg[(0, 0)]
|
|
mem_layout_str = get_string(device, intf.iInterface)
|
|
mem_layout = mem_layout_str.split("/")
|
|
result = []
|
|
for mem_layout_index in range(1, len(mem_layout), 2):
|
|
addr = int(mem_layout[mem_layout_index], 0)
|
|
segments = mem_layout[mem_layout_index + 1].split(",")
|
|
seg_re = re.compile(r"(\d+)\*(\d+)(.)(.)")
|
|
for segment in segments:
|
|
seg_match = seg_re.match(segment)
|
|
num_pages = int(seg_match.groups()[0], 10)
|
|
page_size = int(seg_match.groups()[1], 10)
|
|
multiplier = seg_match.groups()[2]
|
|
if multiplier == "K":
|
|
page_size *= 1024
|
|
if multiplier == "M":
|
|
page_size *= 1024 * 1024
|
|
size = num_pages * page_size
|
|
last_addr = addr + size - 1
|
|
result.append(
|
|
named(
|
|
(addr, last_addr, size, num_pages, page_size),
|
|
"addr last_addr size num_pages page_size",
|
|
)
|
|
)
|
|
addr += size
|
|
return result
|
|
|
|
|
|
def list_dfu_devices(*args, **kwargs):
|
|
"""Prints a lits of devices detected in DFU mode."""
|
|
devices = get_dfu_devices(*args, **kwargs)
|
|
if not devices:
|
|
raise SystemExit(" !!! No DFU capable devices found")
|
|
for device in devices:
|
|
print(
|
|
"Bus {} Device {:03d}: ID {:04x}:{:04x}".format(
|
|
device.bus, device.address, device.idVendor, device.idProduct
|
|
)
|
|
)
|
|
layout = get_memory_layout(device)
|
|
print("Memory Layout")
|
|
for entry in layout:
|
|
print(
|
|
" 0x{:x} {:2d} pages of {:3d}K bytes".format(
|
|
entry["addr"], entry["num_pages"], entry["page_size"] // 1024
|
|
)
|
|
)
|
|
|
|
|
|
def cli_progress(addr, offset, size, strPrefix=None):
|
|
"""Prints a progress report suitable for use on the command line."""
|
|
width = 25
|
|
done = offset * width // size
|
|
print(
|
|
"\r{}0x{:08x} {:7d} [{}{}] {:3d}% ".format((strPrefix if strPrefix != None else ""),
|
|
addr, size, "=" * done, " " * (width - done), offset * 100 // size
|
|
),
|
|
end="",
|
|
)
|
|
try:
|
|
sys.stdout.flush()
|
|
except OSError:
|
|
pass # Ignore Windows CLI "WinError 87" on Python 3.6
|
|
if offset == size:
|
|
print("")
|
|
|
|
|
|
def patch_and_download_firmware(firmwareFile, langFile, platform, progress=None):
|
|
"""Patch the open firmware using the Official one as codec source, then download to the device."""
|
|
encBuf = []
|
|
officialFirmware = ""
|
|
firmwareSize = 0
|
|
foundOfficialFirmware = True
|
|
OFFICIAL_FIRMWARE_HEADER = [ 0x4F, 0x75, 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x42, 0x69, 0x6E, 0x00, 0x00 ]
|
|
addresses = [
|
|
0x0800C000,
|
|
0x08010000,
|
|
0x08020000,
|
|
0x08040000,
|
|
0x08060000,
|
|
0x08080000,
|
|
0x080A0000,
|
|
0x080C0000,
|
|
0x080E0000,
|
|
0x08100000
|
|
]
|
|
sizes = [
|
|
0x4000, # 0c
|
|
0x10000, # 1
|
|
0x20000, # 2
|
|
0x20000, # 4
|
|
0x20000, # 6
|
|
0x20000, # 8
|
|
0x20000, # a
|
|
0x20000, # c
|
|
0x20000, # e
|
|
0x20000 # 10
|
|
]
|
|
blockEnds = [0x11, 0x41, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81]
|
|
firmwareStartAddress = addresses[0]
|
|
|
|
try:
|
|
with open(firmwareFile, 'rb') as f:
|
|
openFirmwareData = bytearray(f.read())
|
|
except:
|
|
print(" !!! " + "Unable to read {}. Exiting...".format(firmwareFile))
|
|
sys.exit(-1)
|
|
|
|
firmwareSize = len(openFirmwareData)
|
|
|
|
# Check firmware
|
|
filename, fileExtension = os.path.splitext(firmwareFile)
|
|
if (fileExtension != '.bin'):
|
|
print(" !!! " + "Wrong file extension: {}".format(fileExtension))
|
|
sys.exit(-3)
|
|
|
|
# Patch the firmware with the specified User language
|
|
if (langFile != None):
|
|
langMergedSuccess = False
|
|
|
|
# Ignore languages (e.g JA builds)
|
|
if (openFirmwareData.find(b'IGNRLANG') >= 0):
|
|
print(" III " + "Ignore language rule found")
|
|
langMergedSuccess = True
|
|
else:
|
|
try:
|
|
with open(langFile, 'rb') as lf:
|
|
langFileData = bytearray(lf.read())
|
|
except:
|
|
print(" !!! " + "Unable to read language file '{}'. Exiting...".format(langFile))
|
|
sys.exit(-1)
|
|
|
|
# Check if user language is valid (per header)
|
|
if (langFileData.find(b'GD77LANG', 0, 8) == 0):
|
|
langVersion = langFileData[8] << 24 | langFileData[9] << 16 | langFileData[10] << 8 | langFileData[11]
|
|
found = openFirmwareData.find(b'GD77LANG')
|
|
|
|
while (found > 0):
|
|
# Search for the first language (English)
|
|
if ((found > 0) and (openFirmwareData.find(b'English', (found + 12), ((found + 12) + 7)) == (found + 12))):
|
|
firmwareLangVersion = openFirmwareData[found + 8] << 24 | openFirmwareData[found + 9] << 16 | openFirmwareData[found + 10] << 8 | openFirmwareData[found + 11]
|
|
|
|
# The specified language file matches the firmware language version: good
|
|
if (firmwareLangVersion == langVersion):
|
|
# Looking for the language #2 tag
|
|
found = openFirmwareData.find(b'GD77LANG', found + 12)
|
|
if (found > 0):
|
|
# Copy the language data into the firmware
|
|
for i in range(0, len(langFileData)):
|
|
openFirmwareData[found + i] = langFileData[i]
|
|
|
|
print(" *** " + "{} merged".format(os.path.splitext(os.path.basename(langFile))[0]))
|
|
langMergedSuccess = True
|
|
else:
|
|
print(" !!! " + "Language version missmatch: FW:{}, File:{}".format(hex(firmwareLangVersion), hex(langVersion)))
|
|
|
|
|
|
break;
|
|
|
|
found = openFirmwareData.find(b'GD77LANG', found + 8)
|
|
else:
|
|
print(" !!! " + "Wrong Language file header: {} {} {} {} {} {} {} {}".format(hex(langFileData[0]), hex(langFileData[1]), hex(langFileData[2]), hex(langFileData[3]), hex(langFileData[4]), hex(langFileData[5]), hex(langFileData[6]), hex(langFileData[7])))
|
|
|
|
if (langMergedSuccess == False):
|
|
print(" !!! " + "Failed to merge language file {}".format(langFile))
|
|
|
|
# Flash the firmware now
|
|
print(" *** " + "Flashing Firmware: {}".format(firmwareFile))
|
|
|
|
# Check if specified FW is not the official one
|
|
for i in range(0, len(OFFICIAL_FIRMWARE_HEADER)):
|
|
if (openFirmwareData[i] != OFFICIAL_FIRMWARE_HEADER[i]):
|
|
foundOfficialFirmware = False;
|
|
break
|
|
|
|
if (foundOfficialFirmware == True):
|
|
print(" !!! " + "You can't flash the official donor firmware file. Exiting...")
|
|
sys.exit(-2)
|
|
|
|
## Get the codec source firmware
|
|
try:
|
|
officialFirmware = config['GLOBAL']['SourceSTM32Firmware']
|
|
except KeyError:
|
|
officialFirmware = ""
|
|
|
|
if ((officialFirmware != '') and (os.path.isfile(officialFirmware) == True)):
|
|
print(" *** " + "Patching for DMR" + " (using " + officialFirmware + ")")
|
|
try:
|
|
with open(officialFirmware, "rb") as f:
|
|
f.seek(0xC2C7C)
|
|
encBuf = bytearray(f.read(0x48BB0))
|
|
except:
|
|
print(" !!! " + "Patching failed. Exiting...")
|
|
sys.exit(-8)
|
|
|
|
## Decrypt the official MD9600 firmware
|
|
AMBE_SECTION_CIPHER_OFSET = (0x6937c % 1024)
|
|
for j in range(0, len(encBuf)):
|
|
encBuf[j] ^= MD9600_ENCODE_CIPHER[(j + AMBE_SECTION_CIPHER_OFSET) % 1024]
|
|
|
|
## Merge the section of the official fw into the open firmware.
|
|
if (len(openFirmwareData) >= len(encBuf) + 0x6937c):
|
|
for j in range(0, len(encBuf)):
|
|
openFirmwareData[0x6937c + j] = encBuf[j];
|
|
|
|
else:
|
|
print(" *** " + "Flashing FM Only firmware")
|
|
|
|
## Encode the open firmware
|
|
print(" *** " + "Flashing a ", end="")
|
|
if (platform == FWPlatformOutput.MD_9600):
|
|
print("MD-9600", end="")
|
|
for j in range(0, len(openFirmwareData)):
|
|
openFirmwareData[j] ^= MD9600_ENCODE_CIPHER[j % 1024]
|
|
elif (platform == FWPlatformOutput.MD_UV380) or (platform == FWPlatformOutput.MD_2017):
|
|
print(("MD-UV380" if platform == FWPlatformOutput.MD_UV380 else "MD-2017"), end="")
|
|
for j in range(0, len(openFirmwareData)):
|
|
openFirmwareData[j] ^= MDUV380_ENCODE_CIPHER[j % 1024]
|
|
elif (platform == FWPlatformOutput.MD_380):
|
|
print("MD-380", end="")
|
|
for j in range(0, len(openFirmwareData)):
|
|
openFirmwareData[j] ^= MD380_ENCODE_CIPHER[j % 1024]
|
|
elif (platform == FWPlatformOutput.DM_1701):
|
|
print("DM-1701", end="")
|
|
for j in range(0, len(openFirmwareData)):
|
|
openFirmwareData[j] ^= DM1701_ENCODE_CIPHER[j % 1024];
|
|
print(":")
|
|
|
|
wait_for_idle()
|
|
|
|
send_custom_command(0x91, 0x01)
|
|
send_custom_command(0x91, 0x31)
|
|
|
|
for address in addresses:
|
|
print("\r *** > Erasing address@ 0x%x" % address,end="")
|
|
sys.stdout.flush()
|
|
page_erase(address)
|
|
|
|
bytesWrote = 0
|
|
totalBlocks = len(openFirmwareData) / BLOCK_WRITE_SIZE
|
|
totalBytes = totalBlocks * BLOCK_WRITE_SIZE
|
|
blockStart = 2
|
|
addressIndex = 0
|
|
numAddresses = len(addresses)
|
|
|
|
while (addressIndex < numAddresses): # for each section
|
|
address = addresses[addressIndex]
|
|
size = sizes[addressIndex]
|
|
|
|
if progress:
|
|
progress(address, 0, size, " *** > ")
|
|
|
|
set_address(address)
|
|
|
|
if addressIndex != len(addresses) - 1:
|
|
assert address + size == addresses[addressIndex + 1]
|
|
|
|
dataWritten = 0
|
|
blockNumber = blockStart
|
|
|
|
while len(openFirmwareData) > 0 and size > dataWritten: # for each block
|
|
assert blockNumber <= blockEnds[addressIndex]
|
|
|
|
chunk, openFirmwareData = openFirmwareData[:BLOCK_WRITE_SIZE], openFirmwareData[BLOCK_WRITE_SIZE:]
|
|
|
|
## Filling data chunk with 0xFF to reach BLOCK_WRITE_SIZE length
|
|
if len(chunk) < BLOCK_WRITE_SIZE:
|
|
chunk += b'\xFF' * (BLOCK_WRITE_SIZE - len(chunk))
|
|
|
|
write_firmware_data(blockNumber, chunk)
|
|
|
|
if progress and blockNumber % 2 == 0:
|
|
progress(address, dataWritten, size, " *** > ")
|
|
|
|
chunkLen = len(chunk)
|
|
dataWritten += chunkLen
|
|
bytesWrote += chunkLen
|
|
blockNumber += 1
|
|
|
|
addressIndex += 1
|
|
|
|
print("\r *** 100% complete, now safe to disconnect and/or reboot the radio.")
|
|
exit_dfu(True)
|
|
|
|
|
|
def main():
|
|
"""Test program for verifying this files functionality."""
|
|
global __verbose
|
|
global config
|
|
home = str(Path.home())
|
|
configFilename = home + "/.gd77firmwareloader.ini"
|
|
config = configparser.ConfigParser()
|
|
|
|
config.read(configFilename)
|
|
|
|
try:
|
|
officialFirmware = config['GLOBAL']['SourceSTM32Firmware']
|
|
except KeyError:
|
|
officialFirmware = ""
|
|
|
|
# Parse CMD args
|
|
parser = argparse.ArgumentParser(
|
|
prog="OpenGD77 firmware loader for STM32 transceivers based",
|
|
description="OpenGD77 STM32 FW Loader v{}".format(version),
|
|
epilog=" -- DMR Enabled -- " if (officialFirmware != '' and os.path.isfile(officialFirmware) == True) else " -- FM Only -- "
|
|
)
|
|
|
|
parser.add_argument(
|
|
"-l", "--list", help="list available DFU devices.", action="store_true", default=False
|
|
)
|
|
parser.add_argument("--vid", help="USB Vendor ID (default: 0x{:X}).".format(defaultVID), type=lambda x: int(x, 0), default=defaultVID)
|
|
parser.add_argument("--pid", help="USB Product ID (default: 0x{:X}).".format(defaultPID), type=lambda x: int(x, 0), default=defaultPID)
|
|
parser.add_argument(
|
|
"-s", "--source", help="official firmware file used as codec source (**Note**: you have to select a source firmware at least once, the file location is stored and used by default).", dest="source", default=False
|
|
)
|
|
parser.add_argument(
|
|
"-f", "--firmware", help="flash the specified firmware.", dest="firmware", default=False
|
|
)
|
|
models="Select transceiver model. Models are: {}".format(", ".join(str(x) for x in FWOutputPlatforms[:-1])) + "."
|
|
parser.add_argument(
|
|
"-m", "--model", help=models, dest="model", default=False
|
|
)
|
|
parser.add_argument(
|
|
"-L", "--lang", help="use <LANG>.gla file as secondary language.", dest="lang", default=None
|
|
)
|
|
#parser.add_argument(
|
|
# "-v", "--verbose", help="increase output verbosity", action="store_true", default=False
|
|
#)
|
|
args = parser.parse_args()
|
|
|
|
#__verbose = args.verbose
|
|
|
|
|
|
print("OpenGD77 STM32 FW Loader v{}\n".format(version))
|
|
|
|
kwargs = {}
|
|
if args.vid:
|
|
kwargs["idVendor"] = args.vid
|
|
|
|
|
|
if args.pid:
|
|
kwargs["idProduct"] = args.pid
|
|
|
|
|
|
if args.list:
|
|
list_dfu_devices(**kwargs)
|
|
return
|
|
|
|
|
|
if args.source:
|
|
fwFile = args.source
|
|
hash256 = GetSHA256Checksum(fwFile)
|
|
|
|
# The checksum doesn't match, ignoring this SGL file
|
|
if (hash256 != FW2645_SHA256_Checksum):
|
|
print(" !!! " + "The specified codec source firmware isn't valid...")
|
|
fwFile = ''
|
|
|
|
try:
|
|
config.set('GLOBAL', 'SourceSTM32Firmware', fwFile)
|
|
except:
|
|
config['GLOBAL'] = { 'SourceSTM32Firmware': fwFile }
|
|
|
|
# Save configuration file
|
|
if (fwFile != ''):
|
|
print(" *** " + "Use {} as codec source.".format(fwFile))
|
|
else:
|
|
print(" *** " + "Unset codec source firmware file.")
|
|
|
|
with open(configFilename, 'w') as cfgFile:
|
|
config.write(cfgFile)
|
|
|
|
# Re-read the configuration file
|
|
config.read(configFilename)
|
|
officialFirmware = fwFile
|
|
|
|
|
|
if args.model:
|
|
try:
|
|
index = FWOutputPlatforms.index(args.model)
|
|
except ValueError as e:
|
|
print(" !!! " + "Model \"{}\" is unknown. Available models are: {}. Exiting...".format(args.model, ", ".join(str(x) for x in FWOutputPlatforms[:-1])))
|
|
sys.exit(-5)
|
|
|
|
global FWPlatformFormat
|
|
FWPlatformFormat = FWPlatformOutput(index)
|
|
|
|
if (FWPlatformFormat == FWPlatformOutput.UNKNOWN):
|
|
print(" !!! " + "Unsupported model. Exiting...")
|
|
sys.exit(-5)
|
|
|
|
## Try to connect the device
|
|
deviceConnected = True
|
|
try:
|
|
init(**kwargs)
|
|
except:
|
|
deviceConnected = False
|
|
|
|
command_run = False
|
|
|
|
|
|
## Upload the firmware (optionnaly, patch it first)
|
|
if args.firmware and deviceConnected == True:
|
|
## A radio model HAS to be specified, there is no default here.
|
|
if (FWPlatformFormat == FWPlatformOutput.UNKNOWN):
|
|
print(" !!! " + "You should specify a radio model (available models are: {}). Exiting...".format(", ".join(str(x) for x in FWOutputPlatforms[:-1])))
|
|
sys.exit(-5)
|
|
|
|
## Download the firmware (and optionnaly patch it for the codec) to the device.
|
|
patch_and_download_firmware(args.firmware, args.lang, FWPlatformFormat, cli_progress)
|
|
command_run = True
|
|
|
|
|
|
if command_run:
|
|
print(" *** " + "Finished")
|
|
else:
|
|
if deviceConnected == False:
|
|
print(" !!! " + "Failed to connect to the device.")
|
|
sys.exit(-6)
|
|
else:
|
|
print(" !!! " + "No command specified")
|
|
sys.exit(-7)
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|