source: azure_iot_hub_riscv/trunk/tools/kflash/kflash.py@ 453

Last change on this file since 453 was 453, checked in by coas-nagasima, 4 years ago

ファイルを追加

File size: 143.5 KB
Line 
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3
4from __future__ import (division, print_function)
5
6import sys
7import time
8import zlib
9import copy
10import struct
11import binascii
12import hashlib
13import argparse
14import math
15import zipfile, tempfile
16import json
17import re
18import os
19
20
21class KFlash:
22 print_callback = None
23
24 def __init__(self, print_callback = None):
25 self.killProcess = False
26 self.loader = None
27 KFlash.print_callback = print_callback
28
29 @staticmethod
30 def log(*args, **kwargs):
31 if KFlash.print_callback:
32 KFlash.print_callback(*args, **kwargs)
33 else:
34 print(*args, **kwargs)
35
36 def process(self, terminal=True, dev="", baudrate=1500000, board=None, sram = False, file="", callback=None, noansi=False, terminal_auto_size=False, terminal_size=(50, 1), slow_mode = False, addr=None, length=None):
37 self.killProcess = False
38 BASH_TIPS = dict(NORMAL='\033[0m',BOLD='\033[1m',DIM='\033[2m',UNDERLINE='\033[4m',
39 DEFAULT='\033[0m', RED='\033[31m', YELLOW='\033[33m', GREEN='\033[32m',
40 BG_DEFAULT='\033[49m', BG_WHITE='\033[107m')
41
42 ERROR_MSG = BASH_TIPS['RED']+BASH_TIPS['BOLD']+'[ERROR]'+BASH_TIPS['NORMAL']
43 WARN_MSG = BASH_TIPS['YELLOW']+BASH_TIPS['BOLD']+'[WARN]'+BASH_TIPS['NORMAL']
44 INFO_MSG = BASH_TIPS['GREEN']+BASH_TIPS['BOLD']+'[INFO]'+BASH_TIPS['NORMAL']
45
46 VID_LIST_FOR_AUTO_LOOKUP = "(1A86)|(0403)|(067B)|(10C4)|(C251)|(0403)"
47 # WCH FTDI PL CL DAP OPENEC
48 ISP_RECEIVE_TIMEOUT = 0.5
49
50 MAX_RETRY_TIMES = 10
51
52 ISP_FLASH_SECTOR_SIZE = 4096
53 ISP_FLASH_DATA_FRAME_SIZE = ISP_FLASH_SECTOR_SIZE * 16
54
55 def tuple2str(t):
56 ret = ""
57 for i in t:
58 ret += i+" "
59 return ret
60
61 def raise_exception(exception):
62 if self.loader:
63 try:
64 self.loader._port.close()
65 except Exception:
66 pass
67 raise exception
68
69 try:
70 from enum import Enum
71 except ImportError:
72 err = (ERROR_MSG,'enum34 must be installed, run '+BASH_TIPS['GREEN']+'`' + ('pip', 'pip3')[sys.version_info > (3, 0)] + ' install enum34`',BASH_TIPS['DEFAULT'])
73 err = tuple2str(err)
74 raise Exception(err)
75 try:
76 import serial
77 import serial.tools.list_ports
78 except ImportError:
79 err = (ERROR_MSG,'PySerial must be installed, run '+BASH_TIPS['GREEN']+'`' + ('pip', 'pip3')[sys.version_info > (3, 0)] + ' install pyserial`',BASH_TIPS['DEFAULT'])
80 err = tuple2str(err)
81 raise Exception(err)
82
83 class TimeoutError(Exception): pass
84
85 class ProgramFileFormat(Enum):
86 FMT_BINARY = 0
87 FMT_ELF = 1
88 FMT_KFPKG = 2
89
90 # AES is from: https://github.com/ricmoo/pyaes, Copyright by Richard Moore
91 class AES:
92 '''Encapsulates the AES block cipher.
93 You generally should not need this. Use the AESModeOfOperation classes
94 below instead.'''
95 @staticmethod
96 def _compact_word(word):
97 return (word[0] << 24) | (word[1] << 16) | (word[2] << 8) | word[3]
98
99 # Number of rounds by keysize
100 number_of_rounds = {16: 10, 24: 12, 32: 14}
101
102 # Round constant words
103 rcon = [ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 ]
104
105 # S-box and Inverse S-box (S is for Substitution)
106 S = [ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 ]
107 Si =[ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d ]
108
109 # Transformations for encryption
110 T1 = [ 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a ]
111 T2 = [ 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0, 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0, 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515, 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a, 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0, 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484, 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf, 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585, 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5, 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2, 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373, 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888, 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c, 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979, 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808, 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6, 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e, 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e, 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf, 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868, 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616 ]
112 T3 = [ 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0, 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0, 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15, 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a, 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0, 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384, 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf, 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185, 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5, 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2, 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673, 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88, 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c, 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279, 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008, 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6, 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e, 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e, 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df, 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068, 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16 ]
113 T4 = [ 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb, 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b, 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a, 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f, 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b, 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713, 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85, 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411, 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1, 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf, 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6, 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b, 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8, 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2, 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810, 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197, 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c, 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927, 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5, 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0, 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c ]
114
115 # Transformations for decryption
116 T5 = [ 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94, 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5, 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742 ]
117 T6 = [ 0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303, 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3, 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9, 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8, 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a, 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b, 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab, 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682, 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe, 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10, 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015, 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee, 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72, 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e, 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a, 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9, 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e, 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611, 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3, 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390, 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf, 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af, 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb, 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8, 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266, 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6, 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551, 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647, 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1, 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db, 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95, 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857 ]
118 T7 = [ 0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3, 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562, 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3, 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9, 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce, 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908, 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655, 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16, 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6, 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e, 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050, 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8, 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a, 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436, 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12, 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e, 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb, 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6, 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1, 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233, 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad, 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3, 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b, 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15, 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2, 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791, 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665, 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6, 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47, 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844, 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d, 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8 ]
119 T8 = [ 0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b, 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5, 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b, 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e, 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d, 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9, 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66, 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced, 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4, 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd, 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60, 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79, 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c, 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24, 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c, 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814, 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b, 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084, 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077, 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22, 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f, 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582, 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb, 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef, 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035, 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17, 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46, 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d, 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a, 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678, 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff, 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0 ]
120
121 # Transformations for decryption key expansion
122 U1 = [ 0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927, 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45, 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb, 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381, 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf, 0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66, 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28, 0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012, 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec, 0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e, 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd, 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7, 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89, 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b, 0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815, 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f, 0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa, 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8, 0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36, 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c, 0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742, 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea, 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4, 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e, 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360, 0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502, 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87, 0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd, 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3, 0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621, 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f, 0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55, 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26, 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844, 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba, 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480, 0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce, 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67, 0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929, 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713, 0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed, 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f, 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3 ]
123 U2 = [ 0x00000000, 0x0b0e090d, 0x161c121a, 0x1d121b17, 0x2c382434, 0x27362d39, 0x3a24362e, 0x312a3f23, 0x58704868, 0x537e4165, 0x4e6c5a72, 0x4562537f, 0x74486c5c, 0x7f466551, 0x62547e46, 0x695a774b, 0xb0e090d0, 0xbbee99dd, 0xa6fc82ca, 0xadf28bc7, 0x9cd8b4e4, 0x97d6bde9, 0x8ac4a6fe, 0x81caaff3, 0xe890d8b8, 0xe39ed1b5, 0xfe8ccaa2, 0xf582c3af, 0xc4a8fc8c, 0xcfa6f581, 0xd2b4ee96, 0xd9bae79b, 0x7bdb3bbb, 0x70d532b6, 0x6dc729a1, 0x66c920ac, 0x57e31f8f, 0x5ced1682, 0x41ff0d95, 0x4af10498, 0x23ab73d3, 0x28a57ade, 0x35b761c9, 0x3eb968c4, 0x0f9357e7, 0x049d5eea, 0x198f45fd, 0x12814cf0, 0xcb3bab6b, 0xc035a266, 0xdd27b971, 0xd629b07c, 0xe7038f5f, 0xec0d8652, 0xf11f9d45, 0xfa119448, 0x934be303, 0x9845ea0e, 0x8557f119, 0x8e59f814, 0xbf73c737, 0xb47dce3a, 0xa96fd52d, 0xa261dc20, 0xf6ad766d, 0xfda37f60, 0xe0b16477, 0xebbf6d7a, 0xda955259, 0xd19b5b54, 0xcc894043, 0xc787494e, 0xaedd3e05, 0xa5d33708, 0xb8c12c1f, 0xb3cf2512, 0x82e51a31, 0x89eb133c, 0x94f9082b, 0x9ff70126, 0x464de6bd, 0x4d43efb0, 0x5051f4a7, 0x5b5ffdaa, 0x6a75c289, 0x617bcb84, 0x7c69d093, 0x7767d99e, 0x1e3daed5, 0x1533a7d8, 0x0821bccf, 0x032fb5c2, 0x32058ae1, 0x390b83ec, 0x241998fb, 0x2f1791f6, 0x8d764dd6, 0x867844db, 0x9b6a5fcc, 0x906456c1, 0xa14e69e2, 0xaa4060ef, 0xb7527bf8, 0xbc5c72f5, 0xd50605be, 0xde080cb3, 0xc31a17a4, 0xc8141ea9, 0xf93e218a, 0xf2302887, 0xef223390, 0xe42c3a9d, 0x3d96dd06, 0x3698d40b, 0x2b8acf1c, 0x2084c611, 0x11aef932, 0x1aa0f03f, 0x07b2eb28, 0x0cbce225, 0x65e6956e, 0x6ee89c63, 0x73fa8774, 0x78f48e79, 0x49deb15a, 0x42d0b857, 0x5fc2a340, 0x54ccaa4d, 0xf741ecda, 0xfc4fe5d7, 0xe15dfec0, 0xea53f7cd, 0xdb79c8ee, 0xd077c1e3, 0xcd65daf4, 0xc66bd3f9, 0xaf31a4b2, 0xa43fadbf, 0xb92db6a8, 0xb223bfa5, 0x83098086, 0x8807898b, 0x9515929c, 0x9e1b9b91, 0x47a17c0a, 0x4caf7507, 0x51bd6e10, 0x5ab3671d, 0x6b99583e, 0x60975133, 0x7d854a24, 0x768b4329, 0x1fd13462, 0x14df3d6f, 0x09cd2678, 0x02c32f75, 0x33e91056, 0x38e7195b, 0x25f5024c, 0x2efb0b41, 0x8c9ad761, 0x8794de6c, 0x9a86c57b, 0x9188cc76, 0xa0a2f355, 0xabacfa58, 0xb6bee14f, 0xbdb0e842, 0xd4ea9f09, 0xdfe49604, 0xc2f68d13, 0xc9f8841e, 0xf8d2bb3d, 0xf3dcb230, 0xeecea927, 0xe5c0a02a, 0x3c7a47b1, 0x37744ebc, 0x2a6655ab, 0x21685ca6, 0x10426385, 0x1b4c6a88, 0x065e719f, 0x0d507892, 0x640a0fd9, 0x6f0406d4, 0x72161dc3, 0x791814ce, 0x48322bed, 0x433c22e0, 0x5e2e39f7, 0x552030fa, 0x01ec9ab7, 0x0ae293ba, 0x17f088ad, 0x1cfe81a0, 0x2dd4be83, 0x26dab78e, 0x3bc8ac99, 0x30c6a594, 0x599cd2df, 0x5292dbd2, 0x4f80c0c5, 0x448ec9c8, 0x75a4f6eb, 0x7eaaffe6, 0x63b8e4f1, 0x68b6edfc, 0xb10c0a67, 0xba02036a, 0xa710187d, 0xac1e1170, 0x9d342e53, 0x963a275e, 0x8b283c49, 0x80263544, 0xe97c420f, 0xe2724b02, 0xff605015, 0xf46e5918, 0xc544663b, 0xce4a6f36, 0xd3587421, 0xd8567d2c, 0x7a37a10c, 0x7139a801, 0x6c2bb316, 0x6725ba1b, 0x560f8538, 0x5d018c35, 0x40139722, 0x4b1d9e2f, 0x2247e964, 0x2949e069, 0x345bfb7e, 0x3f55f273, 0x0e7fcd50, 0x0571c45d, 0x1863df4a, 0x136dd647, 0xcad731dc, 0xc1d938d1, 0xdccb23c6, 0xd7c52acb, 0xe6ef15e8, 0xede11ce5, 0xf0f307f2, 0xfbfd0eff, 0x92a779b4, 0x99a970b9, 0x84bb6bae, 0x8fb562a3, 0xbe9f5d80, 0xb591548d, 0xa8834f9a, 0xa38d4697 ]
124 U3 = [ 0x00000000, 0x0d0b0e09, 0x1a161c12, 0x171d121b, 0x342c3824, 0x3927362d, 0x2e3a2436, 0x23312a3f, 0x68587048, 0x65537e41, 0x724e6c5a, 0x7f456253, 0x5c74486c, 0x517f4665, 0x4662547e, 0x4b695a77, 0xd0b0e090, 0xddbbee99, 0xcaa6fc82, 0xc7adf28b, 0xe49cd8b4, 0xe997d6bd, 0xfe8ac4a6, 0xf381caaf, 0xb8e890d8, 0xb5e39ed1, 0xa2fe8cca, 0xaff582c3, 0x8cc4a8fc, 0x81cfa6f5, 0x96d2b4ee, 0x9bd9bae7, 0xbb7bdb3b, 0xb670d532, 0xa16dc729, 0xac66c920, 0x8f57e31f, 0x825ced16, 0x9541ff0d, 0x984af104, 0xd323ab73, 0xde28a57a, 0xc935b761, 0xc43eb968, 0xe70f9357, 0xea049d5e, 0xfd198f45, 0xf012814c, 0x6bcb3bab, 0x66c035a2, 0x71dd27b9, 0x7cd629b0, 0x5fe7038f, 0x52ec0d86, 0x45f11f9d, 0x48fa1194, 0x03934be3, 0x0e9845ea, 0x198557f1, 0x148e59f8, 0x37bf73c7, 0x3ab47dce, 0x2da96fd5, 0x20a261dc, 0x6df6ad76, 0x60fda37f, 0x77e0b164, 0x7aebbf6d, 0x59da9552, 0x54d19b5b, 0x43cc8940, 0x4ec78749, 0x05aedd3e, 0x08a5d337, 0x1fb8c12c, 0x12b3cf25, 0x3182e51a, 0x3c89eb13, 0x2b94f908, 0x269ff701, 0xbd464de6, 0xb04d43ef, 0xa75051f4, 0xaa5b5ffd, 0x896a75c2, 0x84617bcb, 0x937c69d0, 0x9e7767d9, 0xd51e3dae, 0xd81533a7, 0xcf0821bc, 0xc2032fb5, 0xe132058a, 0xec390b83, 0xfb241998, 0xf62f1791, 0xd68d764d, 0xdb867844, 0xcc9b6a5f, 0xc1906456, 0xe2a14e69, 0xefaa4060, 0xf8b7527b, 0xf5bc5c72, 0xbed50605, 0xb3de080c, 0xa4c31a17, 0xa9c8141e, 0x8af93e21, 0x87f23028, 0x90ef2233, 0x9de42c3a, 0x063d96dd, 0x0b3698d4, 0x1c2b8acf, 0x112084c6, 0x3211aef9, 0x3f1aa0f0, 0x2807b2eb, 0x250cbce2, 0x6e65e695, 0x636ee89c, 0x7473fa87, 0x7978f48e, 0x5a49deb1, 0x5742d0b8, 0x405fc2a3, 0x4d54ccaa, 0xdaf741ec, 0xd7fc4fe5, 0xc0e15dfe, 0xcdea53f7, 0xeedb79c8, 0xe3d077c1, 0xf4cd65da, 0xf9c66bd3, 0xb2af31a4, 0xbfa43fad, 0xa8b92db6, 0xa5b223bf, 0x86830980, 0x8b880789, 0x9c951592, 0x919e1b9b, 0x0a47a17c, 0x074caf75, 0x1051bd6e, 0x1d5ab367, 0x3e6b9958, 0x33609751, 0x247d854a, 0x29768b43, 0x621fd134, 0x6f14df3d, 0x7809cd26, 0x7502c32f, 0x5633e910, 0x5b38e719, 0x4c25f502, 0x412efb0b, 0x618c9ad7, 0x6c8794de, 0x7b9a86c5, 0x769188cc, 0x55a0a2f3, 0x58abacfa, 0x4fb6bee1, 0x42bdb0e8, 0x09d4ea9f, 0x04dfe496, 0x13c2f68d, 0x1ec9f884, 0x3df8d2bb, 0x30f3dcb2, 0x27eecea9, 0x2ae5c0a0, 0xb13c7a47, 0xbc37744e, 0xab2a6655, 0xa621685c, 0x85104263, 0x881b4c6a, 0x9f065e71, 0x920d5078, 0xd9640a0f, 0xd46f0406, 0xc372161d, 0xce791814, 0xed48322b, 0xe0433c22, 0xf75e2e39, 0xfa552030, 0xb701ec9a, 0xba0ae293, 0xad17f088, 0xa01cfe81, 0x832dd4be, 0x8e26dab7, 0x993bc8ac, 0x9430c6a5, 0xdf599cd2, 0xd25292db, 0xc54f80c0, 0xc8448ec9, 0xeb75a4f6, 0xe67eaaff, 0xf163b8e4, 0xfc68b6ed, 0x67b10c0a, 0x6aba0203, 0x7da71018, 0x70ac1e11, 0x539d342e, 0x5e963a27, 0x498b283c, 0x44802635, 0x0fe97c42, 0x02e2724b, 0x15ff6050, 0x18f46e59, 0x3bc54466, 0x36ce4a6f, 0x21d35874, 0x2cd8567d, 0x0c7a37a1, 0x017139a8, 0x166c2bb3, 0x1b6725ba, 0x38560f85, 0x355d018c, 0x22401397, 0x2f4b1d9e, 0x642247e9, 0x692949e0, 0x7e345bfb, 0x733f55f2, 0x500e7fcd, 0x5d0571c4, 0x4a1863df, 0x47136dd6, 0xdccad731, 0xd1c1d938, 0xc6dccb23, 0xcbd7c52a, 0xe8e6ef15, 0xe5ede11c, 0xf2f0f307, 0xfffbfd0e, 0xb492a779, 0xb999a970, 0xae84bb6b, 0xa38fb562, 0x80be9f5d, 0x8db59154, 0x9aa8834f, 0x97a38d46 ]
125 U4 = [ 0x00000000, 0x090d0b0e, 0x121a161c, 0x1b171d12, 0x24342c38, 0x2d392736, 0x362e3a24, 0x3f23312a, 0x48685870, 0x4165537e, 0x5a724e6c, 0x537f4562, 0x6c5c7448, 0x65517f46, 0x7e466254, 0x774b695a, 0x90d0b0e0, 0x99ddbbee, 0x82caa6fc, 0x8bc7adf2, 0xb4e49cd8, 0xbde997d6, 0xa6fe8ac4, 0xaff381ca, 0xd8b8e890, 0xd1b5e39e, 0xcaa2fe8c, 0xc3aff582, 0xfc8cc4a8, 0xf581cfa6, 0xee96d2b4, 0xe79bd9ba, 0x3bbb7bdb, 0x32b670d5, 0x29a16dc7, 0x20ac66c9, 0x1f8f57e3, 0x16825ced, 0x0d9541ff, 0x04984af1, 0x73d323ab, 0x7ade28a5, 0x61c935b7, 0x68c43eb9, 0x57e70f93, 0x5eea049d, 0x45fd198f, 0x4cf01281, 0xab6bcb3b, 0xa266c035, 0xb971dd27, 0xb07cd629, 0x8f5fe703, 0x8652ec0d, 0x9d45f11f, 0x9448fa11, 0xe303934b, 0xea0e9845, 0xf1198557, 0xf8148e59, 0xc737bf73, 0xce3ab47d, 0xd52da96f, 0xdc20a261, 0x766df6ad, 0x7f60fda3, 0x6477e0b1, 0x6d7aebbf, 0x5259da95, 0x5b54d19b, 0x4043cc89, 0x494ec787, 0x3e05aedd, 0x3708a5d3, 0x2c1fb8c1, 0x2512b3cf, 0x1a3182e5, 0x133c89eb, 0x082b94f9, 0x01269ff7, 0xe6bd464d, 0xefb04d43, 0xf4a75051, 0xfdaa5b5f, 0xc2896a75, 0xcb84617b, 0xd0937c69, 0xd99e7767, 0xaed51e3d, 0xa7d81533, 0xbccf0821, 0xb5c2032f, 0x8ae13205, 0x83ec390b, 0x98fb2419, 0x91f62f17, 0x4dd68d76, 0x44db8678, 0x5fcc9b6a, 0x56c19064, 0x69e2a14e, 0x60efaa40, 0x7bf8b752, 0x72f5bc5c, 0x05bed506, 0x0cb3de08, 0x17a4c31a, 0x1ea9c814, 0x218af93e, 0x2887f230, 0x3390ef22, 0x3a9de42c, 0xdd063d96, 0xd40b3698, 0xcf1c2b8a, 0xc6112084, 0xf93211ae, 0xf03f1aa0, 0xeb2807b2, 0xe2250cbc, 0x956e65e6, 0x9c636ee8, 0x877473fa, 0x8e7978f4, 0xb15a49de, 0xb85742d0, 0xa3405fc2, 0xaa4d54cc, 0xecdaf741, 0xe5d7fc4f, 0xfec0e15d, 0xf7cdea53, 0xc8eedb79, 0xc1e3d077, 0xdaf4cd65, 0xd3f9c66b, 0xa4b2af31, 0xadbfa43f, 0xb6a8b92d, 0xbfa5b223, 0x80868309, 0x898b8807, 0x929c9515, 0x9b919e1b, 0x7c0a47a1, 0x75074caf, 0x6e1051bd, 0x671d5ab3, 0x583e6b99, 0x51336097, 0x4a247d85, 0x4329768b, 0x34621fd1, 0x3d6f14df, 0x267809cd, 0x2f7502c3, 0x105633e9, 0x195b38e7, 0x024c25f5, 0x0b412efb, 0xd7618c9a, 0xde6c8794, 0xc57b9a86, 0xcc769188, 0xf355a0a2, 0xfa58abac, 0xe14fb6be, 0xe842bdb0, 0x9f09d4ea, 0x9604dfe4, 0x8d13c2f6, 0x841ec9f8, 0xbb3df8d2, 0xb230f3dc, 0xa927eece, 0xa02ae5c0, 0x47b13c7a, 0x4ebc3774, 0x55ab2a66, 0x5ca62168, 0x63851042, 0x6a881b4c, 0x719f065e, 0x78920d50, 0x0fd9640a, 0x06d46f04, 0x1dc37216, 0x14ce7918, 0x2bed4832, 0x22e0433c, 0x39f75e2e, 0x30fa5520, 0x9ab701ec, 0x93ba0ae2, 0x88ad17f0, 0x81a01cfe, 0xbe832dd4, 0xb78e26da, 0xac993bc8, 0xa59430c6, 0xd2df599c, 0xdbd25292, 0xc0c54f80, 0xc9c8448e, 0xf6eb75a4, 0xffe67eaa, 0xe4f163b8, 0xedfc68b6, 0x0a67b10c, 0x036aba02, 0x187da710, 0x1170ac1e, 0x2e539d34, 0x275e963a, 0x3c498b28, 0x35448026, 0x420fe97c, 0x4b02e272, 0x5015ff60, 0x5918f46e, 0x663bc544, 0x6f36ce4a, 0x7421d358, 0x7d2cd856, 0xa10c7a37, 0xa8017139, 0xb3166c2b, 0xba1b6725, 0x8538560f, 0x8c355d01, 0x97224013, 0x9e2f4b1d, 0xe9642247, 0xe0692949, 0xfb7e345b, 0xf2733f55, 0xcd500e7f, 0xc45d0571, 0xdf4a1863, 0xd647136d, 0x31dccad7, 0x38d1c1d9, 0x23c6dccb, 0x2acbd7c5, 0x15e8e6ef, 0x1ce5ede1, 0x07f2f0f3, 0x0efffbfd, 0x79b492a7, 0x70b999a9, 0x6bae84bb, 0x62a38fb5, 0x5d80be9f, 0x548db591, 0x4f9aa883, 0x4697a38d ]
126
127 def __init__(self, key):
128
129 if len(key) not in (16, 24, 32):
130 raise_exception( ValueError('Invalid key size') )
131
132 rounds = self.number_of_rounds[len(key)]
133
134 # Encryption round keys
135 self._Ke = [[0] * 4 for i in range(rounds + 1)]
136
137 # Decryption round keys
138 self._Kd = [[0] * 4 for i in range(rounds + 1)]
139
140 round_key_count = (rounds + 1) * 4
141 KC = len(key) // 4
142
143 # Convert the key into ints
144 tk = [ struct.unpack('>i', key[i:i + 4])[0] for i in range(0, len(key), 4) ]
145
146 # Copy values into round key arrays
147 for i in range(0, KC):
148 self._Ke[i // 4][i % 4] = tk[i]
149 self._Kd[rounds - (i // 4)][i % 4] = tk[i]
150
151 # Key expansion (fips-197 section 5.2)
152 rconpointer = 0
153 t = KC
154 while t < round_key_count:
155
156 tt = tk[KC - 1]
157 tk[0] ^= ((self.S[(tt >> 16) & 0xFF] << 24) ^
158 (self.S[(tt >> 8) & 0xFF] << 16) ^
159 (self.S[ tt & 0xFF] << 8) ^
160 self.S[(tt >> 24) & 0xFF] ^
161 (self.rcon[rconpointer] << 24))
162 rconpointer += 1
163
164 if KC != 8:
165 for i in range(1, KC):
166 tk[i] ^= tk[i - 1]
167
168 # Key expansion for 256-bit keys is "slightly different" (fips-197)
169 else:
170 for i in range(1, KC // 2):
171 tk[i] ^= tk[i - 1]
172 tt = tk[KC // 2 - 1]
173
174 tk[KC // 2] ^= (self.S[ tt & 0xFF] ^
175 (self.S[(tt >> 8) & 0xFF] << 8) ^
176 (self.S[(tt >> 16) & 0xFF] << 16) ^
177 (self.S[(tt >> 24) & 0xFF] << 24))
178
179 for i in range(KC // 2 + 1, KC):
180 tk[i] ^= tk[i - 1]
181
182 # Copy values into round key arrays
183 j = 0
184 while j < KC and t < round_key_count:
185 self._Ke[t // 4][t % 4] = tk[j]
186 self._Kd[rounds - (t // 4)][t % 4] = tk[j]
187 j += 1
188 t += 1
189
190 # Inverse-Cipher-ify the decryption round key (fips-197 section 5.3)
191 for r in range(1, rounds):
192 for j in range(0, 4):
193 tt = self._Kd[r][j]
194 self._Kd[r][j] = (self.U1[(tt >> 24) & 0xFF] ^
195 self.U2[(tt >> 16) & 0xFF] ^
196 self.U3[(tt >> 8) & 0xFF] ^
197 self.U4[ tt & 0xFF])
198
199 def encrypt(self, plaintext):
200 'Encrypt a block of plain text using the AES block cipher.'
201
202 if len(plaintext) != 16:
203 raise_exception( ValueError('wrong block length') )
204
205 rounds = len(self._Ke) - 1
206 (s1, s2, s3) = [1, 2, 3]
207 a = [0, 0, 0, 0]
208
209 # Convert plaintext to (ints ^ key)
210 t = [(AES._compact_word(plaintext[4 * i:4 * i + 4]) ^ self._Ke[0][i]) for i in range(0, 4)]
211
212 # Apply round transforms
213 for r in range(1, rounds):
214 for i in range(0, 4):
215 a[i] = (self.T1[(t[ i ] >> 24) & 0xFF] ^
216 self.T2[(t[(i + s1) % 4] >> 16) & 0xFF] ^
217 self.T3[(t[(i + s2) % 4] >> 8) & 0xFF] ^
218 self.T4[ t[(i + s3) % 4] & 0xFF] ^
219 self._Ke[r][i])
220 t = copy.copy(a)
221
222 # The last round is special
223 result = [ ]
224 for i in range(0, 4):
225 tt = self._Ke[rounds][i]
226 result.append((self.S[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF)
227 result.append((self.S[(t[(i + s1) % 4] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF)
228 result.append((self.S[(t[(i + s2) % 4] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF)
229 result.append((self.S[ t[(i + s3) % 4] & 0xFF] ^ tt ) & 0xFF)
230
231 return result
232
233 def decrypt(self, ciphertext):
234 'Decrypt a block of cipher text using the AES block cipher.'
235
236 if len(ciphertext) != 16:
237 raise_exception( ValueError('wrong block length') )
238
239 rounds = len(self._Kd) - 1
240 (s1, s2, s3) = [3, 2, 1]
241 a = [0, 0, 0, 0]
242
243 # Convert ciphertext to (ints ^ key)
244 t = [(AES._compact_word(ciphertext[4 * i:4 * i + 4]) ^ self._Kd[0][i]) for i in range(0, 4)]
245
246 # Apply round transforms
247 for r in range(1, rounds):
248 for i in range(0, 4):
249 a[i] = (self.T5[(t[ i ] >> 24) & 0xFF] ^
250 self.T6[(t[(i + s1) % 4] >> 16) & 0xFF] ^
251 self.T7[(t[(i + s2) % 4] >> 8) & 0xFF] ^
252 self.T8[ t[(i + s3) % 4] & 0xFF] ^
253 self._Kd[r][i])
254 t = copy.copy(a)
255
256 # The last round is special
257 result = [ ]
258 for i in range(0, 4):
259 tt = self._Kd[rounds][i]
260 result.append((self.Si[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF)
261 result.append((self.Si[(t[(i + s1) % 4] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF)
262 result.append((self.Si[(t[(i + s2) % 4] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF)
263 result.append((self.Si[ t[(i + s3) % 4] & 0xFF] ^ tt ) & 0xFF)
264
265 return result
266
267 class AES_128_CBC:
268
269 def __init__(self, key, iv = None):
270 self._aes = AES(key)
271 if iv is None:
272 self._last_cipherblock = [ 0 ] * 16
273 elif len(iv) != 16:
274 raise_exception( ValueError('initialization vector must be 16 bytes') )
275 else:
276 self._last_cipherblock = iv
277
278
279 def encrypt(self, plaintext):
280 if len(plaintext) != 16:
281 raise_exception( ValueError('plaintext block must be 16 bytes') )
282
283 precipherblock = [ (p ^ l) for (p, l) in zip(plaintext, self._last_cipherblock) ]
284 self._last_cipherblock = self._aes.encrypt(precipherblock)
285
286 return b''.join(map(lambda x: x.to_bytes(1, 'little'), self._last_cipherblock))
287
288 def decrypt(self, ciphertext):
289 if len(ciphertext) != 16:
290 raise_exception( ValueError('ciphertext block must be 16 bytes') )
291
292 cipherblock = ciphertext
293 plaintext = [ (p ^ l) for (p, l) in zip(self._aes.decrypt(cipherblock), self._last_cipherblock) ]
294 self._last_cipherblock = cipherblock
295
296 return b''.join(map(lambda x: x.to_bytes(1, 'little'), plaintext))
297
298 ISP_PROG = '789cedbd0d5453c7d63f3c27c9c94910141b3058628b4440b92dd78a8aadd60b4a8862ebb57e807a6b0b3d2062d14ad552dbd21292438c68911e2028d82256b0dc5b6f5bd458d12255c4da8fdb2fc57e68d10041c50f2a105030ef9e734e02a4dee73efff5bc6bfdd7bbde275d3ff799af3d7b66f69ed933670e1dbbefe6671f5e24108186fed62f983871fd82004024c664b30821363b7bc4faed0b27ea2289285d14314b378b98ad9b4d44eba2098d4e43c4e86208ad4e4bccd1cd21e6eae612b1ba58629e6e1ef194ee29e269ddd3c47cdd7ce2afbabfee78617d9968e27aef89681142b77e002c228002168980021689810216498002169140018ba440018b28a0804532a0804572a080451e40018b8601052cf2040a58e40514b0683850c0a2114001661db4495757a1bc2c430ad1273f285e16f5ad0f8aec5010be6826f140fe4b010bfe4aa44b9b3dda86b73f706b54e7833d0ff59537553457b5ed6fffe4d6a1ce233d9ff5cdba14d3127b65fef5851d715dcb7b9febbf7ca9b5e5ea951bd77fefe8eebad37baf3f2480f00e1937d23b64fc58ef90471ef30e09887a2064dc330f848c4f7c20e491f4074202743e21e3f27d42c6eff60979e4639f9080ba5121e3be1b1532fed2a890473a4641f9d1507e34941f0de54743797f28ef0fe5fda1bc3f941f03e5c740f931507e0c947f18ca3f0ce51f86f20faf0f0a987c3bc87bb2478e8f885e42a29b0113178f2ebb39b169ee7a6fdfc9e509b3122f278a5e2e7f79d6facbeba549154931c9adc9d2572a5e89c968cdf05855b52a36f56aaac76b55afc5be7ef5f5e169fbd3e6afb9b166f89bfbdf9cffd68db728689b3140e74d8d25461ac7ea465281c403c640dd03949a5018d53a05358ef0318ed3f9504184af3148e74b0513a38cc1ba515408a13486e894d478c2cf385ee7474d20461b27e84653a1c483c650dd83d49f087fe39f74fed42384caf8884e453d4a8c313eaa1b4385110f19c3740f517f261e36fe59f7b0822002d6a38089bcc6468d9436af0f89ec60b4b4ca8e488d19e26d594d336e67444f5c8f167877d59abdb998b3e50984268ac8ce526e4448416a3ccd19a007c68661b4a91229c5284b2116ff8b168b91489f9d85d3f40d94077313f337238e439f994259acb1f22bd397ca64cca3de834b019427305a2594514bed525c07d4f22a42e2393de418ed742545f07551941962f5a76594d79c527aba9f1f119e42114448f1097f63b7e3fc09525bdc5055488f392882a72fbf5aa40bf2379288ee3c84fc8d52a4d3f83310a25b44ac2f25d2e5ef7837aca8e39e7a1f85d4ef5388d0646791a458dbe538fc4366ad781f250d270f2186542392b864e1a5f1ebe7a561e608f2dce3e365f7409a62994b1af5fb4a02e4187550b275918242a21ad21219667493236d400e521b5654fca5824422e66a7e4c71bc6faef5a1c6fb4ab6d182a5126b48906cdf0fc9b55b17618ed3650723e90de7913f25c3dc3703f7556d88e71e56b4e3dd359670d9212c276e4f1945f5d612237768c723987962188db45d2de940c218755c86512613f911648db69ba5b43fe5ec5b9fa8033f2c06147ff9e3225d30ae99de700e6a8536c5f833105adb82d85150eb3ba3df3d54983ea4055c8f32671123c53dfa45eda6f4e0f6fef82ac3464de02d69a7daa703299340272427779b23b12468774bf3180dff9cb0eb49e1a9ec3d9d2648783ebef763cd58415f0326d6e378ee39e1cff99a09c2735958a1e651a74e3fba43f39833ffa3bb34539cf91f512570ba37cdde54c769e11eb1fde26e5e1f45f6a6b3fc1369bfc8f749e5c5525a0ebd77fe4b75052572b611741bd2523cb9bc11f69f75317c4cc83c22c6a4e16227da7fe67b39eb97f275a20d9793088d067a7a82d01e943757788accd76149f9b69b55695ce9c7ede770fd7b18eac70f788924f6733f690b2dc4c8c0b6426da86122f260187e3c91733cd1577aad0ee13155a34e342b098f2c315241762069bb204b9f58d3013948134edb946ed2aa3d3b50493c49ec01cac63388b5db4704922bb6493b036f85354f6a528fd9ede4fe6b7972f6caf1b2b09c7c8da03f5f93d142da1d22c83a8cb9875bcab79318c9822d605de3b84bdcb8b7ab7d9d7cb3cef1bae9e49a75daa995984700f9dfe111f9fd501e912707f3c8eaffeff040df0ce5818e0fe681a4832d27f24ba73d09e163cebc2bd2cb9be6772ebc15d7bebcedb9e69ce6e0bed89e2a53d8964906d603792b862191f975d094dcbf5be4ed1509d2a4cb1b666d2adf247aedf2ea592f96bf48681281076bef1d31dd7827f288915edf8cca8d25060a8d290d36d11b4a90420e53ae6518fa9e99cff84be528dbcc2ae5221d5b63181755237f9c98b9f352df0acb98f4853d8a9d52515ce7f25b2fb429965f2594cf82bd793ed5217f317f7579db99a6f97dcfb5e7b45734871ac24c9f980ee5beb0d37f987f60c9962d63e9f7e4a8352106d63969eae54db35e2b7f4df4fae51767a5119a202c1b8c6a89410ef36c04c14a90a8504bdfc810eb433cd06573b6719b96ef6989d0d306a4501ab8defe294feddb812a7262417bc63b7b7c376b9680ec41a53377d49876442eb37cf81fcaf7c7aba53c9742cd9a5a96fa483cf3246fa721ef17d0d84ec45aea7d93b6c66c43ca57201473a80ccfe20de8a73c3e1cbc9b14c281a77421a59fababe24604e79c619c321dffe7410bf01d36f36409d43cf314cf5dfbae937bc8bb83b99fdb39947b4c89933be6cd52de81eaaaeee11acc51ea94d4b8633bcc28fc9aa9dd6186f5555fbfa468574c8dd28e6a8a0ea1b37966e0a53f9553345dd928c8a9fa5c1d1a3762376ef1f0a19255160c704b29e0b96dccff23b78a7c9e1bcf6be588c72c4c0cace32805edb910613c7cbd3f5e415193742d8a7abb233b4b1f43a28379bb63fccf2911935b43dd8aeccdfb38af7faa2ea4bf9b24fba75caa7d3c3df656845c86027b823bc325414495818c6161a6916be6b74bfbf65004d23f6e40c23cde00fe86779704cf3d2cf9055151288cff4b2514ac5e5f5222d553fe4625ca56ea58bfafbe31abb32a91df5375297514dd6543d08bc355df5e5e376b43f906d1a6cba984662c9ebbe2ad66db3d9f240b2541f994c2188d2accf4ce56e4d3a66ab6c0caf85981fa1f1274c5a26af36baeafc516eced256d0f6cc36b4fa84198699e35b97431212190e17d9f04a684241184f839ee39412f965d4ee067d42a063cf898b131728d7236eebfd99feb1b7c91b88144e5d44f792546dbef6c1125ae7bc7574baf6c9ca98c07bba3b435ac39181d3197ce5e965e7eaba2fd4c5b4ee737cddf37c5f52def79aef3855b2bdb57b7ad6d3e629e640a335419b28de2fa42184f06915a3c4be91bf6a2cf294c0fa2cbd4173086f4063bda16cf941547ca7347de5474d94708d29a88a0fcf8b12da591ac2d04951ed7c54fd9a78a32e576fcb25ba3200dceb65e126b1723bd361a114181d48a3cbd3609f307ba01f8631da10d952253fc1ed48b2ad64937b426c5a456a44a575f7e6dd6ebe5af8bdeb89c366b4df99a64e80bbdf647a48f3e092dafcfd34737a3cf259876a2cb920b5b75e33e8da777750a7506fc43a8db4c0465f6eeb5e8b505604d062889eb7d1f89a30f800c3fe5bd2059b19518c7a484a714a07e6566de685b6646d07b966e07cc38ad88893f68897a71f78bbab90acfbb0e76eb5d07b966e616269659539d6120989b35c6c951f49514b173f4b2ca88a0d17585f1636a85701e5ea79638ea526a4c11c493a5d6961d7d1dc7aa330a886d36aeece58c81b2c544d0a60e4153b7f2e576a75cb25467441397ec38b7f55265bf3377423e1114d52fb4d5c4e7ae313d494c376c43a9b5780cac9ba9667dc359243e538ff0589453d5362d213ed382667954a7dc81f82ef48247f8ea3b88082d21b708fd5676ea3f8d95b5b4b219f7a63eda8098d5fc48bc8ffa1f542ec15e7750213f26078431a9b62f263ebc56bd693941bf23978e4d8b92d4bda8f0ea73306bc8794c9ab567ee85ba947e654bde87d76aa827a2e8d60c2a5868e1f15c68953f79d57ccbe1004d7b0db731d9c116c2ea931fb5b2bcd0992f723bdfbbc74a9faee56568d926dd50b1eedf69113f0bcd3e556d7f9fd86de56abd6e143bb90564413dde64335f6bd6fac1b58e1d546bd3e6dd29a916dcba4207e661bd66b90d695ca9b20c28f51079910f45be34984730430217a1af0d35a619448da114b51c13c348e91bea11d7e70d2d7c9f3774097d3e526b2db19ddb3c5768716de2a7d95951235932523252033b20ced33cce9427b0e402892feca394e1dc4c6bd8948efdaae0f6d836a175fd82579a2b78b04972a7bf9bd791cccf332c4306c805ef35eb75a586db4b6d12b4eef10829eccba539229d86df65ed7d5c4879d89cc2f9f4d3f8127b5f55a6c890fa31fb346134a7e8347297d7092bc84ac89d736a8a528a30bf72932b1599790e648620f3246512d4299184b392807e652aa4c9e74ef25cc5b4a8165cff4db5a0ff173cabe2f55b2dc947665c6b39354990caeb52ad1e66ca586622c22bfd1e09e19a1fb8b918e7aea6c2040bf4781a66ee3dd46e84571612665cf063f97e4a061f16e61fd84579f2fa63edc77b4fd87f79d2de2d2205f9919750639f823cee559e0063c0e5a3ef2aa88fbcac7e2df784f43b0af25baf7acba6743c2ed2ce2a03115d026b0a6db320de6fc7de6cb5d180c4f5140a6b2625826cbde5c997403a697b687358931067cf4e0e4c16f8dec512f2758abbb15ca551b47f0bd2d9186d69ddd87dea3212f5c6cf6460b7a7a58d36648aa1df6e04ffa6df52a224092c6349231565f56eb967d2d6c1ba7fdc8b1ed5858aebc0fff2bc6261a5df7af5c75b479eedc3311f7925d73e393bd448a79f10b1197654673d76897d45ea7872cb91224faba72d8ab2ae69bc37f232b4437a22728b149f531515a56455203565417ba416d88903258102f6488002f6888102f6888002f61040017b105000f8825d5d23d822069dddc6169104f7afe8ecb66516b62804f175e464dbb282ef1465d529c7e4cd2cb2a69fe8d96559965ed15e650863ca617f91d3298cfe70b396f3b3167ed6c4683f6b56f99527cf6c3769677e7b744e681f4986f5847666adcab739ad3dcbef2919a93107703d7d481f2219c6e4ea6eeac16f64ed54c00e9b829478f0a9c7bfd12b2584c21c22a69fa6903c05fc48bf4e844b6ccac854f6e6a9c7777a04331365e5ce596e74ffe291973e88feaf7806fcb050f3948c7fceda8f57c860a63509af8782cdddae6236d3fcd8eb3baa8c0c256eb03bd638c299cac84c5f3c53043649c1f356fb1d44ead1f5b05724917a32603ce9a19e01348014a9c791a2b1313a58b5190f6196b96c56721e5fa7aa8f7f4ab1cf68129efa6634f34f4607ea99d186651525715aafe6b4fe88d9175299201f61b67d523893e910d28f0ae15b7c585ccf8735b79ce585f04d21fd84b30dc278f4cf98a3fb52a891b7b37e7e476ceb99d12e4b827dc1b8ce852c6558a49ed6b910efb1d413250b85b23765abc898bdc24eaaec862c4d1ef385103a7e9dd1ce389d6c51add6d9745a6c2dfa4692189d5ede73e6d6f76d397d159ddfb49f6bfeb9e9b9be177a5676aebeb5b67d77eea42d618650d3d986d235f50d78f4f48f7b20853d04d10f50de30a2b17416e5476874f38879341a365e7e7d79ce079ae79cbedf66da8b0c26c91a8f8d51715be9f57f23966f9525a8d27c16d09d95c1d1d1074be96f0d211799e01c21ff3baa8472703f2accaa26212698f623bd6bb6ec8c2435f40e0f8453f994e3e332afe8233c888a92f0612591d50673a47ada4e74b0ef83b2813ca8ad3ffeb1b38feed31f9123fd0113aa93f79fafc8a1d797a09f73662478beaa0b8ecb8965b2cd745c9907e655b5d3b4156b957a5a15dad4abd3b6ae8bd950b141baa935356675c56ae98b975f9ff546f91ba2cccb6b663272d0cf8861284b17ab8b56cc1b767c8505d7223e866b898eae305ae55ef7c4d05fb204f6152a80ce967ad36b76c9e079ce1767240b3cd36a24a522af6d255e248cea1874d55c73b2404c77752232a846b297506450912b4e54e096f01ed343be2d1f6bd501bd88b3201b25c176d71fff692d96819d77cd413cad9877d7e1f594e9a9b916cfb4b539a1c2c9e1f1742c45798a22c36e51a45032b55f3352b54bbebd61ae311c885235459fbc6abc6aa0d7f7a3ab4659c2cc9c73cc4ca164d6a6a5d1e52963de5b7ad22fe1088c08d7db3bc3bd76b97a5b07de5e708e53c680cc2ae38a0ecf3467ef2704f2d66eb763594d16551add528960ec5fbf20a2d7ef42570dc1509b20e5cbcf464f379a2355094b4fe2d17fe6eec0280648977d37c172d548dffe3bf1b3b1a6a151340dc60e8f5c4d4ea34864ae3258679775b71cd4d740ffd79810a1a99317d69478f8a3f46a7adeaf088ff473dc3843ce79653f671e7b21e7a2d3bb7af1d9e8cb861aa331ead993aa84cbb8e61a7ce610dc3770e610db33bf3374cbfe2dac845c484493f3faff666a0f64fe78da80cf1ac49f82857c6040fd8fd33fca9121e1a75a7dbc9ca05fbf8bf4ca09046dcc20ce300b99ec9d73c12b57c84dc32ed58e49cf692f6fab68c667080b7bf009c373ed2fb4ad6c668d1b61dd6a12d1afd9456c27e5b0e0f35f98f7e84eb3e863adaa8ed0dcef54a13c8d3b55902091f5c681be50933092892cb5ee61f33298414cf287e826b3846d9c8c74217897e8af54a2e1d47c334a61a594831ef523422f9942e8e146892ac92fcd67554749b9b9f886cfb5e214458a1215db12cb148d05b08bbc2526beccd7d22d3619db98844a8c46b11b379272646a68f901e497945e122e3547d20beb3dfa239810f101b9c8bc04cf9f9a51b4e880b75f527f8c90e3d75332d6e68354cdd5d2026486bd9efa68a30f470f34fab029a3d0d61b5baf96b6069abdad4ead3bbe186667e2ecb1efb02ca884b2907b617d8f24691bec751b4f826436e92e0bc4f8f2319d109341e5d7b2d2c8252cd544595b5a3bd9c6714489b1817ab2d6278d9e2345aa5505374baf5653cd688265aa614aad390e24b01cf2e468ed210f9c27d0ac4a616d4aa4b2ed025eb71e161f3621fa72eb282f3d11e21f171249863031b837aa8b4e713d52dd2a2594b87cf839a90fad80bef66ef76943d6ac1bfe8d907b76b8c28ac416e0f1428ab4fa9514b4a3b5a3442ac64ff9212d1733e70ff46e9472bef989cd3319f1e4cd043d5a329a0c625f9982a2642d77d8ee0844ef92aa301f567bdbd19b87f7cbea27ecf7708c544c27c14a325aac024b21c4077211fbda49076ddb89c28d3b23fbb5f4d7b6507ec5d51af97d76c31b59b40fdd1f1fbef56f4470c1135be85ddd7ee0a98aca5df35242667f7c682e3da22b80dec01074c9f4b1e6341962b7fe63b3b8d2138d7d8ff340f7db72e851694a56f994987e871aa5b7c889b80245920fcab209fbf9b7f490db8fa65fb1234ee2c7ec6ff229216f42ec3abb4a68c71b4baa147166941f435f3a2561e35250494e8ed83f6714f21f350a0d97ce2f52905287f70bb45fbd94d4969c0b8eac1ed588b89ec7e5a736de90b57bb7a12be846fac1ef62e89653a8447a88ac03ff0febcb29c4c63500c75669268ef1e563ec10f30a955eab20415fa4a02fa9f53d6c5c085192738a5a66f15e4d4beb91cfca8e9dd6171befc9d66a2c3e49de691d3bab371745d27f7b48cc6bb36a55385580ca8bb6df545de5b4f9635b1b473fb5b5b2363fe479d3f39acaa6fe6814f16835fda50c7296aec4ba55daaa5a85cb8cac9964187d2c4ae9f3627f84f5edd626af63f921bc6eb45c6ca9ae325ea8255332a9270afa3332b7161ed44ff58095812eeaf6e0eaa84e4954bc7117e9b4b4d413d569ab61ae9b594226876fa944cb0b327dab33de47e11e7722c35fab42dfbbc6b5e979e030ba0b053234e9099e8aa723b09088c5a3144e2647d518b544e84e653c8c6d807db562f583bcad1e49f9493d791e61cd996ecdd4d26be3c58c563d19663e18efd2948e927098dfe91633024d3b6d93b8ecd76fcc67d5546ed4a7ef71fcc6db934cb57a4b2e5218b6dc8b2a6672ebf2d407eea2bd31d5c65c54602bb866cd30feca32c308d71a7f74630dcc2884306f403f73567aa0fb5bdd67d8a30e2da27deab9b7287a2d89acdb2cf748b2df52ddb017edca0da7ea6107b14b4bdf684055467a5d8b87fe1489188a21f7e435deb35eb5dd83b9f4958d90967f66700adb9d81fa2dec2b46872247da47df6a90eaab49a4ff8441fa5a9210d73284fe335224fe8c1189ab49b1fe3023661946a2fe2803890f330ef58178a43e6c27d4476d84faa346b1fa4083587d3845a43eaa1483c729511fa51c1b2ddb137753bb49f5d1867bd66b204bb3ad3b3b8bbebd57529d538fe8b7ce8a584db743a7ed57d26c17ec1dc28ddd483c87024b6e40a16635a2880b96706317d2c7401cd50592ab5123b22abba1453a6d8b7092a099ab5470dee548213c870f8b1f1c935ede96d31e6618ba2e7dc28c6e8f496a4d18baea0409fbb2136cd59649cdce7d6079b27eaac10133ac88356d24d8611287a2f79483be1321c62b99e2aedcc1af662962f06bcaee202216af670b1977deb02b1d06abd9da9a3e3a3e758a302f7decfd62b5f14f44710a2deb468a8d36c7cc425932691a7b3dbda45a7e05d1dedd1205394c449ffa40f27349b529358ad7cf8c7fb25746836e4c072fd6e0886302b7b0bda351f59554423d63b243d0c79b7b6be933a944f14ba52f16df545dbb6898528eef18305be87c69a07eb2c4516d2889141f3120c56b671cb13be91ccaaf5aae256855b7074b419ddff48e2a5e559aa6909a1c8a2d124275b3f89a82ca92d0c90d3256ba4ef4bd91ee3f855409a56daaa4d2765897c5b4b5411225618d12915f42b1d52fa9d8e6b7aaf85ab53189c0927333d793f6725ef208a23489c9adbe9242a80f4c26e29cfbb7e6ef0eaa5695de52a59576d2542b3e4d10013fb1a656b50e9ec5a53de208180ba34452dc975e5b0e1e88304abfa4d6d2a752bd705b3979190981db8ce5c772b358eea6060f05b54e4467362090af0de46b5760a95fc2524309912a41754995a46a51ad525d294eaace498dca8c2173ab8d93097addb907ab53af212c6b359344b0ada350414b714a1d19c7f0de84d0e76f395bd2d488fbec420df4c02dbfb462684d37d71aa8479c885bc348247c8bf4d0a2d2be672cce9d66d937cf58e8c8d5f2d2b4e255ceb6b8da70a34172df36ac69407f6cc3f7a6476bef577fc77deabf3450ffa94b9638e1842c800edd621591ad388f82221dbd2517cd74b10de91f671c6cef178e333bd654631939d95a1ba49c6c6f3548fc12fc2ef925f9b570b2d10d220505fe3345123e7481d527a5c0e6f762f1b572c6d9570969c441bf557e57fcd2fcae73725230ea1429fa02cb4949c4aa0e9f0d1016fb74d559aa8c81c635b54e599b6ad6d49e318da9aebe72851b1ba76ff7e131bc0f0d358431e606ee9ca9dc79fad614ceaf07389e35369495cece3fa13a5e9e204ac2370e70a93083be308880fcdcac5c5644cf25d1b3abaacccfb63973e1dd40267f4a00fb81eb16bcf7e4cf8962dbe6374b3b593be55d6508334c321d3299bec4dc4c31448ca0e16f0c2dadf71d47883694affb262736a73c75566a30834f9684f32172883c7cf957fbe3f13e88f6ef42fd19fd0217a7648c708e31a7addf824b0967600f387be313666a0ed7231f50db9d3d824207f74865ded01e2146e219873586b40537571936d3816d52984d47d7cf986bb209e7a6845809a3aba4c4752cdb6d449fde60bb29c27463afb6f438ecd324789f96b904bf2529e7de93e4e7325f3e92a6fb9aa5a2291a6676e7d90d7a4a3d4322c1bda31e2741acddd28f5ba24a83fd1ab75334223ebc833b7b51502800fa793cbdd9067b69d769ef3a2ecdae4464836a813a5882f03b2ad58faa344273ccc19df8d829d9945f9cfbcebd16532ea1cdb7fa2d587ab2a3d6a53316e8a17dd49bce1e4ae8137ac8827bc89839b48706ce6e0fd6e1511fdc375937d3f06d1a7e17b9eddf9c1df1a7007bb174bbac7c9e21291f4ed2a42161076922e63e5d36d0de328f19ab424d3b1a3c5f0dc6bbff4524ca5c267097416c9aebec7deafd7abc6932eef147ded07de13acb0f8718292ffbf1dfb02c6a3f180b89c483c9e54ed9789b78dff9d454c4e74517391979ae6fe2f3d158d0e359a9f88c546fe6ad4361a6c4512c3e4bc556023e07c2bd45bf23f52653141495f5535eb1465ddc85e8a79bd0e165746c13f83afc49ebacd4728ed3b4a4cc46f107204f5184585d2641f4cf52d98255b8bdf9b93b1a54d163de9e91b6e3c48ca540933c5fd5c5e03ee98fd7c781b58ce942a5911bb574b25d16414506905478bc1d91b98ffeab3f8335dadff24bebca2b3153043e5bf56bc29a817550618e10d34b29ec83fae0f2f9d6396d8fa4a9cbc611c7be73efcb8000dc979f5a3c5f256218a859043587e6581fe8ea2e8dfcf437a899b1a1655abac026c1e5c758589b94d3c0cc258fd5ea3f6508eb16f92df1a724f2ca557f3485982e7f3c4aa71d692d7de6d993d6150137f1ceff4ccefc1c6e94b565aeb393ccdaaa1dd3e51f4476d43acfa963dbdc7530b2016b1631f7e0094e1779bd49fa37bac85b62e680866535e39ca1a67fa7b74dfa81918f7c7ee8c80fcc8961066927ece1e7e27dbb2950d0af24ec4f9329861496b2f7871b8c911dc5c1058f6565fa4c92d0cf37a358610d8aa4ddf540a7719d2695631e1566eb835d7dd56456a4333eab0cc66c4c97682067c27b62c8d91f534db5445a7fe8be837d6b3627a6a4e0057eefebbbcd1c0756ff61c5be440be6a9dbca36fb2083cd1c8f6d5ebbaf74762c331d64c4617595b142b0ef65a4a6d042e7900fe1fb37c1cda186fd0669bbd0be38fd41f05572240ee13d8982b5b738c273ba91df4af13492604ce925f498d3922366d315b145e2d8f1f6f6d547ccc56bfd6e785f53804cc5ad4a2d784c931bbd795f91ca871d64bb0df1f371e58eadb4eb5df495406656d2e5043cbf2a6f3b1cb0722cf06b25e6145ed21f9438cc7320ffe6f19edbdede6fdeba9adee22bd71fce019fdd97501f3e8caac956b435993115b61c31fbada6c7c8a4660d77222ca79516a9320624f8cb39194723cec98a6f145f25e7f0d2614f5d65b52a643d0aead6c374925da2688c40fc9901a3ad363720efe4eff2b89233bb45259412959895e86daaca5c4c2b7228c776e005dec0cd7c0b39e7c35aefb5de37fdaeaeb028ce99d1482d9d087e4e630af2a78c627fa952d8158716b1fcaeb8b85eca68fde34322c3cd36a44a5e9187df12a86b6c7d5b6f6cbf5a70c5e746fdb167c0d61ba03cde152bf0294a4a035234e2181bec8a15f814858bb1434c06ec8a59d8152bf029ca95fa1e456308e14f35f0bb62d8a5f8ad4c2fb15eb3ddf3845d31ef23b8d652bc52eca154ce9522ab72f04a617b70e84a31253db8653fb79a075e915e9f64a07f85bd5623ac77655284676ce6264ba1c831fb26caa63a771f0f94afb4fe95ecfb5dfb640a99dc9b274fd991c75a603ffd39cea96a02adca9a5006cf125513a1b99a109b5495e495c89f8663eb937662fb33e586194cff62a90d94aa49d5ce6855df3aed095bd36234116662c182bbcb93434dcef7a3912788ebc29a19b0c9de5182ef0ee0396b45add9e6002fbcf28da3ed784e9035c9da613692719e488aeadb77b4cc09ecd7b8e61039f105ce873928390e38149eda0bcfe388c2da3ff468152575f66859e1e01e6d20ffe8aff125b972fb2991eb2dab717039ade8fee584f143ce5201a621e3776f6829febfe1a4b911b79e1a8b3539f3373c1f119a497a911ebff50b6cd35c0f33f06fad52962b818f82b2dd195b964f8174f7acd76df7f8b7c1c29e7f2fff265858dddf970befaecaaa8595b64019c4bd7f7946786bf5144f23170b6f9c0cc22cbc4f08670bf362b7f29cc3a190b6ce2a67088d590bad3c403de7a27c9e2e81d75c594ab6f96c6d68b3530ac15fc974beb38cec506a713b5296abe88ebbf83e30a1f9ce824f22a2462aa770f2153bfdd3b2503e666fb1109ea020b72f129effac80447304e74f161f318bab2924d29b63a0af732a96e8b4538d0a298adcfa02bd732fca56266a746cb5b152144eda1178b62197a456b6e11eae952f91b370a044fe757c47e8524cb5b15174c4bcd90aad44eac314c26f86b892ef35f4e9b45fd78e40b74610da3f47b47812c03333fe88f19f115d9e38b6ff6e76162bfb96e46fe3af0779b1ef8bc733b839b669fd84c88efe7867de6356e7fbadb2ce31979cb330b2cbafbb66e45ea1e7eeea23b29068bb2ab9d00a76d7a29e1644e8a25d3749ecd82b065f2195f78cfd52fb175b1f08713094aae54a6dffe2af2dc23bb38ea16fd59a3a9d1ccada47d7bbde124ec3b79306bf6bd377e05549da8ed7a5dbe3229d77563a9ca58fb70d481f706d407a7443987d6e3aa537ddc4d24b06af33bc64d7fc52e9c26684253e6b7195bf6a8e861132244d2b4dea77b85a7b6d4defc02e801819dc8c7b37b6a9ca807b57e82fd79b5cf45ba861e41597a72a685764ab6a15adec15a992fa95aa667ace2d68b5045a0f982841583611eca006c977c9e5d90aefe2032e5fa9e5d76a693bf46734c272068b351234b26540bad20452926dbe6e714a09328e431f7909761a394fe44be4879385228b7604be013e2e7c4997e87608fa489767bd5e798fe7c3dffbbc1d12d94194c17fa0b7c4d7e6c6e7f1bcf22bdd5e89b835ebe34a9fec2ce54139580c53939df5cc12c885ef494fcb919943b875fe0d62a422a367c411b3be8142816d930ce0950a3664db72c41cdcac073ddf6f98f1e6b4d726bff248daf855135f96b667178f6fc352289868c4b728730aa3a57b2b450a32eb0e6e9fe94b713d8926352b4cbe28db1cb8f20c93e933f2784b97736598c40c7870d8ab9c24f4d5fb8a2bb513ae8f49777fcf83dffdac6cc6774675d1ca5898013cb678f72f57ce83a7612f7a1f9c37e1291adf0e55c845f8742c9891a65624fdf17d0f2f9d3ec2036d6b004f975c22566ce81aa14626a48f188658cfd18891ec3811085eb0d56bc35deb30c3dd95a6fed12b2cb8445d6d503ddf2f2992629a18f9710a3f7633cde27146873ea4c1516510f9642b89ed5e9a155b85f935cc62bf232a3152b29af82e51846604f6d3c65d4ec0b349757ca76856527863a5a8da5e292a86f5b5b459d05d1821a62e6a6418a390664975f8664f13779fe84a79026e015e2bf896f0eb0c3f873331ce3932e1fc503ba51b611ee5e7f965ce3cc7fb78cd71a6ec5de44c09b83b34855ce23a1be81d9a92fc57d75717763e05fc02e4a5dd964b97da907e1f8914f61e8a16db45bbb4e46c1ad9452e39163a4b46760a1a3cbba4710ee17fde12494b65f8e6ed5ff0a9a7fff9d34891310d9173a6fbb521ffc61e94993b9c9a64f6039f7da659a70d1f5e89c4f387a39287a620920c7fe822516d6b20fc8793c83a7bb8c3bff155c8af28f4130fa7e879a4881e2d169962e811e7f17b11e2bc8889a1479d07afd108fb3263d41345aacb63f73977695fd7ea42fa2d56a9f8de91a2d2cb0a4683b8d58893be25cad5d36d6eed7ed7868aa314e4447c1f86c2b71915e43a11b43dabd2d57632dad59fcdceb693c9fe4bb544497c06227cc33792447f2ebe6da9386b4125321992d7bbfa63a91d295eed2186cb26158ba7c09ad9839fabccf430b1e8f3a2cd2ff8c7372026664cee74732bfe5aa2682a0adfdc88c2e3eab92f224e23ff1c29b26a5aeff1ed9955247ba1d7e2948b99e2940bfdc2cbc5cd20072a7f861591f37f2bcf83dee115969b398c139c2b2c58fecd4ae4415a20003ecb6c989972473714cf26359b4a8a4fc0dcb064f029c67a582960469ec85259b2db16edc4db2992890a2a4b144e358bcc959c5ff4eb678699669f974ca764ebc39ab38bca936f6748269a52c08e36dfaea426aef79e8b4b8baaa94e5185b9f8452f6b69ca8e7f45689168b8e48902fe1dbc739e09e3e619f060b9ba0666dcfd062c07fefe08d7ef5ab16e3f2051ee95617bf83eb05095b8e3842c39db3cb4f6db29d113f97595b7d615e91b3539ce9e7b03fc05894ee3c1f0169bb59f88c1375714e23d4f2864c85b111f17c98e0a46ac6f082a453b8b3e2b2c9d0576d2a7d8d84d949c3312cc969aa20a54dd3a8a184ba9cbcef679500568aa591f4cf595349a0926b7c65c89cee6a903ec7d64b0f541e9dd2d46421b41fe69c1d898ad8bd85121a8aa485d7668f8d6d96408f88365873cadbe0df72a12f8dbfdb08b125519e9d5a093d4ad11994be8951651b6af32847b4f30b15777a4b038ca22ed43fda330c72db08fda98577c02cf4578fc58284ddfa8940e78fdf39b1736614e6106f06957592430221431977ebb4b546588f0f8d302568ec4fea41cb1a05edf9b4b67e3dbf4f44e23a265858825b328a757434eb08e79bc7fd0195b974e3bb01f17ad9ec98d603f77670deba5c248892c52e419484d35ab0328a4301bd19122790a8402c12b1b4721bcaf156ba9bdbe560b893c15526f09ee9bfd45781f4486581f6cb8476acd78df98d35ace1635a2080a794e355ba401c087db2b49d12cece9992bb01f28fd54210d901c32eb62d41f51d8bf454c701d65dd79ea1e2ec1520ba453cd8b67eb82777cde1fd1e260b09e64ddaed44ec47de62da15b2a45f8cbb792f825e841ea88790b1511823c611f3e9b89c163bd240f7fcb35d0cb50e26a2512f9822d796ed2cd2cf4ac73a6716da70224d5469b08fb07ca4aec3387fcb3cafc0ef0dd6add6ee3f24c5698b5627a01e5f178bab40fdf928fbd35bf1d97bd0d3687fb4d51d088a61644500128d01c3d5b3c8142ba718a2289887847e11b0c1a54308b98a00bf6390136295b1fa19db89eb34fbe5ebe4e5be5275c9dc5b4bc61734a18986d79b205f8cd2c883eee66a9dbe74e54078c23066ed18731f8167d188c658796be5c395c24686065ec26dd1385aa28c674c49c6d8ca0a217a8fed65b72619be72fd95938f42c177aca152a29f4455d25fd166728085d2fa97785a6a00b255fd43a431a74ace43b57da12bcbaf42f71a526e3f0dd25aef48d386c7fc695ce7db573f319577a210eff56e84adf8bc3b585168b347ac1afcb33334a0a0f427bec6ff5e65dd8f615cc9d7c7c49613dc2a7f2d72dcef059b429a3bed6196a41e9195fbbd2ba5062c677ae349288caf8c995e64b1019c9aeb4202282ea7324bb52a740b8c791e84ad740f89623d195be04c24d8ebdaef464081f77ec75a56f84709663b72b9d813072ec76a517e2f0bd2057fa5e1cee0b1a68150e378dad05bb10d16d9522e7f8dac2078f2fce5d1a8339652a314fdc575b4f614de7f8b8a57c75ea02c7bf34d6adc4995e6e5454f19ca634d609a1c1ba814303ba814303ba814303ba8143437483e3fa54e387fcc80fe1faec10aecf0ee1faec10ae38c46bcc1257aa508b2b5dd030573aaf51cff07d1ae7a651e7ae1ce3e3dd342a6e8846c50dd1a8b8211a153744a3e28668549c9b46c5b934c895ce6b50a22b5dd020573aaf417b5de9bc86ec76a5f31abadb95ce6b58902b5dd03057fa411cee19eb4a1734ccd57bbcfdee38e60cf3f6bbe360d448063c67ec1f0bbedaa71334c2db8409bc7facd3383de43d16962a13d1d64a29becded4f05392e68e9269b089f33da504443080a5266e691d608ed79949937c6ba237797cdf90ddef1ef9cdf2cf35a84df24a91abfb6384314f175adeb5974c182e7f22b5ada5619ec9afb86f1b6e19af9166d33616d6b29f93a4ff503b60a3e769709eb196bcfe86bb10cc470edb7fec4f54fe9c2cc8c5d26d09587b1d6f5e67d9d57fabd6015cf1f33d5612bf94d53eb0c633d85b2b7a096df52f9f2cf1d33617d63b0be8de0ca5f8cb23853b0c66940e35ab89863a6d2e7b02645501d8e2e7e349ee76e66dba95b6037bf0923fc1c8e8b1ac2f3d78b53b8349c1241118e5f393e99cab34209185f025b39c35bffc57e6e6c67cc1ee0fec889eb0771dea3b3fec8fde8e7bd0707733f3a6b30f7a331380ea7e11a48822b712afd98336d70cdff38f5cc415cf31bda819ad31a182e6f5fcc1f6bee3b957f6c70cd7d31836bee73e3de7e6a0cc77dc6bc41edfa52ce4b121b95816331675c0327e5990b359c34b33ff7ad7ba52ebf0b78a49df8ba9a8fc3357daeac63f99198a11dc8f34843660dd6b97c2d3e1570ea5cc8b5019dc31a26bc11f62535fc935a24d75ca8855da64848f189a8df4ac0ee65df605f7e7e33f8fe649747d0d7262d8dba3cb9bf37319710ce31b25095c9750bd951c5cc77de44cae1ce80f9b38e7b55aefbab09b55506e7d770c7fbaa18671ea4174e0ebb88a0a16f6a2cd056f1074664d06669159b7a51c98fd188edec14937246e2bff87df4e4662c3529c1721fb4f0b91bd049edf13fe486b95b025631c74b4b684a1a2b896db9d65c5b8fb07691b0d3a9a79cef1faf89274808c91c34c7c903d784f93cb99908c2bc48096121847edc739d9b59da2b1f71f67cc38f7ccfe39926b089ef7fe709f0e05dfbec3e5233382cbe22d7d4f3522e6072e9b7a9604273a9d1b933572dc03e6149a3126dcb6542c297742122688d058f9fe067f7e0d6973e7f2c775bd9406c59371f5bd2a8451706e50ee872c65344efa0f8b2dbcef806b4a27650fedfb9f845258d116817d43f7d499768ca607eb79ce929a87e30bf1bce7833ba6471be3d4cf8d9598b11e96ae5ceefa27fc2b17db3b1968fdee78c2d6be463b1a44c087e03f48cc599d67416a71dd5f67223bf6f9e6263d70832a844e98bb056f8834ec0aac4a5f82f61d0d716613e6fc671bf3e8ff72b99425c96958fc312b5087191979d7114f19df09d1f34024ba3bde40c37f1e10e67f8373e0c7c0853adb3edb067cfd5fd8bd0e437086dfa9508e2795faa755a5dbd2b77a35beee33ff1b98fcefed4f2c7dc36b7dc4de79cb97defc3dbee961bfde8cc3d61506ee7d307d583668eef07763e78479d9d259c217eb579f64c23d9c2cd6a0b4b1a43a086fc7f99b4e6a9b0ffdad77d868fc7ef6d8e7e2f9b9d9d85f344409e1d27b641afe1901642577e6360143147bd4d7b9a3ba1e4ce201aaaf02e2473c9b3f340ee06d96c3cc2d959fa1452c47d95e5caa7dd77c48cff9e42a9168f2adb6d47747eab8897903a513a5b17626a50a5c26e7f4db6d9b99aefca1da9b5eeb4dd5325f637ca925b84da538e0f70b595e3da9f9d0773b7e8ba8308929d000bf655c49f258473a2329df68942bab001f93314cacef2493c1f4be66efca56016be71c8df34fcdac297c0dcd5e5d411bea466172f9bf6d3270a8b671321f85de3e6d944507616438a1bba1ce26924d207cf21d86ea9a8e51e11a20e6843c5b0ebe77af59fad073a2c9bd263dbfce5871c78b71e6a086ec73bf16d5afa6e2512cefb8a856f140b89b2422dfd50378219dcdc2d12eadf21bc6366893298e14bbad1d0f8c87788b2a9cd614d50e6aacd43a414faa39a60679a476bf4d1ceb9b2ec6276b2c86763d6f4250745e52b4b0a26a3f275fe71f588cde81ee1af3c8522ba47a0f43c6530fef64ffaf6a402ef84e9544ba47fbc163d1523daa00b625b48d953a79efd9ccdb08f507dee0f1bfbea886f11ce53025556db420805a4a8035a3debf3d4c152a40b79f6d4b331787dd085602f1042b3e0c946c98007b55dac3a85570de1bceb6de11d3b834f34b19f981c24757eeff9bc3fe94308b32ff7c65bff37fe6d0dfec21c5a7da5923b2357ffbdf25d46bb87ea40cac9f8ef8a18de95453adfccc822077f4929d8938dd722aa94d32225778ef626d64df57e4aa6d776707f7380695092dcf9ea778234a7f19b073e8e3cef7c07af3f25e86f59296dbac6a76abee14b240827d50def96d21d3f38bf2017f9b258377db9ef73336616aa12d5fb2d32eeef4c2849116e1d3347c72a8b618f2fdbf728bdcb97620b414a3feefdfe86fdc5e26a19d28f9f8d74e3d9b6f1481da820585996a87ab352fc79b1faf069a43e7a1ec611628c0d227fc94174840997f620d9f781cc24a15f137e0f5c092b3c896f0090a7842f7a7fe7dffab8ee165c37cdb1eef2bd3b50f7aab4a175fbb9d7fd11d47de03cccfc2bd2f17728f8ab14fc2d0aff65cafedcf5a101287319bb4c23562cfb02b1bdbd6f11a1e19b3e40ecf22e319d2517b1d4adb7e86dbde0ed0f975f54e2f7c6ac69f471629e2e3a681f4dca65aebbde19445009c53858f9b7c7c347f7a26ad30791576a694a2e6595c0577eeb2daf7975d1d67aaa8f6d9c27ce5cfc58168ce65be11b3610ec2f77c59f3628703d7a9b94d40e973ca75cb695352a8f135a76d49fd04f6f579b7a23fb477daa0d3ff51a41b7364af9efe6ea93b748f71795ceda0f5e826e2e39ef9805d7229fb7cbe275daf5de6b2d2f55b84f2762a96f8f9bf2365ae45fb1ca9388fe86c2df9fbce5a5ad8b4eadd56949ed33b5382cd7a65bf8f8672c0a5f03a25f3579f78fd6c5281693a2eaa526517fbc8ebd92a77b273cc3243ac584431f8b944bf2e8372822d4cc323d0e3aa512d11b298265da1ca1e6708a8a0a5f6a1485671845d53994985552a25946baaf11559915b0d3839d0ea2bb1ac1f36973404c01292acc5bb6b53ae2165a013dd0fb177ac9ade18a8c0dc8eb845c8befc4d092ab9e5e5a7af8550fdacf0329323af169bdb8118d9428941b107f5feab2b25f9909a5e5910aaae92daf2cfa793bb6cae1776430c749efc868d24396b9988534b67931ca5c82c7e1315de2b6ef950a9f6ef18a6d51db761c5f5fe683eeff6d123baa17346534aa3f1697136b586ec49ced78f614d97d18ad7594bd938826cb9fcb69b1b0cd064444e3be4caf25a3e7fb10315eda2f6ac7de1b2bc9af9df0f3f5da29f7f8d40f6b93ef31b5a476d735f6950d28d0b8eb73a1adc3aecaa0ade2abb240233dda03b1af406b35b4e110f456344a64155a252273494d35d515c94ab3c4f4e7dd32bc96e01b19a6f7aae3de4778d4c32767a1255b59e8c36d274c3c5ff28e04e41d714784fb90e5fb508ffb9055c2789fa7443817110dad115137d8e671a8e358a031ea8e8232a0544ba071d9f7176a37dd190b5e7122b4c22b4ba7b50ea7ae2aec3ea8aed6ebb85007714704755077906f342df54064f4e8b2a0e835f7bcb2303f9d36f56050f4c63bd72db85f701f103175d1bb8e0d843e3c787f6bbd0dd6dabf5801d6fa711678d86fe942af6c659781a58e9073da4c0fc396fab6e4a2f2c256851cdb2911ebbbafeea4eb36c893bc3d28c04aab0ba077b8fb6bc74eb2e69348c1d96854acb5e1fe36bafb4bce460df7b7d13366b0504df8a94d8462b312d12d673d84af5bff3c60a504582953abe0ac74ef202b0d98ec6ea56bfe60a551b1899c95ce15ac3455b0d2b983fa302af67eda4c4b3cd0fa8007ff8d3e67c6132c7b4e2262974844bd5b376d0d270b44e1861cb0d643a26aa650c482dd9717ee2fa0bb0c88d48a94478a321713dbc3ed0694b84da40c352b7ccc48b71d6bd90af65041545e8524bcb91971d6b89c92b1f13e88dc0cb64cf5fc855e70cbc369cbf86b173aefaa14f4db74554a17ff075ba664822d5b17d87f078b33711aacbb23a1b33c24bc2d2b562f4772cbfc9c60de2649fb03d8daed0f80163f60ef21a21fe76c72e6e65db54fff3e56b2a9f6998bd76b37fdce5be07796e47b6bdc2c90933097b3403d67813bfedfb1408e2fc3c99f0716587c7f0bc4b9380b94519715ab4351d0c1ff608112aa4991f1a060815c1d3ace028d9c05e60cb640cc4fa7fda986b740be072e550f68d1c69adb216065f18a78b0323df8506fb1d2a6bf5cc9cbcca74fb522f2e6ae6bd8b31f730562a3e833ad22268608f97e94829c38fb6cdee85dfe54e3f1f0b395089f8d1141a67f31daf5654a7c8706f6ce176aebb4d701994bbab8bb6c788febf5b5c2871411db5d7fb3440ca339dbf49e829a387b3a698f0cf7791f29baec6ff5c77faccfdcbad0376a9beb7678b44e7b01ac204b1c1edf85b0af37da7a49d9755701bd3f26af1ae2786fa6fe4e15b7439f4e5646e2bf9483ff46967307ae1ece7ba79468338d25d26906df7549500a5fb74b37d333d6e49fc836bbeebe041323f9349b34b04de9c3fddd38e998adf8fda197e133c3c8e681fb1c993e2c388015e0c7659b5b2cce7229625739112e17db844beaa2679ae8228388cf1342f039de4763b60a69ef1910cf59948a79b3e6c9e80c706624d9e64b96c1a19fb85bb9aef7ff28ac7d52dbd46669a7705be0145f03d55b4c97af9cb5521f617cf872b2c9c65254807a86fda1626da6867ebec5b91fe8e34b357d95b9049fb1603fd9ebb4c23702cd2c544fabf716efa31e2363a68f6a45e1ab4ee3dbeb8fa9a79d0d30c5d0ca1f91be42fbd892b7d5550d134ba44a24a78653050d47cc3cdf20fb562bcf39b281d0ac000f2daebd6a8b707fa00bcffacbdb9c6bc073cd615b04298ef0b26bafeb3fa510394f7fc0f4f0ae26695245c2d0d94dd867dd4a4c545a39dfb12e2bda5fdee9182e092eb0ce95f7d1720fa48f3004d0a09a998f27fa74594aa37d92fa2368738858fdfe38a2eb9cb852f2d8f4517f22f47f37c04e840891dfcc2e2a8db61667f4ea2da687ad39e6be672cf8fecf4fb5facae8c7f4530cde1d79ba109d2d8ec92eba541b06ff7e51cb6bf9c05f596565dbc5f88657a8815e4ea2e992ac48e7373ba82e73b13f29717d4f31b8ccb7242e433f47227e37226d1e2819f923aac3b77cf00d4fe9f5fd86c02b5b98819288bc5f6de83b5c5b30b3c5f96edb07d73c70877374fa2328a74f90ec4e7f3c2def429334fe4bce4692a6d67572ee1e4a8bb36d424d4df76d57c2195c53203370fb7170995bf72d13d030b48cb09fffb198c6a543f533378fb9e6fccbb5984b8217e60252aaba9c7fc5ed04feba1bb435c1595e7da8f25bf134fcd729899870524c3825e0cbce62ad3ec97d5cbe4f2abf99c55cb20c951349ee2767d9d1a1729626aabdbb5069b27a24fc3bf7d9ba5fe7aaf1ddfda7d5be5de8d7a7d5a3e0395dad847f37a9ae1c4d9c71a574c58c96a3c9aaeb47d7a8ba8e6e54f5676721b4f06387e31dc07180df270ec76ac0278033071c8e6f000b0f391c154025871d8e6ca05169a9296b939302925f7ef9a597c77aa0a792d7a66c58e50aa2bf456b662dd1ae08d0acdd90fc72404c5ae2fa55014fbf94948c849f339d4bc1094f04a4ae4ddd10b031f1e50df004855edeb86ec37df3a5bdf4d23ae421f049dab866ddf3f44b2f273fe1c5456d5cbb2a716d521a48368809fc447f4659f7a38b23ee1fefa45f4dfdafd3273df15fa7c74ee6699240df1468b1403f11e8f6293cad12e84aa1dee593fe6bfac2cbc9892fae7b091acbf7c7cac48d691b0256266fa0570d0aa7bd949834387dfd06e8312e9c9a96969c929806bdb57ec3cb1be90da92fade5e2d7a4ae4f14867880d9d0788ee9a0f000d3ffc98fe2fe855961e84f3a382012fd8fab71fd64ff2799c5ffed9ca1c2f83c22d071029d28d07f08b447a07de13c8d13c2db85303c21022002881f4648f2978f1009900228800c2007780086013c218f1760386004c01b6d178f04fa00945700f501ea0b1805cf4a80dfc3dbd168c083007f800a3006f010e0614000602c2010a0068c03040182012180f180098050c09f008f001e058401fe0c9808780c3009100e980c9802980a88004c033c0e7802301d3003f0246026e02f804890350ae49c057436d068a01aa031d0562d600e602e2016300ff014e069c07cc8f357c002c0338085d00f8b802e86b425c0230e100fe1a5806580e510fe1be059c00ac07310f73c20019008780140039200c990be12900258054885b8d580170169803580b5809700eb203d1df032603d6003c46d04bc02c800bc0a23bc09f01ae075c01b804cc09bde3bd05b802c800e900dd0030c508601e4008cc06f33c004d802c8056c056c03bc0dc803e0fff201ef4cdc815840013c17028a006640316007f0da09280194027601de05bc072803ec069443be3d80f7017b0115804a88df07f8005005f83be01f800f01fb01ff047c04f93e067c02a8061c001c84f843000be030e053c011400de028e018e033402de038a00ef039e004e024a01e700ad000380df8027006f025e02bc0d7806f00ff027c0bf80ef03de007c08f80b320c3394023e03ce027e8a19f1fde817e81e75f01170017610c7e03da04f92f012e03ac8066400ba0156003b401ae00ae02ae01da01d70137003701b7001d80df01b7019d802e4037c00ee801f402ee00ee02fa00fd807b00c7c3dc04b050985216f164dc0221bc18ffb3fa1787e355400ea000500ef808f019e01bc045c00dc03dc0f05f1d8e870053013180c5801700eb006f02b6024a01ff001c057c05f815d00ee803785e7038548073f07c0b2083e700401860062016b014b012f00ac00078075006d80ff80af0e06f0e4728e057783e0a6807f4017c2e3a1ce30093009180f9806701ab016700af01b6007602aa003f03ae028e00ee003c80e752c05a4016e01dc03f004701df03da01f700dee0cb8f034402e2006b01d9807701af5c823a003b010720fc2da00dd007f083b830400c60392007900448bbc4977b0d70eeb2c3d10ce804f40082c1ff9f013000de071c052cb6f2693f024d139e71fae266876315e00dc049c0558843405580ed8032c047cd7c5ec3209e98fe0ef1012dd0678030789ed33c90fe06c47d7599478f001c87d058418f0205aae66852e286c4e7335293c0979bf964c09480e0e0804151339e0c98c6e786c57edd0be0af8d7d326049d4c2c5cf2f5afcd705cf4ffa37f18f3d3fc5b92e8e0d9cbbf615f0189202d625be9cba6153a0101f7bcde198058811e8daf681f07c01380e874307210eb0f9068f77010601af5c1f08e36783909e3d08476f423f102291187e12e147bafda4ffe147fd0f7fb2ffcbbf1edae96720dea92204df8ae07d9d00b12b9dfb4d4ce5c36d022d5b3d34fdffeb3fe7ffd76478f8d77f9ffcc09ad6f68b241af67f55a2fffdfdefef7f7ffffbfbdfdfff9f7e4b5fe4d755275de5465f75a39bdd68b11bdde7460fbbd1d36ef4bc1b6d73a33d6e54963694fab9d1f16e749a1b9de34697bad1556ef45537bad98d16bbd17d6ef4b01b3ded46cfbbd13637dae346656b86523f373ade8d4e73a373dce85237baca8dbeea4637bbd16237bacf8d1e76a3a7dde87937dae6467bdca86ced50eae746c7bbd1696e748e1b5dea4657b9d157dde866375aec46f7b9d1c36ef4b41b3def46dbdc688f1b95bd3494fab9d1f16e749a1b9de34697bad1556ef45537bad98d16bbd17d6ef4b01b3ded46cfbbd13637dae34665eb86523f373ade8d4e73a373dce85237baca8dbeea4637bbd16237bacf8d1e76a3a7dde87937dae6467bdca82c7d28f573a3e3dde834373ac78d2e75a3abdce8ab6e74b31b2d76a3fbdce861377ada8d9e77a36d6eb4c78dca5e1e4afddce878373acd8dce71a34bdde82a37faaa1bddec468bdde83e377ad88d9e76a3e7dd689b1bed71a3b2f543a99f1b1def46a7b9d1396ed4b92f77083fe7f61c5d946721b7dfffc9db90ff07cff9cdf8'
299 ISP_PROG = binascii.unhexlify(ISP_PROG)
300 ISP_PROG = zlib.decompress(ISP_PROG)
301
302 def printProgressBar (iteration, total, prefix = '', suffix = '', filename = '', decimals = 1, length = 100, fill = '='):
303 """
304 Call in a loop to create terminal progress bar
305 @params:
306 iteration - Required : current iteration (Int)
307 total - Required : total iterations (Int)
308 prefix - Optional : prefix string (Str)
309 suffix - Optional : suffix string (Str)
310 decimals - Optional : positive number of decimals in percent complete (Int)
311 length - Optional : character length of bar (Int)
312 fill - Optional : bar fill character (Str)
313 """
314 percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total)))
315 filledLength = int(length * iteration // total)
316 bar = fill * filledLength + '-' * (length - filledLength)
317 KFlash.log('\r%s |%s| %s%% %s' % (prefix, bar, percent, suffix), end = '\r')
318 # Print New Line on Complete
319 if iteration == total:
320 KFlash.log()
321 if callback:
322 fileTypeStr = filename
323 if prefix == "Downloading ISP:":
324 fileTypeStr = "ISP"
325 elif prefix == "Programming BIN:" and fileTypeStr == "":
326 fileTypeStr = "BIN"
327 callback(fileTypeStr, iteration, total, suffix)
328
329 def slip_reader(port):
330 partial_packet = None
331 in_escape = False
332
333 while True:
334 waiting = port.inWaiting()
335 read_bytes = port.read(1 if waiting == 0 else waiting)
336 if read_bytes == b'':
337 raise_exception( Exception("Timed out waiting for packet %s" % ("header" if partial_packet is None else "content")) )
338 for b in read_bytes:
339
340 if type(b) is int:
341 b = bytes([b]) # python 2/3 compat
342
343 if partial_packet is None: # waiting for packet header
344 if b == b'\xc0':
345 partial_packet = b""
346 else:
347 raise_exception( Exception('Invalid head of packet (%r)' % b) )
348 elif in_escape: # part-way through escape sequence
349 in_escape = False
350 if b == b'\xdc':
351 partial_packet += b'\xc0'
352 elif b == b'\xdd':
353 partial_packet += b'\xdb'
354 else:
355 raise_exception( Exception('Invalid SLIP escape (%r%r)' % (b'\xdb', b)) )
356 elif b == b'\xdb': # start of escape sequence
357 in_escape = True
358 elif b == b'\xc0': # end of packet
359 yield partial_packet
360 partial_packet = None
361 else: # normal byte in packet
362 partial_packet += b
363
364
365 class ISPResponse:
366 class ISPOperation(Enum):
367 ISP_ECHO = 0xC1
368 ISP_NOP = 0xC2
369 ISP_MEMORY_WRITE = 0xC3
370 ISP_MEMORY_READ = 0xC4
371 ISP_MEMORY_BOOT = 0xC5
372 ISP_DEBUG_INFO = 0xD1
373 ISP_CHANGE_BAUDRATE = 0xc6
374
375 class ErrorCode(Enum):
376 ISP_RET_DEFAULT = 0
377 ISP_RET_OK = 0xE0
378 ISP_RET_BAD_DATA_LEN = 0xE1
379 ISP_RET_BAD_DATA_CHECKSUM = 0xE2
380 ISP_RET_INVALID_COMMAND = 0xE3
381
382 @staticmethod
383 def parse(data):
384 # type: (bytes) -> (int, int, str)
385 op = 0
386 reason = 0
387 text = ''
388
389 if (sys.version_info > (3, 0)):
390 op = int(data[0])
391 reason = int(data[1])
392 else:
393 op = ord(data[0])
394 reason = ord(data[1])
395
396 try:
397 if ISPResponse.ISPOperation(op) == ISPResponse.ISPOperation.ISP_DEBUG_INFO:
398 text = data[2:].decode()
399 except ValueError:
400 KFlash.log('Warning: recv unknown op', op)
401
402 return (op, reason, text)
403
404
405 class FlashModeResponse:
406 class Operation(Enum):
407 ISP_DEBUG_INFO = 0xD1
408 ISP_NOP = 0xD2
409 ISP_FLASH_ERASE = 0xD3
410 ISP_FLASH_WRITE = 0xD4
411 ISP_REBOOT = 0xD5
412 ISP_UARTHS_BAUDRATE_SET = 0xD6
413 FLASHMODE_FLASH_INIT = 0xD7
414
415 class ErrorCode(Enum):
416 ISP_RET_DEFAULT = 0
417 ISP_RET_OK = 0xE0
418 ISP_RET_BAD_DATA_LEN = 0xE1
419 ISP_RET_BAD_DATA_CHECKSUM = 0xE2
420 ISP_RET_INVALID_COMMAND = 0xE3
421 ISP_RET_BAD_INITIALIZATION = 0xE4
422 ISP_RET_BAD_EXEC = 0xE5
423
424 @staticmethod
425 def parse(data):
426 # type: (bytes) -> (int, int, str)
427 op = 0
428 reason = 0
429 text = ''
430
431 if (sys.version_info > (3, 0)):
432 op = int(data[0])
433 reason = int(data[1])
434 else:
435 op = ord(data[0])
436 reason = ord(data[1])
437
438 if FlashModeResponse.Operation(op) == FlashModeResponse.Operation.ISP_DEBUG_INFO:
439 text = data[2:].decode()
440 reason_enum = FlashModeResponse.ErrorCode(reason)
441 if (not text) or (text.strip() == ""):
442 if reason_enum == FlashModeResponse.ErrorCode.ISP_RET_OK:
443 text = "ok"
444 elif reason_enum == FlashModeResponse.ErrorCode.ISP_RET_BAD_DATA_LEN:
445 text = "bad data len"
446 elif reason_enum == FlashModeResponse.ErrorCode.ISP_RET_BAD_DATA_CHECKSUM:
447 print("aaa")
448 text = "bad data checksum"
449 elif reason_enum == FlashModeResponse.ErrorCode.ISP_RET_BAD_INITIALIZATION:
450 text = "bad initialization"
451 elif reason_enum == FlashModeResponse.ErrorCode.ISP_RET_INVALID_COMMAND:
452 text = "invalid command"
453 elif reason_enum == FlashModeResponse.ErrorCode.ISP_RET_BAD_EXEC:
454 text = "execute cmd error"
455 else:
456 text = "unknown error"
457 return (op, reason, text)
458
459
460 def chunks(l, n, address=None):
461 """Yield successive n-sized chunks from l."""
462 if address != None and (address % n != 0):
463 start_pos = n - (address - address // n * n)
464 if start_pos % ISP_FLASH_SECTOR_SIZE != 0:
465 raise_exception(Exception("data should 4KiB align"))
466 count_4k_blocks = start_pos // ISP_FLASH_SECTOR_SIZE
467 count = math.ceil((len(l) - start_pos)/n) + count_4k_blocks
468 for i in range(count):
469 if i < count_4k_blocks:
470 yield l[ISP_FLASH_SECTOR_SIZE*i:ISP_FLASH_SECTOR_SIZE*(i+1)]
471 else:
472 start = start_pos+(i-count_4k_blocks)*n
473 yield l[start:start+n]
474 else:
475 for i in range(0, len(l), n):
476 yield l[i:i + n]
477
478 class TerminalSize:
479 @staticmethod
480 def getTerminalSize():
481 import platform
482 current_os = platform.system()
483 tuple_xy=None
484 if current_os == 'Windows':
485 tuple_xy = TerminalSize._getTerminalSize_windows()
486 if tuple_xy is None:
487 tuple_xy = TerminalSize._getTerminalSize_tput()
488 # needed for window's python in cygwin's xterm!
489 if current_os == 'Linux' or current_os == 'Darwin' or current_os.startswith('CYGWIN'):
490 tuple_xy = TerminalSize._getTerminalSize_linux()
491 if tuple_xy is None:
492 # Use default value
493 tuple_xy = (80, 25) # default value
494 return tuple_xy
495
496 @staticmethod
497 def _getTerminalSize_windows():
498 res=None
499 try:
500 from ctypes import windll, create_string_buffer
501
502 # stdin handle is -10
503 # stdout handle is -11
504 # stderr handle is -12
505
506 h = windll.kernel32.GetStdHandle(-12)
507 csbi = create_string_buffer(22)
508 res = windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
509 except:
510 return None
511 if res:
512 import struct
513 (bufx, bufy, curx, cury, wattr,
514 left, top, right, bottom, maxx, maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw)
515 sizex = right - left + 1
516 sizey = bottom - top + 1
517 return sizex, sizey
518 else:
519 return None
520
521 @staticmethod
522 def _getTerminalSize_tput():
523 # get terminal width
524 # src: http://stackoverflow.com/questions/263890/how-do-i-find-the-width-height-of-a-terminal-window
525 try:
526 import subprocess
527 proc=subprocess.Popen(["tput", "cols"],stdin=subprocess.PIPE,stdout=subprocess.PIPE)
528 output=proc.communicate(input=None)
529 cols=int(output[0])
530 proc=subprocess.Popen(["tput", "lines"],stdin=subprocess.PIPE,stdout=subprocess.PIPE)
531 output=proc.communicate(input=None)
532 rows=int(output[0])
533 return (cols,rows)
534 except:
535 return None
536
537 @staticmethod
538 def _getTerminalSize_linux():
539 def ioctl_GWINSZ(fd):
540 try:
541 import fcntl, termios, struct, os
542 cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ,'1234'))
543 except:
544 return None
545 return cr
546 cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
547 if not cr:
548 try:
549 fd = os.open(os.ctermid(), os.O_RDONLY)
550 cr = ioctl_GWINSZ(fd)
551 os.close(fd)
552 except:
553 pass
554 if not cr:
555 try:
556 cr = (os.env['LINES'], os.env['COLUMNS'])
557 except:
558 return None
559 return int(cr[1]), int(cr[0])
560
561 @staticmethod
562 def get_terminal_size(fallback=(100, 24), terminal = False):
563 try:
564 columns, rows = TerminalSize.getTerminalSize()
565 if not terminal:
566 if not terminal_auto_size:
567 columns, rows = terminal_size
568 except:
569 columns, rows = fallback
570
571 return columns, rows
572
573 class MAIXLoader:
574 def change_baudrate(self, baudrate):
575 KFlash.log(INFO_MSG,"Selected Baudrate: ", baudrate, BASH_TIPS['DEFAULT'])
576 out = struct.pack('III', 0, 4, baudrate)
577 crc32_checksum = struct.pack('I', binascii.crc32(out) & 0xFFFFFFFF)
578 out = struct.pack('HH', 0xd6, 0x00) + crc32_checksum + out
579 self.write(out)
580 time.sleep(0.05)
581 self._port.baudrate = baudrate
582 if args.Board == "goE":
583 if baudrate >= 4500000:
584 # OPENEC super baudrate
585 KFlash.log(INFO_MSG, "Enable OPENEC super baudrate!!!", BASH_TIPS['DEFAULT'])
586 if baudrate == 4500000:
587 self._port.baudrate = 300
588 if baudrate == 6000000:
589 self._port.baudrate = 250
590 if baudrate == 7500000:
591 self._port.baudrate = 350
592
593 def change_baudrate_stage0(self, baudrate):
594 # Dangerous, here are dinosaur infested!!!!!
595 # Don't touch this code unless you know what you are doing
596 # Stage0 baudrate is fixed
597 # Contributor: [@rgwan](https://github.com/rgwan)
598 # rgwan <dv.xw@qq.com>
599 baudrate = 1500000
600 if args.Board == "goE" or args.Board == "trainer":
601 KFlash.log(INFO_MSG,"Selected Stage0 Baudrate: ", baudrate, BASH_TIPS['DEFAULT'])
602 # This is for openec, contained ft2232, goE and trainer
603 KFlash.log(INFO_MSG,"FT2232 mode", BASH_TIPS['DEFAULT'])
604 baudrate_stage0 = int(baudrate * 38.6 / 38)
605 out = struct.pack('III', 0, 4, baudrate_stage0)
606 crc32_checksum = struct.pack('I', binascii.crc32(out) & 0xFFFFFFFF)
607 out = struct.pack('HH', 0xc6, 0x00) + crc32_checksum + out
608 self.write(out)
609 time.sleep(0.05)
610 self._port.baudrate = baudrate
611
612 retry_count = 0
613 while 1:
614 self.checkKillExit()
615 retry_count = retry_count + 1
616 if retry_count > 3:
617 err = (ERROR_MSG,'Fast mode failed, please use slow mode by add parameter ' + BASH_TIPS['GREEN'] + '--Slow', BASH_TIPS['DEFAULT'])
618 err = tuple2str(err)
619 raise_exception( Exception(err) )
620 try:
621 self.greeting()
622 break
623 except TimeoutError:
624 pass
625 elif args.Board == "dan" or args.Board == "bit" or args.Board == "kd233":
626 KFlash.log(INFO_MSG,"CH340 mode", BASH_TIPS['DEFAULT'])
627 # This is for CH340, contained dan, bit and kd233
628 baudrate_stage0 = int(baudrate * 38.4 / 38)
629 # CH340 can not use this method, test failed, take risks at your own risk
630 else:
631 # This is for unknown board
632 KFlash.log(WARN_MSG,"Unknown mode", BASH_TIPS['DEFAULT'])
633
634 def __init__(self, port='/dev/ttyUSB1', baudrate=115200):
635 # configure the serial connections (the parameters differs on the device you are connecting to)
636 self._port = serial.Serial(
637 port=port,
638 baudrate=baudrate,
639 parity=serial.PARITY_NONE,
640 stopbits=serial.STOPBITS_ONE,
641 bytesize=serial.EIGHTBITS,
642 timeout=0.1
643 )
644 KFlash.log(INFO_MSG, "Default baudrate is", baudrate, ", later it may be changed to the value you set.", BASH_TIPS['DEFAULT'])
645
646 self._port.isOpen()
647 self._slip_reader = slip_reader(self._port)
648 self._kill_process = False
649
650 """ Read a SLIP packet from the serial port """
651
652 def read(self):
653 return next(self._slip_reader)
654
655 """ Write bytes to the serial port while performing SLIP escaping """
656
657 def write(self, packet):
658 buf = b'\xc0' \
659 + (packet.replace(b'\xdb', b'\xdb\xdd').replace(b'\xc0', b'\xdb\xdc')) \
660 + b'\xc0'
661 #KFlash.log('[WRITE]', binascii.hexlify(buf))
662 return self._port.write(buf)
663
664 def read_loop(self):
665 #out = b''
666 # while self._port.inWaiting() > 0:
667 # out += self._port.read(1)
668
669 # KFlash.log(out)
670 while 1:
671 sys.stdout.write('[RECV] raw data: ')
672 sys.stdout.write(binascii.hexlify(self._port.read(1)).decode())
673 sys.stdout.flush()
674
675 def recv_one_return(self, timeout_s = None):
676 timeout_init = time.time()
677 data = b''
678 if timeout_s == None:
679 timeout_s = ISP_RECEIVE_TIMEOUT
680 # find start boarder
681 #sys.stdout.write('[RECV one return] raw data: ')
682 while 1:
683 if time.time() - timeout_init > timeout_s:
684 raise_exception( TimeoutError )
685 c = self._port.read(1)
686 #sys.stdout.write(binascii.hexlify(c).decode())
687 sys.stdout.flush()
688 if c == b'\xc0':
689 break
690
691 in_escape = False
692 while 1:
693 if time.time() - timeout_init > timeout_s:
694 raise_exception( TimeoutError )
695 c = self._port.read(1)
696 #sys.stdout.write(binascii.hexlify(c).decode())
697 sys.stdout.flush()
698 if c == b'\xc0':
699 break
700
701 elif in_escape: # part-way through escape sequence
702 in_escape = False
703 if c == b'\xdc':
704 data += b'\xc0'
705 elif c == b'\xdd':
706 data += b'\xdb'
707 else:
708 raise_exception( Exception('Invalid SLIP escape (%r%r)' % (b'\xdb', c)) )
709 elif c == b'\xdb': # start of escape sequence
710 in_escape = True
711
712 data += c
713
714 #sys.stdout.write('\n')
715 return data
716
717 # kd233 or open-ec or new cmsis-dap
718 def reset_to_isp_kd233(self):
719 self._port.setDTR (False)
720 self._port.setRTS (False)
721 time.sleep(0.1)
722 #KFlash.log('-- RESET to LOW, IO16 to HIGH --')
723 # Pull reset down and keep 10ms
724 self._port.setDTR (True)
725 self._port.setRTS (False)
726 time.sleep(0.1)
727 #KFlash.log('-- IO16 to LOW, RESET to HIGH --')
728 # Pull IO16 to low and release reset
729 self._port.setRTS (True)
730 self._port.setDTR (False)
731 time.sleep(0.1)
732 def reset_to_boot_kd233(self):
733 self._port.setDTR (False)
734 self._port.setRTS (False)
735 time.sleep(0.1)
736 #KFlash.log('-- RESET to LOW --')
737 # Pull reset down and keep 10ms
738 self._port.setDTR (True)
739 self._port.setRTS (False)
740 time.sleep(0.1)
741 #KFlash.log('-- RESET to HIGH, BOOT --')
742 # Pull IO16 to low and release reset
743 self._port.setRTS (False)
744 self._port.setDTR (False)
745 time.sleep(0.1)
746
747 #dan dock
748 def reset_to_isp_dan(self):
749 self._port.setDTR (False)
750 self._port.setRTS (False)
751 time.sleep(0.1)
752 #KFlash.log('-- RESET to LOW, IO16 to HIGH --')
753 # Pull reset down and keep 10ms
754 self._port.setDTR (False)
755 self._port.setRTS (True)
756 time.sleep(0.1)
757 #KFlash.log('-- IO16 to LOW, RESET to HIGH --')
758 # Pull IO16 to low and release reset
759 self._port.setRTS (False)
760 self._port.setDTR (True)
761 time.sleep(0.1)
762 def reset_to_boot_dan(self):
763 self._port.setDTR (False)
764 self._port.setRTS (False)
765 time.sleep(0.1)
766 #KFlash.log('-- RESET to LOW --')
767 # Pull reset down and keep 10ms
768 self._port.setDTR (False)
769 self._port.setRTS (True)
770 time.sleep(0.1)
771 #KFlash.log('-- RESET to HIGH, BOOT --')
772 # Pull IO16 to low and release reset
773 self._port.setRTS (False)
774 self._port.setDTR (False)
775 time.sleep(0.1)
776
777 # maix goD for old cmsis-dap firmware
778 def reset_to_isp_goD(self):
779 self._port.setDTR (True) ## output 0
780 self._port.setRTS (True)
781 time.sleep(0.1)
782 #KFlash.log('-- RESET to LOW --')
783 # Pull reset down and keep 10ms
784 self._port.setRTS (False)
785 self._port.setDTR (True)
786 time.sleep(0.1)
787 #KFlash.log('-- RESET to HIGH, BOOT --')
788 # Pull IO16 to low and release reset
789 self._port.setRTS (False)
790 self._port.setDTR (True)
791 time.sleep(0.1)
792 def reset_to_boot_goD(self):
793 self._port.setDTR (False)
794 self._port.setRTS (False)
795 time.sleep(0.1)
796 #KFlash.log('-- RESET to LOW --')
797 # Pull reset down and keep 10ms
798 self._port.setRTS (False)
799 self._port.setDTR (True)
800 time.sleep(0.1)
801 #KFlash.log('-- RESET to HIGH, BOOT --')
802 # Pull IO16 to low and release reset
803 self._port.setRTS (True)
804 self._port.setDTR (True)
805 time.sleep(0.1)
806
807 # maix goE for openec or new cmsis-dap firmware
808 def reset_to_boot_maixgo(self):
809 self._port.setDTR (False)
810 self._port.setRTS (False)
811 time.sleep(0.1)
812 #KFlash.log('-- RESET to LOW --')
813 # Pull reset down and keep 10ms
814 self._port.setRTS (False)
815 self._port.setDTR (True)
816 time.sleep(0.1)
817 #KFlash.log('-- RESET to HIGH, BOOT --')
818 # Pull IO16 to low and release reset
819 self._port.setRTS (False)
820 self._port.setDTR (False)
821 time.sleep(0.1)
822
823 def greeting(self):
824 self._port.write(b'\xc0\xc2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0')
825 op, reason, text = ISPResponse.parse(self.recv_one_return())
826
827 #KFlash.log('MAIX return op:', ISPResponse.ISPOperation(op).name, 'reason:', ISPResponse.ErrorCode(reason).name)
828
829
830 def flash_greeting(self):
831 retry_count = 0
832 while 1:
833 self.checkKillExit()
834 try:
835 self._port.write(b'\xc0\xd2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0')
836 except Exception:
837 raise_exception( Exception("Connection disconnected, try again or maybe need use Slow mode, or decrease baudrate") )
838 retry_count = retry_count + 1
839 try:
840 op, reason, text = FlashModeResponse.parse(self.recv_one_return())
841 except IndexError:
842 if retry_count > MAX_RETRY_TIMES:
843 err = (ERROR_MSG,"Failed to Connect to K210's Stub",BASH_TIPS['DEFAULT'])
844 err = tuple2str(err)
845 raise_exception( Exception(err) )
846 KFlash.log(WARN_MSG,"Index Error, retrying...",BASH_TIPS['DEFAULT'])
847 time.sleep(0.1)
848 continue
849 except TimeoutError:
850 if retry_count > MAX_RETRY_TIMES:
851 err = (ERROR_MSG,"Failed to Connect to K210's Stub",BASH_TIPS['DEFAULT'])
852 err = tuple2str(err)
853 raise_exception( Exception(err) )
854 KFlash.log(WARN_MSG,"Timeout Error, retrying...",BASH_TIPS['DEFAULT'])
855 time.sleep(0.1)
856 continue
857 except:
858 if retry_count > MAX_RETRY_TIMES:
859 err = (ERROR_MSG,"Failed to Connect to K210's Stub",BASH_TIPS['DEFAULT'])
860 err = tuple2str(err)
861 raise_exception( Exception(err) )
862 KFlash.log(WARN_MSG,"Unexcepted Error, retrying...",BASH_TIPS['DEFAULT'])
863 time.sleep(0.1)
864 continue
865 # KFlash.log('MAIX return op:', FlashModeResponse.Operation(op).name, 'reason:',
866 # FlashModeResponse.ErrorCode(reason).name)
867 if FlashModeResponse.Operation(op) == FlashModeResponse.Operation.ISP_NOP and FlashModeResponse.ErrorCode(reason) == FlashModeResponse.ErrorCode.ISP_RET_OK:
868 KFlash.log(INFO_MSG,"Boot to Flashmode Successfully",BASH_TIPS['DEFAULT'])
869 self._port.flushInput()
870 self._port.flushOutput()
871 break
872 else:
873 if retry_count > MAX_RETRY_TIMES:
874 err = (ERROR_MSG,"Failed to Connect to K210's Stub",BASH_TIPS['DEFAULT'])
875 err = tuple2str(err)
876 raise_exception( Exception(err) )
877 KFlash.log(WARN_MSG,"Unexcepted Return recevied, retrying...",BASH_TIPS['DEFAULT'])
878 time.sleep(0.1)
879 continue
880
881 def boot(self, address=0x80000000):
882 KFlash.log(INFO_MSG,"Booting From " + hex(address),BASH_TIPS['DEFAULT'])
883
884 out = struct.pack('II', address, 0)
885
886 crc32_checksum = struct.pack('I', binascii.crc32(out) & 0xFFFFFFFF)
887
888 out = struct.pack('HH', 0xc5, 0x00) + crc32_checksum + out # op: ISP_MEMORY_WRITE: 0xc3
889 self.write(out)
890
891 def recv_debug(self):
892 op, reason, text = ISPResponse.parse(self.recv_one_return())
893 #KFlash.log('[RECV] op:', ISPResponse.ISPOperation(op).name, 'reason:', ISPResponse.ErrorCode(reason).name)
894 if text:
895 KFlash.log('-' * 30)
896 KFlash.log(text)
897 KFlash.log('-' * 30)
898 if ISPResponse.ErrorCode(reason) not in (ISPResponse.ErrorCode.ISP_RET_DEFAULT, ISPResponse.ErrorCode.ISP_RET_OK):
899 KFlash.log('Failed, retry, errcode=', hex(reason))
900 return False
901 return True
902
903 def flash_recv_debug(self):
904 op, reason, text = FlashModeResponse.parse(self.recv_one_return())
905 #KFlash.log('[Flash-RECV] op:', FlashModeResponse.Operation(op).name, 'reason:',
906 # FlashModeResponse.ErrorCode(reason).name)
907 if text:
908 KFlash.log('-' * 30)
909 KFlash.log(text)
910 KFlash.log('-' * 30)
911
912 if FlashModeResponse.ErrorCode(reason) not in (FlashModeResponse.ErrorCode.ISP_RET_OK, FlashModeResponse.ErrorCode.ISP_RET_OK):
913 KFlash.log('Failed, retry')
914 return False
915 return True
916
917 def init_flash(self, chip_type):
918 chip_type = int(chip_type)
919 KFlash.log(INFO_MSG,"Selected Flash: ",("In-Chip", "On-Board")[chip_type],BASH_TIPS['DEFAULT'])
920 out = struct.pack('II', chip_type, 0)
921 crc32_checksum = struct.pack('I', binascii.crc32(out) & 0xFFFFFFFF)
922 out = struct.pack('HH', 0xd7, 0x00) + crc32_checksum + out
923 '''Retry when it have error'''
924 retry_count = 0
925 while 1:
926 self.checkKillExit()
927 sent = self.write(out)
928 retry_count = retry_count + 1
929 try:
930 op, reason, text = FlashModeResponse.parse(self.recv_one_return())
931 except IndexError:
932 if retry_count > MAX_RETRY_TIMES:
933 err = (ERROR_MSG,"Failed to initialize flash",BASH_TIPS['DEFAULT'])
934 err = tuple2str(err)
935 raise_exception( Exception(err) )
936 KFlash.log(WARN_MSG,"Index Error, retrying...",BASH_TIPS['DEFAULT'])
937 time.sleep(0.1)
938 continue
939 except TimeoutError:
940 if retry_count > MAX_RETRY_TIMES:
941 err = (ERROR_MSG,"Failed to initialize flash",BASH_TIPS['DEFAULT'])
942 err = tuple2str(err)
943 raise_exception( Exception(err) )
944 KFlash.log(WARN_MSG,"Timeout Error, retrying...",BASH_TIPS['DEFAULT'])
945 time.sleep(0.1)
946 continue
947 except:
948 if retry_count > MAX_RETRY_TIMES:
949 err = (ERROR_MSG,"Failed to initialize flash",BASH_TIPS['DEFAULT'])
950 err = tuple2str(err)
951 raise_exception( Exception(err) )
952 KFlash.log(WARN_MSG,"Unexcepted Error, retrying...",BASH_TIPS['DEFAULT'])
953 time.sleep(0.1)
954 continue
955 # KFlash.log('MAIX return op:', FlashModeResponse.Operation(op).name, 'reason:',
956 # FlashModeResponse.ErrorCode(reason).name)
957 if FlashModeResponse.Operation(op) == FlashModeResponse.Operation.FLASHMODE_FLASH_INIT and FlashModeResponse.ErrorCode(reason) == FlashModeResponse.ErrorCode.ISP_RET_OK:
958 KFlash.log(INFO_MSG,"Initialization flash Successfully",BASH_TIPS['DEFAULT'])
959 break
960 else:
961 if retry_count > MAX_RETRY_TIMES:
962 err = (ERROR_MSG,"Failed to initialize flash",BASH_TIPS['DEFAULT'])
963 err = tuple2str(err)
964 raise_exception( Exception(err) )
965 KFlash.log(WARN_MSG,"Unexcepted Return recevied, retrying...",BASH_TIPS['DEFAULT'])
966 time.sleep(0.1)
967 continue
968
969 def flash_dataframe(self, data, address=0x80000000):
970 DATAFRAME_SIZE = 1024
971 data_chunks = chunks(data, DATAFRAME_SIZE)
972 #KFlash.log('[DEBUG] flash dataframe | data length:', len(data))
973 total_chunk = math.ceil(len(data)/DATAFRAME_SIZE)
974
975 time_start = time.time()
976 for n, chunk in enumerate(data_chunks):
977 self.checkKillExit()
978 while 1:
979 self.checkKillExit()
980 #KFlash.log('[INFO] sending chunk', i, '@address', hex(address), 'chunklen', len(chunk))
981 out = struct.pack('II', address, len(chunk))
982
983 crc32_checksum = struct.pack('I', binascii.crc32(out + chunk) & 0xFFFFFFFF)
984
985 out = struct.pack('HH', 0xc3, 0x00) + crc32_checksum + out + chunk # op: ISP_MEMORY_WRITE: 0xc3
986 sent = self.write(out)
987 #KFlash.log('[INFO]', 'sent', sent, 'bytes', 'checksum', binascii.hexlify(crc32_checksum).decode())
988
989 address += len(chunk)
990
991 if self.recv_debug():
992 break
993
994 columns, lines = TerminalSize.get_terminal_size((100, 24), terminal)
995 time_delta = time.time() - time_start
996 speed = ''
997 if (time_delta > 1):
998 speed = str(int((n + 1) * DATAFRAME_SIZE / 1024.0 / time_delta)) + 'kiB/s'
999 printProgressBar(n+1, total_chunk, prefix = 'Downloading ISP:', suffix = speed, length = columns - 35)
1000
1001 def dump_to_flash(self, data, address=0, size=None):
1002 '''
1003 typedef struct __attribute__((packed)) {
1004 uint8_t op;
1005 int32_t checksum; /* All the fields below are involved in the calculation of checksum */
1006 uint32_t address;
1007 uint32_t data_len;
1008 uint8_t data_buf[1024];
1009 } isp_request_t;
1010 '''
1011 if size == None:
1012 DATAFRAME_SIZE = ISP_FLASH_DATA_FRAME_SIZE
1013 size = DATAFRAME_SIZE
1014 data_chunks = chunks(data, size)
1015 #KFlash.log('[DEBUG] flash dataframe | data length:', len(data))
1016
1017
1018
1019 for n, chunk in enumerate(data_chunks):
1020 #KFlash.log('[INFO] sending chunk', i, '@address', hex(address))
1021 out = struct.pack('II', address, len(chunk))
1022
1023 crc32_checksum = struct.pack('I', binascii.crc32(out + chunk) & 0xFFFFFFFF)
1024
1025 out = struct.pack('HH', 0xd4, 0x00) + crc32_checksum + out + chunk
1026 #KFlash.log("[$$$$]", binascii.hexlify(out[:32]).decode())
1027 retry_count = 0
1028 while True:
1029 try:
1030 sent = self.write(out)
1031 #KFlash.log('[INFO]', 'sent', sent, 'bytes', 'checksum', crc32_checksum)
1032 self.flash_recv_debug()
1033 except:
1034 retry_count = retry_count + 1
1035 if retry_count > MAX_RETRY_TIMES:
1036 err = (ERROR_MSG,"Error Count Exceeded, Stop Trying",BASH_TIPS['DEFAULT'])
1037 err = tuple2str(err)
1038 raise_exception( Exception(err) )
1039 continue
1040 break
1041 address += len(chunk)
1042
1043
1044
1045 def flash_erase(self, erase_addr = 0, erase_len = 0):
1046 #KFlash.log('[DEBUG] erasing spi flash.')
1047 cmd0 = b'\xd3\x00\x00\x00'
1048 cmd = struct.pack("I", erase_addr)
1049 cmd += struct.pack("I", erase_len)
1050 cmd = cmd0 + struct.pack('I', binascii.crc32(cmd) & 0xFFFFFFFF) + cmd
1051 self.write(cmd)
1052 t = time.time()
1053 op, reason, text = FlashModeResponse.parse(self.recv_one_return(timeout_s=90))
1054 if FlashModeResponse.ErrorCode(reason) != FlashModeResponse.ErrorCode.ISP_RET_OK:
1055 err = (ERROR_MSG,"erase error, error code: 0x{:02X}: {}".format(reason, text))
1056 err = tuple2str(err)
1057 raise_exception( Exception(err) )
1058 else:
1059 KFlash.log(INFO_MSG,"erase ok")
1060 #KFlash.log('MAIX return op:', FlashModeResponse.Operation(op).name, 'reason:',
1061 # FlashModeResponse.ErrorCode(reason).name)
1062
1063 def install_flash_bootloader(self, data):
1064 # Download flash bootloader
1065 self.flash_dataframe(data, address=0x80000000)
1066
1067 def load_elf_to_sram(self, f):
1068 try:
1069 from elftools.elf.elffile import ELFFile
1070 from elftools.elf.descriptions import describe_p_type
1071 except ImportError:
1072 err = (ERROR_MSG,'pyelftools must be installed, run '+BASH_TIPS['GREEN']+'`' + ('pip', 'pip3')[sys.version_info > (3, 0)] + ' install pyelftools`',BASH_TIPS['DEFAULT'])
1073 err = tuple2str(err)
1074 raise_exception( Exception(err) )
1075
1076 elffile = ELFFile(f)
1077 if elffile['e_entry'] != 0x80000000:
1078 KFlash.log(WARN_MSG,"ELF entry is 0x%x instead of 0x80000000" % (elffile['e_entry']), BASH_TIPS['DEFAULT'])
1079
1080 for segment in elffile.iter_segments():
1081 t = describe_p_type(segment['p_type'])
1082 KFlash.log(INFO_MSG, ("Program Header: Size: %d, Virtual Address: 0x%x, Type: %s" % (segment['p_filesz'], segment['p_vaddr'], t)), BASH_TIPS['DEFAULT'])
1083 if not (segment['p_vaddr'] & 0x80000000):
1084 continue
1085 if segment['p_filesz']==0 or segment['p_vaddr']==0:
1086 KFlash.log("Skipped")
1087 continue
1088 self.flash_dataframe(segment.data(), segment['p_vaddr'])
1089
1090 def flash_firmware(self, firmware_bin, aes_key = None, address_offset = 0, sha256Prefix = True, filename = ""):
1091 # type: (bytes, bytes, int, bool) -> None
1092 # Don't remove above code!
1093
1094 #KFlash.log('[DEBUG] flash_firmware DEBUG: aeskey=', aes_key)
1095
1096 if sha256Prefix == True:
1097 # Add header to the firmware
1098 # Format: SHA256(after)(32bytes) + AES_CIPHER_FLAG (1byte) + firmware_size(4bytes) + firmware_data
1099 aes_cipher_flag = b'\x01' if aes_key else b'\x00'
1100
1101 # Encryption
1102 if aes_key:
1103 enc = AES_128_CBC(aes_key, iv=b'\x00'*16).encrypt
1104 padded = firmware_bin + b'\x00'*15 # zero pad
1105 firmware_bin = b''.join([enc(padded[i*16:i*16+16]) for i in range(len(padded)//16)])
1106
1107 firmware_len = len(firmware_bin)
1108
1109 data = aes_cipher_flag + struct.pack('I', firmware_len) + firmware_bin
1110
1111 sha256_hash = hashlib.sha256(data).digest()
1112
1113 firmware_with_header = data + sha256_hash
1114
1115 total_len = len(firmware_with_header)
1116 # Slice download firmware
1117 data_chunks = chunks(firmware_with_header, ISP_FLASH_DATA_FRAME_SIZE) # 4kiB for a sector, 16kiB for dataframe
1118 else:
1119 total_len = len(firmware_bin)
1120 data_chunks = chunks(firmware_bin, ISP_FLASH_DATA_FRAME_SIZE, address = address_offset)
1121
1122 time_start = time.time()
1123 write_len = 0
1124 for n, chunk in enumerate(data_chunks):
1125 self.checkKillExit()
1126 # 4K align
1127 aligned_chunk = len(chunk)
1128 aligned_chunk = (ISP_FLASH_SECTOR_SIZE - (aligned_chunk % ISP_FLASH_SECTOR_SIZE))%ISP_FLASH_SECTOR_SIZE + aligned_chunk
1129 chunk = chunk.ljust(aligned_chunk, b'\x00') # align by size of dataframe
1130
1131 # Download a dataframe
1132 #KFlash.log('[INFO]', 'Write firmware data piece')
1133 chunk_len = len(chunk)
1134 self.dump_to_flash(chunk, address= write_len + address_offset, size=chunk_len)
1135 write_len += chunk_len
1136 columns, lines = TerminalSize.get_terminal_size((100, 24), terminal)
1137 time_delta = time.time() - time_start
1138 speed = ''
1139 if (time_delta > 1):
1140 speed = str(int(write_len / 1024.0 / time_delta)) + 'kiB/s'
1141 printProgressBar(write_len, total_len, prefix = 'Programming BIN:', filename=filename, suffix = speed, length = columns - 35)
1142
1143 def kill(self):
1144 self._kill_process = True
1145
1146 def checkKillExit(self):
1147 if self._kill_process:
1148 self._port.close()
1149 self._kill_process = False
1150 raise Exception("Cancel")
1151
1152 def open_terminal(reset):
1153 control_signal = '0' if reset else '1'
1154 control_signal_b = not reset
1155 import serial.tools.miniterm
1156 # For using the terminal with MaixPy the 'filter' option must be set to 'direct'
1157 # because some control characters are emited
1158 sys.argv = [sys.argv[0], _port, '115200', '--dtr='+control_signal, '--rts='+control_signal, '--filter=direct']
1159 serial.tools.miniterm.main(default_port=_port, default_baudrate=115200, default_dtr=control_signal_b, default_rts=control_signal_b)
1160 sys.exit(0)
1161
1162 boards_choices = ["kd233", "dan", "bit", "bit_mic", "goE", "goD", "maixduino", "trainer"]
1163 if terminal:
1164 parser = argparse.ArgumentParser()
1165 parser.add_argument("-p", "--port", help="COM Port", default="DEFAULT")
1166 parser.add_argument("-f", "--flash", help="SPI Flash type, 0 for SPI3, 1 for SPI0", default=1)
1167 parser.add_argument("-b", "--baudrate", type=int, help="UART baudrate for uploading firmware", default=115200)
1168 parser.add_argument("-l", "--bootloader", help="Bootloader bin path", required=False, default=None)
1169 parser.add_argument("-k", "--key", help="AES key in hex, if you need encrypt your firmware.", required=False, default=None)
1170 parser.add_argument("-v", "--version", help="Print version.", action='version', version='0.8.3')
1171 parser.add_argument("--verbose", help="Increase output verbosity", default=False, action="store_true")
1172 parser.add_argument("-t", "--terminal", help="Start a terminal after finish (Python miniterm)", default=False, action="store_true")
1173 parser.add_argument("-n", "--noansi", help="Do not use ANSI colors, recommended in Windows CMD", default=False, action="store_true")
1174 parser.add_argument("-s", "--sram", help="Download firmware to SRAM and boot", default=False, action="store_true")
1175 parser.add_argument("-B", "--Board",required=False, type=str, help="Select dev board, e.g. kd233, dan, bit, goD, goE or trainer")
1176 parser.add_argument("-S", "--Slow",required=False, help="Slow download mode", default=False)
1177 parser.add_argument("-A", "--addr",required=False, help="flash addr", type=str, default="-1")
1178 parser.add_argument("-L", "--length",required=False, help="flash addr", type=str, default="-1")
1179 parser.add_argument("firmware", help="firmware bin path")
1180 args = parser.parse_args()
1181 else:
1182 args = argparse.Namespace()
1183 setattr(args, "port", "DEFAULT")
1184 setattr(args, "flash", 1)
1185 setattr(args, "baudrate", 115200)
1186 setattr(args, "bootloader", None)
1187 setattr(args, "key", None)
1188 setattr(args, "verbose", False)
1189 setattr(args, "terminal", False)
1190 setattr(args, "noansi", False)
1191 setattr(args, "sram", False)
1192 setattr(args, "Board", None)
1193 setattr(args, "Slow", False)
1194 setattr(args, "addr", -1)
1195 setattr(args, "length", -1)
1196
1197 # udpate args for none terminal call
1198 if not terminal:
1199 args.port = dev
1200 args.baudrate = baudrate
1201 args.noansi = noansi
1202 args.sram = sram
1203 args.Board = board
1204 args.firmware = file
1205 args.Slow = slow_mode
1206 args.addr = addr
1207 args.length = length
1208
1209 if args.Board == "maixduino" or args.Board == "bit_mic":
1210 args.Board = "goE"
1211
1212 if (args.noansi == True):
1213 BASH_TIPS = dict(NORMAL='',BOLD='',DIM='',UNDERLINE='',
1214 DEFAULT='', RED='', YELLOW='', GREEN='',
1215 BG_DEFAULT='', BG_WHITE='')
1216 ERROR_MSG = BASH_TIPS['RED']+BASH_TIPS['BOLD']+'[ERROR]'+BASH_TIPS['NORMAL']
1217 WARN_MSG = BASH_TIPS['YELLOW']+BASH_TIPS['BOLD']+'[WARN]'+BASH_TIPS['NORMAL']
1218 INFO_MSG = BASH_TIPS['GREEN']+BASH_TIPS['BOLD']+'[INFO]'+BASH_TIPS['NORMAL']
1219 KFlash.log(INFO_MSG,'ANSI colors not used',BASH_TIPS['DEFAULT'])
1220
1221 manually_set_the_board = False
1222 if args.Board:
1223 manually_set_the_board = True
1224
1225 if args.port == "DEFAULT":
1226 if args.Board == "goE":
1227 list_port_info = list(serial.tools.list_ports.grep("0403")) #Take the second one
1228 if len(list_port_info) == 0:
1229 err = (ERROR_MSG,"No vaild COM Port found in Auto Detect, Check Your Connection or Specify One by"+BASH_TIPS['GREEN']+'`--port/-p`',BASH_TIPS['DEFAULT'])
1230 err = tuple2str(err)
1231 raise_exception( Exception(err) )
1232 list_port_info.sort()
1233 if len(list_port_info) == 1:
1234 _port = list_port_info[0].device
1235 elif len(list_port_info) > 1:
1236 _port = list_port_info[1].device
1237 KFlash.log(INFO_MSG,"COM Port Auto Detected, Selected ", _port, BASH_TIPS['DEFAULT'])
1238 elif args.Board == "trainer":
1239 list_port_info = list(serial.tools.list_ports.grep("0403")) #Take the first one
1240 if(len(list_port_info)==0):
1241 err = (ERROR_MSG,"No vaild COM Port found in Auto Detect, Check Your Connection or Specify One by"+BASH_TIPS['GREEN']+'`--port/-p`',BASH_TIPS['DEFAULT'])
1242 err = tuple2str(err)
1243 raise_exception( Exception(err) )
1244 list_port_info.sort()
1245 _port = list_port_info[0].device
1246 KFlash.log(INFO_MSG,"COM Port Auto Detected, Selected ", _port, BASH_TIPS['DEFAULT'])
1247 else:
1248 try:
1249 list_port_info = next(serial.tools.list_ports.grep(VID_LIST_FOR_AUTO_LOOKUP)) #Take the first one within the list
1250 _port = list_port_info.device
1251 KFlash.log(INFO_MSG,"COM Port Auto Detected, Selected ", _port, BASH_TIPS['DEFAULT'])
1252 except StopIteration:
1253 err = (ERROR_MSG,"No vaild COM Port found in Auto Detect, Check Your Connection or Specify One by"+BASH_TIPS['GREEN']+'`--port/-p`',BASH_TIPS['DEFAULT'])
1254 err = tuple2str(err)
1255 raise_exception( Exception(err) )
1256 else:
1257 _port = args.port
1258 KFlash.log(INFO_MSG,"COM Port Selected Manually: ", _port, BASH_TIPS['DEFAULT'])
1259
1260 self.loader = MAIXLoader(port=_port, baudrate=115200)
1261 file_format = ProgramFileFormat.FMT_BINARY
1262
1263 # 0. Check firmware or cmd
1264 cmds = ['erase']
1265 if not args.firmware in cmds:
1266 if not os.path.exists(args.firmware):
1267 err = (ERROR_MSG,'Unable to find the firmware at ', args.firmware, BASH_TIPS['DEFAULT'])
1268 err = tuple2str(err)
1269 raise_exception( Exception(err) )
1270
1271 with open(args.firmware, 'rb') as f:
1272 file_header = f.read(4)
1273 #if file_header.startswith(bytes([0x50, 0x4B])):
1274 if file_header.startswith(b'\x50\x4B'):
1275 if ".kfpkg" != os.path.splitext(args.firmware)[1]:
1276 KFlash.log(INFO_MSG, 'Find a zip file, but not with ext .kfpkg:', args.firmware, BASH_TIPS['DEFAULT'])
1277 else:
1278 file_format = ProgramFileFormat.FMT_KFPKG
1279
1280 #if file_header.startswith(bytes([0x7F, 0x45, 0x4C, 0x46])):
1281 if file_header.startswith(b'\x7f\x45\x4c\x46'):
1282 file_format = ProgramFileFormat.FMT_ELF
1283 if args.sram:
1284 KFlash.log(INFO_MSG, 'Find an ELF file:', args.firmware, BASH_TIPS['DEFAULT'])
1285 else:
1286 err = (ERROR_MSG, 'This is an ELF file and cannot be programmed to flash directly:', args.firmware, BASH_TIPS['DEFAULT'] , '\r\nPlease retry:', args.firmware + '.bin', BASH_TIPS['DEFAULT'])
1287 err = tuple2str(err)
1288 raise_exception( Exception(err) )
1289
1290 # 1. Greeting.
1291 KFlash.log(INFO_MSG,"Trying to Enter the ISP Mode...",BASH_TIPS['DEFAULT'])
1292
1293 retry_count = 0
1294
1295 while 1:
1296 self.checkKillExit()
1297 if not self.loader._port.isOpen():
1298 self.loader._port.open()
1299 try:
1300 retry_count = retry_count + 1
1301 if retry_count > 15:
1302 err = (ERROR_MSG,"No vaild Kendryte K210 found in Auto Detect, Check Your Connection or Specify One by"+BASH_TIPS['GREEN']+'`-p '+('/dev/ttyUSB0', 'COM3')[sys.platform == 'win32']+'`',BASH_TIPS['DEFAULT'])
1303 err = tuple2str(err)
1304 raise_exception( Exception(err) )
1305 if args.Board == "dan" or args.Board == "bit" or args.Board == "trainer":
1306 try:
1307 KFlash.log('.', end='')
1308 self.loader.reset_to_isp_dan()
1309 self.loader.greeting()
1310 break
1311 except TimeoutError:
1312 pass
1313 elif args.Board == "kd233":
1314 try:
1315 KFlash.log('_', end='')
1316 self.loader.reset_to_isp_kd233()
1317 self.loader.greeting()
1318 break
1319 except TimeoutError:
1320 pass
1321 elif args.Board == "goE":
1322 try:
1323 KFlash.log('*', end='')
1324 self.loader.reset_to_isp_kd233()
1325 self.loader.greeting()
1326 break
1327 except TimeoutError:
1328 pass
1329 elif args.Board == "goD":
1330 try:
1331 KFlash.log('#', end='')
1332 self.loader.reset_to_isp_goD()
1333 self.loader.greeting()
1334 break
1335 except TimeoutError:
1336 pass
1337 else:
1338 try:
1339 KFlash.log('.', end='')
1340 self.loader.reset_to_isp_dan()
1341 self.loader.greeting()
1342 args.Board = "dan"
1343 KFlash.log()
1344 KFlash.log(INFO_MSG,"Automatically detected dan/bit/trainer",BASH_TIPS['DEFAULT'])
1345 break
1346 except TimeoutError:
1347 if not self.loader._port.isOpen():
1348 self.loader._port.open()
1349 pass
1350 try:
1351 KFlash.log('_', end='')
1352 self.loader.reset_to_isp_kd233()
1353 self.loader.greeting()
1354 args.Board = "kd233"
1355 KFlash.log()
1356 KFlash.log(INFO_MSG,"Automatically detected goE/kd233",BASH_TIPS['DEFAULT'])
1357 break
1358 except TimeoutError:
1359 if not self.loader._port.isOpen():
1360 self.loader._port.open()
1361 pass
1362 try:
1363 KFlash.log('.', end='')
1364 self.loader.reset_to_isp_goD()
1365 self.loader.greeting()
1366 args.Board = "goD"
1367 KFlash.log()
1368 KFlash.log(INFO_MSG,"Automatically detected goD",BASH_TIPS['DEFAULT'])
1369 break
1370 except TimeoutError:
1371 if not self.loader._port.isOpen():
1372 self.loader._port.open()
1373 pass
1374 try:
1375 # Magic, just repeat, don't remove, it may unstable, don't know why.
1376 KFlash.log('_', end='')
1377 self.loader.reset_to_isp_kd233()
1378 self.loader.greeting()
1379 args.Board = "kd233"
1380 KFlash.log()
1381 KFlash.log(INFO_MSG,"Automatically detected goE/kd233",BASH_TIPS['DEFAULT'])
1382 break
1383 except TimeoutError:
1384 if not self.loader._port.isOpen():
1385 self.loader._port.open()
1386 pass
1387 except Exception as e:
1388 KFlash.log()
1389 raise_exception( Exception("Greeting fail, check serial port ("+str(e)+")" ) )
1390
1391 # Don't remove this line
1392 # Dangerous, here are dinosaur infested!!!!!
1393 ISP_RECEIVE_TIMEOUT = 3
1394
1395 KFlash.log()
1396 KFlash.log(INFO_MSG,"Greeting Message Detected, Start Downloading ISP",BASH_TIPS['DEFAULT'])
1397
1398 if manually_set_the_board and (not args.Slow):
1399 if (args.baudrate >= 1500000) or args.sram:
1400 self.loader.change_baudrate_stage0(args.baudrate)
1401
1402 # 2. download bootloader and firmware
1403 if args.sram:
1404 with open(args.firmware, 'rb') as firmware_bin:
1405 if file_format == ProgramFileFormat.FMT_KFPKG:
1406 err = (ERROR_MSG, "Unable to load kfpkg to SRAM")
1407 err = tuple2str(err)
1408 raise_exception( Exception(err) )
1409 elif file_format == ProgramFileFormat.FMT_ELF:
1410 self.loader.load_elf_to_sram(firmware_bin)
1411 else:
1412 self.loader.install_flash_bootloader(firmware_bin.read())
1413 else:
1414 # install bootloader at 0x80000000
1415 if args.bootloader:
1416 with open(args.bootloader, 'rb') as f:
1417 isp_loader = f.read()
1418 else:
1419 isp_loader = ISP_PROG
1420 self.loader.install_flash_bootloader(isp_loader)
1421
1422 # Boot the code from SRAM
1423 self.loader.boot()
1424
1425 if args.sram:
1426 # Dangerous, here are dinosaur infested!!!!!
1427 # Don't touch this code unless you know what you are doing
1428 self.loader._port.baudrate = args.baudrate
1429 KFlash.log(INFO_MSG,"Boot user code from SRAM", BASH_TIPS['DEFAULT'])
1430 if(args.terminal == True):
1431 open_terminal(False)
1432 msg = "Burn SRAM OK"
1433 raise_exception( Exception(msg) )
1434
1435 # Dangerous, here are dinosaur infested!!!!!
1436 # Don't touch this code unless you know what you are doing
1437 self.loader._port.baudrate = 115200
1438
1439 KFlash.log(INFO_MSG,"Wait For 0.1 second for ISP to Boot", BASH_TIPS['DEFAULT'])
1440
1441 time.sleep(0.1)
1442
1443 self.loader.flash_greeting()
1444
1445 if args.baudrate != 115200:
1446 self.loader.change_baudrate(args.baudrate)
1447 KFlash.log(INFO_MSG,"Baudrate changed, greeting with ISP again ... ", BASH_TIPS['DEFAULT'])
1448 self.loader.flash_greeting()
1449
1450 self.loader.init_flash(args.flash)
1451
1452 if file_format == ProgramFileFormat.FMT_KFPKG:
1453 KFlash.log(INFO_MSG,"Extracting KFPKG ... ", BASH_TIPS['DEFAULT'])
1454 with tempfile.TemporaryDirectory() as tmpdir:
1455 try:
1456 with zipfile.ZipFile(args.firmware) as zf:
1457 zf.extractall(tmpdir)
1458 except zipfile.BadZipFile:
1459 err = (ERROR_MSG,'Unable to Decompress the kfpkg, your file might be corrupted.',BASH_TIPS['DEFAULT'])
1460 err = tuple2str(err)
1461 raise_exception( Exception(err) )
1462
1463 fFlashList = open(os.path.join(tmpdir, 'flash-list.json'), "r")
1464 sFlashList = re.sub(r'"address": (.*),', r'"address": "\1",', fFlashList.read()) #Pack the Hex Number in json into str
1465 fFlashList.close()
1466 jsonFlashList = json.loads(sFlashList)
1467 for lBinFiles in jsonFlashList['files']:
1468 self.checkKillExit()
1469 KFlash.log(INFO_MSG,"Writing",lBinFiles['bin'],"into","0x%08x"%int(lBinFiles['address'], 0),BASH_TIPS['DEFAULT'])
1470 with open(os.path.join(tmpdir, lBinFiles["bin"]), "rb") as firmware_bin:
1471 self.loader.flash_firmware(firmware_bin.read(), None, int(lBinFiles['address'], 0), lBinFiles['sha256Prefix'], filename=lBinFiles['bin'])
1472 else:
1473 if args.firmware == "erase":
1474 if args.addr.lower().startswith("0x"):
1475 addr = int(args.addr, base=16)
1476 else:
1477 addr = int(args.addr)
1478 if args.length.lower() == "all":
1479 addr = 0
1480 length = 0xFFFFFFEE
1481 KFlash.log(INFO_MSG,"erase all")
1482 else:
1483 if args.length.lower().startswith("0x"):
1484 length = int(args.length, base=16)
1485 else:
1486 length = int(args.length)
1487 KFlash.log(INFO_MSG,"erase '0x{:x}' - '0x{:x}' ({}B, {:.02}KiB, {:.02}MiB)".format(addr, addr+length, length, length/1024.0, length/1024.0/1024.0))
1488 if ((addr % 4096) != 0) or ( length != 0xFFFFFFEE and (length % 4096) != 0) or addr < 0 or addr > 0x01000000 or length < 0 or ( length > 0x01000000 and length != 0xFFFFFFEE):
1489 err = (ERROR_MSG,"erase flash addr or length error, addr should >= 0x00000000, and length should >= 4096 or 'all'")
1490 err = tuple2str(err)
1491 raise_exception( Exception(err) )
1492 self.loader.flash_erase(addr, length)
1493 else:
1494 with open(args.firmware, 'rb') as firmware_bin:
1495 if args.key:
1496 aes_key = binascii.a2b_hex(args.key)
1497 if len(aes_key) != 16:
1498 raise_exception( ValueError('AES key must by 16 bytes') )
1499
1500 self.loader.flash_firmware(firmware_bin.read(), aes_key=aes_key)
1501 else:
1502 self.loader.flash_firmware(firmware_bin.read())
1503
1504 # 3. boot
1505 if args.Board == "dan" or args.Board == "bit" or args.Board == "trainer":
1506 self.loader.reset_to_boot_dan()
1507 elif args.Board == "kd233":
1508 self.loader.reset_to_boot_kd233()
1509 elif args.Board == "goE":
1510 self.loader.reset_to_boot_maixgo()
1511 elif args.Board == "goD":
1512 self.loader.reset_to_boot_goD()
1513 else:
1514 KFlash.log(WARN_MSG,"Board unknown !! please press reset to boot!!")
1515
1516 KFlash.log(INFO_MSG,"Rebooting...", BASH_TIPS['DEFAULT'])
1517 try:
1518 self.loader._port.close()
1519 except Exception:
1520 pass
1521
1522 if(args.terminal == True):
1523 open_terminal(True)
1524
1525 def kill(self):
1526 if self.loader:
1527 self.loader.kill()
1528 self.killProcess = True
1529
1530 def checkKillExit(self):
1531 if self.killProcess:
1532 if self.loader:
1533 self.loader._port.close()
1534 raise Exception("Cancel")
1535
1536
1537def main():
1538 kflash = KFlash()
1539 try:
1540 kflash.process()
1541 except Exception as e:
1542 if str(e) == "Burn SRAM OK":
1543 sys.exit(0)
1544 kflash.log(str(e))
1545 sys.exit(1)
1546
1547if __name__ == '__main__':
1548 main()
Note: See TracBrowser for help on using the repository browser.