66import argparse
77import hashlib
88import datetime
9+ import gzip
910
1011def main ():
1112 parser = argparse .ArgumentParser (description = 'Generate firmware manifest and copy binary' )
@@ -93,24 +94,50 @@ def main():
9394 sys .exit (1 )
9495
9596 # Destination binary name
96- bin_name = f"{ product_id .replace ('/' , '-' )} _firmware_ce_v{ version } .bin"
97- dest_bin = os .path .join (output_dir , bin_name )
97+ merged_bin_name = f"{ product_id .replace ('/' , '-' )} _firmware_ce_v{ version } .bin"
98+ merged_dest_bin = os .path .join (output_dir , merged_bin_name )
9899
99100 # Copy the binary
100- shutil .copy2 (source_bin , dest_bin )
101- print (f"Copied { source_bin } to { dest_bin } " )
101+ shutil .copy2 (source_bin , merged_dest_bin )
102+ print (f"Copied { source_bin } to { merged_dest_bin } " )
102103
103104 # Calculate sha256 of the copied binary
104105 sha256_hash = hashlib .sha256 ()
105- with open (dest_bin , "rb" ) as f :
106+ with open (merged_dest_bin , "rb" ) as f :
106107 for chunk in iter (lambda : f .read (4096 ), b"" ):
107108 sha256_hash .update (chunk )
108- binary_sha256 = sha256_hash .hexdigest ()
109- print (f"SHA256 of { dest_bin } : { binary_sha256 } " )
109+ merged_binary_sha256 = sha256_hash .hexdigest ()
110+ print (f"SHA256 of { merged_dest_bin } : { merged_binary_sha256 } " )
111+
112+ # Handle optional "app" binary which should be compressed and hashed
113+ app_source = os .path .join (
114+ base_dir , 'build' , f"{ product_id .replace ('/' , '_' )} .bin" )
115+ if not os .path .exists (app_source ):
116+ print (f"App binary { app_source } does not exist" )
117+ sys .exit (1 )
118+
119+ ota_filename = f"{ product_id .replace ('/' , '-' )} _ota_ce_v{ version } .bin.gz"
120+ ota_dest = os .path .join (output_dir , ota_filename )
121+
122+ # gzip-compress the app binary
123+ with open (app_source , "rb" ) as src , gzip .open (ota_dest , "wb" ) as dst :
124+ shutil .copyfileobj (src , dst )
125+ print (f"Compressed { app_source } to { ota_dest } " )
126+
127+ # Calculate sha256 of the compressed app
128+ ota_sha256 = hashlib .sha256 ()
129+ with open (ota_dest , "rb" ) as f :
130+ for chunk in iter (lambda : f .read (4096 ), b"" ):
131+ ota_sha256 .update (chunk )
132+ ota_hash = ota_sha256 .hexdigest ()
133+ print (f"SHA256 of { ota_dest } : { ota_hash } " )
110134
111135 # Generate manifest
112136 # timestamp in milliseconds since epoch
113137 timestamp_ms = int (datetime .datetime .utcnow ().timestamp () * 1000 )
138+ # The manifest now includes an optional gzip-compressed "app" binary
139+ # alongside the merged firmware. app_path is the filename (relative to
140+ # output_dir) and app_hash is the SHA256 of the compressed file.
114141
115142 manifest = {
116143 "name" : device_name ,
@@ -119,7 +146,10 @@ def main():
119146 "manufacturer" : manufacturer ,
120147 "compatible" : compatible ,
121148 "version" : version ,
122- "sha256" : binary_sha256 ,
149+ "sha256" : merged_binary_sha256 ,
150+ "ota_filename" : ota_filename ,
151+ "ota_sha256" : ota_hash ,
152+ "merged_filename" : merged_bin_name ,
123153 "timestamp" : timestamp_ms ,
124154 "new_install_prompt_erase" : True ,
125155 "new_install_improv_wait_time" : 0 ,
@@ -128,7 +158,7 @@ def main():
128158 "chipFamily" : chip_family ,
129159 "parts" : [
130160 {
131- "path" : "/firmware/" + bin_name ,
161+ "path" : "/firmware/" + merged_bin_name ,
132162 "offset" : 0
133163 }
134164 ]
0 commit comments