3232import errno
3333
3434MAX_PARTITION_LENGTH = 0xC00 # 3K for partition data (96 entries) leaves 1K in a 4K sector for signature
35- MD5_PARTITION_BEGIN = b"\xEB \xEB " + b"\xFF " * 14 # The first 2 bytes are like magic numbers for MD5 sum
35+ MD5_PARTITION_BEGIN = b"\xEB \xEB " + b"\xFF " * 14 # The first 2 bytes are like magic numbers for MD5 sum
3636PARTITION_TABLE_SIZE = 0x1000 # Size of partition table
3737
3838MIN_PARTITION_SUBTYPE_APP_OTA = 0x10
4444DATA_TYPE = 0x01
4545
4646TYPES = {
47- "app" : APP_TYPE ,
48- "data" : DATA_TYPE ,
47+ "app" : APP_TYPE ,
48+ "data" : DATA_TYPE ,
4949}
5050
5151# Keep this map in sync with esp_partition_subtype_t enum in esp_partition.h
5252SUBTYPES = {
53- APP_TYPE : {
54- "factory" : 0x00 ,
55- "test" : 0x20 ,
53+ APP_TYPE : {
54+ "factory" : 0x00 ,
55+ "test" : 0x20 ,
5656 },
57- DATA_TYPE : {
58- "ota" : 0x00 ,
59- "phy" : 0x01 ,
60- "nvs" : 0x02 ,
61- "coredump" : 0x03 ,
62- "nvs_keys" : 0x04 ,
63- "esphttpd" : 0x80 ,
64- "fat" : 0x81 ,
65- "spiffs" : 0x82 ,
57+ DATA_TYPE : {
58+ "ota" : 0x00 ,
59+ "phy" : 0x01 ,
60+ "nvs" : 0x02 ,
61+ "coredump" : 0x03 ,
62+ "nvs_keys" : 0x04 ,
63+ "esphttpd" : 0x80 ,
64+ "fat" : 0x81 ,
65+ "spiffs" : 0x82 ,
6666 },
6767}
6868
7171secure = False
7272offset_part_table = 0
7373
74+
7475def status (msg ):
7576 """ Print status message to stderr """
7677 if not quiet :
7778 critical (msg )
7879
80+
7981def critical (msg ):
8082 """ Print critical message to stderr """
8183 sys .stderr .write (msg )
8284 sys .stderr .write ('\n ' )
8385
86+
8487class PartitionTable (list ):
8588 def __init__ (self ):
8689 super (PartitionTable , self ).__init__ (self )
@@ -102,15 +105,15 @@ def expand_vars(f):
102105 if line .startswith ("#" ) or len (line ) == 0 :
103106 continue
104107 try :
105- res .append (PartitionDefinition .from_csv (line , line_no + 1 ))
108+ res .append (PartitionDefinition .from_csv (line , line_no + 1 ))
106109 except InputError as e :
107- raise InputError ("Error at line %d: %s" % (line_no + 1 , e ))
110+ raise InputError ("Error at line %d: %s" % (line_no + 1 , e ))
108111 except Exception :
109- critical ("Unexpected error parsing CSV line %d: %s" % (line_no + 1 , line ))
112+ critical ("Unexpected error parsing CSV line %d: %s" % (line_no + 1 , line ))
110113 raise
111114
112115 # fix up missing offsets & negative sizes
113- last_end = offset_part_table + PARTITION_TABLE_SIZE # first offset after partition table
116+ last_end = offset_part_table + PARTITION_TABLE_SIZE # first offset after partition table
114117 for e in res :
115118 if e .offset is not None and e .offset < last_end :
116119 if e == res [0 ]:
@@ -149,14 +152,14 @@ def find_by_type(self, ptype, subtype):
149152 ptype = TYPES [ptype ]
150153 except KeyError :
151154 try :
152- ptypes = int (ptype , 0 )
155+ ptype = int (ptype , 0 )
153156 except TypeError :
154157 pass
155158 try :
156159 subtype = SUBTYPES [int (ptype )][subtype ]
157160 except KeyError :
158161 try :
159- ptypes = int (ptype , 0 )
162+ ptype = int (ptype , 0 )
160163 except TypeError :
161164 pass
162165
@@ -175,26 +178,26 @@ def verify(self):
175178 # verify each partition individually
176179 for p in self :
177180 p .verify ()
178-
181+
179182 # check on duplicate name
180- names = [ p .name for p in self ]
181- duplicates = set ( n for n in names if names .count (n ) > 1 )
182-
183+ names = [p .name for p in self ]
184+ duplicates = set (n for n in names if names .count (n ) > 1 )
185+
183186 # print sorted duplicate partitions by name
184187 if len (duplicates ) != 0 :
185188 print ("A list of partitions that have the same name:" )
186189 for p in sorted (self , key = lambda x :x .name ):
187190 if len (duplicates .intersection ([p .name ])) != 0 :
188191 print ("%s" % (p .to_csv ()))
189192 raise InputError ("Partition names must be unique" )
190-
193+
191194 # check for overlaps
192195 last = None
193196 for p in sorted (self , key = lambda x :x .offset ):
194197 if p .offset < offset_part_table + PARTITION_TABLE_SIZE :
195198 raise InputError ("Partition offset 0x%x is below 0x%x" % (p .offset , offset_part_table + PARTITION_TABLE_SIZE ))
196199 if last is not None and p .offset < last .offset + last .size :
197- raise InputError ("Partition at 0x%x overlaps 0x%x-0x%x" % (p .offset , last .offset , last .offset + last .size - 1 ))
200+ raise InputError ("Partition at 0x%x overlaps 0x%x-0x%x" % (p .offset , last .offset , last .offset + last .size - 1 ))
198201 last = p
199202
200203 def flash_size (self ):
@@ -209,17 +212,17 @@ def flash_size(self):
209212
210213 @classmethod
211214 def from_binary (cls , b ):
212- md5 = hashlib .md5 ();
215+ md5 = hashlib .md5 ()
213216 result = cls ()
214217 for o in range (0 ,len (b ),32 ):
215- data = b [o :o + 32 ]
218+ data = b [o :o + 32 ]
216219 if len (data ) != 32 :
217220 raise InputError ("Partition table length must be a multiple of 32 bytes" )
218- if data == b'\xFF ' * 32 :
221+ if data == b'\xFF ' * 32 :
219222 return result # got end marker
220- if md5sum and data [:2 ] == MD5_PARTITION_BEGIN [:2 ]: # check only the magic number part
223+ if md5sum and data [:2 ] == MD5_PARTITION_BEGIN [:2 ]: # check only the magic number part
221224 if data [16 :] == md5 .digest ():
222- continue # the next iteration will check for the end marker
225+ continue # the next iteration will check for the end marker
223226 else :
224227 raise InputError ("MD5 checksums don't match! (computed: 0x%s, parsed: 0x%s)" % (md5 .hexdigest (), binascii .hexlify (data [16 :])))
225228 else :
@@ -231,29 +234,30 @@ def to_binary(self):
231234 result = b"" .join (e .to_binary () for e in self )
232235 if md5sum :
233236 result += MD5_PARTITION_BEGIN + hashlib .md5 (result ).digest ()
234- if len (result ) >= MAX_PARTITION_LENGTH :
237+ if len (result ) >= MAX_PARTITION_LENGTH :
235238 raise InputError ("Binary partition table length (%d) longer than max" % len (result ))
236239 result += b"\xFF " * (MAX_PARTITION_LENGTH - len (result )) # pad the sector, for signing
237240 return result
238241
239242 def to_csv (self , simple_formatting = False ):
240- rows = [ "# Espressif ESP32 Partition Table" ,
241- "# Name, Type, SubType, Offset, Size, Flags" ]
242- rows += [ x .to_csv (simple_formatting ) for x in self ]
243+ rows = ["# Espressif ESP32 Partition Table" ,
244+ "# Name, Type, SubType, Offset, Size, Flags" ]
245+ rows += [x .to_csv (simple_formatting ) for x in self ]
243246 return "\n " .join (rows ) + "\n "
244247
248+
245249class PartitionDefinition (object ):
246250 MAGIC_BYTES = b"\xAA \x50 "
247251
248252 ALIGNMENT = {
249- APP_TYPE : 0x10000 ,
250- DATA_TYPE : 0x04 ,
253+ APP_TYPE : 0x10000 ,
254+ DATA_TYPE : 0x04 ,
251255 }
252256
253257 # dictionary maps flag name (as used in CSV flags list, property name)
254258 # to bit set in flags words in binary format
255259 FLAGS = {
256- "encrypted" : 0
260+ "encrypted" : 0
257261 }
258262
259263 # add subtypes for the 16 OTA slot values ("ota_XX, etc.")
@@ -272,7 +276,7 @@ def __init__(self):
272276 def from_csv (cls , line , line_no ):
273277 """ Parse a line from the CSV """
274278 line_w_defaults = line + ",,,," # lazy way to support default fields
275- fields = [ f .strip () for f in line_w_defaults .split ("," ) ]
279+ fields = [f .strip () for f in line_w_defaults .split ("," )]
276280
277281 res = PartitionDefinition ()
278282 res .line_no = line_no
@@ -302,7 +306,7 @@ def __repr__(self):
302306 def maybe_hex (x ):
303307 return "0x%x" % x if x is not None else "None"
304308 return "PartitionDefinition('%s', 0x%x, 0x%x, %s, %s)" % (self .name , self .type , self .subtype or 0 ,
305- maybe_hex (self .offset ), maybe_hex (self .size ))
309+ maybe_hex (self .offset ), maybe_hex (self .size ))
306310
307311 def __str__ (self ):
308312 return "Part '%s' %d/%d @ 0x%x size 0x%x" % (self .name , self .type , self .subtype , self .offset or - 1 , self .size or - 1 )
@@ -329,7 +333,7 @@ def parse_type(self, strval):
329333
330334 def parse_subtype (self , strval ):
331335 if strval == "" :
332- return 0 # default
336+ return 0 # default
333337 return parse_int (strval , SUBTYPES .get (self .type , {}))
334338
335339 def parse_address (self , strval ):
@@ -353,12 +357,14 @@ def verify(self):
353357 raise ValidationError (self , "Size field is not set" )
354358
355359 if self .name in TYPES and TYPES .get (self .name , "" ) != self .type :
356- 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 ))
360+ critical ("WARNING: Partition has name '%s' which is a partition type, but does not match this partition's "
361+ "type (0x%x). Mistake in partition table?" % (self .name , self .type ))
357362 all_subtype_names = []
358363 for names in (t .keys () for t in SUBTYPES .values ()):
359364 all_subtype_names += names
360365 if self .name in all_subtype_names and SUBTYPES .get (self .type , {}).get (self .name , "" ) != self .subtype :
361- 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 ))
366+ critical ("WARNING: Partition has name '%s' which is a partition subtype, but this partition has "
367+ "non-matching type 0x%x and subtype 0x%x. Mistake in partition table?" % (self .name , self .type , self .subtype ))
362368
363369 STRUCT_FORMAT = b"<2sBBLL16sL"
364370
@@ -369,21 +375,21 @@ def from_binary(cls, b):
369375 res = cls ()
370376 (magic , res .type , res .subtype , res .offset ,
371377 res .size , res .name , flags ) = struct .unpack (cls .STRUCT_FORMAT , b )
372- if b"\x00 " in res .name : # strip null byte padding from name string
378+ if b"\x00 " in res .name : # strip null byte padding from name string
373379 res .name = res .name [:res .name .index (b"\x00 " )]
374380 res .name = res .name .decode ()
375381 if magic != cls .MAGIC_BYTES :
376382 raise InputError ("Invalid magic bytes (%r) for partition definition" % magic )
377383 for flag ,bit in cls .FLAGS .items ():
378- if flags & (1 << bit ):
384+ if flags & (1 << bit ):
379385 setattr (res , flag , True )
380- flags &= ~ (1 << bit )
386+ flags &= ~ (1 << bit )
381387 if flags != 0 :
382388 critical ("WARNING: Partition definition had unknown flag(s) 0x%08x. Newer binary format?" % flags )
383389 return res
384390
385391 def get_flags_list (self ):
386- return [ flag for flag in self .FLAGS .keys () if getattr (self , flag ) ]
392+ return [flag for flag in self .FLAGS .keys () if getattr (self , flag )]
387393
388394 def to_binary (self ):
389395 flags = sum ((1 << self .FLAGS [flag ]) for flag in self .get_flags_list ())
@@ -397,35 +403,35 @@ def to_binary(self):
397403 def to_csv (self , simple_formatting = False ):
398404 def addr_format (a , include_sizes ):
399405 if not simple_formatting and include_sizes :
400- for (val , suffix ) in [ (0x100000 , "M" ), (0x400 , "K" ) ]:
406+ for (val , suffix ) in [(0x100000 , "M" ), (0x400 , "K" )]:
401407 if a % val == 0 :
402408 return "%d%s" % (a // val , suffix )
403409 return "0x%x" % a
404410
405411 def lookup_keyword (t , keywords ):
406412 for k ,v in keywords .items ():
407- if simple_formatting == False and t == v :
413+ if simple_formatting is False and t == v :
408414 return k
409415 return "%d" % t
410416
411417 def generate_text_flags ():
412418 """ colon-delimited list of flags """
413419 return ":" .join (self .get_flags_list ())
414420
415- return "," .join ([ self .name ,
416- lookup_keyword (self .type , TYPES ),
417- lookup_keyword (self .subtype , SUBTYPES .get (self .type , {})),
418- addr_format (self .offset , False ),
419- addr_format (self .size , True ),
420- generate_text_flags ()])
421+ return "," .join ([self .name ,
422+ lookup_keyword (self .type , TYPES ),
423+ lookup_keyword (self .subtype , SUBTYPES .get (self .type , {})),
424+ addr_format (self .offset , False ),
425+ addr_format (self .size , True ),
426+ generate_text_flags ()])
421427
422428
423429def parse_int (v , keywords = {}):
424430 """Generic parser for integer fields - int(x,0) with provision for
425431 k/m/K/M suffixes and 'keyword' value lookup.
426432 """
427433 try :
428- for letter , multiplier in [ ("k" ,1024 ), ("m" ,1024 * 1024 ) ]:
434+ for letter , multiplier in [("k" , 1024 ), ("m" , 1024 * 1024 )]:
429435 if v .lower ().endswith (letter ):
430436 return parse_int (v [:- 1 ], keywords ) * multiplier
431437 return int (v , 0 )
@@ -437,6 +443,7 @@ def parse_int(v, keywords={}):
437443 except KeyError :
438444 raise InputError ("Value '%s' is not valid. Known keywords: %s" % (v , ", " .join (keywords )))
439445
446+
440447def main ():
441448 global quiet
442449 global md5sum
@@ -445,10 +452,11 @@ def main():
445452 parser = argparse .ArgumentParser (description = 'ESP32 partition table utility' )
446453
447454 parser .add_argument ('--flash-size' , help = 'Optional flash size limit, checks partition table fits in flash' ,
448- nargs = '?' , choices = [ '1MB' , '2MB' , '4MB' , '8MB' , '16MB' ])
455+ nargs = '?' , choices = ['1MB' , '2MB' , '4MB' , '8MB' , '16MB' ])
449456 parser .add_argument ('--disable-md5sum' , help = 'Disable md5 checksum for the partition table' , default = False , action = 'store_true' )
450457 parser .add_argument ('--no-verify' , help = "Don't verify partition table fields" , action = 'store_true' )
451- 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' )
458+ parser .add_argument ('--verify' , '-v' , help = "Verify partition table fields (deprecated, this behaviour is "
459+ "enabled by default and this flag does nothing." , action = 'store_true' )
452460 parser .add_argument ('--quiet' , '-q' , help = "Don't print non-critical status messages to stderr" , action = 'store_true' )
453461 parser .add_argument ('--offset' , '-o' , help = 'Set offset partition table' , default = '0x8000' )
454462 parser .add_argument ('--secure' , help = "Require app partitions to be suitable for secure boot" , action = 'store_true' )
@@ -481,7 +489,8 @@ def main():
481489 size = size_mb * 1024 * 1024 # flash memory uses honest megabytes!
482490 table_size = table .flash_size ()
483491 if size < table_size :
484- raise InputError ("Partitions defined in '%s' occupy %.1fMB of flash (%d bytes) which does not fit in configured flash size %dMB. Change the flash size in menuconfig under the 'Serial Flasher Config' menu." %
492+ raise InputError ("Partitions defined in '%s' occupy %.1fMB of flash (%d bytes) which does not fit in configured "
493+ "flash size %dMB. Change the flash size in menuconfig under the 'Serial Flasher Config' menu." %
485494 (args .input .name , table_size / 1024.0 / 1024.0 , table_size , size_mb ))
486495
487496 # Make sure that the output directory is created
@@ -490,7 +499,7 @@ def main():
490499 if not os .path .exists (output_dir ):
491500 try :
492501 os .makedirs (output_dir )
493- except OSError as exc :
502+ except OSError as exc :
494503 if exc .errno != errno .EEXIST :
495504 raise
496505
0 commit comments