style: format python files with isort and double-quote-string-fixer
This commit is contained in:
@@ -16,23 +16,24 @@
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from __future__ import print_function, division
|
||||
from __future__ import division, print_function
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import binascii
|
||||
import tempfile
|
||||
import collections
|
||||
import os
|
||||
import struct
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
try:
|
||||
from parttool import PartitionName, PartitionType, ParttoolTarget, PARTITION_TABLE_OFFSET
|
||||
from parttool import PARTITION_TABLE_OFFSET, PartitionName, PartitionType, ParttoolTarget
|
||||
except ImportError:
|
||||
COMPONENTS_PATH = os.path.expandvars(os.path.join("$IDF_PATH", "components"))
|
||||
PARTTOOL_DIR = os.path.join(COMPONENTS_PATH, "partition_table")
|
||||
COMPONENTS_PATH = os.path.expandvars(os.path.join('$IDF_PATH', 'components'))
|
||||
PARTTOOL_DIR = os.path.join(COMPONENTS_PATH, 'partition_table')
|
||||
|
||||
sys.path.append(PARTTOOL_DIR)
|
||||
from parttool import PartitionName, PartitionType, ParttoolTarget, PARTITION_TABLE_OFFSET
|
||||
from parttool import PARTITION_TABLE_OFFSET, PartitionName, PartitionType, ParttoolTarget
|
||||
|
||||
__version__ = '2.0'
|
||||
|
||||
@@ -48,7 +49,7 @@ def status(msg):
|
||||
|
||||
class OtatoolTarget():
|
||||
|
||||
OTADATA_PARTITION = PartitionType("data", "ota")
|
||||
OTADATA_PARTITION = PartitionType('data', 'ota')
|
||||
|
||||
def __init__(self, port=None, baud=None, partition_table_offset=PARTITION_TABLE_OFFSET, partition_table_file=None,
|
||||
spi_flash_sec_size=SPI_FLASH_SEC_SIZE, esptool_args=[], esptool_write_args=[],
|
||||
@@ -61,14 +62,14 @@ class OtatoolTarget():
|
||||
temp_file.close()
|
||||
try:
|
||||
self.target.read_partition(OtatoolTarget.OTADATA_PARTITION, temp_file.name)
|
||||
with open(temp_file.name, "rb") as f:
|
||||
with open(temp_file.name, 'rb') as f:
|
||||
self.otadata = f.read()
|
||||
finally:
|
||||
os.unlink(temp_file.name)
|
||||
|
||||
def _check_otadata_partition(self):
|
||||
if not self.otadata:
|
||||
raise Exception("No otadata partition found")
|
||||
raise Exception('No otadata partition found')
|
||||
|
||||
def erase_otadata(self):
|
||||
self._check_otadata_partition()
|
||||
@@ -77,7 +78,7 @@ class OtatoolTarget():
|
||||
def _get_otadata_info(self):
|
||||
info = []
|
||||
|
||||
otadata_info = collections.namedtuple("otadata_info", "seq crc")
|
||||
otadata_info = collections.namedtuple('otadata_info', 'seq crc')
|
||||
|
||||
for i in range(2):
|
||||
start = i * (self.spi_flash_sec_size >> 1)
|
||||
@@ -94,7 +95,7 @@ class OtatoolTarget():
|
||||
|
||||
def _get_partition_id_from_ota_id(self, ota_id):
|
||||
if isinstance(ota_id, int):
|
||||
return PartitionType("app", "ota_" + str(ota_id))
|
||||
return PartitionType('app', 'ota_' + str(ota_id))
|
||||
else:
|
||||
return PartitionName(ota_id)
|
||||
|
||||
@@ -106,7 +107,7 @@ class OtatoolTarget():
|
||||
|
||||
def is_otadata_info_valid(status):
|
||||
seq = status.seq % (1 << 32)
|
||||
crc = hex(binascii.crc32(struct.pack("I", seq), 0xFFFFFFFF) % (1 << 32))
|
||||
crc = hex(binascii.crc32(struct.pack('I', seq), 0xFFFFFFFF) % (1 << 32))
|
||||
return seq < (int('0xFFFFFFFF', 16) % (1 << 32)) and status.crc == crc
|
||||
|
||||
partition_table = self.target.partition_table
|
||||
@@ -124,7 +125,7 @@ class OtatoolTarget():
|
||||
ota_partitions = sorted(ota_partitions, key=lambda p: p.subtype)
|
||||
|
||||
if not ota_partitions:
|
||||
raise Exception("No ota app partitions found")
|
||||
raise Exception('No ota app partitions found')
|
||||
|
||||
# Look for the app partition to switch to
|
||||
ota_partition_next = None
|
||||
@@ -137,7 +138,7 @@ class OtatoolTarget():
|
||||
|
||||
ota_partition_next = list(ota_partition_next)[0]
|
||||
except IndexError:
|
||||
raise Exception("Partition to switch to not found")
|
||||
raise Exception('Partition to switch to not found')
|
||||
|
||||
otadata_info = self._get_otadata_info()
|
||||
|
||||
@@ -177,15 +178,15 @@ class OtatoolTarget():
|
||||
ota_seq_next = target_seq
|
||||
|
||||
# Create binary data from computed values
|
||||
ota_seq_next = struct.pack("I", ota_seq_next)
|
||||
ota_seq_next = struct.pack('I', ota_seq_next)
|
||||
ota_seq_crc_next = binascii.crc32(ota_seq_next, 0xFFFFFFFF) % (1 << 32)
|
||||
ota_seq_crc_next = struct.pack("I", ota_seq_crc_next)
|
||||
ota_seq_crc_next = struct.pack('I', ota_seq_crc_next)
|
||||
|
||||
temp_file = tempfile.NamedTemporaryFile(delete=False)
|
||||
temp_file.close()
|
||||
|
||||
try:
|
||||
with open(temp_file.name, "wb") as otadata_next_file:
|
||||
with open(temp_file.name, 'wb') as otadata_next_file:
|
||||
start = (1 if otadata_compute_base == 0 else 0) * (self.spi_flash_sec_size >> 1)
|
||||
|
||||
otadata_next_file.write(self.otadata)
|
||||
@@ -217,14 +218,14 @@ def _read_otadata(target):
|
||||
|
||||
otadata_info = target._get_otadata_info()
|
||||
|
||||
print(" {:8s} \t {:8s} | \t {:8s} \t {:8s}".format("OTA_SEQ", "CRC", "OTA_SEQ", "CRC"))
|
||||
print("Firmware: 0x{:8x} \t0x{:8x} | \t0x{:8x} \t 0x{:8x}".format(otadata_info[0].seq, otadata_info[0].crc,
|
||||
print(' {:8s} \t {:8s} | \t {:8s} \t {:8s}'.format('OTA_SEQ', 'CRC', 'OTA_SEQ', 'CRC'))
|
||||
print('Firmware: 0x{:8x} \t0x{:8x} | \t0x{:8x} \t 0x{:8x}'.format(otadata_info[0].seq, otadata_info[0].crc,
|
||||
otadata_info[1].seq, otadata_info[1].crc))
|
||||
|
||||
|
||||
def _erase_otadata(target):
|
||||
target.erase_otadata()
|
||||
status("Erased ota_data partition contents")
|
||||
status('Erased ota_data partition contents')
|
||||
|
||||
|
||||
def _switch_ota_partition(target, ota_id):
|
||||
@@ -233,68 +234,68 @@ def _switch_ota_partition(target, ota_id):
|
||||
|
||||
def _read_ota_partition(target, ota_id, output):
|
||||
target.read_ota_partition(ota_id, output)
|
||||
status("Read ota partition contents to file {}".format(output))
|
||||
status('Read ota partition contents to file {}'.format(output))
|
||||
|
||||
|
||||
def _write_ota_partition(target, ota_id, input):
|
||||
target.write_ota_partition(ota_id, input)
|
||||
status("Written contents of file {} to ota partition".format(input))
|
||||
status('Written contents of file {} to ota partition'.format(input))
|
||||
|
||||
|
||||
def _erase_ota_partition(target, ota_id):
|
||||
target.erase_ota_partition(ota_id)
|
||||
status("Erased contents of ota partition")
|
||||
status('Erased contents of ota partition')
|
||||
|
||||
|
||||
def main():
|
||||
if sys.version_info[0] < 3:
|
||||
print("WARNING: Support for Python 2 is deprecated and will be removed in future versions.", file=sys.stderr)
|
||||
print('WARNING: Support for Python 2 is deprecated and will be removed in future versions.', file=sys.stderr)
|
||||
elif sys.version_info[0] == 3 and sys.version_info[1] < 6:
|
||||
print("WARNING: Python 3 versions older than 3.6 are not supported.", file=sys.stderr)
|
||||
print('WARNING: Python 3 versions older than 3.6 are not supported.', file=sys.stderr)
|
||||
global quiet
|
||||
|
||||
parser = argparse.ArgumentParser("ESP-IDF OTA Partitions Tool")
|
||||
parser = argparse.ArgumentParser('ESP-IDF OTA Partitions Tool')
|
||||
|
||||
parser.add_argument("--quiet", "-q", help="suppress stderr messages", action="store_true")
|
||||
parser.add_argument("--esptool-args", help="additional main arguments for esptool", nargs="+")
|
||||
parser.add_argument("--esptool-write-args", help="additional subcommand arguments for esptool write_flash", nargs="+")
|
||||
parser.add_argument("--esptool-read-args", help="additional subcommand arguments for esptool read_flash", nargs="+")
|
||||
parser.add_argument("--esptool-erase-args", help="additional subcommand arguments for esptool erase_region", nargs="+")
|
||||
parser.add_argument('--quiet', '-q', help='suppress stderr messages', action='store_true')
|
||||
parser.add_argument('--esptool-args', help='additional main arguments for esptool', nargs='+')
|
||||
parser.add_argument('--esptool-write-args', help='additional subcommand arguments for esptool write_flash', nargs='+')
|
||||
parser.add_argument('--esptool-read-args', help='additional subcommand arguments for esptool read_flash', nargs='+')
|
||||
parser.add_argument('--esptool-erase-args', help='additional subcommand arguments for esptool erase_region', nargs='+')
|
||||
|
||||
# There are two possible sources for the partition table: a device attached to the host
|
||||
# or a partition table CSV/binary file. These sources are mutually exclusive.
|
||||
parser.add_argument("--port", "-p", help="port where the device to read the partition table from is attached")
|
||||
parser.add_argument('--port', '-p', help='port where the device to read the partition table from is attached')
|
||||
|
||||
parser.add_argument("--baud", "-b", help="baudrate to use", type=int)
|
||||
parser.add_argument('--baud', '-b', help='baudrate to use', type=int)
|
||||
|
||||
parser.add_argument("--partition-table-offset", "-o", help="offset to read the partition table from", type=str)
|
||||
parser.add_argument('--partition-table-offset', '-o', help='offset to read the partition table from', type=str)
|
||||
|
||||
parser.add_argument("--partition-table-file", "-f", help="file (CSV/binary) to read the partition table from; \
|
||||
overrides device attached to specified port as the partition table source when defined")
|
||||
parser.add_argument('--partition-table-file', '-f', help='file (CSV/binary) to read the partition table from; \
|
||||
overrides device attached to specified port as the partition table source when defined')
|
||||
|
||||
subparsers = parser.add_subparsers(dest="operation", help="run otatool -h for additional help")
|
||||
subparsers = parser.add_subparsers(dest='operation', help='run otatool -h for additional help')
|
||||
|
||||
spi_flash_sec_size = argparse.ArgumentParser(add_help=False)
|
||||
spi_flash_sec_size.add_argument("--spi-flash-sec-size", help="value of SPI_FLASH_SEC_SIZE macro", type=str)
|
||||
spi_flash_sec_size.add_argument('--spi-flash-sec-size', help='value of SPI_FLASH_SEC_SIZE macro', type=str)
|
||||
|
||||
# Specify the supported operations
|
||||
subparsers.add_parser("read_otadata", help="read otadata partition", parents=[spi_flash_sec_size])
|
||||
subparsers.add_parser("erase_otadata", help="erase otadata partition")
|
||||
subparsers.add_parser('read_otadata', help='read otadata partition', parents=[spi_flash_sec_size])
|
||||
subparsers.add_parser('erase_otadata', help='erase otadata partition')
|
||||
|
||||
slot_or_name_parser = argparse.ArgumentParser(add_help=False)
|
||||
slot_or_name_parser_args = slot_or_name_parser.add_mutually_exclusive_group()
|
||||
slot_or_name_parser_args.add_argument("--slot", help="slot number of the ota partition", type=int)
|
||||
slot_or_name_parser_args.add_argument("--name", help="name of the ota partition")
|
||||
slot_or_name_parser_args.add_argument('--slot', help='slot number of the ota partition', type=int)
|
||||
slot_or_name_parser_args.add_argument('--name', help='name of the ota partition')
|
||||
|
||||
subparsers.add_parser("switch_ota_partition", help="switch otadata partition", parents=[slot_or_name_parser, spi_flash_sec_size])
|
||||
subparsers.add_parser('switch_ota_partition', help='switch otadata partition', parents=[slot_or_name_parser, spi_flash_sec_size])
|
||||
|
||||
read_ota_partition_subparser = subparsers.add_parser("read_ota_partition", help="read contents of an ota partition", parents=[slot_or_name_parser])
|
||||
read_ota_partition_subparser.add_argument("--output", help="file to write the contents of the ota partition to")
|
||||
read_ota_partition_subparser = subparsers.add_parser('read_ota_partition', help='read contents of an ota partition', parents=[slot_or_name_parser])
|
||||
read_ota_partition_subparser.add_argument('--output', help='file to write the contents of the ota partition to')
|
||||
|
||||
write_ota_partition_subparser = subparsers.add_parser("write_ota_partition", help="write contents to an ota partition", parents=[slot_or_name_parser])
|
||||
write_ota_partition_subparser.add_argument("--input", help="file whose contents to write to the ota partition")
|
||||
write_ota_partition_subparser = subparsers.add_parser('write_ota_partition', help='write contents to an ota partition', parents=[slot_or_name_parser])
|
||||
write_ota_partition_subparser.add_argument('--input', help='file whose contents to write to the ota partition')
|
||||
|
||||
subparsers.add_parser("erase_ota_partition", help="erase contents of an ota partition", parents=[slot_or_name_parser])
|
||||
subparsers.add_parser('erase_ota_partition', help='erase contents of an ota partition', parents=[slot_or_name_parser])
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
@@ -309,34 +310,34 @@ def main():
|
||||
target_args = {}
|
||||
|
||||
if args.port:
|
||||
target_args["port"] = args.port
|
||||
target_args['port'] = args.port
|
||||
|
||||
if args.partition_table_file:
|
||||
target_args["partition_table_file"] = args.partition_table_file
|
||||
target_args['partition_table_file'] = args.partition_table_file
|
||||
|
||||
if args.partition_table_offset:
|
||||
target_args["partition_table_offset"] = int(args.partition_table_offset, 0)
|
||||
target_args['partition_table_offset'] = int(args.partition_table_offset, 0)
|
||||
|
||||
try:
|
||||
if args.spi_flash_sec_size:
|
||||
target_args["spi_flash_sec_size"] = int(args.spi_flash_sec_size, 0)
|
||||
target_args['spi_flash_sec_size'] = int(args.spi_flash_sec_size, 0)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
if args.esptool_args:
|
||||
target_args["esptool_args"] = args.esptool_args
|
||||
target_args['esptool_args'] = args.esptool_args
|
||||
|
||||
if args.esptool_write_args:
|
||||
target_args["esptool_write_args"] = args.esptool_write_args
|
||||
target_args['esptool_write_args'] = args.esptool_write_args
|
||||
|
||||
if args.esptool_read_args:
|
||||
target_args["esptool_read_args"] = args.esptool_read_args
|
||||
target_args['esptool_read_args'] = args.esptool_read_args
|
||||
|
||||
if args.esptool_erase_args:
|
||||
target_args["esptool_erase_args"] = args.esptool_erase_args
|
||||
target_args['esptool_erase_args'] = args.esptool_erase_args
|
||||
|
||||
if args.baud:
|
||||
target_args["baud"] = args.baud
|
||||
target_args['baud'] = args.baud
|
||||
|
||||
target = OtatoolTarget(**target_args)
|
||||
|
||||
@@ -347,10 +348,10 @@ def main():
|
||||
|
||||
try:
|
||||
if args.name is not None:
|
||||
ota_id = ["name"]
|
||||
ota_id = ['name']
|
||||
else:
|
||||
if args.slot is not None:
|
||||
ota_id = ["slot"]
|
||||
ota_id = ['slot']
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
@@ -358,8 +359,8 @@ def main():
|
||||
'read_otadata':(_read_otadata, []),
|
||||
'erase_otadata':(_erase_otadata, []),
|
||||
'switch_ota_partition':(_switch_ota_partition, ota_id),
|
||||
'read_ota_partition':(_read_ota_partition, ["output"] + ota_id),
|
||||
'write_ota_partition':(_write_ota_partition, ["input"] + ota_id),
|
||||
'read_ota_partition':(_read_ota_partition, ['output'] + ota_id),
|
||||
'write_ota_partition':(_write_ota_partition, ['input'] + ota_id),
|
||||
'erase_ota_partition':(_erase_ota_partition, ota_id)
|
||||
}
|
||||
|
||||
|
||||
@@ -17,18 +17,19 @@
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from __future__ import print_function, division
|
||||
from __future__ import division, print_function
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import hashlib
|
||||
|
||||
__version__ = '1.0'
|
||||
|
||||
quiet = False
|
||||
max_blk_len = 256
|
||||
idf_target = "esp32"
|
||||
idf_target = 'esp32'
|
||||
|
||||
copyright = '''// Copyright 2017-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
@@ -61,7 +62,7 @@ def critical(msg):
|
||||
class FuseTable(list):
|
||||
def __init__(self):
|
||||
super(FuseTable, self).__init__(self)
|
||||
self.md5_digest_table = ""
|
||||
self.md5_digest_table = ''
|
||||
|
||||
@classmethod
|
||||
def from_csv(cls, csv_contents):
|
||||
@@ -77,14 +78,14 @@ class FuseTable(list):
|
||||
|
||||
for line_no in range(len(lines)):
|
||||
line = expand_vars(lines[line_no]).strip()
|
||||
if line.startswith("#") or len(line) == 0:
|
||||
if line.startswith('#') or len(line) == 0:
|
||||
continue
|
||||
try:
|
||||
res.append(FuseDefinition.from_csv(line))
|
||||
except InputError as e:
|
||||
raise InputError("Error at line %d: %s" % (line_no + 1, e))
|
||||
raise InputError('Error at line %d: %s' % (line_no + 1, e))
|
||||
except Exception:
|
||||
critical("Unexpected error parsing line %d: %s" % (line_no + 1, line))
|
||||
critical('Unexpected error parsing line %d: %s' % (line_no + 1, line))
|
||||
raise
|
||||
|
||||
# fix up missing bit_start
|
||||
@@ -102,9 +103,9 @@ class FuseTable(list):
|
||||
# fix up missing field_name
|
||||
last_field = None
|
||||
for e in res:
|
||||
if e.field_name == "" and last_field is None:
|
||||
raise InputError("Error at line %d: %s missing field name" % (line_no + 1, e))
|
||||
elif e.field_name == "" and last_field is not None:
|
||||
if e.field_name == '' and last_field is None:
|
||||
raise InputError('Error at line %d: %s missing field name' % (line_no + 1, e))
|
||||
elif e.field_name == '' and last_field is not None:
|
||||
e.field_name = last_field.field_name
|
||||
last_field = e
|
||||
|
||||
@@ -136,12 +137,12 @@ class FuseTable(list):
|
||||
fl_error = False
|
||||
for p in self:
|
||||
field_name = p.field_name + p.group
|
||||
if field_name != "" and len(duplicates.intersection([field_name])) != 0:
|
||||
if field_name != '' and len(duplicates.intersection([field_name])) != 0:
|
||||
fl_error = True
|
||||
print("Field at %s, %s, %s, %s have dublicate field_name" %
|
||||
print('Field at %s, %s, %s, %s have dublicate field_name' %
|
||||
(p.field_name, p.efuse_block, p.bit_start, p.bit_count))
|
||||
if fl_error is True:
|
||||
raise InputError("Field names must be unique")
|
||||
raise InputError('Field names must be unique')
|
||||
|
||||
def verify(self, type_table=None):
|
||||
for p in self:
|
||||
@@ -153,7 +154,7 @@ class FuseTable(list):
|
||||
last = None
|
||||
for p in sorted(self, key=lambda x:(x.efuse_block, x.bit_start)):
|
||||
if last is not None and last.efuse_block == p.efuse_block and p.bit_start < last.bit_start + last.bit_count:
|
||||
raise InputError("Field at %s, %s, %s, %s overlaps %s, %s, %s, %s" %
|
||||
raise InputError('Field at %s, %s, %s, %s overlaps %s, %s, %s, %s' %
|
||||
(p.field_name, p.efuse_block, p.bit_start, p.bit_count,
|
||||
last.field_name, last.efuse_block, last.bit_start, last.bit_count))
|
||||
last = p
|
||||
@@ -161,7 +162,7 @@ class FuseTable(list):
|
||||
def calc_md5(self):
|
||||
txt_table = ''
|
||||
for p in self:
|
||||
txt_table += "%s %s %d %s %s" % (p.field_name, p.efuse_block, p.bit_start, str(p.get_bit_count()), p.comment) + "\n"
|
||||
txt_table += '%s %s %d %s %s' % (p.field_name, p.efuse_block, p.bit_start, str(p.get_bit_count()), p.comment) + '\n'
|
||||
self.md5_digest_table = hashlib.md5(txt_table.encode('utf-8')).hexdigest()
|
||||
|
||||
def show_range_used_bits(self):
|
||||
@@ -169,9 +170,9 @@ class FuseTable(list):
|
||||
rows = ''
|
||||
rows += 'Sorted efuse table:\n'
|
||||
num = 1
|
||||
rows += "{0} \t{1:<30} \t{2} \t{3} \t{4}".format("#", "field_name", "efuse_block", "bit_start", "bit_count") + "\n"
|
||||
rows += '{0} \t{1:<30} \t{2} \t{3} \t{4}'.format('#', 'field_name', 'efuse_block', 'bit_start', 'bit_count') + '\n'
|
||||
for p in sorted(self, key=lambda x:(x.efuse_block, x.bit_start)):
|
||||
rows += "{0} \t{1:<30} \t{2} \t{3:^8} \t{4:^8}".format(num, p.field_name, p.efuse_block, p.bit_start, p.bit_count) + "\n"
|
||||
rows += '{0} \t{1:<30} \t{2} \t{3:^8} \t{4:^8}'.format(num, p.field_name, p.efuse_block, p.bit_start, p.bit_count) + '\n'
|
||||
num += 1
|
||||
|
||||
rows += '\nUsed bits in efuse table:\n'
|
||||
@@ -204,30 +205,30 @@ class FuseTable(list):
|
||||
|
||||
def to_header(self, file_name):
|
||||
rows = [copyright]
|
||||
rows += ["#ifdef __cplusplus",
|
||||
rows += ['#ifdef __cplusplus',
|
||||
'extern "C" {',
|
||||
"#endif",
|
||||
"",
|
||||
"",
|
||||
"// md5_digest_table " + self.md5_digest_table,
|
||||
"// This file was generated from the file " + file_name + ".csv. DO NOT CHANGE THIS FILE MANUALLY.",
|
||||
"// If you want to change some fields, you need to change " + file_name + ".csv file",
|
||||
"// then run `efuse_common_table` or `efuse_custom_table` command it will generate this file.",
|
||||
'#endif',
|
||||
'',
|
||||
'',
|
||||
'// md5_digest_table ' + self.md5_digest_table,
|
||||
'// This file was generated from the file ' + file_name + '.csv. DO NOT CHANGE THIS FILE MANUALLY.',
|
||||
'// If you want to change some fields, you need to change ' + file_name + '.csv file',
|
||||
'// then run `efuse_common_table` or `efuse_custom_table` command it will generate this file.',
|
||||
"// To show efuse_table run the command 'show_efuse_table'.",
|
||||
"",
|
||||
""]
|
||||
'',
|
||||
'']
|
||||
|
||||
last_field_name = ''
|
||||
for p in self:
|
||||
if (p.field_name != last_field_name):
|
||||
rows += ["extern const esp_efuse_desc_t* " + "ESP_EFUSE_" + p.field_name + "[];"]
|
||||
rows += ['extern const esp_efuse_desc_t* ' + 'ESP_EFUSE_' + p.field_name + '[];']
|
||||
last_field_name = p.field_name
|
||||
|
||||
rows += ["",
|
||||
"#ifdef __cplusplus",
|
||||
"}",
|
||||
"#endif",
|
||||
""]
|
||||
rows += ['',
|
||||
'#ifdef __cplusplus',
|
||||
'}',
|
||||
'#endif',
|
||||
'']
|
||||
return '\n'.join(rows)
|
||||
|
||||
def to_c_file(self, file_name, debug):
|
||||
@@ -236,33 +237,33 @@ class FuseTable(list):
|
||||
'#include "esp_efuse.h"',
|
||||
'#include <assert.h>',
|
||||
'#include "' + file_name + '.h"',
|
||||
"",
|
||||
"// md5_digest_table " + self.md5_digest_table,
|
||||
"// This file was generated from the file " + file_name + ".csv. DO NOT CHANGE THIS FILE MANUALLY.",
|
||||
"// If you want to change some fields, you need to change " + file_name + ".csv file",
|
||||
"// then run `efuse_common_table` or `efuse_custom_table` command it will generate this file.",
|
||||
'',
|
||||
'// md5_digest_table ' + self.md5_digest_table,
|
||||
'// This file was generated from the file ' + file_name + '.csv. DO NOT CHANGE THIS FILE MANUALLY.',
|
||||
'// If you want to change some fields, you need to change ' + file_name + '.csv file',
|
||||
'// then run `efuse_common_table` or `efuse_custom_table` command it will generate this file.',
|
||||
"// To show efuse_table run the command 'show_efuse_table'."]
|
||||
|
||||
rows += [""]
|
||||
rows += ['']
|
||||
|
||||
if idf_target == "esp32":
|
||||
rows += ["#define MAX_BLK_LEN CONFIG_EFUSE_MAX_BLK_LEN"]
|
||||
if idf_target == 'esp32':
|
||||
rows += ['#define MAX_BLK_LEN CONFIG_EFUSE_MAX_BLK_LEN']
|
||||
|
||||
rows += [""]
|
||||
rows += ['']
|
||||
|
||||
last_free_bit_blk1 = self.get_str_position_last_free_bit_in_blk("EFUSE_BLK1")
|
||||
last_free_bit_blk2 = self.get_str_position_last_free_bit_in_blk("EFUSE_BLK2")
|
||||
last_free_bit_blk3 = self.get_str_position_last_free_bit_in_blk("EFUSE_BLK3")
|
||||
last_free_bit_blk1 = self.get_str_position_last_free_bit_in_blk('EFUSE_BLK1')
|
||||
last_free_bit_blk2 = self.get_str_position_last_free_bit_in_blk('EFUSE_BLK2')
|
||||
last_free_bit_blk3 = self.get_str_position_last_free_bit_in_blk('EFUSE_BLK3')
|
||||
|
||||
rows += ["// The last free bit in the block is counted over the entire file."]
|
||||
rows += ['// The last free bit in the block is counted over the entire file.']
|
||||
if last_free_bit_blk1 is not None:
|
||||
rows += ["#define LAST_FREE_BIT_BLK1 " + last_free_bit_blk1]
|
||||
rows += ['#define LAST_FREE_BIT_BLK1 ' + last_free_bit_blk1]
|
||||
if last_free_bit_blk2 is not None:
|
||||
rows += ["#define LAST_FREE_BIT_BLK2 " + last_free_bit_blk2]
|
||||
rows += ['#define LAST_FREE_BIT_BLK2 ' + last_free_bit_blk2]
|
||||
if last_free_bit_blk3 is not None:
|
||||
rows += ["#define LAST_FREE_BIT_BLK3 " + last_free_bit_blk3]
|
||||
rows += ['#define LAST_FREE_BIT_BLK3 ' + last_free_bit_blk3]
|
||||
|
||||
rows += [""]
|
||||
rows += ['']
|
||||
|
||||
if last_free_bit_blk1 is not None:
|
||||
rows += ['_Static_assert(LAST_FREE_BIT_BLK1 <= MAX_BLK_LEN, "The eFuse table does not match the coding scheme. '
|
||||
@@ -274,50 +275,50 @@ class FuseTable(list):
|
||||
rows += ['_Static_assert(LAST_FREE_BIT_BLK3 <= MAX_BLK_LEN, "The eFuse table does not match the coding scheme. '
|
||||
'Edit the table and restart the efuse_common_table or efuse_custom_table command to regenerate the new files.");']
|
||||
|
||||
rows += [""]
|
||||
rows += ['']
|
||||
|
||||
last_name = ''
|
||||
for p in self:
|
||||
if (p.field_name != last_name):
|
||||
if last_name != '':
|
||||
rows += ["};\n"]
|
||||
rows += ["static const esp_efuse_desc_t " + p.field_name + "[] = {"]
|
||||
rows += ['};\n']
|
||||
rows += ['static const esp_efuse_desc_t ' + p.field_name + '[] = {']
|
||||
last_name = p.field_name
|
||||
rows += [p.to_struct(debug) + ","]
|
||||
rows += ["};\n"]
|
||||
rows += ["\n\n\n"]
|
||||
rows += [p.to_struct(debug) + ',']
|
||||
rows += ['};\n']
|
||||
rows += ['\n\n\n']
|
||||
|
||||
last_name = ''
|
||||
for p in self:
|
||||
if (p.field_name != last_name):
|
||||
if last_name != '':
|
||||
rows += [" NULL",
|
||||
"};\n"]
|
||||
rows += ["const esp_efuse_desc_t* " + "ESP_EFUSE_" + p.field_name + "[] = {"]
|
||||
rows += [' NULL',
|
||||
'};\n']
|
||||
rows += ['const esp_efuse_desc_t* ' + 'ESP_EFUSE_' + p.field_name + '[] = {']
|
||||
last_name = p.field_name
|
||||
index = str(0) if str(p.group) == "" else str(p.group)
|
||||
rows += [" &" + p.field_name + "[" + index + "], \t\t// " + p.comment]
|
||||
rows += [" NULL",
|
||||
"};\n"]
|
||||
index = str(0) if str(p.group) == '' else str(p.group)
|
||||
rows += [' &' + p.field_name + '[' + index + '], \t\t// ' + p.comment]
|
||||
rows += [' NULL',
|
||||
'};\n']
|
||||
|
||||
return '\n'.join(rows)
|
||||
|
||||
|
||||
class FuseDefinition(object):
|
||||
def __init__(self):
|
||||
self.field_name = ""
|
||||
self.group = ""
|
||||
self.efuse_block = ""
|
||||
self.field_name = ''
|
||||
self.group = ''
|
||||
self.efuse_block = ''
|
||||
self.bit_start = None
|
||||
self.bit_count = None
|
||||
self.define = None
|
||||
self.comment = ""
|
||||
self.comment = ''
|
||||
|
||||
@classmethod
|
||||
def from_csv(cls, line):
|
||||
""" Parse a line from the CSV """
|
||||
line_w_defaults = line + ",,,," # lazy way to support default fields
|
||||
fields = [f.strip() for f in line_w_defaults.split(",")]
|
||||
line_w_defaults = line + ',,,,' # lazy way to support default fields
|
||||
fields = [f.strip() for f in line_w_defaults.split(',')]
|
||||
|
||||
res = FuseDefinition()
|
||||
res.field_name = fields[0]
|
||||
@@ -330,12 +331,12 @@ class FuseDefinition(object):
|
||||
return res
|
||||
|
||||
def parse_num(self, strval):
|
||||
if strval == "":
|
||||
if strval == '':
|
||||
return None # Field will fill in default
|
||||
return self.parse_int(strval)
|
||||
|
||||
def parse_bit_count(self, strval):
|
||||
if strval == "MAX_BLK_LEN":
|
||||
if strval == 'MAX_BLK_LEN':
|
||||
self.define = strval
|
||||
return self.get_max_bits_of_block()
|
||||
else:
|
||||
@@ -345,18 +346,18 @@ class FuseDefinition(object):
|
||||
try:
|
||||
return int(v, 0)
|
||||
except ValueError:
|
||||
raise InputError("Invalid field value %s" % v)
|
||||
raise InputError('Invalid field value %s' % v)
|
||||
|
||||
def parse_block(self, strval):
|
||||
if strval == "":
|
||||
if strval == '':
|
||||
raise InputError("Field 'efuse_block' can't be left empty.")
|
||||
if idf_target == "esp32":
|
||||
if strval not in ["EFUSE_BLK0", "EFUSE_BLK1", "EFUSE_BLK2", "EFUSE_BLK3"]:
|
||||
if idf_target == 'esp32':
|
||||
if strval not in ['EFUSE_BLK0', 'EFUSE_BLK1', 'EFUSE_BLK2', 'EFUSE_BLK3']:
|
||||
raise InputError("Field 'efuse_block' should be one of EFUSE_BLK0..EFUSE_BLK3")
|
||||
else:
|
||||
if strval not in ["EFUSE_BLK0", "EFUSE_BLK1", "EFUSE_BLK2", "EFUSE_BLK3", "EFUSE_BLK4",
|
||||
"EFUSE_BLK5", "EFUSE_BLK6", "EFUSE_BLK7", "EFUSE_BLK8", "EFUSE_BLK9",
|
||||
"EFUSE_BLK10"]:
|
||||
if strval not in ['EFUSE_BLK0', 'EFUSE_BLK1', 'EFUSE_BLK2', 'EFUSE_BLK3', 'EFUSE_BLK4',
|
||||
'EFUSE_BLK5', 'EFUSE_BLK6', 'EFUSE_BLK7', 'EFUSE_BLK8', 'EFUSE_BLK9',
|
||||
'EFUSE_BLK10']:
|
||||
raise InputError("Field 'efuse_block' should be one of EFUSE_BLK0..EFUSE_BLK10")
|
||||
|
||||
return strval
|
||||
@@ -365,32 +366,32 @@ class FuseDefinition(object):
|
||||
'''common_table: EFUSE_BLK0, EFUSE_BLK1, EFUSE_BLK2, EFUSE_BLK3
|
||||
custom_table: ----------, ----------, ----------, EFUSE_BLK3(some reserved in common_table)
|
||||
'''
|
||||
if self.efuse_block == "EFUSE_BLK0":
|
||||
if self.efuse_block == 'EFUSE_BLK0':
|
||||
return 256
|
||||
else:
|
||||
return max_blk_len
|
||||
|
||||
def verify(self, type_table):
|
||||
if self.efuse_block is None:
|
||||
raise ValidationError(self, "efuse_block field is not set")
|
||||
raise ValidationError(self, 'efuse_block field is not set')
|
||||
if self.bit_count is None:
|
||||
raise ValidationError(self, "bit_count field is not set")
|
||||
raise ValidationError(self, 'bit_count field is not set')
|
||||
|
||||
if type_table is not None:
|
||||
if type_table == "custom_table":
|
||||
if self.efuse_block != "EFUSE_BLK3":
|
||||
raise ValidationError(self, "custom_table should use only EFUSE_BLK3")
|
||||
if type_table == 'custom_table':
|
||||
if self.efuse_block != 'EFUSE_BLK3':
|
||||
raise ValidationError(self, 'custom_table should use only EFUSE_BLK3')
|
||||
|
||||
max_bits = self.get_max_bits_of_block()
|
||||
|
||||
if self.bit_start + self.bit_count > max_bits:
|
||||
raise ValidationError(self, "The field is outside the boundaries(max_bits = %d) of the %s block" % (max_bits, self.efuse_block))
|
||||
raise ValidationError(self, 'The field is outside the boundaries(max_bits = %d) of the %s block' % (max_bits, self.efuse_block))
|
||||
|
||||
def get_full_name(self):
|
||||
def get_postfix(group):
|
||||
postfix = ""
|
||||
if group != "":
|
||||
postfix = "_PART_" + group
|
||||
postfix = ''
|
||||
if group != '':
|
||||
postfix = '_PART_' + group
|
||||
return postfix
|
||||
|
||||
return self.field_name + get_postfix(self.group)
|
||||
@@ -402,19 +403,19 @@ class FuseDefinition(object):
|
||||
return self.bit_count
|
||||
|
||||
def to_struct(self, debug):
|
||||
start = " {"
|
||||
start = ' {'
|
||||
if debug is True:
|
||||
start = " {" + '"' + self.field_name + '" ,'
|
||||
return ", ".join([start + self.efuse_block,
|
||||
start = ' {' + '"' + self.field_name + '" ,'
|
||||
return ', '.join([start + self.efuse_block,
|
||||
str(self.bit_start),
|
||||
str(self.get_bit_count()) + "}, \t // " + self.comment])
|
||||
str(self.get_bit_count()) + '}, \t // ' + self.comment])
|
||||
|
||||
|
||||
def process_input_file(file, type_table):
|
||||
status("Parsing efuse CSV input file " + file.name + " ...")
|
||||
status('Parsing efuse CSV input file ' + file.name + ' ...')
|
||||
input = file.read()
|
||||
table = FuseTable.from_csv(input)
|
||||
status("Verifying efuse table...")
|
||||
status('Verifying efuse table...')
|
||||
table.verify(type_table)
|
||||
return table
|
||||
|
||||
@@ -432,35 +433,35 @@ def create_output_files(name, output_table, debug):
|
||||
file_name = os.path.splitext(os.path.basename(name))[0]
|
||||
gen_dir = os.path.dirname(name)
|
||||
|
||||
dir_for_file_h = gen_dir + "/include"
|
||||
dir_for_file_h = gen_dir + '/include'
|
||||
try:
|
||||
os.stat(dir_for_file_h)
|
||||
except Exception:
|
||||
os.mkdir(dir_for_file_h)
|
||||
|
||||
file_h_path = os.path.join(dir_for_file_h, file_name + ".h")
|
||||
file_c_path = os.path.join(gen_dir, file_name + ".c")
|
||||
file_h_path = os.path.join(dir_for_file_h, file_name + '.h')
|
||||
file_c_path = os.path.join(gen_dir, file_name + '.c')
|
||||
|
||||
# src files are the same
|
||||
if ckeck_md5_in_file(output_table.md5_digest_table, file_c_path) is False:
|
||||
status("Creating efuse *.h file " + file_h_path + " ...")
|
||||
status('Creating efuse *.h file ' + file_h_path + ' ...')
|
||||
output = output_table.to_header(file_name)
|
||||
with open(file_h_path, 'w') as f:
|
||||
f.write(output)
|
||||
|
||||
status("Creating efuse *.c file " + file_c_path + " ...")
|
||||
status('Creating efuse *.c file ' + file_c_path + ' ...')
|
||||
output = output_table.to_c_file(file_name, debug)
|
||||
with open(file_c_path, 'w') as f:
|
||||
f.write(output)
|
||||
else:
|
||||
print("Source files do not require updating correspond to csv file.")
|
||||
print('Source files do not require updating correspond to csv file.')
|
||||
|
||||
|
||||
def main():
|
||||
if sys.version_info[0] < 3:
|
||||
print("WARNING: Support for Python 2 is deprecated and will be removed in future versions.", file=sys.stderr)
|
||||
print('WARNING: Support for Python 2 is deprecated and will be removed in future versions.', file=sys.stderr)
|
||||
elif sys.version_info[0] == 3 and sys.version_info[1] < 6:
|
||||
print("WARNING: Python 3 versions older than 3.6 are not supported.", file=sys.stderr)
|
||||
print('WARNING: Python 3 versions older than 3.6 are not supported.', file=sys.stderr)
|
||||
global quiet
|
||||
global max_blk_len
|
||||
global idf_target
|
||||
@@ -468,8 +469,8 @@ def main():
|
||||
parser = argparse.ArgumentParser(description='ESP32 eFuse Manager')
|
||||
parser.add_argument('--idf_target', '-t', help='Target chip type', choices=['esp32', 'esp32s2', 'esp32s3', 'esp32c3'], default='esp32')
|
||||
parser.add_argument('--quiet', '-q', help="Don't print non-critical status messages to stderr", action='store_true')
|
||||
parser.add_argument('--debug', help='Create header file with debug info', default=False, action="store_false")
|
||||
parser.add_argument('--info', help='Print info about range of used bits', default=False, action="store_true")
|
||||
parser.add_argument('--debug', help='Create header file with debug info', default=False, action='store_false')
|
||||
parser.add_argument('--info', help='Print info about range of used bits', default=False, action='store_true')
|
||||
parser.add_argument('--max_blk_len', help='Max number of bits in BLOCKs', type=int, default=256)
|
||||
parser.add_argument('common_input', help='Path to common CSV file to parse.', type=argparse.FileType('r'))
|
||||
parser.add_argument('custom_input', help='Path to custom CSV file to parse.', type=argparse.FileType('r'), nargs='?', default=None)
|
||||
@@ -479,18 +480,18 @@ def main():
|
||||
idf_target = args.idf_target
|
||||
|
||||
max_blk_len = args.max_blk_len
|
||||
print("Max number of bits in BLK %d" % (max_blk_len))
|
||||
print('Max number of bits in BLK %d' % (max_blk_len))
|
||||
if max_blk_len not in [256, 192, 128]:
|
||||
raise InputError("Unsupported block length = %d" % (max_blk_len))
|
||||
raise InputError('Unsupported block length = %d' % (max_blk_len))
|
||||
|
||||
quiet = args.quiet
|
||||
debug = args.debug
|
||||
info = args.info
|
||||
|
||||
common_table = process_input_file(args.common_input, "common_table")
|
||||
common_table = process_input_file(args.common_input, 'common_table')
|
||||
two_table = common_table
|
||||
if args.custom_input is not None:
|
||||
custom_table = process_input_file(args.custom_input, "custom_table")
|
||||
custom_table = process_input_file(args.custom_input, 'custom_table')
|
||||
two_table += custom_table
|
||||
two_table.verify()
|
||||
|
||||
@@ -512,7 +513,7 @@ class InputError(RuntimeError):
|
||||
|
||||
class ValidationError(InputError):
|
||||
def __init__(self, p, message):
|
||||
super(ValidationError, self).__init__("Entry %s invalid: %s" % (p.field_name, message))
|
||||
super(ValidationError, self).__init__('Entry %s invalid: %s' % (p.field_name, message))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
#!/usr/bin/env python
|
||||
from __future__ import print_function, division
|
||||
import unittest
|
||||
from __future__ import division, print_function
|
||||
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
try:
|
||||
import efuse_table_gen
|
||||
except ImportError:
|
||||
sys.path.append("..")
|
||||
sys.path.append('..')
|
||||
import efuse_table_gen
|
||||
|
||||
|
||||
@@ -117,7 +118,7 @@ name2, EFUSE_BLK2, ,
|
||||
, EFUSE_BLK2, , 4,
|
||||
name1, EFUSE_BLK3, , 5,
|
||||
"""
|
||||
with self.assertRaisesRegex(efuse_table_gen.InputError, "Field names must be unique"):
|
||||
with self.assertRaisesRegex(efuse_table_gen.InputError, 'Field names must be unique'):
|
||||
efuse_table_gen.FuseTable.from_csv(csv)
|
||||
|
||||
def test_seq_bit_start5_fill(self):
|
||||
@@ -154,7 +155,7 @@ name1, EFUSE_BLK3, 1,
|
||||
name2, EFUSE_BLK3, 5, 4, Use for test name 2
|
||||
"""
|
||||
t = efuse_table_gen.FuseTable.from_csv(csv)
|
||||
with self.assertRaisesRegex(efuse_table_gen.InputError, "overlap"):
|
||||
with self.assertRaisesRegex(efuse_table_gen.InputError, 'overlap'):
|
||||
t.verify()
|
||||
|
||||
def test_empty_field_name_fail(self):
|
||||
@@ -163,7 +164,7 @@ name2, EFUSE_BLK3, 5,
|
||||
, EFUSE_BLK3, , 5,
|
||||
name2, EFUSE_BLK2, , 4,
|
||||
"""
|
||||
with self.assertRaisesRegex(efuse_table_gen.InputError, "missing field name"):
|
||||
with self.assertRaisesRegex(efuse_table_gen.InputError, 'missing field name'):
|
||||
efuse_table_gen.FuseTable.from_csv(csv)
|
||||
|
||||
def test_unique_field_name_fail(self):
|
||||
@@ -172,7 +173,7 @@ name2, EFUSE_BLK2, ,
|
||||
name1, EFUSE_BLK3, 0, 5, Use for test name 1
|
||||
name1, EFUSE_BLK3, 5, 4, Use for test name 2
|
||||
"""
|
||||
with self.assertRaisesRegex(efuse_table_gen.InputError, "Field names must be unique"):
|
||||
with self.assertRaisesRegex(efuse_table_gen.InputError, 'Field names must be unique'):
|
||||
efuse_table_gen.FuseTable.from_csv(csv)
|
||||
|
||||
def test_bit_count_empty_fail(self):
|
||||
@@ -181,7 +182,7 @@ name1, EFUSE_BLK3, 5,
|
||||
name1, EFUSE_BLK3, 0, , Use for test name 1
|
||||
name2, EFUSE_BLK3, 5, 4, Use for test name 2
|
||||
"""
|
||||
with self.assertRaisesRegex(efuse_table_gen.InputError, "empty"):
|
||||
with self.assertRaisesRegex(efuse_table_gen.InputError, 'empty'):
|
||||
efuse_table_gen.FuseTable.from_csv(csv)
|
||||
|
||||
def test_bit_start_num_fail(self):
|
||||
@@ -190,7 +191,7 @@ name2, EFUSE_BLK3, 5,
|
||||
name1, EFUSE_BLK3, k, 5, Use for test name 1
|
||||
name2, EFUSE_BLK3, 5, 4, Use for test name 2
|
||||
"""
|
||||
with self.assertRaisesRegex(efuse_table_gen.InputError, "Invalid field value"):
|
||||
with self.assertRaisesRegex(efuse_table_gen.InputError, 'Invalid field value'):
|
||||
efuse_table_gen.FuseTable.from_csv(csv)
|
||||
|
||||
def test_join_entry(self):
|
||||
@@ -257,7 +258,7 @@ name2, EFUSE_BLK3, 191,
|
||||
"""
|
||||
efuse_table_gen.max_blk_len = 192
|
||||
t = efuse_table_gen.FuseTable.from_csv(csv)
|
||||
with self.assertRaisesRegex(efuse_table_gen.InputError, "The field is outside the boundaries"):
|
||||
with self.assertRaisesRegex(efuse_table_gen.InputError, 'The field is outside the boundaries'):
|
||||
t.verify()
|
||||
|
||||
def test_field_blk1_size_is_more(self):
|
||||
@@ -267,7 +268,7 @@ name1, EFUSE_BLK0, 0,
|
||||
name2, EFUSE_BLK1, 1, 256, Use for test name 2
|
||||
"""
|
||||
t = efuse_table_gen.FuseTable.from_csv(csv)
|
||||
with self.assertRaisesRegex(efuse_table_gen.InputError, "The field is outside the boundaries"):
|
||||
with self.assertRaisesRegex(efuse_table_gen.InputError, 'The field is outside the boundaries'):
|
||||
t.verify()
|
||||
|
||||
|
||||
@@ -311,8 +312,8 @@ name1, EFUSE_BLK3, 0,
|
||||
name2, EFUSE_BLK2, 5, 4, Use for test name 2
|
||||
"""
|
||||
t = efuse_table_gen.FuseTable.from_csv(csv)
|
||||
with self.assertRaisesRegex(efuse_table_gen.ValidationError, "custom_table should use only EFUSE_BLK3"):
|
||||
t.verify("custom_table")
|
||||
with self.assertRaisesRegex(efuse_table_gen.ValidationError, 'custom_table should use only EFUSE_BLK3'):
|
||||
t.verify('custom_table')
|
||||
|
||||
def test_common_and_custom_table_use_the_same_bits(self):
|
||||
csv_common = """
|
||||
@@ -321,7 +322,7 @@ name1, EFUSE_BLK3, 0,
|
||||
name2, EFUSE_BLK2, 5, 4, Use for test name 2
|
||||
"""
|
||||
common_table = efuse_table_gen.FuseTable.from_csv(csv_common)
|
||||
common_table.verify("common_table")
|
||||
common_table.verify('common_table')
|
||||
two_tables = common_table
|
||||
|
||||
csv_custom = """
|
||||
@@ -330,12 +331,12 @@ name3, EFUSE_BLK3, 20,
|
||||
name4, EFUSE_BLK3, 4, 1, Use for test name 2
|
||||
"""
|
||||
custom_table = efuse_table_gen.FuseTable.from_csv(csv_custom)
|
||||
custom_table.verify("custom_table")
|
||||
custom_table.verify('custom_table')
|
||||
|
||||
two_tables += custom_table
|
||||
with self.assertRaisesRegex(efuse_table_gen.InputError, "overlaps"):
|
||||
with self.assertRaisesRegex(efuse_table_gen.InputError, 'overlaps'):
|
||||
two_tables.verify()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
import hashlib
|
||||
import hmac
|
||||
import struct
|
||||
import os
|
||||
import random
|
||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||
import struct
|
||||
|
||||
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||
from cryptography.utils import int_to_bytes
|
||||
|
||||
|
||||
@@ -19,9 +19,9 @@ def number_as_bignum_words(number):
|
||||
"""
|
||||
result = []
|
||||
while number != 0:
|
||||
result.append("0x%08x" % (number & 0xFFFFFFFF))
|
||||
result.append('0x%08x' % (number & 0xFFFFFFFF))
|
||||
number >>= 32
|
||||
return "{ " + ", ".join(result) + " }"
|
||||
return '{ ' + ', '.join(result) + ' }'
|
||||
|
||||
|
||||
def number_as_bytes(number, pad_bits=None):
|
||||
@@ -38,7 +38,7 @@ def bytes_as_char_array(b):
|
||||
"""
|
||||
Given a sequence of bytes, format as a char array
|
||||
"""
|
||||
return "{ " + ", ".join("0x%02x" % x for x in b) + " }"
|
||||
return '{ ' + ', '.join('0x%02x' % x for x in b) + ' }'
|
||||
|
||||
|
||||
NUM_HMAC_KEYS = 3
|
||||
@@ -50,36 +50,36 @@ hmac_keys = [os.urandom(32) for x in range(NUM_HMAC_KEYS)]
|
||||
|
||||
messages = [random.randrange(0, 1 << 4096) for x in range(NUM_MESSAGES)]
|
||||
|
||||
with open("digital_signature_test_cases.h", "w") as f:
|
||||
f.write("/* File generated by gen_digital_signature_tests.py */\n\n")
|
||||
with open('digital_signature_test_cases.h', 'w') as f:
|
||||
f.write('/* File generated by gen_digital_signature_tests.py */\n\n')
|
||||
|
||||
# Write out HMAC keys
|
||||
f.write("#define NUM_HMAC_KEYS %d\n\n" % NUM_HMAC_KEYS)
|
||||
f.write("static const uint8_t test_hmac_keys[NUM_HMAC_KEYS][32] = {\n")
|
||||
f.write('#define NUM_HMAC_KEYS %d\n\n' % NUM_HMAC_KEYS)
|
||||
f.write('static const uint8_t test_hmac_keys[NUM_HMAC_KEYS][32] = {\n')
|
||||
for h in hmac_keys:
|
||||
f.write(" %s,\n" % bytes_as_char_array(h))
|
||||
f.write("};\n\n")
|
||||
f.write(' %s,\n' % bytes_as_char_array(h))
|
||||
f.write('};\n\n')
|
||||
|
||||
# Write out messages
|
||||
f.write("#define NUM_MESSAGES %d\n\n" % NUM_MESSAGES)
|
||||
f.write("static const uint32_t test_messages[NUM_MESSAGES][4096/32] = {\n")
|
||||
f.write('#define NUM_MESSAGES %d\n\n' % NUM_MESSAGES)
|
||||
f.write('static const uint32_t test_messages[NUM_MESSAGES][4096/32] = {\n')
|
||||
for m in messages:
|
||||
f.write(" // Message %d\n" % messages.index(m))
|
||||
f.write(" %s,\n" % number_as_bignum_words(m))
|
||||
f.write(" };\n")
|
||||
f.write("\n\n\n")
|
||||
f.write(' // Message %d\n' % messages.index(m))
|
||||
f.write(' %s,\n' % number_as_bignum_words(m))
|
||||
f.write(' };\n')
|
||||
f.write('\n\n\n')
|
||||
|
||||
f.write("#define NUM_CASES %d\n\n" % NUM_CASES)
|
||||
f.write("static const encrypt_testcase_t test_cases[NUM_CASES] = {\n")
|
||||
f.write('#define NUM_CASES %d\n\n' % NUM_CASES)
|
||||
f.write('static const encrypt_testcase_t test_cases[NUM_CASES] = {\n')
|
||||
|
||||
for case in range(NUM_CASES):
|
||||
f.write(" { /* Case %d */\n" % case)
|
||||
f.write(' { /* Case %d */\n' % case)
|
||||
|
||||
iv = os.urandom(16)
|
||||
f.write(" .iv = %s,\n" % (bytes_as_char_array(iv)))
|
||||
f.write(' .iv = %s,\n' % (bytes_as_char_array(iv)))
|
||||
|
||||
hmac_key_idx = random.randrange(0, NUM_HMAC_KEYS)
|
||||
aes_key = hmac.HMAC(hmac_keys[hmac_key_idx], b"\xFF" * 32, hashlib.sha256).digest()
|
||||
aes_key = hmac.HMAC(hmac_keys[hmac_key_idx], b'\xFF' * 32, hashlib.sha256).digest()
|
||||
|
||||
sizes = [4096, 3072, 2048, 1024, 512]
|
||||
key_size = sizes[case % len(sizes)]
|
||||
@@ -100,13 +100,13 @@ with open("digital_signature_test_cases.h", "w") as f:
|
||||
mprime &= 0xFFFFFFFF
|
||||
length = key_size // 32 - 1
|
||||
|
||||
f.write(" .p_data = {\n")
|
||||
f.write(" .Y = %s,\n" % number_as_bignum_words(Y))
|
||||
f.write(" .M = %s,\n" % number_as_bignum_words(M))
|
||||
f.write(" .Rb = %s,\n" % number_as_bignum_words(rinv))
|
||||
f.write(" .M_prime = 0x%08x,\n" % mprime)
|
||||
f.write(" .length = %d, // %d bit\n" % (length, key_size))
|
||||
f.write(" },\n")
|
||||
f.write(' .p_data = {\n')
|
||||
f.write(' .Y = %s,\n' % number_as_bignum_words(Y))
|
||||
f.write(' .M = %s,\n' % number_as_bignum_words(M))
|
||||
f.write(' .Rb = %s,\n' % number_as_bignum_words(rinv))
|
||||
f.write(' .M_prime = 0x%08x,\n' % mprime)
|
||||
f.write(' .length = %d, // %d bit\n' % (length, key_size))
|
||||
f.write(' },\n')
|
||||
|
||||
# calculate MD from preceding values and IV
|
||||
|
||||
@@ -114,7 +114,7 @@ with open("digital_signature_test_cases.h", "w") as f:
|
||||
md_in = number_as_bytes(Y, 4096) + \
|
||||
number_as_bytes(M, 4096) + \
|
||||
number_as_bytes(rinv, 4096) + \
|
||||
struct.pack("<II", mprime, length) + \
|
||||
struct.pack('<II', mprime, length) + \
|
||||
iv
|
||||
assert len(md_in) == 12480 / 8
|
||||
md = hashlib.sha256(md_in).digest()
|
||||
@@ -126,7 +126,7 @@ with open("digital_signature_test_cases.h", "w") as f:
|
||||
number_as_bytes(M, 4096) + \
|
||||
number_as_bytes(rinv, 4096) + \
|
||||
md + \
|
||||
struct.pack("<II", mprime, length) + \
|
||||
struct.pack('<II', mprime, length) + \
|
||||
b'\x08' * 8
|
||||
|
||||
assert len(p) == 12672 / 8
|
||||
@@ -135,16 +135,16 @@ with open("digital_signature_test_cases.h", "w") as f:
|
||||
encryptor = cipher.encryptor()
|
||||
c = encryptor.update(p) + encryptor.finalize()
|
||||
|
||||
f.write(" .expected_c = %s,\n" % bytes_as_char_array(c))
|
||||
f.write(" .hmac_key_idx = %d,\n" % (hmac_key_idx))
|
||||
f.write(' .expected_c = %s,\n' % bytes_as_char_array(c))
|
||||
f.write(' .hmac_key_idx = %d,\n' % (hmac_key_idx))
|
||||
|
||||
f.write(" // results of message array encrypted with these keys\n")
|
||||
f.write(" .expected_results = {\n")
|
||||
f.write(' // results of message array encrypted with these keys\n')
|
||||
f.write(' .expected_results = {\n')
|
||||
mask = (1 << key_size) - 1 # truncate messages if needed
|
||||
for m in messages:
|
||||
f.write(" // Message %d\n" % messages.index(m))
|
||||
f.write(" %s," % (number_as_bignum_words(pow(m & mask, Y, M))))
|
||||
f.write(" },\n")
|
||||
f.write(" },\n")
|
||||
f.write(' // Message %d\n' % messages.index(m))
|
||||
f.write(' %s,' % (number_as_bignum_words(pow(m & mask, Y, M))))
|
||||
f.write(' },\n')
|
||||
f.write(' },\n')
|
||||
|
||||
f.write("};\n")
|
||||
f.write('};\n')
|
||||
|
||||
@@ -3,12 +3,14 @@
|
||||
# source: esp_local_ctrl.proto
|
||||
|
||||
import sys
|
||||
|
||||
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
|
||||
from google.protobuf.internal import enum_type_wrapper
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import enum_type_wrapper
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
@@ -16,7 +18,6 @@ _sym_db = _symbol_database.Default()
|
||||
|
||||
import constants_pb2 as constants__pb2
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name='esp_local_ctrl.proto',
|
||||
package='',
|
||||
@@ -153,7 +154,7 @@ _PROPERTYINFO = _descriptor.Descriptor(
|
||||
_descriptor.FieldDescriptor(
|
||||
name='name', full_name='PropertyInfo.name', index=1,
|
||||
number=2, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b("").decode('utf-8'),
|
||||
has_default_value=False, default_value=_b('').decode('utf-8'),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
@@ -174,7 +175,7 @@ _PROPERTYINFO = _descriptor.Descriptor(
|
||||
_descriptor.FieldDescriptor(
|
||||
name='value', full_name='PropertyInfo.value', index=4,
|
||||
number=5, type=12, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b(""),
|
||||
has_default_value=False, default_value=_b(''),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
@@ -281,7 +282,7 @@ _PROPERTYVALUE = _descriptor.Descriptor(
|
||||
_descriptor.FieldDescriptor(
|
||||
name='value', full_name='PropertyValue.value', index=1,
|
||||
number=2, type=12, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b(""),
|
||||
has_default_value=False, default_value=_b(''),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import re
|
||||
import os
|
||||
import re
|
||||
import socket
|
||||
from threading import Thread, Event
|
||||
import subprocess
|
||||
import time
|
||||
from shutil import copyfile
|
||||
from threading import Event, Thread
|
||||
|
||||
from tiny_test_fw import Utility, DUT
|
||||
import ttfw_idf
|
||||
from tiny_test_fw import DUT, Utility
|
||||
|
||||
stop_sock_listener = Event()
|
||||
stop_io_listener = Event()
|
||||
@@ -22,16 +22,16 @@ def io_listener(dut1):
|
||||
data = b''
|
||||
while not stop_io_listener.is_set():
|
||||
try:
|
||||
data = dut1.expect(re.compile(r"PacketOut:\[([a-fA-F0-9]+)\]"), timeout=5)
|
||||
data = dut1.expect(re.compile(r'PacketOut:\[([a-fA-F0-9]+)\]'), timeout=5)
|
||||
except DUT.ExpectTimeout:
|
||||
continue
|
||||
if data != () and data[0] != b'':
|
||||
packet_data = data[0]
|
||||
print("Packet_data>{}<".format(packet_data))
|
||||
print('Packet_data>{}<'.format(packet_data))
|
||||
response = bytearray.fromhex(packet_data.decode())
|
||||
print("Sending to socket:")
|
||||
print('Sending to socket:')
|
||||
packet = ' '.join(format(x, '02x') for x in bytearray(response))
|
||||
print("Packet>{}<".format(packet))
|
||||
print('Packet>{}<'.format(packet))
|
||||
if client_address is not None:
|
||||
sock.sendto(response, ('127.0.0.1', 7777))
|
||||
|
||||
@@ -50,7 +50,7 @@ def sock_listener(dut1):
|
||||
try:
|
||||
payload, client_address = sock.recvfrom(1024)
|
||||
packet = ' '.join(format(x, '02x') for x in bytearray(payload))
|
||||
print("Received from address {}, data {}".format(client_address, packet))
|
||||
print('Received from address {}, data {}'.format(client_address, packet))
|
||||
dut1.write(str.encode(packet))
|
||||
except socket.timeout:
|
||||
pass
|
||||
@@ -59,7 +59,7 @@ def sock_listener(dut1):
|
||||
sock = None
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag="Example_WIFI")
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_WIFI')
|
||||
def lwip_test_suite(env, extra_data):
|
||||
global stop_io_listener
|
||||
global stop_sock_listener
|
||||
@@ -70,12 +70,12 @@ def lwip_test_suite(env, extra_data):
|
||||
3. Execute ttcn3 test suite
|
||||
4. Collect result from ttcn3
|
||||
"""
|
||||
dut1 = env.get_dut("net_suite", "examples/system/network_tests", dut_class=ttfw_idf.ESP32DUT)
|
||||
dut1 = env.get_dut('net_suite', 'examples/system/network_tests', dut_class=ttfw_idf.ESP32DUT)
|
||||
# check and log bin size
|
||||
binary_file = os.path.join(dut1.app.binary_path, "net_suite.bin")
|
||||
binary_file = os.path.join(dut1.app.binary_path, 'net_suite.bin')
|
||||
bin_size = os.path.getsize(binary_file)
|
||||
ttfw_idf.log_performance("net_suite", "{}KB".format(bin_size // 1024))
|
||||
ttfw_idf.check_performance("net_suite", bin_size // 1024, dut1.TARGET)
|
||||
ttfw_idf.log_performance('net_suite', '{}KB'.format(bin_size // 1024))
|
||||
ttfw_idf.check_performance('net_suite', bin_size // 1024, dut1.TARGET)
|
||||
dut1.start_app()
|
||||
thread1 = Thread(target=sock_listener, args=(dut1, ))
|
||||
thread2 = Thread(target=io_listener, args=(dut1, ))
|
||||
@@ -84,48 +84,48 @@ def lwip_test_suite(env, extra_data):
|
||||
TTCN_SRC = 'esp32_netsuite.ttcn'
|
||||
TTCN_CFG = 'esp32_netsuite.cfg'
|
||||
# System Paths
|
||||
netsuite_path = os.getenv("NETSUITE_PATH")
|
||||
netsuite_src_path = os.path.join(netsuite_path, "src")
|
||||
netsuite_path = os.getenv('NETSUITE_PATH')
|
||||
netsuite_src_path = os.path.join(netsuite_path, 'src')
|
||||
test_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
# Building the suite
|
||||
print("Rebuilding the test suite")
|
||||
print("-------------------------")
|
||||
print('Rebuilding the test suite')
|
||||
print('-------------------------')
|
||||
# copy esp32 specific files to ttcn net-suite dir
|
||||
copyfile(os.path.join(test_dir, TTCN_SRC), os.path.join(netsuite_src_path, TTCN_SRC))
|
||||
copyfile(os.path.join(test_dir, TTCN_CFG), os.path.join(netsuite_src_path, TTCN_CFG))
|
||||
proc = subprocess.Popen(['bash', '-c', 'cd ' + netsuite_src_path + ' && source make.sh'],
|
||||
cwd=netsuite_path, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
output = proc.stdout.read()
|
||||
print("Note: First build step we expect failure (titan/net_suite build system not suitable for multijob make)")
|
||||
print('Note: First build step we expect failure (titan/net_suite build system not suitable for multijob make)')
|
||||
print(output)
|
||||
proc = subprocess.Popen(['bash', '-c', 'cd ' + netsuite_src_path + ' && make'],
|
||||
cwd=netsuite_path, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
print("Note: This time all dependencies shall be generated -- multijob make shall pass")
|
||||
print('Note: This time all dependencies shall be generated -- multijob make shall pass')
|
||||
output = proc.stdout.read()
|
||||
print(output)
|
||||
# Executing the test suite
|
||||
thread1.start()
|
||||
thread2.start()
|
||||
time.sleep(2)
|
||||
print("Executing the test suite")
|
||||
print("------------------------")
|
||||
print('Executing the test suite')
|
||||
print('------------------------')
|
||||
proc = subprocess.Popen(['ttcn3_start', os.path.join(netsuite_src_path,'test_suite'), os.path.join(netsuite_src_path, TTCN_CFG)],
|
||||
stdout=subprocess.PIPE)
|
||||
output = proc.stdout.read()
|
||||
print(output)
|
||||
print("Collecting results")
|
||||
print("------------------")
|
||||
print('Collecting results')
|
||||
print('------------------')
|
||||
verdict_stats = re.search('(Verdict statistics:.*)', output)
|
||||
if verdict_stats:
|
||||
verdict_stats = verdict_stats.group(1)
|
||||
else:
|
||||
verdict_stats = b""
|
||||
verdict_stats = b''
|
||||
verdict = re.search('Overall verdict: pass', output)
|
||||
if verdict:
|
||||
print("Test passed!")
|
||||
Utility.console_log(verdict_stats, "green")
|
||||
print('Test passed!')
|
||||
Utility.console_log(verdict_stats, 'green')
|
||||
else:
|
||||
Utility.console_log(verdict_stats, "red")
|
||||
Utility.console_log(verdict_stats, 'red')
|
||||
raise ValueError('Test failed with: {}'.format(verdict_stats))
|
||||
else:
|
||||
try:
|
||||
@@ -137,8 +137,8 @@ def lwip_test_suite(env, extra_data):
|
||||
time.sleep(0.5)
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
print("Executing done, waiting for tests to finish")
|
||||
print("-------------------------------------------")
|
||||
print('Executing done, waiting for tests to finish')
|
||||
print('-------------------------------------------')
|
||||
stop_io_listener.set()
|
||||
stop_sock_listener.set()
|
||||
thread1.join()
|
||||
@@ -146,6 +146,6 @@ def lwip_test_suite(env, extra_data):
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Manual execution, please build and start ttcn in a separate console")
|
||||
print('Manual execution, please build and start ttcn in a separate console')
|
||||
manual_test = True
|
||||
lwip_test_suite()
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
|
||||
from __future__ import with_statement
|
||||
|
||||
import os
|
||||
import sys
|
||||
import struct
|
||||
import argparse
|
||||
import csv
|
||||
import os
|
||||
import re
|
||||
import struct
|
||||
import sys
|
||||
from io import open
|
||||
|
||||
try:
|
||||
@@ -80,22 +80,22 @@ class CertificateBundle:
|
||||
def add_from_file(self, file_path):
|
||||
try:
|
||||
if file_path.endswith('.pem'):
|
||||
status("Parsing certificates from %s" % file_path)
|
||||
status('Parsing certificates from %s' % file_path)
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
crt_str = f.read()
|
||||
self.add_from_pem(crt_str)
|
||||
return True
|
||||
|
||||
elif file_path.endswith('.der'):
|
||||
status("Parsing certificates from %s" % file_path)
|
||||
status('Parsing certificates from %s' % file_path)
|
||||
with open(file_path, 'rb') as f:
|
||||
crt_str = f.read()
|
||||
self.add_from_der(crt_str)
|
||||
return True
|
||||
|
||||
except ValueError:
|
||||
critical("Invalid certificate in %s" % file_path)
|
||||
raise InputError("Invalid certificate")
|
||||
critical('Invalid certificate in %s' % file_path)
|
||||
raise InputError('Invalid certificate')
|
||||
|
||||
return False
|
||||
|
||||
@@ -119,13 +119,13 @@ class CertificateBundle:
|
||||
crt += strg
|
||||
|
||||
if(count == 0):
|
||||
raise InputError("No certificate found")
|
||||
raise InputError('No certificate found')
|
||||
|
||||
status("Successfully added %d certificates" % count)
|
||||
status('Successfully added %d certificates' % count)
|
||||
|
||||
def add_from_der(self, crt_str):
|
||||
self.certificates.append(x509.load_der_x509_certificate(crt_str, default_backend()))
|
||||
status("Successfully added 1 certificate")
|
||||
status('Successfully added 1 certificate')
|
||||
|
||||
def create_bundle(self):
|
||||
# Sort certificates in order to do binary search when looking up certificates
|
||||
@@ -162,7 +162,7 @@ class CertificateBundle:
|
||||
for row in csv_reader:
|
||||
filter_set.add(row[1])
|
||||
|
||||
status("Parsing certificates from %s" % crts_path)
|
||||
status('Parsing certificates from %s' % crts_path)
|
||||
crt_str = []
|
||||
with open(crts_path, 'r', encoding='utf-8') as f:
|
||||
crt_str = f.read()
|
||||
@@ -202,14 +202,14 @@ def main():
|
||||
|
||||
for path in args.input:
|
||||
if os.path.isfile(path):
|
||||
if os.path.basename(path) == "cacrt_all.pem" and args.filter:
|
||||
if os.path.basename(path) == 'cacrt_all.pem' and args.filter:
|
||||
bundle.add_with_filter(path, args.filter)
|
||||
else:
|
||||
bundle.add_from_file(path)
|
||||
elif os.path.isdir(path):
|
||||
bundle.add_from_path(path)
|
||||
else:
|
||||
raise InputError("Invalid --input=%s, is neither file nor folder" % args.input)
|
||||
raise InputError('Invalid --input=%s, is neither file nor folder' % args.input)
|
||||
|
||||
status('Successfully added %d certificates in total' % len(bundle.certificates))
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import unittest
|
||||
import sys
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
try:
|
||||
import gen_crt_bundle
|
||||
except ImportError:
|
||||
sys.path.append("..")
|
||||
sys.path.append('..')
|
||||
import gen_crt_bundle
|
||||
|
||||
|
||||
@@ -67,11 +67,11 @@ class GenCrtBundleTests(Py23TestCase):
|
||||
def test_invalid_crt_input(self):
|
||||
bundle = gen_crt_bundle.CertificateBundle()
|
||||
|
||||
with self.assertRaisesRegex(gen_crt_bundle.InputError, "Invalid certificate"):
|
||||
with self.assertRaisesRegex(gen_crt_bundle.InputError, 'Invalid certificate'):
|
||||
bundle.add_from_file(test_crts_path + invalid_test_file)
|
||||
|
||||
with self.assertRaisesRegex(gen_crt_bundle.InputError, "No certificate found"):
|
||||
bundle.add_from_pem("")
|
||||
with self.assertRaisesRegex(gen_crt_bundle.InputError, 'No certificate found'):
|
||||
bundle.add_from_pem('')
|
||||
|
||||
def test_non_ascii_crt_input(self):
|
||||
bundle = gen_crt_bundle.CertificateBundle()
|
||||
@@ -80,5 +80,5 @@ class GenCrtBundleTests(Py23TestCase):
|
||||
self.assertTrue(len(bundle.certificates))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
@@ -1,36 +1,35 @@
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
from builtins import str
|
||||
import re
|
||||
import sys
|
||||
import ssl
|
||||
import paho.mqtt.client as mqtt
|
||||
from threading import Thread, Event
|
||||
import time
|
||||
import string
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import random
|
||||
import re
|
||||
import ssl
|
||||
import string
|
||||
import sys
|
||||
import time
|
||||
from builtins import str
|
||||
from threading import Event, Thread
|
||||
|
||||
from tiny_test_fw import DUT
|
||||
import paho.mqtt.client as mqtt
|
||||
import ttfw_idf
|
||||
|
||||
from tiny_test_fw import DUT
|
||||
|
||||
event_client_connected = Event()
|
||||
event_stop_client = Event()
|
||||
event_client_received_correct = Event()
|
||||
message_log = ""
|
||||
message_log = ''
|
||||
broker_host = {}
|
||||
broker_port = {}
|
||||
expected_data = ""
|
||||
subscribe_topic = ""
|
||||
publish_topic = ""
|
||||
expected_data = ''
|
||||
subscribe_topic = ''
|
||||
publish_topic = ''
|
||||
expected_count = 0
|
||||
|
||||
|
||||
# The callback for when the client receives a CONNACK response from the server.
|
||||
def on_connect(client, userdata, flags, rc):
|
||||
print("Connected with result code " + str(rc))
|
||||
print('Connected with result code ' + str(rc))
|
||||
event_client_connected.set()
|
||||
client.subscribe("/topic/qos0")
|
||||
client.subscribe('/topic/qos0')
|
||||
|
||||
|
||||
def mqtt_client_task(client):
|
||||
@@ -52,8 +51,8 @@ def on_message(client, userdata, msg):
|
||||
payload = msg.payload.decode()
|
||||
if payload == expected_data:
|
||||
expected_count += 1
|
||||
print("[{}] Received...".format(msg.mid))
|
||||
message_log += "Received data:" + msg.topic + " " + payload + "\n"
|
||||
print('[{}] Received...'.format(msg.mid))
|
||||
message_log += 'Received data:' + msg.topic + ' ' + payload + '\n'
|
||||
|
||||
|
||||
def test_single_config(dut, transport, qos, repeat, published, queue=0):
|
||||
@@ -63,49 +62,49 @@ def test_single_config(dut, transport, qos, repeat, published, queue=0):
|
||||
sample_string = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(16))
|
||||
event_client_connected.clear()
|
||||
expected_count = 0
|
||||
message_log = ""
|
||||
message_log = ''
|
||||
expected_data = sample_string * repeat
|
||||
print("PUBLISH TEST: transport:{}, qos:{}, sequence:{}, enqueue:{}, sample msg:'{}'".format(transport, qos, published, queue, expected_data))
|
||||
client = None
|
||||
try:
|
||||
if transport in ["ws", "wss"]:
|
||||
client = mqtt.Client(transport="websockets")
|
||||
if transport in ['ws', 'wss']:
|
||||
client = mqtt.Client(transport='websockets')
|
||||
else:
|
||||
client = mqtt.Client()
|
||||
client.on_connect = on_connect
|
||||
client.on_message = on_message
|
||||
if transport in ["ssl", "wss"]:
|
||||
if transport in ['ssl', 'wss']:
|
||||
client.tls_set(None, None, None, cert_reqs=ssl.CERT_NONE, tls_version=ssl.PROTOCOL_TLSv1_2, ciphers=None)
|
||||
client.tls_insecure_set(True)
|
||||
print("Connecting...")
|
||||
print('Connecting...')
|
||||
client.connect(broker_host[transport], broker_port[transport], 60)
|
||||
except Exception:
|
||||
print("ENV_TEST_FAILURE: Unexpected error while connecting to broker {}: {}:".format(broker_host[transport], sys.exc_info()[0]))
|
||||
print('ENV_TEST_FAILURE: Unexpected error while connecting to broker {}: {}:'.format(broker_host[transport], sys.exc_info()[0]))
|
||||
raise
|
||||
# Starting a py-client in a separate thread
|
||||
thread1 = Thread(target=mqtt_client_task, args=(client,))
|
||||
thread1.start()
|
||||
print("Connecting py-client to broker {}:{}...".format(broker_host[transport], broker_port[transport]))
|
||||
print('Connecting py-client to broker {}:{}...'.format(broker_host[transport], broker_port[transport]))
|
||||
if not event_client_connected.wait(timeout=30):
|
||||
raise ValueError("ENV_TEST_FAILURE: Test script cannot connect to broker: {}".format(broker_host[transport]))
|
||||
raise ValueError('ENV_TEST_FAILURE: Test script cannot connect to broker: {}'.format(broker_host[transport]))
|
||||
client.subscribe(subscribe_topic, qos)
|
||||
dut.write(' '.join(str(x) for x in (transport, sample_string, repeat, published, qos, queue)), eol="\n")
|
||||
dut.write(' '.join(str(x) for x in (transport, sample_string, repeat, published, qos, queue)), eol='\n')
|
||||
try:
|
||||
# waiting till subscribed to defined topic
|
||||
dut.expect(re.compile(r"MQTT_EVENT_SUBSCRIBED"), timeout=30)
|
||||
dut.expect(re.compile(r'MQTT_EVENT_SUBSCRIBED'), timeout=30)
|
||||
for i in range(published):
|
||||
client.publish(publish_topic, sample_string * repeat, qos)
|
||||
print("Publishing...")
|
||||
print("Checking esp-client received msg published from py-client...")
|
||||
dut.expect(re.compile(r"Correct pattern received exactly x times"), timeout=60)
|
||||
print('Publishing...')
|
||||
print('Checking esp-client received msg published from py-client...')
|
||||
dut.expect(re.compile(r'Correct pattern received exactly x times'), timeout=60)
|
||||
start = time.time()
|
||||
while expected_count < published and time.time() - start <= 60:
|
||||
time.sleep(1)
|
||||
# Note: tolerate that messages qos=1 to be received more than once
|
||||
if expected_count == published or (expected_count > published and qos == 1):
|
||||
print("All data received from ESP32...")
|
||||
print('All data received from ESP32...')
|
||||
else:
|
||||
raise ValueError("Not all data received from ESP32: Expected:{}x{}, Received:{}x{}".format(expected_count, published, expected_data, message_log))
|
||||
raise ValueError('Not all data received from ESP32: Expected:{}x{}, Received:{}x{}'.format(expected_count, published, expected_data, message_log))
|
||||
finally:
|
||||
event_stop_client.set()
|
||||
thread1.join()
|
||||
@@ -113,7 +112,7 @@ def test_single_config(dut, transport, qos, repeat, published, queue=0):
|
||||
event_stop_client.clear()
|
||||
|
||||
|
||||
@ttfw_idf.idf_custom_test(env_tag="Example_WIFI")
|
||||
@ttfw_idf.idf_custom_test(env_tag='Example_WIFI')
|
||||
def test_weekend_mqtt_publish(env, extra_data):
|
||||
# Using broker url dictionary for different transport
|
||||
global broker_host
|
||||
@@ -127,28 +126,28 @@ def test_weekend_mqtt_publish(env, extra_data):
|
||||
3. Test evaluates python client received correct qos0 message
|
||||
4. Test ESP32 client received correct qos0 message
|
||||
"""
|
||||
dut1 = env.get_dut("mqtt_publish_connect_test", "tools/test_apps/protocols/mqtt/publish_connect_test")
|
||||
dut1 = env.get_dut('mqtt_publish_connect_test', 'tools/test_apps/protocols/mqtt/publish_connect_test')
|
||||
# Look for host:port in sdkconfig
|
||||
try:
|
||||
# python client subscribes to the topic to which esp client publishes and vice versa
|
||||
publish_topic = dut1.app.get_sdkconfig()["CONFIG_EXAMPLE_SUBSCIBE_TOPIC"].replace('"','')
|
||||
subscribe_topic = dut1.app.get_sdkconfig()["CONFIG_EXAMPLE_PUBLISH_TOPIC"].replace('"','')
|
||||
broker_host["ssl"], broker_port["ssl"] = get_host_port_from_dut(dut1, "CONFIG_EXAMPLE_BROKER_SSL_URI")
|
||||
broker_host["tcp"], broker_port["tcp"] = get_host_port_from_dut(dut1, "CONFIG_EXAMPLE_BROKER_TCP_URI")
|
||||
broker_host["ws"], broker_port["ws"] = get_host_port_from_dut(dut1, "CONFIG_EXAMPLE_BROKER_WS_URI")
|
||||
broker_host["wss"], broker_port["wss"] = get_host_port_from_dut(dut1, "CONFIG_EXAMPLE_BROKER_WSS_URI")
|
||||
publish_topic = dut1.app.get_sdkconfig()['CONFIG_EXAMPLE_SUBSCIBE_TOPIC'].replace('"','')
|
||||
subscribe_topic = dut1.app.get_sdkconfig()['CONFIG_EXAMPLE_PUBLISH_TOPIC'].replace('"','')
|
||||
broker_host['ssl'], broker_port['ssl'] = get_host_port_from_dut(dut1, 'CONFIG_EXAMPLE_BROKER_SSL_URI')
|
||||
broker_host['tcp'], broker_port['tcp'] = get_host_port_from_dut(dut1, 'CONFIG_EXAMPLE_BROKER_TCP_URI')
|
||||
broker_host['ws'], broker_port['ws'] = get_host_port_from_dut(dut1, 'CONFIG_EXAMPLE_BROKER_WS_URI')
|
||||
broker_host['wss'], broker_port['wss'] = get_host_port_from_dut(dut1, 'CONFIG_EXAMPLE_BROKER_WSS_URI')
|
||||
except Exception:
|
||||
print('ENV_TEST_FAILURE: Cannot find broker url in sdkconfig')
|
||||
raise
|
||||
dut1.start_app()
|
||||
try:
|
||||
ip_address = dut1.expect(re.compile(r" IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)"), timeout=30)
|
||||
print("Connected to AP with IP: {}".format(ip_address))
|
||||
ip_address = dut1.expect(re.compile(r' IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'), timeout=30)
|
||||
print('Connected to AP with IP: {}'.format(ip_address))
|
||||
except DUT.ExpectTimeout:
|
||||
print('ENV_TEST_FAILURE: Cannot connect to AP')
|
||||
raise
|
||||
for qos in [0, 1, 2]:
|
||||
for transport in ["tcp", "ssl", "ws", "wss"]:
|
||||
for transport in ['tcp', 'ssl', 'ws', 'wss']:
|
||||
for q in [0, 1]:
|
||||
if broker_host[transport] is None:
|
||||
print('Skipping transport: {}...'.format(transport))
|
||||
@@ -156,14 +155,14 @@ def test_weekend_mqtt_publish(env, extra_data):
|
||||
# simple test with empty message
|
||||
test_single_config(dut1, transport, qos, 0, 5, q)
|
||||
# decide on broker what level of test will pass (local broker works the best)
|
||||
if broker_host[transport].startswith("192.168") and qos > 0 and q == 0:
|
||||
if broker_host[transport].startswith('192.168') and qos > 0 and q == 0:
|
||||
# medium size, medium repeated
|
||||
test_single_config(dut1, transport, qos, 5, 50, q)
|
||||
# long data
|
||||
test_single_config(dut1, transport, qos, 1000, 10, q)
|
||||
# short data, many repeats
|
||||
test_single_config(dut1, transport, qos, 2, 200, q)
|
||||
elif transport in ["ws", "wss"]:
|
||||
elif transport in ['ws', 'wss']:
|
||||
# more relaxed criteria for websockets!
|
||||
test_single_config(dut1, transport, qos, 2, 5, q)
|
||||
test_single_config(dut1, transport, qos, 50, 1, q)
|
||||
|
||||
@@ -19,40 +19,42 @@
|
||||
#
|
||||
|
||||
from __future__ import division, print_function
|
||||
from future.moves.itertools import zip_longest
|
||||
from builtins import int, range, bytes
|
||||
from io import open
|
||||
import sys
|
||||
|
||||
import argparse
|
||||
import binascii
|
||||
import random
|
||||
import struct
|
||||
import os
|
||||
import array
|
||||
import zlib
|
||||
import binascii
|
||||
import codecs
|
||||
import datetime
|
||||
import distutils.dir_util
|
||||
import os
|
||||
import random
|
||||
import struct
|
||||
import sys
|
||||
import zlib
|
||||
from builtins import bytes, int, range
|
||||
from io import open
|
||||
|
||||
from future.moves.itertools import zip_longest
|
||||
|
||||
try:
|
||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||
except ImportError:
|
||||
print('The cryptography package is not installed.'
|
||||
'Please refer to the Get Started section of the ESP-IDF Programming Guide for '
|
||||
'setting up the required packages.')
|
||||
raise
|
||||
|
||||
VERSION1_PRINT = "V1 - Multipage Blob Support Disabled"
|
||||
VERSION2_PRINT = "V2 - Multipage Blob Support Enabled"
|
||||
VERSION1_PRINT = 'V1 - Multipage Blob Support Disabled'
|
||||
VERSION2_PRINT = 'V2 - Multipage Blob Support Enabled'
|
||||
|
||||
|
||||
def reverse_hexbytes(addr_tmp):
|
||||
addr = []
|
||||
reversed_bytes = ""
|
||||
reversed_bytes = ''
|
||||
for i in range(0, len(addr_tmp), 2):
|
||||
addr.append(addr_tmp[i:i + 2])
|
||||
reversed_bytes = "".join(reversed(addr))
|
||||
reversed_bytes = ''.join(reversed(addr))
|
||||
|
||||
return reversed_bytes
|
||||
|
||||
@@ -62,10 +64,10 @@ def reverse_hexbytes(addr_tmp):
|
||||
|
||||
class Page(object):
|
||||
PAGE_PARAMS = {
|
||||
"max_size": 4096,
|
||||
"max_old_blob_size": 1984,
|
||||
"max_new_blob_size": 4000,
|
||||
"max_entries": 126
|
||||
'max_size': 4096,
|
||||
'max_old_blob_size': 1984,
|
||||
'max_new_blob_size': 4000,
|
||||
'max_entries': 126
|
||||
}
|
||||
|
||||
# Item type codes
|
||||
@@ -98,7 +100,7 @@ class Page(object):
|
||||
self.entry_num = 0
|
||||
self.bitmap_array = array.array('B')
|
||||
self.version = version
|
||||
self.page_buf = bytearray(b'\xff') * Page.PAGE_PARAMS["max_size"]
|
||||
self.page_buf = bytearray(b'\xff') * Page.PAGE_PARAMS['max_size']
|
||||
if not is_rsrv_page:
|
||||
self.bitmap_array = self.create_bitmap_array()
|
||||
self.set_header(page_num, version)
|
||||
@@ -167,7 +169,7 @@ class Page(object):
|
||||
else:
|
||||
encr_key_input = codecs.decode(nvs_obj.encr_key, 'hex')
|
||||
|
||||
rel_addr = nvs_obj.page_num * Page.PAGE_PARAMS["max_size"] + Page.FIRST_ENTRY_OFFSET
|
||||
rel_addr = nvs_obj.page_num * Page.PAGE_PARAMS['max_size'] + Page.FIRST_ENTRY_OFFSET
|
||||
|
||||
if not isinstance(data_input, bytearray):
|
||||
byte_arr = bytearray(b'\xff') * 32
|
||||
@@ -249,8 +251,8 @@ class Page(object):
|
||||
chunk_size = 0
|
||||
|
||||
# Get the size available in current page
|
||||
tailroom = (Page.PAGE_PARAMS["max_entries"] - self.entry_num - 1) * Page.SINGLE_ENTRY_SIZE
|
||||
assert tailroom >= 0, "Page overflow!!"
|
||||
tailroom = (Page.PAGE_PARAMS['max_entries'] - self.entry_num - 1) * Page.SINGLE_ENTRY_SIZE
|
||||
assert tailroom >= 0, 'Page overflow!!'
|
||||
|
||||
# Split the binary data into two and store a chunk of available size onto curr page
|
||||
if tailroom < remaining_size:
|
||||
@@ -358,14 +360,14 @@ class Page(object):
|
||||
# Set size of data
|
||||
datalen = len(data)
|
||||
|
||||
if datalen > Page.PAGE_PARAMS["max_old_blob_size"]:
|
||||
if datalen > Page.PAGE_PARAMS['max_old_blob_size']:
|
||||
if self.version == Page.VERSION1:
|
||||
raise InputError(" Input File: Size (%d) exceeds max allowed length `%s` bytes for key `%s`."
|
||||
% (datalen, Page.PAGE_PARAMS["max_old_blob_size"], key))
|
||||
raise InputError(' Input File: Size (%d) exceeds max allowed length `%s` bytes for key `%s`.'
|
||||
% (datalen, Page.PAGE_PARAMS['max_old_blob_size'], key))
|
||||
else:
|
||||
if encoding == "string":
|
||||
raise InputError(" Input File: Size (%d) exceeds max allowed length `%s` bytes for key `%s`."
|
||||
% (datalen, Page.PAGE_PARAMS["max_old_blob_size"], key))
|
||||
if encoding == 'string':
|
||||
raise InputError(' Input File: Size (%d) exceeds max allowed length `%s` bytes for key `%s`.'
|
||||
% (datalen, Page.PAGE_PARAMS['max_old_blob_size'], key))
|
||||
|
||||
# Calculate no. of entries data will require
|
||||
rounded_size = (datalen + 31) & ~31
|
||||
@@ -373,10 +375,10 @@ class Page(object):
|
||||
total_entry_count = data_entry_count + 1 # +1 for the entry header
|
||||
|
||||
# Check if page is already full and new page is needed to be created right away
|
||||
if self.entry_num >= Page.PAGE_PARAMS["max_entries"]:
|
||||
if self.entry_num >= Page.PAGE_PARAMS['max_entries']:
|
||||
raise PageFullError()
|
||||
elif (self.entry_num + total_entry_count) >= Page.PAGE_PARAMS["max_entries"]:
|
||||
if not (self.version == Page.VERSION2 and encoding in ["hex2bin", "binary", "base64"]):
|
||||
elif (self.entry_num + total_entry_count) >= Page.PAGE_PARAMS['max_entries']:
|
||||
if not (self.version == Page.VERSION2 and encoding in ['hex2bin', 'binary', 'base64']):
|
||||
raise PageFullError()
|
||||
|
||||
# Entry header
|
||||
@@ -385,7 +387,7 @@ class Page(object):
|
||||
entry_struct[0] = ns_index
|
||||
# Set Span
|
||||
if self.version == Page.VERSION2:
|
||||
if encoding == "string":
|
||||
if encoding == 'string':
|
||||
entry_struct[2] = data_entry_count + 1
|
||||
# Set Chunk Index
|
||||
chunk_index = Page.CHUNK_ANY
|
||||
@@ -399,12 +401,12 @@ class Page(object):
|
||||
entry_struct[8:8 + len(key)] = key.encode()
|
||||
|
||||
# set Type
|
||||
if encoding == "string":
|
||||
if encoding == 'string':
|
||||
entry_struct[1] = Page.SZ
|
||||
elif encoding in ["hex2bin", "binary", "base64"]:
|
||||
elif encoding in ['hex2bin', 'binary', 'base64']:
|
||||
entry_struct[1] = Page.BLOB
|
||||
|
||||
if self.version == Page.VERSION2 and (encoding in ["hex2bin", "binary", "base64"]):
|
||||
if self.version == Page.VERSION2 and (encoding in ['hex2bin', 'binary', 'base64']):
|
||||
entry_struct = self.write_varlen_binary_data(entry_struct,ns_index,key,data,
|
||||
datalen,total_entry_count, encoding, nvs_obj)
|
||||
else:
|
||||
@@ -413,7 +415,7 @@ class Page(object):
|
||||
""" Low-level function to write data of primitive type into page buffer. """
|
||||
def write_primitive_data(self, key, data, encoding, ns_index,nvs_obj):
|
||||
# Check if entry exceeds max number of entries allowed per page
|
||||
if self.entry_num >= Page.PAGE_PARAMS["max_entries"]:
|
||||
if self.entry_num >= Page.PAGE_PARAMS['max_entries']:
|
||||
raise PageFullError()
|
||||
|
||||
entry_struct = bytearray(b'\xff') * 32
|
||||
@@ -427,28 +429,28 @@ class Page(object):
|
||||
entry_struct[8:24] = key_array
|
||||
entry_struct[8:8 + len(key)] = key.encode()
|
||||
|
||||
if encoding == "u8":
|
||||
if encoding == 'u8':
|
||||
entry_struct[1] = Page.U8
|
||||
struct.pack_into('<B', entry_struct, 24, data)
|
||||
elif encoding == "i8":
|
||||
elif encoding == 'i8':
|
||||
entry_struct[1] = Page.I8
|
||||
struct.pack_into('<b', entry_struct, 24, data)
|
||||
elif encoding == "u16":
|
||||
elif encoding == 'u16':
|
||||
entry_struct[1] = Page.U16
|
||||
struct.pack_into('<H', entry_struct, 24, data)
|
||||
elif encoding == "i16":
|
||||
elif encoding == 'i16':
|
||||
entry_struct[1] = Page.I16
|
||||
struct.pack_into('<h', entry_struct, 24, data)
|
||||
elif encoding == "u32":
|
||||
elif encoding == 'u32':
|
||||
entry_struct[1] = Page.U32
|
||||
struct.pack_into('<I', entry_struct, 24, data)
|
||||
elif encoding == "i32":
|
||||
elif encoding == 'i32':
|
||||
entry_struct[1] = Page.I32
|
||||
struct.pack_into('<i', entry_struct, 24, data)
|
||||
elif encoding == "u64":
|
||||
elif encoding == 'u64':
|
||||
entry_struct[1] = Page.U64
|
||||
struct.pack_into('<Q', entry_struct, 24, data)
|
||||
elif encoding == "i64":
|
||||
elif encoding == 'i64':
|
||||
entry_struct[1] = Page.I64
|
||||
struct.pack_into('<q', entry_struct, 24, data)
|
||||
|
||||
@@ -516,9 +518,9 @@ class NVS(object):
|
||||
version = self.version
|
||||
# Update available size as each page is created
|
||||
if self.size == 0:
|
||||
raise InsufficientSizeError("Error: Size parameter is less than the size of data in csv.Please increase size.")
|
||||
raise InsufficientSizeError('Error: Size parameter is less than the size of data in csv.Please increase size.')
|
||||
if not is_rsrv_page:
|
||||
self.size = self.size - Page.PAGE_PARAMS["max_size"]
|
||||
self.size = self.size - Page.PAGE_PARAMS['max_size']
|
||||
self.page_num += 1
|
||||
# Set version for each page and page header
|
||||
new_page = Page(self.page_num, version, is_rsrv_page)
|
||||
@@ -533,10 +535,10 @@ class NVS(object):
|
||||
def write_namespace(self, key):
|
||||
self.namespace_idx += 1
|
||||
try:
|
||||
self.cur_page.write_primitive_data(key, self.namespace_idx, "u8", 0,self)
|
||||
self.cur_page.write_primitive_data(key, self.namespace_idx, 'u8', 0,self)
|
||||
except PageFullError:
|
||||
new_page = self.create_new_page()
|
||||
new_page.write_primitive_data(key, self.namespace_idx, "u8", 0,self)
|
||||
new_page.write_primitive_data(key, self.namespace_idx, 'u8', 0,self)
|
||||
|
||||
"""
|
||||
Write key-value pair. Function accepts value in the form of ascii character and converts
|
||||
@@ -545,23 +547,23 @@ class NVS(object):
|
||||
We don't have to guard re-invocation with try-except since no entry can span multiple pages.
|
||||
"""
|
||||
def write_entry(self, key, value, encoding):
|
||||
if encoding == "hex2bin":
|
||||
if encoding == 'hex2bin':
|
||||
value = value.strip()
|
||||
if len(value) % 2 != 0:
|
||||
raise InputError("%s: Invalid data length. Should be multiple of 2." % key)
|
||||
raise InputError('%s: Invalid data length. Should be multiple of 2.' % key)
|
||||
value = binascii.a2b_hex(value)
|
||||
|
||||
if encoding == "base64":
|
||||
if encoding == 'base64':
|
||||
value = binascii.a2b_base64(value)
|
||||
|
||||
if encoding == "string":
|
||||
if encoding == 'string':
|
||||
if type(value) == bytes:
|
||||
value = value.decode()
|
||||
value += '\0'
|
||||
|
||||
encoding = encoding.lower()
|
||||
varlen_encodings = ["string", "binary", "hex2bin", "base64"]
|
||||
primitive_encodings = ["u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64"]
|
||||
varlen_encodings = ['string', 'binary', 'hex2bin', 'base64']
|
||||
primitive_encodings = ['u8', 'i8', 'u16', 'i16', 'u32', 'i32', 'u64', 'i64']
|
||||
|
||||
if encoding in varlen_encodings:
|
||||
try:
|
||||
@@ -576,7 +578,7 @@ class NVS(object):
|
||||
new_page = self.create_new_page()
|
||||
new_page.write_primitive_data(key, int(value), encoding, self.namespace_idx,self)
|
||||
else:
|
||||
raise InputError("%s: Unsupported encoding" % encoding)
|
||||
raise InputError('%s: Unsupported encoding' % encoding)
|
||||
|
||||
""" Return accumulated data of all pages """
|
||||
def get_binary_data(self):
|
||||
@@ -600,7 +602,7 @@ class InputError(RuntimeError):
|
||||
Represents error on the input
|
||||
"""
|
||||
def __init__(self, e):
|
||||
print("\nError:")
|
||||
print('\nError:')
|
||||
super(InputError, self).__init__(e)
|
||||
|
||||
|
||||
@@ -634,7 +636,7 @@ def write_entry(nvs_instance, key, datatype, encoding, value):
|
||||
:return: None
|
||||
"""
|
||||
|
||||
if datatype == "file":
|
||||
if datatype == 'file':
|
||||
abs_file_path = value
|
||||
if os.path.isabs(value) is False:
|
||||
script_dir = os.getcwd()
|
||||
@@ -643,7 +645,7 @@ def write_entry(nvs_instance, key, datatype, encoding, value):
|
||||
with open(abs_file_path, 'rb') as f:
|
||||
value = f.read()
|
||||
|
||||
if datatype == "namespace":
|
||||
if datatype == 'namespace':
|
||||
nvs_instance.write_namespace(key)
|
||||
else:
|
||||
nvs_instance.write_entry(key, value, encoding)
|
||||
@@ -667,13 +669,13 @@ def check_size(size):
|
||||
# Set size
|
||||
input_size = int(size, 0)
|
||||
if input_size % 4096 != 0:
|
||||
sys.exit("Size of partition must be multiple of 4096")
|
||||
sys.exit('Size of partition must be multiple of 4096')
|
||||
|
||||
# Update size as a page needs to be reserved of size 4KB
|
||||
input_size = input_size - Page.PAGE_PARAMS["max_size"]
|
||||
input_size = input_size - Page.PAGE_PARAMS['max_size']
|
||||
|
||||
if input_size < (2 * Page.PAGE_PARAMS["max_size"]):
|
||||
sys.exit("Minimum NVS partition size needed is 0x3000 bytes.")
|
||||
if input_size < (2 * Page.PAGE_PARAMS['max_size']):
|
||||
sys.exit('Minimum NVS partition size needed is 0x3000 bytes.')
|
||||
return input_size
|
||||
except Exception as e:
|
||||
print(e)
|
||||
@@ -708,7 +710,7 @@ def set_target_filepath(outdir, filepath):
|
||||
|
||||
if os.path.isabs(filepath):
|
||||
if not outdir == os.getcwd():
|
||||
print("\nWarning: `%s` \n\t==> absolute path given so outdir is ignored for this file." % filepath)
|
||||
print('\nWarning: `%s` \n\t==> absolute path given so outdir is ignored for this file.' % filepath)
|
||||
# Set to empty as outdir is ignored here
|
||||
outdir = ''
|
||||
|
||||
@@ -728,11 +730,11 @@ def encrypt(args):
|
||||
|
||||
check_size(args.size)
|
||||
if (args.keygen is False) and (not args.inputkey):
|
||||
sys.exit("Error. --keygen or --inputkey argument needed.")
|
||||
sys.exit('Error. --keygen or --inputkey argument needed.')
|
||||
elif args.keygen and args.inputkey:
|
||||
sys.exit("Error. --keygen and --inputkey both are not allowed.")
|
||||
sys.exit('Error. --keygen and --inputkey both are not allowed.')
|
||||
elif not args.keygen and args.keyfile:
|
||||
print("\nWarning:","--inputkey argument is given. --keyfile argument will be ignored...")
|
||||
print('\nWarning:','--inputkey argument is given. --keyfile argument will be ignored...')
|
||||
|
||||
if args.inputkey:
|
||||
# Check if key file has .bin extension
|
||||
@@ -835,7 +837,7 @@ def decrypt(args):
|
||||
start_entry_offset += nvs_read_bytes
|
||||
output_file.write(output_buf)
|
||||
|
||||
print("\nCreated NVS decrypted binary: ===>", args.output)
|
||||
print('\nCreated NVS decrypted binary: ===>', args.output)
|
||||
|
||||
|
||||
def generate_key(args):
|
||||
@@ -850,7 +852,7 @@ def generate_key(args):
|
||||
|
||||
if not args.keyfile:
|
||||
timestamp = datetime.datetime.now().strftime('%m-%d_%H-%M')
|
||||
args.keyfile = "keys-" + timestamp + bin_ext
|
||||
args.keyfile = 'keys-' + timestamp + bin_ext
|
||||
|
||||
keys_outdir = os.path.join(args.outdir,keys_dir, '')
|
||||
# Create keys/ dir in <outdir> if does not exist
|
||||
@@ -872,7 +874,7 @@ def generate_key(args):
|
||||
with open(output_keyfile, 'wb') as output_keys_file:
|
||||
output_keys_file.write(keys_buf)
|
||||
|
||||
print("\nCreated encryption keys: ===> ", output_keyfile)
|
||||
print('\nCreated encryption keys: ===> ', output_keyfile)
|
||||
|
||||
return key
|
||||
|
||||
@@ -914,7 +916,7 @@ def generate(args, is_encr_enabled=False, encr_key=None):
|
||||
else:
|
||||
version_set = VERSION2_PRINT
|
||||
|
||||
print("\nCreating NVS binary with version:", version_set)
|
||||
print('\nCreating NVS binary with version:', version_set)
|
||||
|
||||
line = input_file.readline().strip()
|
||||
|
||||
@@ -939,25 +941,25 @@ def generate(args, is_encr_enabled=False, encr_key=None):
|
||||
|
||||
try:
|
||||
# Check key length
|
||||
if len(data["key"]) > 15:
|
||||
raise InputError("Length of key `{}` should be <= 15 characters.".format(data["key"]))
|
||||
write_entry(nvs_obj, data["key"], data["type"], data["encoding"], data["value"])
|
||||
if len(data['key']) > 15:
|
||||
raise InputError('Length of key `{}` should be <= 15 characters.'.format(data['key']))
|
||||
write_entry(nvs_obj, data['key'], data['type'], data['encoding'], data['value'])
|
||||
except InputError as e:
|
||||
print(e)
|
||||
filedir, filename = os.path.split(args.output)
|
||||
if filename:
|
||||
print("\nWarning: NVS binary not created...")
|
||||
print('\nWarning: NVS binary not created...')
|
||||
os.remove(args.output)
|
||||
if is_dir_new and not filedir == os.getcwd():
|
||||
print("\nWarning: Output dir not created...")
|
||||
print('\nWarning: Output dir not created...')
|
||||
os.rmdir(filedir)
|
||||
sys.exit(-2)
|
||||
|
||||
print("\nCreated NVS binary: ===>", args.output)
|
||||
print('\nCreated NVS binary: ===>', args.output)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="\nESP NVS partition generation utility", formatter_class=argparse.RawTextHelpFormatter)
|
||||
parser = argparse.ArgumentParser(description='\nESP NVS partition generation utility', formatter_class=argparse.RawTextHelpFormatter)
|
||||
subparser = parser.add_subparsers(title='Commands',
|
||||
dest='command',
|
||||
help='\nRun nvs_partition_gen.py {command} -h for additional help\n\n')
|
||||
@@ -1022,7 +1024,7 @@ def main():
|
||||
\nVersion 2 - Multipage blob support enabled.\
|
||||
\nDefault: Version 2''')
|
||||
parser_encr.add_argument('--keygen',
|
||||
action="store_true",
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='Generates key for encrypting NVS partition')
|
||||
parser_encr.add_argument('--keyfile',
|
||||
@@ -1057,5 +1059,5 @@ def main():
|
||||
args.func(args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from __future__ import print_function, division
|
||||
from __future__ import unicode_literals
|
||||
from __future__ import division, print_function, unicode_literals
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
@@ -28,7 +28,7 @@ quiet = False
|
||||
|
||||
|
||||
def generate_blanked_file(size, output_path):
|
||||
output = b"\xFF" * size
|
||||
output = b'\xFF' * size
|
||||
try:
|
||||
stdout_binary = sys.stdout.buffer # Python 3
|
||||
except AttributeError:
|
||||
|
||||
@@ -20,19 +20,19 @@
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from __future__ import print_function, division
|
||||
from __future__ import unicode_literals
|
||||
from __future__ import division, print_function, unicode_literals
|
||||
|
||||
import argparse
|
||||
import binascii
|
||||
import errno
|
||||
import hashlib
|
||||
import os
|
||||
import re
|
||||
import struct
|
||||
import sys
|
||||
import hashlib
|
||||
import binascii
|
||||
import errno
|
||||
|
||||
MAX_PARTITION_LENGTH = 0xC00 # 3K for partition data (96 entries) leaves 1K in a 4K sector for signature
|
||||
MD5_PARTITION_BEGIN = b"\xEB\xEB" + b"\xFF" * 14 # The first 2 bytes are like magic numbers for MD5 sum
|
||||
MD5_PARTITION_BEGIN = b'\xEB\xEB' + b'\xFF' * 14 # The first 2 bytes are like magic numbers for MD5 sum
|
||||
PARTITION_TABLE_SIZE = 0x1000 # Size of partition table
|
||||
|
||||
MIN_PARTITION_SUBTYPE_APP_OTA = 0x10
|
||||
@@ -44,26 +44,26 @@ APP_TYPE = 0x00
|
||||
DATA_TYPE = 0x01
|
||||
|
||||
TYPES = {
|
||||
"app": APP_TYPE,
|
||||
"data": DATA_TYPE,
|
||||
'app': APP_TYPE,
|
||||
'data': DATA_TYPE,
|
||||
}
|
||||
|
||||
# Keep this map in sync with esp_partition_subtype_t enum in esp_partition.h
|
||||
SUBTYPES = {
|
||||
APP_TYPE: {
|
||||
"factory": 0x00,
|
||||
"test": 0x20,
|
||||
'factory': 0x00,
|
||||
'test': 0x20,
|
||||
},
|
||||
DATA_TYPE: {
|
||||
"ota": 0x00,
|
||||
"phy": 0x01,
|
||||
"nvs": 0x02,
|
||||
"coredump": 0x03,
|
||||
"nvs_keys": 0x04,
|
||||
"efuse": 0x05,
|
||||
"esphttpd": 0x80,
|
||||
"fat": 0x81,
|
||||
"spiffs": 0x82,
|
||||
'ota': 0x00,
|
||||
'phy': 0x01,
|
||||
'nvs': 0x02,
|
||||
'coredump': 0x03,
|
||||
'nvs_keys': 0x04,
|
||||
'efuse': 0x05,
|
||||
'esphttpd': 0x80,
|
||||
'fat': 0x81,
|
||||
'spiffs': 0x82,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -103,14 +103,14 @@ class PartitionTable(list):
|
||||
|
||||
for line_no in range(len(lines)):
|
||||
line = expand_vars(lines[line_no]).strip()
|
||||
if line.startswith("#") or len(line) == 0:
|
||||
if line.startswith('#') or len(line) == 0:
|
||||
continue
|
||||
try:
|
||||
res.append(PartitionDefinition.from_csv(line, line_no + 1))
|
||||
except InputError as e:
|
||||
raise InputError("Error at line %d: %s" % (line_no + 1, e))
|
||||
raise InputError('Error at line %d: %s' % (line_no + 1, e))
|
||||
except Exception:
|
||||
critical("Unexpected error parsing CSV line %d: %s" % (line_no + 1, line))
|
||||
critical('Unexpected error parsing CSV line %d: %s' % (line_no + 1, line))
|
||||
raise
|
||||
|
||||
# fix up missing offsets & negative sizes
|
||||
@@ -118,10 +118,10 @@ class PartitionTable(list):
|
||||
for e in res:
|
||||
if e.offset is not None and e.offset < last_end:
|
||||
if e == res[0]:
|
||||
raise InputError("CSV Error: First partition offset 0x%x overlaps end of partition table 0x%x"
|
||||
raise InputError('CSV Error: First partition offset 0x%x overlaps end of partition table 0x%x'
|
||||
% (e.offset, last_end))
|
||||
else:
|
||||
raise InputError("CSV Error: Partitions overlap. Partition at line %d sets offset 0x%x. Previous partition ends 0x%x"
|
||||
raise InputError('CSV Error: Partitions overlap. Partition at line %d sets offset 0x%x. Previous partition ends 0x%x'
|
||||
% (e.line_no, e.offset, last_end))
|
||||
if e.offset is None:
|
||||
pad_to = 0x10000 if e.type == APP_TYPE else 4
|
||||
@@ -186,19 +186,19 @@ class PartitionTable(list):
|
||||
|
||||
# print sorted duplicate partitions by name
|
||||
if len(duplicates) != 0:
|
||||
print("A list of partitions that have the same name:")
|
||||
print('A list of partitions that have the same name:')
|
||||
for p in sorted(self, key=lambda x:x.name):
|
||||
if len(duplicates.intersection([p.name])) != 0:
|
||||
print("%s" % (p.to_csv()))
|
||||
raise InputError("Partition names must be unique")
|
||||
print('%s' % (p.to_csv()))
|
||||
raise InputError('Partition names must be unique')
|
||||
|
||||
# check for overlaps
|
||||
last = None
|
||||
for p in sorted(self, key=lambda x:x.offset):
|
||||
if p.offset < offset_part_table + PARTITION_TABLE_SIZE:
|
||||
raise InputError("Partition offset 0x%x is below 0x%x" % (p.offset, offset_part_table + PARTITION_TABLE_SIZE))
|
||||
raise InputError('Partition offset 0x%x is below 0x%x' % (p.offset, offset_part_table + PARTITION_TABLE_SIZE))
|
||||
if last is not None and p.offset < last.offset + last.size:
|
||||
raise InputError("Partition at 0x%x overlaps 0x%x-0x%x" % (p.offset, last.offset, last.offset + last.size - 1))
|
||||
raise InputError('Partition at 0x%x overlaps 0x%x-0x%x' % (p.offset, last.offset, last.offset + last.size - 1))
|
||||
last = p
|
||||
|
||||
def flash_size(self):
|
||||
@@ -218,7 +218,7 @@ class PartitionTable(list):
|
||||
for o in range(0,len(b),32):
|
||||
data = b[o:o + 32]
|
||||
if len(data) != 32:
|
||||
raise InputError("Partition table length must be a multiple of 32 bytes")
|
||||
raise InputError('Partition table length must be a multiple of 32 bytes')
|
||||
if data == b'\xFF' * 32:
|
||||
return result # got end marker
|
||||
if md5sum and data[:2] == MD5_PARTITION_BEGIN[:2]: # check only the magic number part
|
||||
@@ -229,26 +229,26 @@ class PartitionTable(list):
|
||||
else:
|
||||
md5.update(data)
|
||||
result.append(PartitionDefinition.from_binary(data))
|
||||
raise InputError("Partition table is missing an end-of-table marker")
|
||||
raise InputError('Partition table is missing an end-of-table marker')
|
||||
|
||||
def to_binary(self):
|
||||
result = b"".join(e.to_binary() for e in self)
|
||||
result = b''.join(e.to_binary() for e in self)
|
||||
if md5sum:
|
||||
result += MD5_PARTITION_BEGIN + hashlib.md5(result).digest()
|
||||
if len(result) >= MAX_PARTITION_LENGTH:
|
||||
raise InputError("Binary partition table length (%d) longer than max" % len(result))
|
||||
result += b"\xFF" * (MAX_PARTITION_LENGTH - len(result)) # pad the sector, for signing
|
||||
raise InputError('Binary partition table length (%d) longer than max' % len(result))
|
||||
result += b'\xFF' * (MAX_PARTITION_LENGTH - len(result)) # pad the sector, for signing
|
||||
return result
|
||||
|
||||
def to_csv(self, simple_formatting=False):
|
||||
rows = ["# ESP-IDF Partition Table",
|
||||
"# Name, Type, SubType, Offset, Size, Flags"]
|
||||
rows = ['# ESP-IDF Partition Table',
|
||||
'# Name, Type, SubType, Offset, Size, Flags']
|
||||
rows += [x.to_csv(simple_formatting) for x in self]
|
||||
return "\n".join(rows) + "\n"
|
||||
return '\n'.join(rows) + '\n'
|
||||
|
||||
|
||||
class PartitionDefinition(object):
|
||||
MAGIC_BYTES = b"\xAA\x50"
|
||||
MAGIC_BYTES = b'\xAA\x50'
|
||||
|
||||
ALIGNMENT = {
|
||||
APP_TYPE: 0x10000,
|
||||
@@ -258,15 +258,15 @@ class PartitionDefinition(object):
|
||||
# dictionary maps flag name (as used in CSV flags list, property name)
|
||||
# to bit set in flags words in binary format
|
||||
FLAGS = {
|
||||
"encrypted": 0
|
||||
'encrypted': 0
|
||||
}
|
||||
|
||||
# add subtypes for the 16 OTA slot values ("ota_XX, etc.")
|
||||
for ota_slot in range(NUM_PARTITION_SUBTYPE_APP_OTA):
|
||||
SUBTYPES[TYPES["app"]]["ota_%d" % ota_slot] = MIN_PARTITION_SUBTYPE_APP_OTA + ota_slot
|
||||
SUBTYPES[TYPES['app']]['ota_%d' % ota_slot] = MIN_PARTITION_SUBTYPE_APP_OTA + ota_slot
|
||||
|
||||
def __init__(self):
|
||||
self.name = ""
|
||||
self.name = ''
|
||||
self.type = None
|
||||
self.subtype = None
|
||||
self.offset = None
|
||||
@@ -276,8 +276,8 @@ class PartitionDefinition(object):
|
||||
@classmethod
|
||||
def from_csv(cls, line, line_no):
|
||||
""" Parse a line from the CSV """
|
||||
line_w_defaults = line + ",,,," # lazy way to support default fields
|
||||
fields = [f.strip() for f in line_w_defaults.split(",")]
|
||||
line_w_defaults = line + ',,,,' # lazy way to support default fields
|
||||
fields = [f.strip() for f in line_w_defaults.split(',')]
|
||||
|
||||
res = PartitionDefinition()
|
||||
res.line_no = line_no
|
||||
@@ -289,7 +289,7 @@ class PartitionDefinition(object):
|
||||
if res.size is None:
|
||||
raise InputError("Size field can't be empty")
|
||||
|
||||
flags = fields[5].split(":")
|
||||
flags = fields[5].split(':')
|
||||
for flag in flags:
|
||||
if flag in cls.FLAGS:
|
||||
setattr(res, flag, True)
|
||||
@@ -305,7 +305,7 @@ class PartitionDefinition(object):
|
||||
|
||||
def __repr__(self):
|
||||
def maybe_hex(x):
|
||||
return "0x%x" % x if x is not None else "None"
|
||||
return '0x%x' % x if x is not None else 'None'
|
||||
return "PartitionDefinition('%s', 0x%x, 0x%x, %s, %s)" % (self.name, self.type, self.subtype or 0,
|
||||
maybe_hex(self.offset), maybe_hex(self.size))
|
||||
|
||||
@@ -328,65 +328,65 @@ class PartitionDefinition(object):
|
||||
return self.offset >= other.offset
|
||||
|
||||
def parse_type(self, strval):
|
||||
if strval == "":
|
||||
if strval == '':
|
||||
raise InputError("Field 'type' can't be left empty.")
|
||||
return parse_int(strval, TYPES)
|
||||
|
||||
def parse_subtype(self, strval):
|
||||
if strval == "":
|
||||
if strval == '':
|
||||
return 0 # default
|
||||
return parse_int(strval, SUBTYPES.get(self.type, {}))
|
||||
|
||||
def parse_address(self, strval):
|
||||
if strval == "":
|
||||
if strval == '':
|
||||
return None # PartitionTable will fill in default
|
||||
return parse_int(strval)
|
||||
|
||||
def verify(self):
|
||||
if self.type is None:
|
||||
raise ValidationError(self, "Type field is not set")
|
||||
raise ValidationError(self, 'Type field is not set')
|
||||
if self.subtype is None:
|
||||
raise ValidationError(self, "Subtype field is not set")
|
||||
raise ValidationError(self, 'Subtype field is not set')
|
||||
if self.offset is None:
|
||||
raise ValidationError(self, "Offset field is not set")
|
||||
raise ValidationError(self, 'Offset field is not set')
|
||||
align = self.ALIGNMENT.get(self.type, 4)
|
||||
if self.offset % align:
|
||||
raise ValidationError(self, "Offset 0x%x is not aligned to 0x%x" % (self.offset, align))
|
||||
raise ValidationError(self, 'Offset 0x%x is not aligned to 0x%x' % (self.offset, align))
|
||||
if self.size % align and secure:
|
||||
raise ValidationError(self, "Size 0x%x is not aligned to 0x%x" % (self.size, align))
|
||||
raise ValidationError(self, 'Size 0x%x is not aligned to 0x%x' % (self.size, align))
|
||||
if self.size is None:
|
||||
raise ValidationError(self, "Size field is not set")
|
||||
raise ValidationError(self, 'Size field is not set')
|
||||
|
||||
if self.name in TYPES and TYPES.get(self.name, "") != self.type:
|
||||
if self.name in TYPES and TYPES.get(self.name, '') != self.type:
|
||||
critical("WARNING: Partition has name '%s' which is a partition type, but does not match this partition's "
|
||||
"type (0x%x). Mistake in partition table?" % (self.name, self.type))
|
||||
'type (0x%x). Mistake in partition table?' % (self.name, self.type))
|
||||
all_subtype_names = []
|
||||
for names in (t.keys() for t in SUBTYPES.values()):
|
||||
all_subtype_names += names
|
||||
if self.name in all_subtype_names and SUBTYPES.get(self.type, {}).get(self.name, "") != self.subtype:
|
||||
if self.name in all_subtype_names and SUBTYPES.get(self.type, {}).get(self.name, '') != self.subtype:
|
||||
critical("WARNING: Partition has name '%s' which is a partition subtype, but this partition has "
|
||||
"non-matching type 0x%x and subtype 0x%x. Mistake in partition table?" % (self.name, self.type, self.subtype))
|
||||
'non-matching type 0x%x and subtype 0x%x. Mistake in partition table?' % (self.name, self.type, self.subtype))
|
||||
|
||||
STRUCT_FORMAT = b"<2sBBLL16sL"
|
||||
STRUCT_FORMAT = b'<2sBBLL16sL'
|
||||
|
||||
@classmethod
|
||||
def from_binary(cls, b):
|
||||
if len(b) != 32:
|
||||
raise InputError("Partition definition length must be exactly 32 bytes. Got %d bytes." % len(b))
|
||||
raise InputError('Partition definition length must be exactly 32 bytes. Got %d bytes.' % len(b))
|
||||
res = cls()
|
||||
(magic, res.type, res.subtype, res.offset,
|
||||
res.size, res.name, flags) = struct.unpack(cls.STRUCT_FORMAT, b)
|
||||
if b"\x00" in res.name: # strip null byte padding from name string
|
||||
res.name = res.name[:res.name.index(b"\x00")]
|
||||
if b'\x00' in res.name: # strip null byte padding from name string
|
||||
res.name = res.name[:res.name.index(b'\x00')]
|
||||
res.name = res.name.decode()
|
||||
if magic != cls.MAGIC_BYTES:
|
||||
raise InputError("Invalid magic bytes (%r) for partition definition" % magic)
|
||||
raise InputError('Invalid magic bytes (%r) for partition definition' % magic)
|
||||
for flag,bit in cls.FLAGS.items():
|
||||
if flags & (1 << bit):
|
||||
setattr(res, flag, True)
|
||||
flags &= ~(1 << bit)
|
||||
if flags != 0:
|
||||
critical("WARNING: Partition definition had unknown flag(s) 0x%08x. Newer binary format?" % flags)
|
||||
critical('WARNING: Partition definition had unknown flag(s) 0x%08x. Newer binary format?' % flags)
|
||||
return res
|
||||
|
||||
def get_flags_list(self):
|
||||
@@ -404,22 +404,22 @@ class PartitionDefinition(object):
|
||||
def to_csv(self, simple_formatting=False):
|
||||
def addr_format(a, include_sizes):
|
||||
if not simple_formatting and include_sizes:
|
||||
for (val, suffix) in [(0x100000, "M"), (0x400, "K")]:
|
||||
for (val, suffix) in [(0x100000, 'M'), (0x400, 'K')]:
|
||||
if a % val == 0:
|
||||
return "%d%s" % (a // val, suffix)
|
||||
return "0x%x" % a
|
||||
return '%d%s' % (a // val, suffix)
|
||||
return '0x%x' % a
|
||||
|
||||
def lookup_keyword(t, keywords):
|
||||
for k,v in keywords.items():
|
||||
if simple_formatting is False and t == v:
|
||||
return k
|
||||
return "%d" % t
|
||||
return '%d' % t
|
||||
|
||||
def generate_text_flags():
|
||||
""" colon-delimited list of flags """
|
||||
return ":".join(self.get_flags_list())
|
||||
return ':'.join(self.get_flags_list())
|
||||
|
||||
return ",".join([self.name,
|
||||
return ','.join([self.name,
|
||||
lookup_keyword(self.type, TYPES),
|
||||
lookup_keyword(self.subtype, SUBTYPES.get(self.type, {})),
|
||||
addr_format(self.offset, False),
|
||||
@@ -432,17 +432,17 @@ def parse_int(v, keywords={}):
|
||||
k/m/K/M suffixes and 'keyword' value lookup.
|
||||
"""
|
||||
try:
|
||||
for letter, multiplier in [("k", 1024), ("m", 1024 * 1024)]:
|
||||
for letter, multiplier in [('k', 1024), ('m', 1024 * 1024)]:
|
||||
if v.lower().endswith(letter):
|
||||
return parse_int(v[:-1], keywords) * multiplier
|
||||
return int(v, 0)
|
||||
except ValueError:
|
||||
if len(keywords) == 0:
|
||||
raise InputError("Invalid field value %s" % v)
|
||||
raise InputError('Invalid field value %s' % v)
|
||||
try:
|
||||
return keywords[v.lower()]
|
||||
except KeyError:
|
||||
raise InputError("Value '%s' is not valid. Known keywords: %s" % (v, ", ".join(keywords)))
|
||||
raise InputError("Value '%s' is not valid. Known keywords: %s" % (v, ', '.join(keywords)))
|
||||
|
||||
|
||||
def main():
|
||||
@@ -456,11 +456,11 @@ def main():
|
||||
nargs='?', choices=['1MB', '2MB', '4MB', '8MB', '16MB'])
|
||||
parser.add_argument('--disable-md5sum', help='Disable md5 checksum for the partition table', default=False, action='store_true')
|
||||
parser.add_argument('--no-verify', help="Don't verify partition table fields", action='store_true')
|
||||
parser.add_argument('--verify', '-v', help="Verify partition table fields (deprecated, this behaviour is "
|
||||
"enabled by default and this flag does nothing.", action='store_true')
|
||||
parser.add_argument('--verify', '-v', help='Verify partition table fields (deprecated, this behaviour is '
|
||||
'enabled by default and this flag does nothing.', action='store_true')
|
||||
parser.add_argument('--quiet', '-q', help="Don't print non-critical status messages to stderr", action='store_true')
|
||||
parser.add_argument('--offset', '-o', help='Set offset partition table', default='0x8000')
|
||||
parser.add_argument('--secure', help="Require app partitions to be suitable for secure boot", action='store_true')
|
||||
parser.add_argument('--secure', help='Require app partitions to be suitable for secure boot', action='store_true')
|
||||
parser.add_argument('input', help='Path to CSV or binary file to parse.', type=argparse.FileType('rb'))
|
||||
parser.add_argument('output', help='Path to output converted binary or CSV file. Will use stdout if omitted.',
|
||||
nargs='?', default='-')
|
||||
@@ -474,19 +474,19 @@ def main():
|
||||
input = args.input.read()
|
||||
input_is_binary = input[0:2] == PartitionDefinition.MAGIC_BYTES
|
||||
if input_is_binary:
|
||||
status("Parsing binary partition input...")
|
||||
status('Parsing binary partition input...')
|
||||
table = PartitionTable.from_binary(input)
|
||||
else:
|
||||
input = input.decode()
|
||||
status("Parsing CSV input...")
|
||||
status('Parsing CSV input...')
|
||||
table = PartitionTable.from_csv(input)
|
||||
|
||||
if not args.no_verify:
|
||||
status("Verifying table...")
|
||||
status('Verifying table...')
|
||||
table.verify()
|
||||
|
||||
if args.flash_size:
|
||||
size_mb = int(args.flash_size.replace("MB", ""))
|
||||
size_mb = int(args.flash_size.replace('MB', ''))
|
||||
size = size_mb * 1024 * 1024 # flash memory uses honest megabytes!
|
||||
table_size = table.flash_size()
|
||||
if size < table_size:
|
||||
@@ -526,7 +526,7 @@ class InputError(RuntimeError):
|
||||
class ValidationError(InputError):
|
||||
def __init__(self, partition, message):
|
||||
super(ValidationError, self).__init__(
|
||||
"Partition %s invalid: %s" % (partition.name, message))
|
||||
'Partition %s invalid: %s' % (partition.name, message))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -16,20 +16,21 @@
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from __future__ import print_function, division
|
||||
from __future__ import division, print_function
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import tempfile
|
||||
import re
|
||||
import gen_esp32part as gen
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
import gen_esp32part as gen
|
||||
|
||||
__version__ = '2.0'
|
||||
|
||||
COMPONENTS_PATH = os.path.expandvars(os.path.join("$IDF_PATH", "components"))
|
||||
ESPTOOL_PY = os.path.join(COMPONENTS_PATH, "esptool_py", "esptool", "esptool.py")
|
||||
COMPONENTS_PATH = os.path.expandvars(os.path.join('$IDF_PATH', 'components'))
|
||||
ESPTOOL_PY = os.path.join(COMPONENTS_PATH, 'esptool_py', 'esptool', 'esptool.py')
|
||||
|
||||
PARTITION_TABLE_OFFSET = 0x8000
|
||||
|
||||
@@ -78,14 +79,14 @@ class ParttoolTarget():
|
||||
def parse_esptool_args(esptool_args):
|
||||
results = list()
|
||||
for arg in esptool_args:
|
||||
pattern = re.compile(r"(.+)=(.+)")
|
||||
pattern = re.compile(r'(.+)=(.+)')
|
||||
result = pattern.match(arg)
|
||||
try:
|
||||
key = result.group(1)
|
||||
value = result.group(2)
|
||||
results.extend(["--" + key, value])
|
||||
results.extend(['--' + key, value])
|
||||
except AttributeError:
|
||||
results.extend(["--" + arg])
|
||||
results.extend(['--' + arg])
|
||||
return results
|
||||
|
||||
self.esptool_args = parse_esptool_args(esptool_args)
|
||||
@@ -95,14 +96,14 @@ class ParttoolTarget():
|
||||
|
||||
if partition_table_file:
|
||||
partition_table = None
|
||||
with open(partition_table_file, "rb") as f:
|
||||
with open(partition_table_file, 'rb') as f:
|
||||
input_is_binary = (f.read(2) == gen.PartitionDefinition.MAGIC_BYTES)
|
||||
f.seek(0)
|
||||
if input_is_binary:
|
||||
partition_table = gen.PartitionTable.from_binary(f.read())
|
||||
|
||||
if partition_table is None:
|
||||
with open(partition_table_file, "r") as f:
|
||||
with open(partition_table_file, 'r') as f:
|
||||
f.seek(0)
|
||||
partition_table = gen.PartitionTable.from_csv(f.read())
|
||||
else:
|
||||
@@ -110,8 +111,8 @@ class ParttoolTarget():
|
||||
temp_file.close()
|
||||
|
||||
try:
|
||||
self._call_esptool(["read_flash", str(partition_table_offset), str(gen.MAX_PARTITION_LENGTH), temp_file.name])
|
||||
with open(temp_file.name, "rb") as f:
|
||||
self._call_esptool(['read_flash', str(partition_table_offset), str(gen.MAX_PARTITION_LENGTH), temp_file.name])
|
||||
with open(temp_file.name, 'rb') as f:
|
||||
partition_table = gen.PartitionTable.from_binary(f.read())
|
||||
finally:
|
||||
os.unlink(temp_file.name)
|
||||
@@ -125,18 +126,18 @@ class ParttoolTarget():
|
||||
esptool_args = [sys.executable, ESPTOOL_PY] + self.esptool_args
|
||||
|
||||
if self.port:
|
||||
esptool_args += ["--port", self.port]
|
||||
esptool_args += ['--port', self.port]
|
||||
|
||||
if self.baud:
|
||||
esptool_args += ["--baud", str(self.baud)]
|
||||
esptool_args += ['--baud', str(self.baud)]
|
||||
|
||||
esptool_args += args
|
||||
|
||||
print("Running %s..." % (" ".join(esptool_args)))
|
||||
print('Running %s...' % (' '.join(esptool_args)))
|
||||
try:
|
||||
subprocess.check_call(esptool_args, stdout=out, stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print("An exception: **", str(e), "** occurred in _call_esptool.", file=out)
|
||||
print('An exception: **', str(e), '** occurred in _call_esptool.', file=out)
|
||||
raise e
|
||||
|
||||
def get_partition_info(self, partition_id):
|
||||
@@ -149,37 +150,37 @@ class ParttoolTarget():
|
||||
if not partition_id.part_list:
|
||||
partition = partition[0]
|
||||
else: # default boot partition
|
||||
search = ["factory"] + ["ota_{}".format(d) for d in range(16)]
|
||||
search = ['factory'] + ['ota_{}'.format(d) for d in range(16)]
|
||||
for subtype in search:
|
||||
partition = next(self.partition_table.find_by_type("app", subtype), None)
|
||||
partition = next(self.partition_table.find_by_type('app', subtype), None)
|
||||
if partition:
|
||||
break
|
||||
|
||||
if not partition:
|
||||
raise Exception("Partition does not exist")
|
||||
raise Exception('Partition does not exist')
|
||||
|
||||
return partition
|
||||
|
||||
def erase_partition(self, partition_id):
|
||||
partition = self.get_partition_info(partition_id)
|
||||
self._call_esptool(["erase_region", str(partition.offset), str(partition.size)] + self.esptool_erase_args)
|
||||
self._call_esptool(['erase_region', str(partition.offset), str(partition.size)] + self.esptool_erase_args)
|
||||
|
||||
def read_partition(self, partition_id, output):
|
||||
partition = self.get_partition_info(partition_id)
|
||||
self._call_esptool(["read_flash", str(partition.offset), str(partition.size), output] + self.esptool_read_args)
|
||||
self._call_esptool(['read_flash', str(partition.offset), str(partition.size), output] + self.esptool_read_args)
|
||||
|
||||
def write_partition(self, partition_id, input):
|
||||
self.erase_partition(partition_id)
|
||||
|
||||
partition = self.get_partition_info(partition_id)
|
||||
|
||||
with open(input, "rb") as input_file:
|
||||
with open(input, 'rb') as input_file:
|
||||
content_len = len(input_file.read())
|
||||
|
||||
if content_len > partition.size:
|
||||
raise Exception("Input file size exceeds partition size")
|
||||
raise Exception('Input file size exceeds partition size')
|
||||
|
||||
self._call_esptool(["write_flash", str(partition.offset), input] + self.esptool_write_args)
|
||||
self._call_esptool(['write_flash', str(partition.offset), input] + self.esptool_write_args)
|
||||
|
||||
|
||||
def _write_partition(target, partition_id, input):
|
||||
@@ -214,41 +215,41 @@ def _get_partition_info(target, partition_id, info):
|
||||
try:
|
||||
for p in partitions:
|
||||
info_dict = {
|
||||
"name": '{}'.format(p.name),
|
||||
"type": '{}'.format(p.type),
|
||||
"subtype": '{}'.format(p.subtype),
|
||||
"offset": '0x{:x}'.format(p.offset),
|
||||
"size": '0x{:x}'.format(p.size),
|
||||
"encrypted": '{}'.format(p.encrypted)
|
||||
'name': '{}'.format(p.name),
|
||||
'type': '{}'.format(p.type),
|
||||
'subtype': '{}'.format(p.subtype),
|
||||
'offset': '0x{:x}'.format(p.offset),
|
||||
'size': '0x{:x}'.format(p.size),
|
||||
'encrypted': '{}'.format(p.encrypted)
|
||||
}
|
||||
for i in info:
|
||||
infos += [info_dict[i]]
|
||||
except KeyError:
|
||||
raise RuntimeError("Request for unknown partition info {}".format(i))
|
||||
raise RuntimeError('Request for unknown partition info {}'.format(i))
|
||||
|
||||
print(" ".join(infos))
|
||||
print(' '.join(infos))
|
||||
|
||||
|
||||
def main():
|
||||
global quiet
|
||||
|
||||
parser = argparse.ArgumentParser("ESP-IDF Partitions Tool")
|
||||
parser = argparse.ArgumentParser('ESP-IDF Partitions Tool')
|
||||
|
||||
parser.add_argument("--quiet", "-q", help="suppress stderr messages", action="store_true")
|
||||
parser.add_argument("--esptool-args", help="additional main arguments for esptool", nargs="+")
|
||||
parser.add_argument("--esptool-write-args", help="additional subcommand arguments when writing to flash", nargs="+")
|
||||
parser.add_argument("--esptool-read-args", help="additional subcommand arguments when reading flash", nargs="+")
|
||||
parser.add_argument("--esptool-erase-args", help="additional subcommand arguments when erasing regions of flash", nargs="+")
|
||||
parser.add_argument('--quiet', '-q', help='suppress stderr messages', action='store_true')
|
||||
parser.add_argument('--esptool-args', help='additional main arguments for esptool', nargs='+')
|
||||
parser.add_argument('--esptool-write-args', help='additional subcommand arguments when writing to flash', nargs='+')
|
||||
parser.add_argument('--esptool-read-args', help='additional subcommand arguments when reading flash', nargs='+')
|
||||
parser.add_argument('--esptool-erase-args', help='additional subcommand arguments when erasing regions of flash', nargs='+')
|
||||
|
||||
# By default the device attached to the specified port is queried for the partition table. If a partition table file
|
||||
# is specified, that is used instead.
|
||||
parser.add_argument("--port", "-p", help="port where the target device of the command is connected to; the partition table is sourced from this device \
|
||||
when the partition table file is not defined")
|
||||
parser.add_argument("--baud", "-b", help="baudrate to use", type=int)
|
||||
parser.add_argument('--port', '-p', help='port where the target device of the command is connected to; the partition table is sourced from this device \
|
||||
when the partition table file is not defined')
|
||||
parser.add_argument('--baud', '-b', help='baudrate to use', type=int)
|
||||
|
||||
parser.add_argument("--partition-table-offset", "-o", help="offset to read the partition table from", type=str)
|
||||
parser.add_argument("--partition-table-file", "-f", help="file (CSV/binary) to read the partition table from; \
|
||||
overrides device attached to specified port as the partition table source when defined")
|
||||
parser.add_argument('--partition-table-offset', '-o', help='offset to read the partition table from', type=str)
|
||||
parser.add_argument('--partition-table-file', '-f', help='file (CSV/binary) to read the partition table from; \
|
||||
overrides device attached to specified port as the partition table source when defined')
|
||||
|
||||
partition_selection_parser = argparse.ArgumentParser(add_help=False)
|
||||
|
||||
@@ -256,30 +257,30 @@ def main():
|
||||
# partition name or the first partition that matches the specified type/subtype
|
||||
partition_selection_args = partition_selection_parser.add_mutually_exclusive_group()
|
||||
|
||||
partition_selection_args.add_argument("--partition-name", "-n", help="name of the partition")
|
||||
partition_selection_args.add_argument("--partition-type", "-t", help="type of the partition")
|
||||
partition_selection_args.add_argument('--partition-boot-default', "-d", help='select the default boot partition \
|
||||
using the same fallback logic as the IDF bootloader', action="store_true")
|
||||
partition_selection_args.add_argument('--partition-name', '-n', help='name of the partition')
|
||||
partition_selection_args.add_argument('--partition-type', '-t', help='type of the partition')
|
||||
partition_selection_args.add_argument('--partition-boot-default', '-d', help='select the default boot partition \
|
||||
using the same fallback logic as the IDF bootloader', action='store_true')
|
||||
|
||||
partition_selection_parser.add_argument("--partition-subtype", "-s", help="subtype of the partition")
|
||||
partition_selection_parser.add_argument('--partition-subtype', '-s', help='subtype of the partition')
|
||||
|
||||
subparsers = parser.add_subparsers(dest="operation", help="run parttool -h for additional help")
|
||||
subparsers = parser.add_subparsers(dest='operation', help='run parttool -h for additional help')
|
||||
|
||||
# Specify the supported operations
|
||||
read_part_subparser = subparsers.add_parser("read_partition", help="read partition from device and dump contents into a file",
|
||||
read_part_subparser = subparsers.add_parser('read_partition', help='read partition from device and dump contents into a file',
|
||||
parents=[partition_selection_parser])
|
||||
read_part_subparser.add_argument("--output", help="file to dump the read partition contents to")
|
||||
read_part_subparser.add_argument('--output', help='file to dump the read partition contents to')
|
||||
|
||||
write_part_subparser = subparsers.add_parser("write_partition", help="write contents of a binary file to partition on device",
|
||||
write_part_subparser = subparsers.add_parser('write_partition', help='write contents of a binary file to partition on device',
|
||||
parents=[partition_selection_parser])
|
||||
write_part_subparser.add_argument("--input", help="file whose contents are to be written to the partition offset")
|
||||
write_part_subparser.add_argument('--input', help='file whose contents are to be written to the partition offset')
|
||||
|
||||
subparsers.add_parser("erase_partition", help="erase the contents of a partition on the device", parents=[partition_selection_parser])
|
||||
subparsers.add_parser('erase_partition', help='erase the contents of a partition on the device', parents=[partition_selection_parser])
|
||||
|
||||
print_partition_info_subparser = subparsers.add_parser("get_partition_info", help="get partition information", parents=[partition_selection_parser])
|
||||
print_partition_info_subparser.add_argument("--info", help="type of partition information to get",
|
||||
choices=["name", "type", "subtype", "offset", "size", "encrypted"], default=["offset", "size"], nargs="+")
|
||||
print_partition_info_subparser.add_argument('--part_list', help="Get a list of partitions suitable for a given type", action='store_true')
|
||||
print_partition_info_subparser = subparsers.add_parser('get_partition_info', help='get partition information', parents=[partition_selection_parser])
|
||||
print_partition_info_subparser.add_argument('--info', help='type of partition information to get',
|
||||
choices=['name', 'type', 'subtype', 'offset', 'size', 'encrypted'], default=['offset', 'size'], nargs='+')
|
||||
print_partition_info_subparser.add_argument('--part_list', help='Get a list of partitions suitable for a given type', action='store_true')
|
||||
|
||||
args = parser.parse_args()
|
||||
quiet = args.quiet
|
||||
@@ -295,40 +296,40 @@ def main():
|
||||
partition_id = PartitionName(args.partition_name)
|
||||
elif args.partition_type:
|
||||
if not args.partition_subtype:
|
||||
raise RuntimeError("--partition-subtype should be defined when --partition-type is defined")
|
||||
raise RuntimeError('--partition-subtype should be defined when --partition-type is defined')
|
||||
partition_id = PartitionType(args.partition_type, args.partition_subtype, getattr(args, 'part_list', None))
|
||||
elif args.partition_boot_default:
|
||||
partition_id = PARTITION_BOOT_DEFAULT
|
||||
else:
|
||||
raise RuntimeError("Partition to operate on should be defined using --partition-name OR \
|
||||
partition-type,--partition-subtype OR partition-boot-default")
|
||||
raise RuntimeError('Partition to operate on should be defined using --partition-name OR \
|
||||
partition-type,--partition-subtype OR partition-boot-default')
|
||||
|
||||
# Prepare the device to perform operation on
|
||||
target_args = {}
|
||||
|
||||
if args.port:
|
||||
target_args["port"] = args.port
|
||||
target_args['port'] = args.port
|
||||
|
||||
if args.baud:
|
||||
target_args["baud"] = args.baud
|
||||
target_args['baud'] = args.baud
|
||||
|
||||
if args.partition_table_file:
|
||||
target_args["partition_table_file"] = args.partition_table_file
|
||||
target_args['partition_table_file'] = args.partition_table_file
|
||||
|
||||
if args.partition_table_offset:
|
||||
target_args["partition_table_offset"] = int(args.partition_table_offset, 0)
|
||||
target_args['partition_table_offset'] = int(args.partition_table_offset, 0)
|
||||
|
||||
if args.esptool_args:
|
||||
target_args["esptool_args"] = args.esptool_args
|
||||
target_args['esptool_args'] = args.esptool_args
|
||||
|
||||
if args.esptool_write_args:
|
||||
target_args["esptool_write_args"] = args.esptool_write_args
|
||||
target_args['esptool_write_args'] = args.esptool_write_args
|
||||
|
||||
if args.esptool_read_args:
|
||||
target_args["esptool_read_args"] = args.esptool_read_args
|
||||
target_args['esptool_read_args'] = args.esptool_read_args
|
||||
|
||||
if args.esptool_erase_args:
|
||||
target_args["esptool_erase_args"] = args.esptool_erase_args
|
||||
target_args['esptool_erase_args'] = args.esptool_erase_args
|
||||
|
||||
target = ParttoolTarget(**target_args)
|
||||
|
||||
@@ -336,9 +337,9 @@ def main():
|
||||
common_args = {'target':target, 'partition_id':partition_id}
|
||||
parttool_ops = {
|
||||
'erase_partition':(_erase_partition, []),
|
||||
'read_partition':(_read_partition, ["output"]),
|
||||
'write_partition':(_write_partition, ["input"]),
|
||||
'get_partition_info':(_get_partition_info, ["info"])
|
||||
'read_partition':(_read_partition, ['output']),
|
||||
'write_partition':(_write_partition, ['input']),
|
||||
'get_partition_info':(_get_partition_info, ['info'])
|
||||
}
|
||||
|
||||
(op, op_args) = parttool_ops[args.operation]
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
#!/usr/bin/env python
|
||||
from __future__ import print_function, division
|
||||
import unittest
|
||||
import struct
|
||||
from __future__ import division, print_function
|
||||
|
||||
import csv
|
||||
import sys
|
||||
import subprocess
|
||||
import tempfile
|
||||
import os
|
||||
import io
|
||||
import os
|
||||
import struct
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
try:
|
||||
import gen_esp32part
|
||||
except ImportError:
|
||||
sys.path.append("..")
|
||||
sys.path.append('..')
|
||||
import gen_esp32part
|
||||
|
||||
SIMPLE_CSV = """
|
||||
@@ -20,40 +21,40 @@ SIMPLE_CSV = """
|
||||
factory,0,2,65536,1048576,
|
||||
"""
|
||||
|
||||
LONGER_BINARY_TABLE = b""
|
||||
LONGER_BINARY_TABLE = b''
|
||||
# type 0x00, subtype 0x00,
|
||||
# offset 64KB, size 1MB
|
||||
LONGER_BINARY_TABLE += b"\xAA\x50\x00\x00" + \
|
||||
b"\x00\x00\x01\x00" + \
|
||||
b"\x00\x00\x10\x00" + \
|
||||
b"factory\0" + (b"\0" * 8) + \
|
||||
b"\x00\x00\x00\x00"
|
||||
LONGER_BINARY_TABLE += b'\xAA\x50\x00\x00' + \
|
||||
b'\x00\x00\x01\x00' + \
|
||||
b'\x00\x00\x10\x00' + \
|
||||
b'factory\0' + (b'\0' * 8) + \
|
||||
b'\x00\x00\x00\x00'
|
||||
# type 0x01, subtype 0x20,
|
||||
# offset 0x110000, size 128KB
|
||||
LONGER_BINARY_TABLE += b"\xAA\x50\x01\x20" + \
|
||||
b"\x00\x00\x11\x00" + \
|
||||
b"\x00\x02\x00\x00" + \
|
||||
b"data" + (b"\0" * 12) + \
|
||||
b"\x00\x00\x00\x00"
|
||||
LONGER_BINARY_TABLE += b'\xAA\x50\x01\x20' + \
|
||||
b'\x00\x00\x11\x00' + \
|
||||
b'\x00\x02\x00\x00' + \
|
||||
b'data' + (b'\0' * 12) + \
|
||||
b'\x00\x00\x00\x00'
|
||||
# type 0x10, subtype 0x00,
|
||||
# offset 0x150000, size 1MB
|
||||
LONGER_BINARY_TABLE += b"\xAA\x50\x10\x00" + \
|
||||
b"\x00\x00\x15\x00" + \
|
||||
b"\x00\x10\x00\x00" + \
|
||||
b"second" + (b"\0" * 10) + \
|
||||
b"\x00\x00\x00\x00"
|
||||
LONGER_BINARY_TABLE += b'\xAA\x50\x10\x00' + \
|
||||
b'\x00\x00\x15\x00' + \
|
||||
b'\x00\x10\x00\x00' + \
|
||||
b'second' + (b'\0' * 10) + \
|
||||
b'\x00\x00\x00\x00'
|
||||
# MD5 checksum
|
||||
LONGER_BINARY_TABLE += b"\xEB\xEB" + b"\xFF" * 14
|
||||
LONGER_BINARY_TABLE += b'\xEB\xEB' + b'\xFF' * 14
|
||||
LONGER_BINARY_TABLE += b'\xf9\xbd\x06\x1b\x45\x68\x6f\x86\x57\x1a\x2c\xd5\x2a\x1d\xa6\x5b'
|
||||
# empty partition
|
||||
LONGER_BINARY_TABLE += b"\xFF" * 32
|
||||
LONGER_BINARY_TABLE += b'\xFF' * 32
|
||||
|
||||
|
||||
def _strip_trailing_ffs(binary_table):
|
||||
"""
|
||||
Strip all FFs down to the last 32 bytes (terminating entry)
|
||||
"""
|
||||
while binary_table.endswith(b"\xFF" * 64):
|
||||
while binary_table.endswith(b'\xFF' * 64):
|
||||
binary_table = binary_table[0:len(binary_table) - 32]
|
||||
return binary_table
|
||||
|
||||
@@ -75,7 +76,7 @@ class CSVParserTests(Py23TestCase):
|
||||
def test_simple_partition(self):
|
||||
table = gen_esp32part.PartitionTable.from_csv(SIMPLE_CSV)
|
||||
self.assertEqual(len(table), 1)
|
||||
self.assertEqual(table[0].name, "factory")
|
||||
self.assertEqual(table[0].name, 'factory')
|
||||
self.assertEqual(table[0].type, 0)
|
||||
self.assertEqual(table[0].subtype, 2)
|
||||
self.assertEqual(table[0].offset, 65536)
|
||||
@@ -86,7 +87,7 @@ class CSVParserTests(Py23TestCase):
|
||||
# Name,Type, SubType,Offset,Size
|
||||
ihavenotype,
|
||||
"""
|
||||
with self.assertRaisesRegex(gen_esp32part.InputError, "type"):
|
||||
with self.assertRaisesRegex(gen_esp32part.InputError, 'type'):
|
||||
gen_esp32part.PartitionTable.from_csv(csv)
|
||||
|
||||
def test_type_subtype_names(self):
|
||||
@@ -115,15 +116,15 @@ myota_status, data, ota,, 0x100000
|
||||
nomagic = gen_esp32part.PartitionTable.from_csv(csv_nomagicnumbers)
|
||||
nomagic.verify()
|
||||
|
||||
self.assertEqual(nomagic["myapp"].type, 0)
|
||||
self.assertEqual(nomagic["myapp"].subtype, 0)
|
||||
self.assertEqual(nomagic["myapp"], magic["myapp"])
|
||||
self.assertEqual(nomagic["myota_0"].type, 0)
|
||||
self.assertEqual(nomagic["myota_0"].subtype, 0x10)
|
||||
self.assertEqual(nomagic["myota_0"], magic["myota_0"])
|
||||
self.assertEqual(nomagic["myota_15"], magic["myota_15"])
|
||||
self.assertEqual(nomagic["mytest"], magic["mytest"])
|
||||
self.assertEqual(nomagic["myota_status"], magic["myota_status"])
|
||||
self.assertEqual(nomagic['myapp'].type, 0)
|
||||
self.assertEqual(nomagic['myapp'].subtype, 0)
|
||||
self.assertEqual(nomagic['myapp'], magic['myapp'])
|
||||
self.assertEqual(nomagic['myota_0'].type, 0)
|
||||
self.assertEqual(nomagic['myota_0'].subtype, 0x10)
|
||||
self.assertEqual(nomagic['myota_0'], magic['myota_0'])
|
||||
self.assertEqual(nomagic['myota_15'], magic['myota_15'])
|
||||
self.assertEqual(nomagic['mytest'], magic['mytest'])
|
||||
self.assertEqual(nomagic['myota_status'], magic['myota_status'])
|
||||
|
||||
# self.assertEqual(nomagic.to_binary(), magic.to_binary())
|
||||
|
||||
@@ -176,7 +177,7 @@ second, data, 0x15, , 1M
|
||||
first, app, factory, 0x100000, 2M
|
||||
second, app, ota_0, 0x200000, 1M
|
||||
"""
|
||||
with self.assertRaisesRegex(gen_esp32part.InputError, "overlap"):
|
||||
with self.assertRaisesRegex(gen_esp32part.InputError, 'overlap'):
|
||||
t = gen_esp32part.PartitionTable.from_csv(csv)
|
||||
t.verify()
|
||||
|
||||
@@ -185,7 +186,7 @@ second, app, ota_0, 0x200000, 1M
|
||||
first, app, factory, 0x100000, 1M
|
||||
first, app, ota_0, 0x200000, 1M
|
||||
"""
|
||||
with self.assertRaisesRegex(gen_esp32part.InputError, "Partition names must be unique"):
|
||||
with self.assertRaisesRegex(gen_esp32part.InputError, 'Partition names must be unique'):
|
||||
t = gen_esp32part.PartitionTable.from_csv(csv)
|
||||
t.verify()
|
||||
|
||||
@@ -200,10 +201,10 @@ first, 0x30, 0xEE, 0x100400, 0x300000
|
||||
self.assertEqual(len(tb), 64 + 32)
|
||||
self.assertEqual(b'\xAA\x50', tb[0:2]) # magic
|
||||
self.assertEqual(b'\x30\xee', tb[2:4]) # type, subtype
|
||||
eo, es = struct.unpack("<LL", tb[4:12])
|
||||
eo, es = struct.unpack('<LL', tb[4:12])
|
||||
self.assertEqual(eo, 0x100400) # offset
|
||||
self.assertEqual(es, 0x300000) # size
|
||||
self.assertEqual(b"\xEB\xEB" + b"\xFF" * 14, tb[32:48])
|
||||
self.assertEqual(b'\xEB\xEB' + b'\xFF' * 14, tb[32:48])
|
||||
self.assertEqual(b'\x43\x03\x3f\x33\x40\x87\x57\x51\x69\x83\x9b\x40\x61\xb1\x27\x26', tb[48:64])
|
||||
|
||||
def test_multiple_entries(self):
|
||||
@@ -233,12 +234,12 @@ class BinaryParserTests(Py23TestCase):
|
||||
def test_parse_one_entry(self):
|
||||
# type 0x30, subtype 0xee,
|
||||
# offset 1MB, size 2MB
|
||||
entry = b"\xAA\x50\x30\xee" + \
|
||||
b"\x00\x00\x10\x00" + \
|
||||
b"\x00\x00\x20\x00" + \
|
||||
b"0123456789abc\0\0\0" + \
|
||||
b"\x00\x00\x00\x00" + \
|
||||
b"\xFF" * 32
|
||||
entry = b'\xAA\x50\x30\xee' + \
|
||||
b'\x00\x00\x10\x00' + \
|
||||
b'\x00\x00\x20\x00' + \
|
||||
b'0123456789abc\0\0\0' + \
|
||||
b'\x00\x00\x00\x00' + \
|
||||
b'\xFF' * 32
|
||||
# verify that parsing 32 bytes as a table
|
||||
# or as a single Definition are the same thing
|
||||
t = gen_esp32part.PartitionTable.from_binary(entry)
|
||||
@@ -253,7 +254,7 @@ class BinaryParserTests(Py23TestCase):
|
||||
self.assertEqual(e.subtype, 0xEE)
|
||||
self.assertEqual(e.offset, 0x100000)
|
||||
self.assertEqual(e.size, 0x200000)
|
||||
self.assertEqual(e.name, "0123456789abc")
|
||||
self.assertEqual(e.name, '0123456789abc')
|
||||
|
||||
def test_multiple_entries(self):
|
||||
t = gen_esp32part.PartitionTable.from_binary(LONGER_BINARY_TABLE)
|
||||
@@ -261,53 +262,53 @@ class BinaryParserTests(Py23TestCase):
|
||||
|
||||
self.assertEqual(3, len(t))
|
||||
self.assertEqual(t[0].type, gen_esp32part.APP_TYPE)
|
||||
self.assertEqual(t[0].name, "factory")
|
||||
self.assertEqual(t[0].name, 'factory')
|
||||
|
||||
self.assertEqual(t[1].type, gen_esp32part.DATA_TYPE)
|
||||
self.assertEqual(t[1].name, "data")
|
||||
self.assertEqual(t[1].name, 'data')
|
||||
|
||||
self.assertEqual(t[2].type, 0x10)
|
||||
self.assertEqual(t[2].name, "second")
|
||||
self.assertEqual(t[2].name, 'second')
|
||||
|
||||
round_trip = _strip_trailing_ffs(t.to_binary())
|
||||
self.assertEqual(round_trip, LONGER_BINARY_TABLE)
|
||||
|
||||
def test_bad_magic(self):
|
||||
bad_magic = b"OHAI" + \
|
||||
b"\x00\x00\x10\x00" + \
|
||||
b"\x00\x00\x20\x00" + \
|
||||
b"0123456789abc\0\0\0" + \
|
||||
b"\x00\x00\x00\x00"
|
||||
with self.assertRaisesRegex(gen_esp32part.InputError, "Invalid magic bytes"):
|
||||
bad_magic = b'OHAI' + \
|
||||
b'\x00\x00\x10\x00' + \
|
||||
b'\x00\x00\x20\x00' + \
|
||||
b'0123456789abc\0\0\0' + \
|
||||
b'\x00\x00\x00\x00'
|
||||
with self.assertRaisesRegex(gen_esp32part.InputError, 'Invalid magic bytes'):
|
||||
gen_esp32part.PartitionTable.from_binary(bad_magic)
|
||||
|
||||
def test_bad_length(self):
|
||||
bad_length = b"OHAI" + \
|
||||
b"\x00\x00\x10\x00" + \
|
||||
b"\x00\x00\x20\x00" + \
|
||||
b"0123456789"
|
||||
with self.assertRaisesRegex(gen_esp32part.InputError, "32 bytes"):
|
||||
bad_length = b'OHAI' + \
|
||||
b'\x00\x00\x10\x00' + \
|
||||
b'\x00\x00\x20\x00' + \
|
||||
b'0123456789'
|
||||
with self.assertRaisesRegex(gen_esp32part.InputError, '32 bytes'):
|
||||
gen_esp32part.PartitionTable.from_binary(bad_length)
|
||||
|
||||
|
||||
class CSVOutputTests(Py23TestCase):
|
||||
|
||||
def _readcsv(self, source_str):
|
||||
return list(csv.reader(source_str.split("\n")))
|
||||
return list(csv.reader(source_str.split('\n')))
|
||||
|
||||
def test_output_simple_formatting(self):
|
||||
table = gen_esp32part.PartitionTable.from_csv(SIMPLE_CSV)
|
||||
as_csv = table.to_csv(True)
|
||||
c = self._readcsv(as_csv)
|
||||
# first two lines should start with comments
|
||||
self.assertEqual(c[0][0][0], "#")
|
||||
self.assertEqual(c[1][0][0], "#")
|
||||
self.assertEqual(c[0][0][0], '#')
|
||||
self.assertEqual(c[1][0][0], '#')
|
||||
row = c[2]
|
||||
self.assertEqual(row[0], "factory")
|
||||
self.assertEqual(row[1], "0")
|
||||
self.assertEqual(row[2], "2")
|
||||
self.assertEqual(row[3], "0x10000") # reformatted as hex
|
||||
self.assertEqual(row[4], "0x100000") # also hex
|
||||
self.assertEqual(row[0], 'factory')
|
||||
self.assertEqual(row[1], '0')
|
||||
self.assertEqual(row[2], '2')
|
||||
self.assertEqual(row[3], '0x10000') # reformatted as hex
|
||||
self.assertEqual(row[4], '0x100000') # also hex
|
||||
|
||||
# round trip back to a PartitionTable and check is identical
|
||||
roundtrip = gen_esp32part.PartitionTable.from_csv(as_csv)
|
||||
@@ -318,14 +319,14 @@ class CSVOutputTests(Py23TestCase):
|
||||
as_csv = table.to_csv(False)
|
||||
c = self._readcsv(as_csv)
|
||||
# first two lines should start with comments
|
||||
self.assertEqual(c[0][0][0], "#")
|
||||
self.assertEqual(c[1][0][0], "#")
|
||||
self.assertEqual(c[0][0][0], '#')
|
||||
self.assertEqual(c[1][0][0], '#')
|
||||
row = c[2]
|
||||
self.assertEqual(row[0], "factory")
|
||||
self.assertEqual(row[1], "app")
|
||||
self.assertEqual(row[2], "2")
|
||||
self.assertEqual(row[3], "0x10000")
|
||||
self.assertEqual(row[4], "1M")
|
||||
self.assertEqual(row[0], 'factory')
|
||||
self.assertEqual(row[1], 'app')
|
||||
self.assertEqual(row[2], '2')
|
||||
self.assertEqual(row[3], '0x10000')
|
||||
self.assertEqual(row[4], '1M')
|
||||
|
||||
# round trip back to a PartitionTable and check is identical
|
||||
roundtrip = gen_esp32part.PartitionTable.from_csv(as_csv)
|
||||
@@ -344,18 +345,18 @@ class CommandLineTests(Py23TestCase):
|
||||
f.write(LONGER_BINARY_TABLE)
|
||||
|
||||
# run gen_esp32part.py to convert binary file to CSV
|
||||
output = subprocess.check_output([sys.executable, "../gen_esp32part.py",
|
||||
output = subprocess.check_output([sys.executable, '../gen_esp32part.py',
|
||||
binpath, csvpath], stderr=subprocess.STDOUT)
|
||||
# reopen the CSV and check the generated binary is identical
|
||||
self.assertNotIn(b"WARNING", output)
|
||||
self.assertNotIn(b'WARNING', output)
|
||||
with open(csvpath, 'r') as f:
|
||||
from_csv = gen_esp32part.PartitionTable.from_csv(f.read())
|
||||
self.assertEqual(_strip_trailing_ffs(from_csv.to_binary()), LONGER_BINARY_TABLE)
|
||||
|
||||
# run gen_esp32part.py to conver the CSV to binary again
|
||||
output = subprocess.check_output([sys.executable, "../gen_esp32part.py",
|
||||
output = subprocess.check_output([sys.executable, '../gen_esp32part.py',
|
||||
csvpath, binpath], stderr=subprocess.STDOUT)
|
||||
self.assertNotIn(b"WARNING", output)
|
||||
self.assertNotIn(b'WARNING', output)
|
||||
# assert that file reads back as identical
|
||||
with open(binpath, 'rb') as f:
|
||||
binary_readback = f.read()
|
||||
@@ -377,7 +378,7 @@ class VerificationTests(Py23TestCase):
|
||||
# Name,Type, SubType,Offset,Size
|
||||
app,app, factory, 32K, 1M
|
||||
"""
|
||||
with self.assertRaisesRegex(gen_esp32part.ValidationError, r"Offset.+not aligned"):
|
||||
with self.assertRaisesRegex(gen_esp32part.ValidationError, r'Offset.+not aligned'):
|
||||
t = gen_esp32part.PartitionTable.from_csv(csv)
|
||||
t.verify()
|
||||
|
||||
@@ -385,16 +386,16 @@ app,app, factory, 32K, 1M
|
||||
try:
|
||||
sys.stderr = io.StringIO() # capture stderr
|
||||
|
||||
csv_1 = "app, 1, 2, 32K, 1M\n"
|
||||
csv_1 = 'app, 1, 2, 32K, 1M\n'
|
||||
gen_esp32part.PartitionTable.from_csv(csv_1).verify()
|
||||
self.assertIn("WARNING", sys.stderr.getvalue())
|
||||
self.assertIn("partition type", sys.stderr.getvalue())
|
||||
self.assertIn('WARNING', sys.stderr.getvalue())
|
||||
self.assertIn('partition type', sys.stderr.getvalue())
|
||||
|
||||
sys.stderr = io.StringIO()
|
||||
csv_2 = "ota_0, app, ota_1, , 1M\n"
|
||||
csv_2 = 'ota_0, app, ota_1, , 1M\n'
|
||||
gen_esp32part.PartitionTable.from_csv(csv_2).verify()
|
||||
self.assertIn("WARNING", sys.stderr.getvalue())
|
||||
self.assertIn("partition subtype", sys.stderr.getvalue())
|
||||
self.assertIn('WARNING', sys.stderr.getvalue())
|
||||
self.assertIn('partition subtype', sys.stderr.getvalue())
|
||||
|
||||
finally:
|
||||
sys.stderr = sys.__stderr__
|
||||
@@ -404,13 +405,13 @@ class PartToolTests(Py23TestCase):
|
||||
|
||||
def _run_parttool(self, csvcontents, args):
|
||||
csvpath = tempfile.mktemp()
|
||||
with open(csvpath, "w") as f:
|
||||
with open(csvpath, 'w') as f:
|
||||
f.write(csvcontents)
|
||||
try:
|
||||
output = subprocess.check_output([sys.executable, "../parttool.py", "-q", "--partition-table-file",
|
||||
csvpath, "get_partition_info"] + args,
|
||||
output = subprocess.check_output([sys.executable, '../parttool.py', '-q', '--partition-table-file',
|
||||
csvpath, 'get_partition_info'] + args,
|
||||
stderr=subprocess.STDOUT)
|
||||
self.assertNotIn(b"WARNING", output)
|
||||
self.assertNotIn(b'WARNING', output)
|
||||
return output.strip()
|
||||
finally:
|
||||
os.remove(csvpath)
|
||||
@@ -431,41 +432,41 @@ nvs_key2, data, nvs_keys, 0x119000, 0x1000, encrypted
|
||||
return self._run_parttool(csv, args)
|
||||
|
||||
self.assertEqual(
|
||||
rpt(["--partition-type", "data", "--partition-subtype", "nvs", "--info", "offset"]), b"0x9000")
|
||||
rpt(['--partition-type', 'data', '--partition-subtype', 'nvs', '--info', 'offset']), b'0x9000')
|
||||
self.assertEqual(
|
||||
rpt(["--partition-type", "data", "--partition-subtype", "nvs", "--info", "size"]), b"0x4000")
|
||||
rpt(['--partition-type', 'data', '--partition-subtype', 'nvs', '--info', 'size']), b'0x4000')
|
||||
self.assertEqual(
|
||||
rpt(["--partition-name", "otadata", "--info", "offset"]), b"0xd000")
|
||||
rpt(['--partition-name', 'otadata', '--info', 'offset']), b'0xd000')
|
||||
self.assertEqual(
|
||||
rpt(["--partition-boot-default", "--info", "offset"]), b"0x10000")
|
||||
rpt(['--partition-boot-default', '--info', 'offset']), b'0x10000')
|
||||
self.assertEqual(
|
||||
rpt(["--partition-type", "data", "--partition-subtype", "nvs", "--info", "name", "offset", "size", "encrypted"]),
|
||||
b"nvs 0x9000 0x4000 False")
|
||||
rpt(['--partition-type', 'data', '--partition-subtype', 'nvs', '--info', 'name', 'offset', 'size', 'encrypted']),
|
||||
b'nvs 0x9000 0x4000 False')
|
||||
self.assertEqual(
|
||||
rpt(["--partition-type", "data", "--partition-subtype", "nvs", "--info", "name", "offset", "size", "encrypted", "--part_list"]),
|
||||
b"nvs 0x9000 0x4000 False nvs1_user 0x110000 0x4000 False nvs2_user 0x114000 0x4000 False")
|
||||
rpt(['--partition-type', 'data', '--partition-subtype', 'nvs', '--info', 'name', 'offset', 'size', 'encrypted', '--part_list']),
|
||||
b'nvs 0x9000 0x4000 False nvs1_user 0x110000 0x4000 False nvs2_user 0x114000 0x4000 False')
|
||||
self.assertEqual(
|
||||
rpt(["--partition-type", "data", "--partition-subtype", "nvs", "--info", "name", "--part_list"]),
|
||||
b"nvs nvs1_user nvs2_user")
|
||||
rpt(['--partition-type', 'data', '--partition-subtype', 'nvs', '--info', 'name', '--part_list']),
|
||||
b'nvs nvs1_user nvs2_user')
|
||||
self.assertEqual(
|
||||
rpt(["--partition-type", "data", "--partition-subtype", "nvs_keys", "--info", "name", "--part_list"]),
|
||||
b"nvs_key1 nvs_key2")
|
||||
rpt(['--partition-type', 'data', '--partition-subtype', 'nvs_keys', '--info', 'name', '--part_list']),
|
||||
b'nvs_key1 nvs_key2')
|
||||
self.assertEqual(
|
||||
rpt(["--partition-name", "nvs", "--info", "encrypted"]), b"False")
|
||||
rpt(['--partition-name', 'nvs', '--info', 'encrypted']), b'False')
|
||||
self.assertEqual(
|
||||
rpt(["--partition-name", "nvs1_user", "--info", "encrypted"]), b"False")
|
||||
rpt(['--partition-name', 'nvs1_user', '--info', 'encrypted']), b'False')
|
||||
self.assertEqual(
|
||||
rpt(["--partition-name", "nvs2_user", "--info", "encrypted"]), b"False")
|
||||
rpt(['--partition-name', 'nvs2_user', '--info', 'encrypted']), b'False')
|
||||
self.assertEqual(
|
||||
rpt(["--partition-name", "nvs_key1", "--info", "encrypted"]), b"True")
|
||||
rpt(['--partition-name', 'nvs_key1', '--info', 'encrypted']), b'True')
|
||||
self.assertEqual(
|
||||
rpt(["--partition-name", "nvs_key2", "--info", "encrypted"]), b"True")
|
||||
rpt(['--partition-name', 'nvs_key2', '--info', 'encrypted']), b'True')
|
||||
self.assertEqual(
|
||||
rpt(["--partition-type", "data", "--partition-subtype", "nvs_keys", "--info", "name", "encrypted", "--part_list"]),
|
||||
b"nvs_key1 True nvs_key2 True")
|
||||
rpt(['--partition-type', 'data', '--partition-subtype', 'nvs_keys', '--info', 'name', 'encrypted', '--part_list']),
|
||||
b'nvs_key1 True nvs_key2 True')
|
||||
self.assertEqual(
|
||||
rpt(["--partition-type", "data", "--partition-subtype", "nvs", "--info", "name", "encrypted", "--part_list"]),
|
||||
b"nvs False nvs1_user False nvs2_user False")
|
||||
rpt(['--partition-type', 'data', '--partition-subtype', 'nvs', '--info', 'name', 'encrypted', '--part_list']),
|
||||
b'nvs False nvs1_user False nvs2_user False')
|
||||
|
||||
def test_fallback(self):
|
||||
csv = """
|
||||
@@ -480,14 +481,14 @@ ota_1, app, ota_1, , 1M
|
||||
return self._run_parttool(csv, args)
|
||||
|
||||
self.assertEqual(
|
||||
rpt(["--partition-type", "app", "--partition-subtype", "ota_1", "--info", "offset"]), b"0x130000")
|
||||
rpt(['--partition-type', 'app', '--partition-subtype', 'ota_1', '--info', 'offset']), b'0x130000')
|
||||
self.assertEqual(
|
||||
rpt(["--partition-boot-default", "--info", "offset"]), b"0x30000") # ota_0
|
||||
csv_mod = csv.replace("ota_0", "ota_2")
|
||||
rpt(['--partition-boot-default', '--info', 'offset']), b'0x30000') # ota_0
|
||||
csv_mod = csv.replace('ota_0', 'ota_2')
|
||||
self.assertEqual(
|
||||
self._run_parttool(csv_mod, ["--partition-boot-default", "--info", "offset"]),
|
||||
b"0x130000") # now default is ota_1
|
||||
self._run_parttool(csv_mod, ['--partition-boot-default', '--info', 'offset']),
|
||||
b'0x130000') # now default is ota_1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
# source: constants.proto
|
||||
|
||||
import sys
|
||||
|
||||
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
|
||||
from google.protobuf.internal import enum_type_wrapper
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pb2
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf import descriptor_pb2
|
||||
from google.protobuf.internal import enum_type_wrapper
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
# source: sec0.proto
|
||||
|
||||
import sys
|
||||
|
||||
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
|
||||
from google.protobuf.internal import enum_type_wrapper
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pb2
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf import descriptor_pb2
|
||||
from google.protobuf.internal import enum_type_wrapper
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
@@ -16,7 +18,6 @@ _sym_db = _symbol_database.Default()
|
||||
|
||||
import constants_pb2 as constants__pb2
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name='sec0.proto',
|
||||
package='',
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
# source: sec1.proto
|
||||
|
||||
import sys
|
||||
|
||||
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
|
||||
from google.protobuf.internal import enum_type_wrapper
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pb2
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf import descriptor_pb2
|
||||
from google.protobuf.internal import enum_type_wrapper
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
@@ -16,7 +18,6 @@ _sym_db = _symbol_database.Default()
|
||||
|
||||
import constants_pb2 as constants__pb2
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name='sec1.proto',
|
||||
package='',
|
||||
@@ -73,7 +74,7 @@ _SESSIONCMD1 = _descriptor.Descriptor(
|
||||
_descriptor.FieldDescriptor(
|
||||
name='client_verify_data', full_name='SessionCmd1.client_verify_data', index=0,
|
||||
number=2, type=12, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b(""),
|
||||
has_default_value=False, default_value=_b(''),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
@@ -111,7 +112,7 @@ _SESSIONRESP1 = _descriptor.Descriptor(
|
||||
_descriptor.FieldDescriptor(
|
||||
name='device_verify_data', full_name='SessionResp1.device_verify_data', index=1,
|
||||
number=3, type=12, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b(""),
|
||||
has_default_value=False, default_value=_b(''),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
@@ -142,7 +143,7 @@ _SESSIONCMD0 = _descriptor.Descriptor(
|
||||
_descriptor.FieldDescriptor(
|
||||
name='client_pubkey', full_name='SessionCmd0.client_pubkey', index=0,
|
||||
number=1, type=12, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b(""),
|
||||
has_default_value=False, default_value=_b(''),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
@@ -180,14 +181,14 @@ _SESSIONRESP0 = _descriptor.Descriptor(
|
||||
_descriptor.FieldDescriptor(
|
||||
name='device_pubkey', full_name='SessionResp0.device_pubkey', index=1,
|
||||
number=2, type=12, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b(""),
|
||||
has_default_value=False, default_value=_b(''),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='device_random', full_name='SessionResp0.device_random', index=2,
|
||||
number=3, type=12, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b(""),
|
||||
has_default_value=False, default_value=_b(''),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
# source: session.proto
|
||||
|
||||
import sys
|
||||
|
||||
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
|
||||
from google.protobuf.internal import enum_type_wrapper
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pb2
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf import descriptor_pb2
|
||||
from google.protobuf.internal import enum_type_wrapper
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
@@ -17,7 +19,6 @@ _sym_db = _symbol_database.Default()
|
||||
import sec0_pb2 as sec0__pb2
|
||||
import sec1_pb2 as sec1__pb2
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name='session.proto',
|
||||
package='',
|
||||
|
||||
@@ -17,13 +17,14 @@
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import division, print_function
|
||||
import os
|
||||
import sys
|
||||
import io
|
||||
import math
|
||||
import struct
|
||||
|
||||
import argparse
|
||||
import ctypes
|
||||
import io
|
||||
import math
|
||||
import os
|
||||
import struct
|
||||
import sys
|
||||
|
||||
SPIFFS_PH_FLAG_USED_FINAL_INDEX = 0xF8
|
||||
SPIFFS_PH_FLAG_USED_FINAL = 0xFC
|
||||
@@ -45,7 +46,7 @@ class SpiffsBuildConfig():
|
||||
block_ix_len, meta_len, obj_name_len, obj_id_len,
|
||||
span_ix_len, packed, aligned, endianness, use_magic, use_magic_len):
|
||||
if block_size % page_size != 0:
|
||||
raise RuntimeError("block size should be a multiple of page size")
|
||||
raise RuntimeError('block size should be a multiple of page size')
|
||||
|
||||
self.page_size = page_size
|
||||
self.block_size = block_size
|
||||
@@ -88,15 +89,15 @@ class SpiffsFullError(RuntimeError):
|
||||
|
||||
class SpiffsPage():
|
||||
_endianness_dict = {
|
||||
"little": "<",
|
||||
"big": ">"
|
||||
'little': '<',
|
||||
'big': '>'
|
||||
}
|
||||
|
||||
_len_dict = {
|
||||
1: "B",
|
||||
2: "H",
|
||||
4: "I",
|
||||
8: "Q"
|
||||
1: 'B',
|
||||
2: 'H',
|
||||
4: 'I',
|
||||
8: 'Q'
|
||||
}
|
||||
|
||||
_type_dict = {
|
||||
@@ -137,7 +138,7 @@ class SpiffsObjLuPage(SpiffsPage):
|
||||
|
||||
def to_binary(self):
|
||||
global test
|
||||
img = b""
|
||||
img = b''
|
||||
|
||||
for (obj_id, page_type) in self.obj_ids:
|
||||
if page_type == SpiffsObjIndexPage:
|
||||
@@ -147,7 +148,7 @@ class SpiffsObjLuPage(SpiffsPage):
|
||||
|
||||
assert(len(img) <= self.build_config.page_size)
|
||||
|
||||
img += b"\xFF" * (self.build_config.page_size - len(img))
|
||||
img += b'\xFF' * (self.build_config.page_size - len(img))
|
||||
|
||||
return img
|
||||
|
||||
@@ -205,7 +206,7 @@ class SpiffsObjIndexPage(SpiffsPage):
|
||||
SPIFFS_PH_FLAG_USED_FINAL_INDEX)
|
||||
|
||||
# Add padding before the object index page specific information
|
||||
img += b"\xFF" * self.build_config.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED_PAD
|
||||
img += b'\xFF' * self.build_config.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED_PAD
|
||||
|
||||
# If this is the first object index page for the object, add filname, type
|
||||
# and size information
|
||||
@@ -216,7 +217,7 @@ class SpiffsObjIndexPage(SpiffsPage):
|
||||
self.size,
|
||||
SPIFFS_TYPE_FILE)
|
||||
|
||||
img += self.name.encode() + (b"\x00" * ((self.build_config.obj_name_len - len(self.name)) + self.build_config.meta_len))
|
||||
img += self.name.encode() + (b'\x00' * ((self.build_config.obj_name_len - len(self.name)) + self.build_config.meta_len))
|
||||
|
||||
# Finally, add the page index of daa pages
|
||||
for page in self.pages:
|
||||
@@ -226,7 +227,7 @@ class SpiffsObjIndexPage(SpiffsPage):
|
||||
|
||||
assert(len(img) <= self.build_config.page_size)
|
||||
|
||||
img += b"\xFF" * (self.build_config.page_size - len(img))
|
||||
img += b'\xFF' * (self.build_config.page_size - len(img))
|
||||
|
||||
return img
|
||||
|
||||
@@ -252,7 +253,7 @@ class SpiffsObjDataPage(SpiffsPage):
|
||||
|
||||
assert(len(img) <= self.build_config.page_size)
|
||||
|
||||
img += b"\xFF" * (self.build_config.page_size - len(img))
|
||||
img += b'\xFF' * (self.build_config.page_size - len(img))
|
||||
|
||||
return img
|
||||
|
||||
@@ -296,7 +297,7 @@ class SpiffsBlock():
|
||||
except AttributeError: # no next lookup page
|
||||
# Since the amount of lookup pages is pre-computed at every block instance,
|
||||
# this should never occur
|
||||
raise RuntimeError("invalid attempt to add page to a block when there is no more space in lookup")
|
||||
raise RuntimeError('invalid attempt to add page to a block when there is no more space in lookup')
|
||||
|
||||
self.pages.append(page)
|
||||
|
||||
@@ -335,7 +336,7 @@ class SpiffsBlock():
|
||||
return self.remaining_pages <= 0
|
||||
|
||||
def to_binary(self, blocks_lim):
|
||||
img = b""
|
||||
img = b''
|
||||
|
||||
if self.build_config.use_magic:
|
||||
for (idx, page) in enumerate(self.pages):
|
||||
@@ -348,14 +349,14 @@ class SpiffsBlock():
|
||||
|
||||
assert(len(img) <= self.build_config.block_size)
|
||||
|
||||
img += b"\xFF" * (self.build_config.block_size - len(img))
|
||||
img += b'\xFF' * (self.build_config.block_size - len(img))
|
||||
return img
|
||||
|
||||
|
||||
class SpiffsFS():
|
||||
def __init__(self, img_size, build_config):
|
||||
if img_size % build_config.block_size != 0:
|
||||
raise RuntimeError("image size should be a multiple of block size")
|
||||
raise RuntimeError('image size should be a multiple of block size')
|
||||
|
||||
self.img_size = img_size
|
||||
self.build_config = build_config
|
||||
@@ -367,7 +368,7 @@ class SpiffsFS():
|
||||
|
||||
def _create_block(self):
|
||||
if self.is_full():
|
||||
raise SpiffsFullError("the image size has been exceeded")
|
||||
raise SpiffsFullError('the image size has been exceeded')
|
||||
|
||||
block = SpiffsBlock(len(self.blocks), self.blocks_lim, self.build_config)
|
||||
self.blocks.append(block)
|
||||
@@ -385,7 +386,7 @@ class SpiffsFS():
|
||||
|
||||
name = img_path
|
||||
|
||||
with open(file_path, "rb") as obj:
|
||||
with open(file_path, 'rb') as obj:
|
||||
contents = obj.read()
|
||||
|
||||
stream = io.BytesIO(contents)
|
||||
@@ -434,7 +435,7 @@ class SpiffsFS():
|
||||
self.cur_obj_id += 1
|
||||
|
||||
def to_binary(self):
|
||||
img = b""
|
||||
img = b''
|
||||
for block in self.blocks:
|
||||
img += block.to_binary(self.blocks_lim)
|
||||
bix = len(self.blocks)
|
||||
@@ -447,78 +448,78 @@ class SpiffsFS():
|
||||
bix += 1
|
||||
else:
|
||||
# Just fill remaining spaces FF's
|
||||
img += "\xFF" * (self.img_size - len(img))
|
||||
img += '\xFF' * (self.img_size - len(img))
|
||||
return img
|
||||
|
||||
|
||||
def main():
|
||||
if sys.version_info[0] < 3:
|
||||
print("WARNING: Support for Python 2 is deprecated and will be removed in future versions.", file=sys.stderr)
|
||||
print('WARNING: Support for Python 2 is deprecated and will be removed in future versions.', file=sys.stderr)
|
||||
elif sys.version_info[0] == 3 and sys.version_info[1] < 6:
|
||||
print("WARNING: Python 3 versions older than 3.6 are not supported.", file=sys.stderr)
|
||||
parser = argparse.ArgumentParser(description="SPIFFS Image Generator",
|
||||
print('WARNING: Python 3 versions older than 3.6 are not supported.', file=sys.stderr)
|
||||
parser = argparse.ArgumentParser(description='SPIFFS Image Generator',
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
|
||||
parser.add_argument("image_size",
|
||||
help="Size of the created image")
|
||||
parser.add_argument('image_size',
|
||||
help='Size of the created image')
|
||||
|
||||
parser.add_argument("base_dir",
|
||||
help="Path to directory from which the image will be created")
|
||||
parser.add_argument('base_dir',
|
||||
help='Path to directory from which the image will be created')
|
||||
|
||||
parser.add_argument("output_file",
|
||||
help="Created image output file path")
|
||||
parser.add_argument('output_file',
|
||||
help='Created image output file path')
|
||||
|
||||
parser.add_argument("--page-size",
|
||||
help="Logical page size. Set to value same as CONFIG_SPIFFS_PAGE_SIZE.",
|
||||
parser.add_argument('--page-size',
|
||||
help='Logical page size. Set to value same as CONFIG_SPIFFS_PAGE_SIZE.',
|
||||
type=int,
|
||||
default=256)
|
||||
|
||||
parser.add_argument("--block-size",
|
||||
parser.add_argument('--block-size',
|
||||
help="Logical block size. Set to the same value as the flash chip's sector size (g_rom_flashchip.sector_size).",
|
||||
type=int,
|
||||
default=4096)
|
||||
|
||||
parser.add_argument("--obj-name-len",
|
||||
help="File full path maximum length. Set to value same as CONFIG_SPIFFS_OBJ_NAME_LEN.",
|
||||
parser.add_argument('--obj-name-len',
|
||||
help='File full path maximum length. Set to value same as CONFIG_SPIFFS_OBJ_NAME_LEN.',
|
||||
type=int,
|
||||
default=32)
|
||||
|
||||
parser.add_argument("--meta-len",
|
||||
help="File metadata length. Set to value same as CONFIG_SPIFFS_META_LENGTH.",
|
||||
parser.add_argument('--meta-len',
|
||||
help='File metadata length. Set to value same as CONFIG_SPIFFS_META_LENGTH.',
|
||||
type=int,
|
||||
default=4)
|
||||
|
||||
parser.add_argument("--use-magic",
|
||||
help="Use magic number to create an identifiable SPIFFS image. Specify if CONFIG_SPIFFS_USE_MAGIC.",
|
||||
action="store_true",
|
||||
parser.add_argument('--use-magic',
|
||||
help='Use magic number to create an identifiable SPIFFS image. Specify if CONFIG_SPIFFS_USE_MAGIC.',
|
||||
action='store_true',
|
||||
default=True)
|
||||
|
||||
parser.add_argument("--follow-symlinks",
|
||||
help="Take into account symbolic links during partition image creation.",
|
||||
action="store_true",
|
||||
parser.add_argument('--follow-symlinks',
|
||||
help='Take into account symbolic links during partition image creation.',
|
||||
action='store_true',
|
||||
default=False)
|
||||
|
||||
parser.add_argument("--use-magic-len",
|
||||
help="Use position in memory to create different magic numbers for each block. Specify if CONFIG_SPIFFS_USE_MAGIC_LENGTH.",
|
||||
action="store_true",
|
||||
parser.add_argument('--use-magic-len',
|
||||
help='Use position in memory to create different magic numbers for each block. Specify if CONFIG_SPIFFS_USE_MAGIC_LENGTH.',
|
||||
action='store_true',
|
||||
default=True)
|
||||
|
||||
parser.add_argument("--big-endian",
|
||||
help="Specify if the target architecture is big-endian. If not specified, little-endian is assumed.",
|
||||
action="store_true",
|
||||
parser.add_argument('--big-endian',
|
||||
help='Specify if the target architecture is big-endian. If not specified, little-endian is assumed.',
|
||||
action='store_true',
|
||||
default=False)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not os.path.exists(args.base_dir):
|
||||
raise RuntimeError("given base directory %s does not exist" % args.base_dir)
|
||||
raise RuntimeError('given base directory %s does not exist' % args.base_dir)
|
||||
|
||||
with open(args.output_file, "wb") as image_file:
|
||||
with open(args.output_file, 'wb') as image_file:
|
||||
image_size = int(args.image_size, 0)
|
||||
spiffs_build_default = SpiffsBuildConfig(args.page_size, SPIFFS_PAGE_IX_LEN,
|
||||
args.block_size, SPIFFS_BLOCK_IX_LEN, args.meta_len,
|
||||
args.obj_name_len, SPIFFS_OBJ_ID_LEN, SPIFFS_SPAN_IX_LEN,
|
||||
True, True, "big" if args.big_endian else "little",
|
||||
True, True, 'big' if args.big_endian else 'little',
|
||||
args.use_magic, args.use_magic_len)
|
||||
|
||||
spiffs = SpiffsFS(image_size, spiffs_build_default)
|
||||
@@ -526,12 +527,12 @@ def main():
|
||||
for root, dirs, files in os.walk(args.base_dir, followlinks=args.follow_symlinks):
|
||||
for f in files:
|
||||
full_path = os.path.join(root, f)
|
||||
spiffs.create_file("/" + os.path.relpath(full_path, args.base_dir).replace("\\", "/"), full_path)
|
||||
spiffs.create_file('/' + os.path.relpath(full_path, args.base_dir).replace('\\', '/'), full_path)
|
||||
|
||||
image = spiffs.to_binary()
|
||||
|
||||
image_file.write(image)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
@@ -6,58 +6,59 @@
|
||||
# Distributed under the terms of Apache License v2.0 found in the top-level LICENSE file.
|
||||
|
||||
from __future__ import print_function
|
||||
from optparse import OptionParser
|
||||
|
||||
import sys
|
||||
from optparse import OptionParser
|
||||
|
||||
BASE_ADDR = 0x50000000
|
||||
|
||||
|
||||
def gen_ld_h_from_sym(f_sym, f_ld, f_h):
|
||||
f_ld.write("/* Variable definitions for ESP32ULP linker\n")
|
||||
f_ld.write(" * This file is generated automatically by esp32ulp_mapgen.py utility.\n")
|
||||
f_ld.write(" */\n\n")
|
||||
f_h.write("// Variable definitions for ESP32ULP\n")
|
||||
f_h.write("// This file is generated automatically by esp32ulp_mapgen.py utility\n\n")
|
||||
f_h.write("#pragma once\n\n")
|
||||
f_ld.write('/* Variable definitions for ESP32ULP linker\n')
|
||||
f_ld.write(' * This file is generated automatically by esp32ulp_mapgen.py utility.\n')
|
||||
f_ld.write(' */\n\n')
|
||||
f_h.write('// Variable definitions for ESP32ULP\n')
|
||||
f_h.write('// This file is generated automatically by esp32ulp_mapgen.py utility\n\n')
|
||||
f_h.write('#pragma once\n\n')
|
||||
|
||||
for line in f_sym:
|
||||
name, _, addr_str = line.split(" ", 2)
|
||||
name, _, addr_str = line.split(' ', 2)
|
||||
addr = int(addr_str, 16) + BASE_ADDR
|
||||
f_h.write("extern uint32_t ulp_{0};\n".format(name))
|
||||
f_ld.write("PROVIDE ( ulp_{0} = 0x{1:08x} );\n".format(name, addr))
|
||||
f_h.write('extern uint32_t ulp_{0};\n'.format(name))
|
||||
f_ld.write('PROVIDE ( ulp_{0} = 0x{1:08x} );\n'.format(name, addr))
|
||||
|
||||
|
||||
def gen_ld_h_from_sym_riscv(f_sym, f_ld, f_h):
|
||||
f_ld.write("/* Variable definitions for ESP32ULP linker\n")
|
||||
f_ld.write(" * This file is generated automatically by esp32ulp_mapgen.py utility.\n")
|
||||
f_ld.write(" */\n\n")
|
||||
f_h.write("// Variable definitions for ESP32ULP\n")
|
||||
f_h.write("// This file is generated automatically by esp32ulp_mapgen.py utility\n\n")
|
||||
f_h.write("#pragma once\n\n")
|
||||
f_ld.write('/* Variable definitions for ESP32ULP linker\n')
|
||||
f_ld.write(' * This file is generated automatically by esp32ulp_mapgen.py utility.\n')
|
||||
f_ld.write(' */\n\n')
|
||||
f_h.write('// Variable definitions for ESP32ULP\n')
|
||||
f_h.write('// This file is generated automatically by esp32ulp_mapgen.py utility\n\n')
|
||||
f_h.write('#pragma once\n\n')
|
||||
|
||||
for line in f_sym:
|
||||
addr_str, _, name = line.split()
|
||||
addr = int(addr_str, 16) + BASE_ADDR
|
||||
f_h.write("extern uint32_t ulp_{0};\n".format(name))
|
||||
f_ld.write("PROVIDE ( ulp_{0} = 0x{1:08x} );\n".format(name, addr))
|
||||
f_h.write('extern uint32_t ulp_{0};\n'.format(name))
|
||||
f_ld.write('PROVIDE ( ulp_{0} = 0x{1:08x} );\n'.format(name, addr))
|
||||
|
||||
|
||||
def main():
|
||||
if sys.version_info[0] < 3:
|
||||
print("WARNING: Support for Python 2 is deprecated and will be removed in future versions.", file=sys.stderr)
|
||||
print('WARNING: Support for Python 2 is deprecated and will be removed in future versions.', file=sys.stderr)
|
||||
elif sys.version_info[0] == 3 and sys.version_info[1] < 6:
|
||||
print("WARNING: Python 3 versions older than 3.6 are not supported.", file=sys.stderr)
|
||||
description = ("This application generates .h and .ld files for symbols defined in input file. "
|
||||
"The input symbols file can be generated using nm utility like this: "
|
||||
"esp32-ulp-nm -g -f posix <elf_file> > <symbols_file>")
|
||||
print('WARNING: Python 3 versions older than 3.6 are not supported.', file=sys.stderr)
|
||||
description = ('This application generates .h and .ld files for symbols defined in input file. '
|
||||
'The input symbols file can be generated using nm utility like this: '
|
||||
'esp32-ulp-nm -g -f posix <elf_file> > <symbols_file>')
|
||||
|
||||
parser = OptionParser(description=description)
|
||||
parser.add_option("-s", "--symfile", dest="symfile",
|
||||
help="symbols file name", metavar="SYMFILE")
|
||||
parser.add_option("-o", "--outputfile", dest="outputfile",
|
||||
help="destination .h and .ld files name prefix", metavar="OUTFILE")
|
||||
parser.add_option('-s', '--symfile', dest='symfile',
|
||||
help='symbols file name', metavar='SYMFILE')
|
||||
parser.add_option('-o', '--outputfile', dest='outputfile',
|
||||
help='destination .h and .ld files name prefix', metavar='OUTFILE')
|
||||
|
||||
parser.add_option("--riscv", action="store_true", help="use format for ulp riscv .sym file")
|
||||
parser.add_option('--riscv', action='store_true', help='use format for ulp riscv .sym file')
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
if options.symfile is None:
|
||||
@@ -69,14 +70,14 @@ def main():
|
||||
return 1
|
||||
|
||||
if options.riscv:
|
||||
with open(options.outputfile + ".h", 'w') as f_h, open(options.outputfile + ".ld", 'w') as f_ld, open(options.symfile) as f_sym:
|
||||
with open(options.outputfile + '.h', 'w') as f_h, open(options.outputfile + '.ld', 'w') as f_ld, open(options.symfile) as f_sym:
|
||||
gen_ld_h_from_sym_riscv(f_sym, f_ld, f_h)
|
||||
return 0
|
||||
|
||||
with open(options.outputfile + ".h", 'w') as f_h, open(options.outputfile + ".ld", 'w') as f_ld, open(options.symfile) as f_sym:
|
||||
with open(options.outputfile + '.h', 'w') as f_h, open(options.outputfile + '.ld', 'w') as f_ld, open(options.symfile) as f_sym:
|
||||
gen_ld_h_from_sym(f_sym, f_ld, f_h)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if __name__ == '__main__':
|
||||
exit(main())
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
# source: wifi_config.proto
|
||||
|
||||
import sys
|
||||
|
||||
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
|
||||
from google.protobuf.internal import enum_type_wrapper
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pb2
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf import descriptor_pb2
|
||||
from google.protobuf.internal import enum_type_wrapper
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
@@ -17,7 +19,6 @@ _sym_db = _symbol_database.Default()
|
||||
import constants_pb2 as constants__pb2
|
||||
import wifi_constants_pb2 as wifi__constants__pb2
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name='wifi_config.proto',
|
||||
package='',
|
||||
@@ -163,21 +164,21 @@ _CMDSETCONFIG = _descriptor.Descriptor(
|
||||
_descriptor.FieldDescriptor(
|
||||
name='ssid', full_name='CmdSetConfig.ssid', index=0,
|
||||
number=1, type=12, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b(""),
|
||||
has_default_value=False, default_value=_b(''),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='passphrase', full_name='CmdSetConfig.passphrase', index=1,
|
||||
number=2, type=12, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b(""),
|
||||
has_default_value=False, default_value=_b(''),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='bssid', full_name='CmdSetConfig.bssid', index=2,
|
||||
number=3, type=12, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b(""),
|
||||
has_default_value=False, default_value=_b(''),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
# source: wifi_constants.proto
|
||||
|
||||
import sys
|
||||
|
||||
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
|
||||
from google.protobuf.internal import enum_type_wrapper
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pb2
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf import descriptor_pb2
|
||||
from google.protobuf.internal import enum_type_wrapper
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
@@ -141,7 +143,7 @@ _WIFICONNECTEDSTATE = _descriptor.Descriptor(
|
||||
_descriptor.FieldDescriptor(
|
||||
name='ip4_addr', full_name='WifiConnectedState.ip4_addr', index=0,
|
||||
number=1, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b("").decode('utf-8'),
|
||||
has_default_value=False, default_value=_b('').decode('utf-8'),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
@@ -155,14 +157,14 @@ _WIFICONNECTEDSTATE = _descriptor.Descriptor(
|
||||
_descriptor.FieldDescriptor(
|
||||
name='ssid', full_name='WifiConnectedState.ssid', index=2,
|
||||
number=3, type=12, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b(""),
|
||||
has_default_value=False, default_value=_b(''),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='bssid', full_name='WifiConnectedState.bssid', index=3,
|
||||
number=4, type=12, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b(""),
|
||||
has_default_value=False, default_value=_b(''),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None, file=DESCRIPTOR),
|
||||
|
||||
@@ -3,12 +3,14 @@
|
||||
# source: wifi_scan.proto
|
||||
|
||||
import sys
|
||||
|
||||
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
|
||||
from google.protobuf.internal import enum_type_wrapper
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import enum_type_wrapper
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
@@ -17,7 +19,6 @@ _sym_db = _symbol_database.Default()
|
||||
import constants_pb2 as constants__pb2
|
||||
import wifi_constants_pb2 as wifi__constants__pb2
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name='wifi_scan.proto',
|
||||
package='',
|
||||
@@ -261,7 +262,7 @@ _WIFISCANRESULT = _descriptor.Descriptor(
|
||||
_descriptor.FieldDescriptor(
|
||||
name='ssid', full_name='WiFiScanResult.ssid', index=0,
|
||||
number=1, type=12, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b(""),
|
||||
has_default_value=False, default_value=_b(''),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
@@ -282,7 +283,7 @@ _WIFISCANRESULT = _descriptor.Descriptor(
|
||||
_descriptor.FieldDescriptor(
|
||||
name='bssid', full_name='WiFiScanResult.bssid', index=3,
|
||||
number=4, type=12, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b(""),
|
||||
has_default_value=False, default_value=_b(''),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
|
||||
@@ -50,11 +50,12 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
|
||||
# Check if loaded into GDB
|
||||
try:
|
||||
assert gdb.__name__ == "gdb"
|
||||
assert gdb.__name__ == 'gdb'
|
||||
WITH_GDB = True
|
||||
except NameError:
|
||||
WITH_GDB = False
|
||||
@@ -114,7 +115,7 @@ class TraxPacket(object):
|
||||
return result
|
||||
|
||||
def __str__(self):
|
||||
return "%d byte packet%s" % (self.size_bytes, " (truncated)" if self.truncated else "")
|
||||
return '%d byte packet%s' % (self.size_bytes, ' (truncated)' if self.truncated else '')
|
||||
|
||||
|
||||
class TraxMessage(object):
|
||||
@@ -175,7 +176,7 @@ class TraxMessage(object):
|
||||
self.icnt = self.packets[0].get_bits(12, -1)
|
||||
self.is_correlation = True
|
||||
else:
|
||||
raise NotImplementedError("Unknown message type (%d)" % self.msg_type)
|
||||
raise NotImplementedError('Unknown message type (%d)' % self.msg_type)
|
||||
|
||||
def process_forward(self, cur_pc):
|
||||
"""
|
||||
@@ -229,23 +230,23 @@ class TraxMessage(object):
|
||||
return prev_pc
|
||||
|
||||
def __str__(self):
|
||||
desc = "Unknown (%d)" % self.msg_type
|
||||
extra = ""
|
||||
desc = 'Unknown (%d)' % self.msg_type
|
||||
extra = ''
|
||||
if self.truncated:
|
||||
desc = "Truncated"
|
||||
desc = 'Truncated'
|
||||
if self.msg_type == TVAL_INDBR:
|
||||
desc = "Indirect branch"
|
||||
extra = ", icnt=%d, uaddr=0x%x, exc=%d" % (self.icnt, self.uaddr, self.is_exception)
|
||||
desc = 'Indirect branch'
|
||||
extra = ', icnt=%d, uaddr=0x%x, exc=%d' % (self.icnt, self.uaddr, self.is_exception)
|
||||
if self.msg_type == TVAL_INDBRSYNC:
|
||||
desc = "Indirect branch w/sync"
|
||||
extra = ", icnt=%d, dcont=%d, exc=%d" % (self.icnt, self.dcont, self.is_exception)
|
||||
desc = 'Indirect branch w/sync'
|
||||
extra = ', icnt=%d, dcont=%d, exc=%d' % (self.icnt, self.dcont, self.is_exception)
|
||||
if self.msg_type == TVAL_SYNC:
|
||||
desc = "Synchronization"
|
||||
extra = ", icnt=%d, dcont=%d" % (self.icnt, self.dcont)
|
||||
desc = 'Synchronization'
|
||||
extra = ', icnt=%d, dcont=%d' % (self.icnt, self.dcont)
|
||||
if self.msg_type == TVAL_CORR:
|
||||
desc = "Correlation"
|
||||
extra = ", icnt=%d" % self.icnt
|
||||
return "%s message, %d packets, PC range 0x%08x - 0x%08x, target PC 0x%08x" % (
|
||||
desc = 'Correlation'
|
||||
extra = ', icnt=%d' % self.icnt
|
||||
return '%s message, %d packets, PC range 0x%08x - 0x%08x, target PC 0x%08x' % (
|
||||
desc, len(self.packets), self.pc_start, self.pc_end, self.pc_target) + extra
|
||||
|
||||
|
||||
@@ -264,7 +265,7 @@ def load_messages(data):
|
||||
# Iterate over the input data, splitting bytes into packets and messages
|
||||
for i, b in enumerate(data):
|
||||
if (b & MSEO_MSGEND) and not (b & MSEO_PKTEND):
|
||||
raise AssertionError("Invalid MSEO bits in b=0x%x. Not a TRAX dump?" % b)
|
||||
raise AssertionError('Invalid MSEO bits in b=0x%x. Not a TRAX dump?' % b)
|
||||
|
||||
if b & MSEO_PKTEND:
|
||||
pkt_cnt += 1
|
||||
@@ -276,7 +277,7 @@ def load_messages(data):
|
||||
try:
|
||||
messages.append(TraxMessage(packets, len(messages) == 0))
|
||||
except NotImplementedError as e:
|
||||
sys.stderr.write("Failed to parse message #%03d (at %d bytes): %s\n" % (msg_cnt, i, str(e)))
|
||||
sys.stderr.write('Failed to parse message #%03d (at %d bytes): %s\n' % (msg_cnt, i, str(e)))
|
||||
packets = []
|
||||
|
||||
# Resolve PC ranges of messages.
|
||||
@@ -312,32 +313,32 @@ def parse_and_dump(filename, disassemble=WITH_GDB):
|
||||
data = f.read()
|
||||
|
||||
messages = load_messages(data)
|
||||
sys.stderr.write("Loaded %d messages in %d bytes\n" % (len(messages), len(data)))
|
||||
sys.stderr.write('Loaded %d messages in %d bytes\n' % (len(messages), len(data)))
|
||||
|
||||
for i, m in enumerate(messages):
|
||||
if m.truncated:
|
||||
continue
|
||||
print("%04d: %s" % (i, str(m)))
|
||||
print('%04d: %s' % (i, str(m)))
|
||||
if m.is_exception:
|
||||
print("*** Exception occurred ***")
|
||||
print('*** Exception occurred ***')
|
||||
if disassemble and WITH_GDB:
|
||||
try:
|
||||
gdb.execute("disassemble 0x%08x, 0x%08x" % (m.pc_start, m.pc_end)) # noqa: F821
|
||||
gdb.execute('disassemble 0x%08x, 0x%08x' % (m.pc_start, m.pc_end)) # noqa: F821
|
||||
except gdb.MemoryError: # noqa: F821
|
||||
print("Failed to disassemble from 0x%08x to 0x%08x" % (m.pc_start, m.pc_end))
|
||||
print('Failed to disassemble from 0x%08x to 0x%08x' % (m.pc_start, m.pc_end))
|
||||
|
||||
|
||||
def main():
|
||||
if sys.version_info[0] < 3:
|
||||
print("WARNING: Support for Python 2 is deprecated and will be removed in future versions.", file=sys.stderr)
|
||||
print('WARNING: Support for Python 2 is deprecated and will be removed in future versions.', file=sys.stderr)
|
||||
elif sys.version_info[0] == 3 and sys.version_info[1] < 6:
|
||||
print("WARNING: Python 3 versions older than 3.6 are not supported.", file=sys.stderr)
|
||||
print('WARNING: Python 3 versions older than 3.6 are not supported.', file=sys.stderr)
|
||||
if len(sys.argv) < 2:
|
||||
sys.stderr.write("Usage: %s <dump_file>\n")
|
||||
sys.stderr.write('Usage: %s <dump_file>\n')
|
||||
raise SystemExit(1)
|
||||
|
||||
parse_and_dump(sys.argv[1])
|
||||
|
||||
|
||||
if __name__ == "__main__" and not WITH_GDB:
|
||||
if __name__ == '__main__' and not WITH_GDB:
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user