pacgen.py 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242
  1. #!/usr/bin/env python3
  2. # Copyright (C) 2018 RDA Technologies Limited and/or its affiliates("RDA").
  3. # All rights reserved.
  4. #
  5. # This software is supplied "AS IS" without any warranties.
  6. # RDA assumes no responsibility or liability for the use of the software,
  7. # conveys no license or title under any patent, copyright, or mask work
  8. # right to the product. RDA reserves the right to make changes in the
  9. # software without notification. RDA also make no representation or
  10. # warranty that such application will be suitable for the specified use
  11. # without further testing or modification.
  12. import os
  13. import sys
  14. import argparse
  15. import json
  16. import struct
  17. from xml.etree import ElementTree as ET
  18. from xml.dom import minidom
  19. DESCRIPTION = '''
  20. Tool for pac configuration and generation.
  21. '''
  22. RESERVED_UTF16 = "".encode("utf-16le")
  23. RESERVED_BYTE = "".encode("ascii")
  24. PAC_HEADER_FMT = "48sI512s512s7I200s3I800sI2H"
  25. FILE_HEADER_FMT = "I512s512s512s6I5I996s"
  26. CPIO_FILE_FORMAT = '=2s12H{}s{}s'
  27. CPIO_OLDLE_MAGIC = b'\xc7\x71'
  28. ERASE_NV_LOGIC_ADDRESS = 0xFE000001
  29. PHASECHECK_LOGIC_ADDRESS = 0xFE000002
  30. NV_LOGIC_ADDRESS = 0xFE000003
  31. PRE_PACK_FILE_LOGIC_ADDRESS = 0xFE000004
  32. DEL_APPIMG_LOGIC_ADDRESS = 0xFE000005
  33. FMT_FLASH_LOGIC_ADDRESS = 0xFE000006
  34. PHASE_CHECK_SIZE = 0x100
  35. CRC16_TABLE = [
  36. 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
  37. 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
  38. 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
  39. 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
  40. 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
  41. 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
  42. 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
  43. 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
  44. 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
  45. 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
  46. 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
  47. 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
  48. 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
  49. 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
  50. 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
  51. 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
  52. 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
  53. 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
  54. 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
  55. 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
  56. 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
  57. 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
  58. 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
  59. 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
  60. 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
  61. 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
  62. 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
  63. 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
  64. 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
  65. 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
  66. 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
  67. 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
  68. ]
  69. def ensure_dir(dname):
  70. # Create directory if not exists
  71. if dname and not os.path.exists(dname):
  72. os.makedirs(dname)
  73. def write_file_if_change(fname, data):
  74. # Write file if changes, data is bytes
  75. if os.path.exists(fname):
  76. with open(fname, 'rb') as fh:
  77. old_data = fh.read()
  78. if old_data == data:
  79. return
  80. ensure_dir(os.path.dirname(fname))
  81. with open(fname, 'wb') as fh:
  82. fh.write(data)
  83. def calc_crc16(crc_base, s):
  84. ''' calculate/update CRC16 used in pac
  85. '''
  86. for b in s:
  87. crc_base = (crc_base >> 8) ^ (CRC16_TABLE[(crc_base ^ b) & 0xff])
  88. return crc_base
  89. def auto_int(x: str) -> int:
  90. ''' convert decimal or hexdecimal string to integer
  91. '''
  92. return int(x, 0)
  93. def ushort_lo(x: int) -> int:
  94. ''' get the low 16bits of an integer
  95. '''
  96. return int(x) & 0xffff
  97. def ushort_hi(x: int):
  98. ''' get the high 16bits of an integer
  99. '''
  100. return (int(x) >> 16) & 0xffff
  101. class CpioConfig():
  102. ''' CPIO configuration. Internally, there is only a local -> remote
  103. map. Local can be file or directory.
  104. Local path will be normalized:
  105. * all /, without \ (backslash)
  106. * remove duplicated /
  107. Remove path will be normalized:
  108. * all /, without \ (backslash)
  109. * remove duplicated /
  110. * remove leading /
  111. '''
  112. def __init__(self):
  113. self.items = {}
  114. def local_path(self):
  115. ''' All local path, file or directory.
  116. '''
  117. return self.items.keys()
  118. def _insert_path(self, local, remote):
  119. ''' normalize and insert (local, remote)
  120. even local isn't exist, the record will be kept.
  121. '''
  122. local = local.replace('\\', '/').replace('//', '/')
  123. remote = remote.replace('\\', '/').replace('//', '/').lstrip('/')
  124. # special case: when remote is / (root), don't record it
  125. if remote:
  126. self.items[local] = remote
  127. if os.path.isdir(local):
  128. for f in os.listdir(local):
  129. self._insert_path('{}/{}'.format(local, f),
  130. '{}/{}'.format(remote, f))
  131. def add_path(self, local, remote):
  132. ''' Add path, file or directory. When local is directory,
  133. all childrens will be added recursively.
  134. '''
  135. self._insert_path(local, remote)
  136. def _gen_file_data(self, local, remote) -> bytes:
  137. ''' Generate data for one file or directory. The format is:
  138. * magic in short
  139. * 12 short
  140. * remote name with NUL, padding to even length
  141. * file data if exists, padding to even length
  142. '''
  143. name = self.items[local].encode('utf-8')
  144. name_size = len(name) + 1 # include NUL
  145. name_size_aligned = (name_size + 1) & ~1 # pad to even
  146. file_data = bytes()
  147. if os.path.isfile(local):
  148. with open(local, 'rb') as fh:
  149. file_data = fh.read()
  150. file_size = len(file_data)
  151. file_size_aligned = (file_size + 1) & ~1 # pad to even
  152. fstat = os.stat(local)
  153. fmt = CPIO_FILE_FORMAT.format(name_size_aligned, file_size_aligned)
  154. data = struct.pack(fmt,
  155. CPIO_OLDLE_MAGIC,
  156. ushort_lo(fstat.st_dev),
  157. ushort_lo(fstat.st_ino),
  158. ushort_lo(fstat.st_mode),
  159. ushort_lo(fstat.st_uid),
  160. ushort_lo(fstat.st_gid),
  161. ushort_lo(fstat.st_nlink),
  162. 0, # rdevice_num
  163. ushort_hi(fstat.st_mtime),
  164. ushort_lo(fstat.st_mtime),
  165. ushort_lo(name_size),
  166. ushort_hi(file_size),
  167. ushort_lo(file_size),
  168. name,
  169. file_data)
  170. return data
  171. def _gen_trailer(self) -> bytes:
  172. ''' Generate trailer data, for end of cpio.
  173. '''
  174. name = b'TRAILER!!!'
  175. name_size = len(name) + 1
  176. name_size_aligned = (name_size + 1) & ~1
  177. fmt = CPIO_FILE_FORMAT.format(name_size_aligned, 0)
  178. data = struct.pack(fmt,
  179. CPIO_OLDLE_MAGIC,
  180. 0, 0, 0, 0, 0,
  181. 1, 0, 0, 0,
  182. ushort_lo(name_size),
  183. 0, 0,
  184. name,
  185. bytes())
  186. return data
  187. def gen_data(self) -> bytes:
  188. ''' Generate content of cpio, all files and trailer
  189. '''
  190. data = bytes()
  191. for local in sorted(self.items.keys()):
  192. data += self._gen_file_data(local, self.items[local])
  193. data += self._gen_trailer()
  194. return data
  195. class PacNvitemConfig():
  196. ''' nvitem configuration. It will be easier to be accessed than dict
  197. '''
  198. def __init__(self, name: str, id: int, use: int, replace: int, cont: int, backup: int):
  199. self.name = name
  200. self.ID = id
  201. self.use = use
  202. self.replace = replace
  203. self.cont = cont
  204. self.backup = backup
  205. class PacFileConfig():
  206. ''' pac file configuration, bunch of information. Inherit isn't
  207. used, rathe cfgType indicates the type. And if-else shall
  208. be used for different file type.
  209. File header will use:
  210. * szFileID
  211. * szFileName
  212. * dwFileFlag
  213. * defaultCheck
  214. * dwCanOmitFlag
  215. XML block will use:
  216. * szFileID
  217. * type
  218. * dwAddress
  219. * fixedSize
  220. * dwFileFlag
  221. * forceCheck
  222. * description
  223. '''
  224. PLAIN_FILE = 1 # there is a normal local file
  225. EMPTY_FILE = 2 # there are no file content
  226. XML_FILE = 3 # special type for the generated XML
  227. PACK_FILE = 4 # pack one file or directory with cpio
  228. def __init__(self):
  229. self.content = None
  230. def set_plain_file(self, type: str, szFileID: str, description: str,
  231. dwCanOmitFlag: int, defaultCheck: int, forceCheck: int,
  232. dwAddress: int, fixedSize: int,
  233. filePath: str, szFileName: str):
  234. ''' set plain file properties
  235. '''
  236. self.cfgType = self.PLAIN_FILE
  237. self.type = type
  238. self.szFileID = szFileID
  239. self.description = description
  240. self.dwFileFlag = 1
  241. self.dwCanOmitFlag = dwCanOmitFlag
  242. self.defaultCheck = defaultCheck
  243. self.forceCheck = forceCheck
  244. self.dwAddress = dwAddress
  245. self.fixedSize = fixedSize
  246. self.filePath = filePath
  247. self.szFileName = szFileName
  248. def set_empty_file(self, type: str, szFileID: str, description: str,
  249. dwCanOmitFlag: int, defaultCheck: int, forceCheck: int,
  250. dwAddress: int, fixedSize: int):
  251. ''' set empty file properties
  252. '''
  253. self.cfgType = self.EMPTY_FILE
  254. self.type = type
  255. self.szFileID = szFileID
  256. self.description = description
  257. self.dwFileFlag = 0
  258. self.dwCanOmitFlag = dwCanOmitFlag
  259. self.defaultCheck = defaultCheck
  260. self.forceCheck = forceCheck
  261. self.dwAddress = dwAddress
  262. self.fixedSize = fixedSize
  263. self.szFileName = ''
  264. def set_xml_file(self, szPrdName: str, xml_data: bytes):
  265. ''' set xml file properties
  266. '''
  267. self.cfgType = self.XML_FILE
  268. self.szFileID = ''
  269. self.szFileName = '{}.xml'.format(szPrdName)
  270. self.dwFileFlag = 2
  271. self.defaultCheck = 0
  272. self.dwCanOmitFlag = 0
  273. self.dwAddress = 0
  274. self.content = xml_data
  275. def set_pack_file(self, szFileID: str, description: str,
  276. dwCanOmitFlag: int, defaultCheck: int, forceCheck: int,
  277. filePath: str, remotePath: str):
  278. ''' set pack file or directory properties
  279. '''
  280. self.cfgType = self.PACK_FILE
  281. self.type = 'CODE'
  282. self.szFileID = szFileID
  283. self.description = description
  284. self.dwFileFlag = 1
  285. self.dwCanOmitFlag = dwCanOmitFlag
  286. self.defaultCheck = defaultCheck
  287. self.forceCheck = forceCheck
  288. self.dwAddress = PRE_PACK_FILE_LOGIC_ADDRESS
  289. self.fixedSize = 0
  290. self.filePath = filePath
  291. self.szFileName = '{}.cpio'.format(szFileID)
  292. self.remotePath = remotePath
  293. self.cpioConfig = CpioConfig()
  294. self.cpioConfig.add_path(self.filePath, self.remotePath)
  295. def dep_files(self):
  296. ''' Get the used local files or directories (in cpio).
  297. '''
  298. flist = []
  299. if self.cfgType == self.PLAIN_FILE:
  300. flist.append(self.filePath)
  301. elif self.cfgType == self.PACK_FILE:
  302. flist.extend(self.cpioConfig.local_path())
  303. return flist
  304. def _prepare_content(self):
  305. ''' Prepare pac file content.
  306. '''
  307. if self.cfgType == self.PLAIN_FILE:
  308. with open(self.filePath, 'rb') as fh:
  309. self.content = fh.read()
  310. elif self.cfgType == self.EMPTY_FILE:
  311. self.content = bytes()
  312. elif self.cfgType == self.PACK_FILE:
  313. self.content = self.cpioConfig.gen_data()
  314. def _file_size(self) -> int:
  315. ''' Size in pac
  316. '''
  317. if self.content is None:
  318. self._prepare_content()
  319. return len(self.content)
  320. def file_data(self):
  321. ''' Data in pac
  322. '''
  323. if self.content is None:
  324. self._prepare_content()
  325. return self.content
  326. def file_header(self, offset: int):
  327. ''' Header in pac. Offset will be embeded into header, and it is
  328. not a file property. So, it is a parameter.
  329. '''
  330. return struct.pack(
  331. FILE_HEADER_FMT,
  332. struct.calcsize(FILE_HEADER_FMT),
  333. self.szFileID.encode('utf-16le'),
  334. self.szFileName.encode('utf-16le'),
  335. RESERVED_UTF16,
  336. self._file_size(),
  337. self.dwFileFlag,
  338. self.defaultCheck,
  339. offset,
  340. self.dwCanOmitFlag,
  341. 1,
  342. self.dwAddress, 0, 0, 0, 0,
  343. RESERVED_BYTE)
  344. class PacConfig():
  345. ''' configuration for PAC
  346. '''
  347. def __init__(self):
  348. self.dwNandStrategy = 1
  349. self.dwNandPageType = 0
  350. self.nvitems = []
  351. self.files = []
  352. def load_from_json(self, fname: str):
  353. ''' Load pac configuration from json. Json format should
  354. match store.
  355. '''
  356. with open(fname, 'r') as fh:
  357. cfg = json.load(fh)
  358. self.szVersion = cfg['szVersion']
  359. self.szPrdName = cfg['szPrdName']
  360. self.szPrdVersion = cfg['szPrdVersion']
  361. self.szPrdAlias = cfg['szPrdAlias']
  362. self.dwMode = cfg['dwMode']
  363. self.rebootByAt = cfg['rebootByAt']
  364. self.dwFlashType = cfg['dwFlashType']
  365. self.dwIsNvBackup = cfg['dwIsNvBackup']
  366. self.dwOmaDmProductFlag = cfg['dwOmaDmProductFlag']
  367. self.dwIsOmaDm = cfg['dwIsOmaDm']
  368. self.dwIsPreload = cfg['dwIsPreload']
  369. for f in cfg.get('NVItem', []):
  370. nc = PacNvitemConfig(f['name'],
  371. int(f['ID'], 16),
  372. f['use'],
  373. f['Replace'],
  374. f['Continue'],
  375. f['backup'])
  376. self.nvitems.append(nc)
  377. for f in cfg.get('pacFiles', []):
  378. fc = PacFileConfig()
  379. if f['cfgType'] == 'PLAIN_FILE':
  380. fc.set_plain_file(f['type'],
  381. f['szFileID'],
  382. f['description'],
  383. f['dwCanOmitFlag'],
  384. f['defaultCheck'],
  385. f['forceCheck'],
  386. int(f['dwAddress'], 16),
  387. int(f['fixedSize'], 16),
  388. f['filePath'],
  389. f['szFileName'])
  390. elif f['cfgType'] == 'EMPTY_FILE':
  391. fc.set_empty_file(f['type'],
  392. f['szFileID'],
  393. f['description'],
  394. f['dwCanOmitFlag'],
  395. f['defaultCheck'],
  396. f['forceCheck'],
  397. int(f['dwAddress'], 16),
  398. int(f['fixedSize'], 16))
  399. elif f['cfgType'] == 'PACK_FILE':
  400. fc.set_pack_file(f['szFileID'],
  401. f['description'],
  402. f['dwCanOmitFlag'],
  403. f['defaultCheck'],
  404. f['forceCheck'],
  405. f['filePath'],
  406. f['remotePath'])
  407. self.files.append(fc)
  408. def store_to_json(self, fname: str):
  409. ''' Store pac configuration to json. Json format should
  410. match load.
  411. '''
  412. cfg = {}
  413. cfg['szVersion'] = self.szVersion
  414. cfg['szPrdName'] = self.szPrdName
  415. cfg['szPrdVersion'] = self.szPrdVersion
  416. cfg['szPrdAlias'] = self.szPrdAlias
  417. cfg['dwMode'] = self.dwMode
  418. cfg['rebootByAt'] = self.rebootByAt
  419. cfg['dwFlashType'] = self.dwFlashType
  420. cfg['dwIsNvBackup'] = self.dwIsNvBackup
  421. cfg['dwOmaDmProductFlag'] = self.dwOmaDmProductFlag
  422. cfg['dwIsOmaDm'] = self.dwIsOmaDm
  423. cfg['dwIsPreload'] = self.dwIsPreload
  424. cfg['NVItem'] = []
  425. for nc in self.nvitems:
  426. f = {}
  427. f['name'] = nc.name
  428. f['ID'] = hex(nc.ID)
  429. f['use'] = nc.use
  430. f['Replace'] = nc.replace
  431. f['Continue'] = nc.cont
  432. f['backup'] = nc.backup
  433. cfg['NVItem'].append(f)
  434. cfg['pacFiles'] = []
  435. for fc in self.files:
  436. if fc.cfgType == fc.XML_FILE:
  437. continue
  438. f = {}
  439. if fc.cfgType == fc.PLAIN_FILE:
  440. f['cfgType'] = 'PLAIN_FILE'
  441. f['type'] = fc.type
  442. f['szFileID'] = fc.szFileID
  443. f['description'] = fc.description
  444. f['dwCanOmitFlag'] = fc.dwCanOmitFlag
  445. f['defaultCheck'] = fc.defaultCheck
  446. f['forceCheck'] = fc.forceCheck
  447. f['dwAddress'] = hex(fc.dwAddress)
  448. f['fixedSize'] = hex(fc.fixedSize)
  449. f['filePath'] = fc.filePath
  450. f['szFileName'] = fc.szFileName
  451. elif fc.cfgType == fc.EMPTY_FILE:
  452. f['cfgType'] = 'EMPTY_FILE'
  453. f['type'] = fc.type
  454. f['szFileID'] = fc.szFileID
  455. f['description'] = fc.description
  456. f['dwCanOmitFlag'] = fc.dwCanOmitFlag
  457. f['defaultCheck'] = fc.defaultCheck
  458. f['forceCheck'] = fc.forceCheck
  459. f['dwAddress'] = hex(fc.dwAddress)
  460. f['fixedSize'] = hex(fc.fixedSize)
  461. elif fc.cfgType == fc.PACK_FILE:
  462. f['cfgType'] = 'PACK_FILE'
  463. f['type'] = fc.type
  464. f['szFileID'] = fc.szFileID
  465. f['description'] = fc.description
  466. f['dwCanOmitFlag'] = fc.dwCanOmitFlag
  467. f['defaultCheck'] = fc.defaultCheck
  468. f['forceCheck'] = fc.forceCheck
  469. f['filePath'] = fc.filePath
  470. f['remotePath'] = fc.remotePath
  471. cfg['pacFiles'].append(f)
  472. with open(fname, 'w') as fh:
  473. json.dump(cfg, fh, indent=4, sort_keys=True)
  474. def add_nvitem(self, name: str, id: int, use: int, replace: int, cont: int, backup: int):
  475. ''' Add backup nvitem.
  476. '''
  477. nc = PacNvitemConfig(name, id, use, replace, cont, backup)
  478. self.nvitems.append(nc)
  479. self.dwIsNvBackup = 1
  480. def add_host_fdl(self, address: int, size: int, filePath: str, szFileName: str):
  481. ''' Add HOST_FDL pac file
  482. '''
  483. fc = PacFileConfig()
  484. fc.set_plain_file('HOST_FDL', 'HOST_FDL', 'HOST_FDL',
  485. 0, 1, 1,
  486. address, size, filePath, szFileName)
  487. self.files.append(fc)
  488. def add_fdl2(self, address: int, size: int, filePath: str, szFileName: str):
  489. ''' Add FDL2 pac file
  490. '''
  491. fc = PacFileConfig()
  492. fc.set_plain_file('FDL2', 'FDL2', 'FDL2',
  493. 0, 1, 1,
  494. address, size, filePath, szFileName)
  495. self.files.append(fc)
  496. def add_fdl(self, address: int, size: int, filePath: str, szFileName: str):
  497. ''' Add FDL pac file
  498. '''
  499. fc = PacFileConfig()
  500. fc.set_plain_file('FDL', 'FDL', 'FDL',
  501. 0, 1, 1,
  502. address, size, filePath, szFileName)
  503. self.files.append(fc)
  504. def add_code(self, szFileID: str, description: str, dwCanOmitFlag: int,
  505. defaultCheck: int, forceCheck: int, address: int, size: int,
  506. filePath: str, szFileName: str):
  507. ''' Add generic code pac file.
  508. '''
  509. fc = PacFileConfig()
  510. fc.set_plain_file('CODE', szFileID, description,
  511. dwCanOmitFlag, defaultCheck, forceCheck,
  512. address, size, filePath, szFileName)
  513. self.files.append(fc)
  514. def add_clear_nv(self):
  515. ''' Add clear NV operation.
  516. '''
  517. fc = PacFileConfig()
  518. fc.set_empty_file('EraseFlash', 'FLASH', 'Erase NV',
  519. 1, 1, 0, ERASE_NV_LOGIC_ADDRESS, 0x0)
  520. self.files.append(fc)
  521. def add_erase_flash(self, szFileID: str, address: int, size: int, defcheck: bool):
  522. ''' Add clear flash operation.
  523. '''
  524. fc = PacFileConfig()
  525. fc.set_empty_file('EraseFlash', szFileID, 'Erase flash',
  526. 1, defcheck, 0, address, size)
  527. self.files.append(fc)
  528. def add_del_appimg(self, szFileID: str):
  529. ''' Add delete appimg file operation.
  530. '''
  531. fc = PacFileConfig()
  532. fc.set_empty_file('EraseFlash', szFileID, 'Delete appimg file',
  533. 1, 1, 0, DEL_APPIMG_LOGIC_ADDRESS, 0)
  534. self.files.append(fc)
  535. def add_nv(self, size: int, filePath: str, szFileName: str):
  536. ''' Add NV download operation.
  537. '''
  538. fc = PacFileConfig()
  539. fc.set_plain_file('NV', 'NV', 'NV',
  540. 1, 1, 0,
  541. NV_LOGIC_ADDRESS, size, filePath, szFileName)
  542. self.files.append(fc)
  543. def add_phase_check(self):
  544. ''' Add phase check operation.
  545. '''
  546. fc = PacFileConfig()
  547. fc.set_empty_file('CODE', 'PhaseCheck', 'Producting phases information section',
  548. 1, 1, 0, PHASECHECK_LOGIC_ADDRESS, PHASE_CHECK_SIZE)
  549. self.files.append(fc)
  550. def add_pack_file(self, szFileID: str, description: str, dwCanOmitFlag: int,
  551. defaultCheck: int, forceCheck: int,
  552. filePath: str, remotePath: str):
  553. ''' Add pack one file or directory operation.
  554. '''
  555. fc = PacFileConfig()
  556. fc.set_pack_file(szFileID, description,
  557. dwCanOmitFlag, defaultCheck, forceCheck,
  558. filePath, remotePath)
  559. self.files.append(fc)
  560. def add_pack_cpio(self, szFileID: str, description: str, dwCanOmitFlag: int,
  561. defaultCheck: int, forceCheck: int,
  562. filePath: str, szFileName: str):
  563. ''' Add pre-generated cpio operation.
  564. '''
  565. fc = PacFileConfig()
  566. fc.set_plain_file('CODE', szFileID, description,
  567. dwCanOmitFlag, defaultCheck, forceCheck,
  568. PRE_PACK_FILE_LOGIC_ADDRESS, 0x0, filePath, szFileName)
  569. self.files.append(fc)
  570. def dep_files(self):
  571. ''' Get the used local files or directories (in cpio).
  572. '''
  573. flist = []
  574. for f in self.files:
  575. flist.extend(f.dep_files())
  576. return flist
  577. def _create_xml(self):
  578. ''' Create embeded XML
  579. '''
  580. root = ET.Element("BMAConfig")
  581. # ProductList
  582. product_list = ET.SubElement(root, "ProductList")
  583. # ProductList -> Product
  584. product = ET.SubElement(product_list, "Product",
  585. {"name": self.szPrdName})
  586. ET.SubElement(product, "SchemeName").text = self.szPrdName
  587. ET.SubElement(product, "RebootByAT").text = str(self.rebootByAt)
  588. ET.SubElement(product, "FlashTypeID").text = str(self.dwFlashType)
  589. ET.SubElement(product, "Mode").text = str(self.dwMode)
  590. NVBackup = ET.SubElement(product, "NVBackup",
  591. backup=str(self.dwIsNvBackup))
  592. for nc in self.nvitems:
  593. NVItem = ET.SubElement(NVBackup, "NVItem",
  594. name=nc.name, backup=str(nc.backup))
  595. ET.SubElement(NVItem, "ID").text = hex(nc.ID)
  596. BackupFlag = ET.SubElement(NVItem, "BackupFlag", use=str(nc.use))
  597. if nc.replace:
  598. ET.SubElement(BackupFlag, "NVFlag",
  599. name="Replace", check=str(nc.replace))
  600. if nc.cont:
  601. ET.SubElement(BackupFlag, "NVFlag",
  602. name="Continue", check=str(nc.cont))
  603. prod_chips = ET.SubElement(product, "Chips", {"enable": "0"})
  604. ET.SubElement(prod_chips, "ChipItem", {"id": "0x2222", "name": "L2"})
  605. ET.SubElement(prod_chips, "ChipItem", {"id": "0x7777", "name": "L7"})
  606. # SchemeList
  607. scheme_list = ET.SubElement(root, "SchemeList")
  608. # SchemeList -> Scheme
  609. scheme = ET.SubElement(scheme_list, "Scheme", {
  610. "name": self.szPrdName})
  611. for fc in self.files:
  612. if fc.cfgType == fc.XML_FILE:
  613. continue
  614. sf = ET.SubElement(scheme, "File")
  615. ET.SubElement(sf, "ID").text = fc.szFileID
  616. ET.SubElement(sf, "IDAlias").text = fc.szFileID
  617. ET.SubElement(sf, "Type").text = fc.type
  618. block = ET.SubElement(sf, "Block")
  619. ET.SubElement(block, "Base").text = hex(fc.dwAddress)
  620. ET.SubElement(block, "Size").text = hex(fc.fixedSize)
  621. ET.SubElement(sf, "Flag").text = str(fc.dwFileFlag)
  622. ET.SubElement(sf, "CheckFlag").text = str(fc.forceCheck)
  623. ET.SubElement(sf, "Description").text = fc.description
  624. xml_string = ET.tostring(root, encoding='utf8', method='xml')
  625. return minidom.parseString(xml_string).toprettyxml(encoding='utf-8', newl='\r\n')
  626. def pac_gen(self, fname):
  627. ''' Generate pac, and write to file.
  628. '''
  629. # append xml to the file list
  630. fc = PacFileConfig()
  631. fc.set_xml_file(self.szPrdName, self._create_xml())
  632. files = self.files
  633. files.append(fc)
  634. # generate header and data of all files
  635. files_header = []
  636. files_data = []
  637. # offset is moving, always for the current file to be handled.
  638. file_count = len(files)
  639. offset = struct.calcsize(PAC_HEADER_FMT) + \
  640. file_count * struct.calcsize(FILE_HEADER_FMT)
  641. for fc in self.files:
  642. fheader = fc.file_header(offset)
  643. fdata = fc.file_data()
  644. offset += len(fdata)
  645. files_header.append(fheader)
  646. files_data.append(fdata)
  647. # After all files are handled, offset is just the whole pac size
  648. pac_size = offset
  649. file_offset = struct.calcsize(PAC_HEADER_FMT)
  650. magic = 0xFFFAFFFA
  651. header_no_crc = struct.pack(
  652. PAC_HEADER_FMT[:-2],
  653. self.szVersion.encode('utf-16le'),
  654. pac_size,
  655. self.szPrdName.encode('utf-16le'),
  656. self.szPrdVersion.encode('utf-16le'),
  657. file_count,
  658. file_offset,
  659. self.dwMode,
  660. self.dwFlashType,
  661. self.dwNandStrategy,
  662. self.dwIsNvBackup,
  663. self.dwNandPageType,
  664. self.szPrdAlias.encode('utf-16le'),
  665. self.dwOmaDmProductFlag,
  666. self.dwIsOmaDm,
  667. self.dwIsPreload,
  668. RESERVED_BYTE,
  669. magic)
  670. crc1 = calc_crc16(0, header_no_crc)
  671. crc2 = 0
  672. for d in files_header:
  673. crc2 = calc_crc16(crc2, d)
  674. for d in files_data:
  675. crc2 = calc_crc16(crc2, d)
  676. header = struct.pack(
  677. PAC_HEADER_FMT,
  678. self.szVersion.encode('utf-16le'),
  679. pac_size,
  680. self.szPrdName.encode('utf-16le'),
  681. self.szPrdVersion.encode('utf-16le'),
  682. file_count,
  683. file_offset,
  684. self.dwMode,
  685. self.dwFlashType,
  686. self.dwNandStrategy,
  687. self.dwIsNvBackup,
  688. self.dwNandPageType,
  689. self.szPrdAlias.encode('utf-16le'),
  690. self.dwOmaDmProductFlag,
  691. self.dwIsOmaDm,
  692. self.dwIsPreload,
  693. RESERVED_BYTE,
  694. magic,
  695. crc1,
  696. crc2)
  697. with open(fname, 'wb') as fh:
  698. fh.write(header)
  699. [fh.write(x) for x in files_header]
  700. [fh.write(x) for x in files_data]
  701. # Global PacConfig
  702. pc = PacConfig()
  703. def cfg_init(args):
  704. global pc
  705. pc.szVersion = args.version
  706. pc.szPrdName = args.pname
  707. pc.szPrdVersion = args.pversion
  708. pc.szPrdAlias = args.palias
  709. pc.dwMode = args.mode
  710. pc.rebootByAt = args.rebootat
  711. pc.dwFlashType = args.flashtype
  712. pc.dwIsNvBackup = 0
  713. pc.dwOmaDmProductFlag = args.productflag
  714. pc.dwIsOmaDm = args.omadm
  715. pc.dwIsPreload = args.preload
  716. return 0
  717. def cfg_nvitem(args):
  718. global pc
  719. pc.add_nvitem(args.name, int(args.id, 16),
  720. args.use, args.replace, args.cont, args.backup)
  721. return 0
  722. def cfg_host_fdl(args):
  723. name = args.name if args.name else os.path.basename(args.path)
  724. global pc
  725. pc.add_host_fdl(args.address, args.size, args.path, name)
  726. return 0
  727. def cfg_fdl2(args):
  728. name = args.name if args.name else os.path.basename(args.path)
  729. global pc
  730. pc.add_fdl2(args.address, args.size, args.path, name)
  731. return 0
  732. def cfg_fdl(args):
  733. name = args.name if args.name else os.path.basename(args.path)
  734. global pc
  735. pc.add_fdl(args.address, args.size, args.path, name)
  736. return 0
  737. def cfg_image(args):
  738. name = args.name if args.name else os.path.basename(args.path)
  739. desc = args.desc if args.desc else args.id
  740. global pc
  741. image_size = os.path.getsize(args.path)
  742. if image_size == 0:
  743. return 0 # ignore when the file is empty
  744. if image_size > args.size:
  745. raise Exception('image size is too large %d/%d %s' % (image_size, args.size, name))
  746. pc.add_code(args.id, desc, args.can_omit, args.default_check,
  747. args.force_check, args.address, args.size,
  748. args.path, name)
  749. return 0
  750. def cfg_clear_nv(args):
  751. global pc
  752. pc.add_clear_nv()
  753. return 0
  754. def cfg_erase_flash(args):
  755. global pc
  756. pc.add_erase_flash(args.id, args.address, args.size, not args.nocheck)
  757. return 0
  758. def cfg_fmt_flash(args):
  759. if len(args.bname) != 4:
  760. print('block device name should be 4 characters')
  761. return -1
  762. global pc
  763. size = struct.unpack('I', args.bname.encode('utf-8'))
  764. pc.add_erase_flash(args.id, FMT_FLASH_LOGIC_ADDRESS, size[0], not args.nocheck)
  765. return 0
  766. def cfg_del_appimg(args):
  767. global pc
  768. pc.add_del_appimg(args.id)
  769. return 0
  770. def cfg_phase_check(args):
  771. global pc
  772. pc.add_phase_check()
  773. return 0
  774. def cfg_nv(args):
  775. name = args.name if args.name else os.path.basename(args.path)
  776. global pc
  777. pc.add_nv(args.size, args.path, name)
  778. return 0
  779. def cfg_pack_file(args):
  780. name = args.name if args.name else os.path.basename(args.path)
  781. desc = args.desc if args.desc else args.id
  782. global pc
  783. pc.add_pack_file(args.id, desc, args.can_omit, args.default_check,
  784. args.force_check, args.path, name)
  785. return 0
  786. def cfg_pack_cpio(args):
  787. name = args.name if args.name else os.path.basename(args.path)
  788. desc = args.desc if args.desc else args.id
  789. global pc
  790. if os.path.getsize(args.path) == 0:
  791. return 0 # ignore when the file is empty
  792. pc.add_pack_cpio(args.id, desc, args.can_omit, args.default_check,
  793. args.force_check, args.path, name)
  794. return 0
  795. def dep_gen(args):
  796. global pc
  797. flist = pc.dep_files()
  798. flist.append(__file__)
  799. dep = '{}: {}\n'.format(os.path.relpath(args.target, args.base),
  800. ' '.join([os.path.relpath(x, args.base) for x in flist]))
  801. write_file_if_change(args.output, dep.encode('utf-8'))
  802. return 0
  803. def pac_gen(args):
  804. global pc
  805. if args.cfg:
  806. pc.store_to_json(args.cfg)
  807. pc.pac_gen(args.fname)
  808. return 0
  809. def cfg_init_args(sub_parsers):
  810. parser = sub_parsers.add_parser('cfg-init', help='init configuration')
  811. parser.set_defaults(func=cfg_init)
  812. parser.add_argument('--pname', dest='pname', required=True,
  813. help='product name')
  814. parser.add_argument('--palias', dest='palias', required=True,
  815. help='product alias')
  816. parser.add_argument('--pversion', dest='pversion', required=True,
  817. help='product version')
  818. parser.add_argument('--version', dest='version', required=True,
  819. help='version string')
  820. parser.add_argument('--rebootat', dest='rebootat',
  821. type=int, choices=[0, 1], default=1)
  822. parser.add_argument('--flashtype', dest='flashtype',
  823. type=int, required=True)
  824. parser.add_argument('--mode', dest='mode', type=int, default=0)
  825. parser.add_argument('--productflag', dest='productflag',
  826. type=int, choices=[0, 1], default=0)
  827. parser.add_argument('--omadm', dest='omadm',
  828. type=int, choices=[0, 1], default=1)
  829. parser.add_argument('--preload', dest='preload',
  830. type=int, choices=[0, 1], default=1)
  831. def cfg_nvitem_args(sub_parsers):
  832. parser = sub_parsers.add_parser('cfg-nvitem', help='add backup nvitem')
  833. parser.set_defaults(func=cfg_nvitem)
  834. parser.add_argument('-n', '--name', dest='name', required=True,
  835. help='nvitem name, for display')
  836. parser.add_argument('-i', '--id', dest='id', required=True,
  837. help='NV id')
  838. parser.add_argument('--use', dest='use', type=int, choices=[0, 1], default=1,
  839. help='nvitem use flag')
  840. parser.add_argument('--replace', dest='replace', type=int, choices=[0, 1], default=0,
  841. help='nvitem replace flag')
  842. parser.add_argument('--continue', dest='cont', type=int, choices=[0, 1], required=True,
  843. help='nvitem replace flag')
  844. parser.add_argument('--backup', dest='backup', type=int, choices=[0, 1], default=1,
  845. help='nvitem backup flag')
  846. def cfg_host_fdl_args(sub_parsers):
  847. parser = sub_parsers.add_parser(
  848. 'cfg-host-fdl', help='add fdl through 8910 ROM protocol')
  849. parser.set_defaults(func=cfg_host_fdl)
  850. parser.add_argument('-a', '--address', dest='address', type=auto_int, required=True,
  851. help='host fdl load address')
  852. parser.add_argument('-s', '--size', dest='size', type=auto_int, required=True,
  853. help='host fdl size')
  854. parser.add_argument('-p', '--path', dest='path', required=True,
  855. help='local host fdl image file path')
  856. parser.add_argument('-n', '--name', dest='name', default=None,
  857. help='host fdl image file name in pac')
  858. def cfg_fdl2_args(sub_parsers):
  859. parser = sub_parsers.add_parser(
  860. 'cfg-fdl2', help='add fdl2')
  861. parser.set_defaults(func=cfg_fdl2)
  862. parser.add_argument('-a', '--address', dest='address', type=auto_int, required=True,
  863. help='fdl2 load address')
  864. parser.add_argument('-s', '--size', dest='size', type=auto_int, required=True,
  865. help='fdl2 size')
  866. parser.add_argument('-p', '--path', dest='path', required=True,
  867. help='local fdl2 image file path')
  868. parser.add_argument('-n', '--name', dest='name', default=None,
  869. help='fdl2 image file name in pac')
  870. def cfg_fdl_args(sub_parsers):
  871. parser = sub_parsers.add_parser(
  872. 'cfg-fdl', help='add fdl')
  873. parser.set_defaults(func=cfg_fdl)
  874. parser.add_argument('-a', '--address', dest='address', type=auto_int, required=True,
  875. help='fdl load address')
  876. parser.add_argument('-s', '--size', dest='size', type=auto_int, required=True,
  877. help='fdl size')
  878. parser.add_argument('-p', '--path', dest='path', required=True,
  879. help='local fdl image file path')
  880. parser.add_argument('-n', '--name', dest='name', default=None,
  881. help='fdl image file name in pac')
  882. def cfg_image_args(sub_parsers):
  883. parser = sub_parsers.add_parser(
  884. 'cfg-image', help='add image')
  885. parser.set_defaults(func=cfg_image)
  886. parser.add_argument('-i', '--id', dest='id', required=True,
  887. help='file ID in pac')
  888. parser.add_argument('-d', '--desc', dest='desc', default=None,
  889. help='file description in pac')
  890. parser.add_argument('--can-omit', dest='can_omit',
  891. type=int, choices=[0, 1], default=0,
  892. help='file can omit flag in pac')
  893. parser.add_argument('--default-check', dest='default_check',
  894. type=int, choices=[0, 1], default=1,
  895. help='file default check flag in pac')
  896. parser.add_argument('--force-check', dest='force_check',
  897. type=int, choices=[0, 1], default=0,
  898. help='file force check flag in pac')
  899. parser.add_argument('-a', '--address', dest='address', type=auto_int, required=True,
  900. help='image load address')
  901. parser.add_argument('-s', '--size', dest='size', type=auto_int, required=True,
  902. help='image size')
  903. parser.add_argument('-p', '--path', dest='path', required=True,
  904. help='local image file path')
  905. parser.add_argument('-n', '--name', dest='name', default=None,
  906. help='image file name in pac')
  907. def cfg_clear_nv_args(sub_parsers):
  908. parser = sub_parsers.add_parser(
  909. 'cfg-clear-nv', help='add erase running NV')
  910. parser.set_defaults(func=cfg_clear_nv)
  911. def cfg_erase_flash_args(sub_parsers):
  912. parser = sub_parsers.add_parser(
  913. 'cfg-erase-flash', help='add erase flash')
  914. parser.set_defaults(func=cfg_erase_flash)
  915. parser.add_argument('-i', '--id', dest='id', required=True,
  916. help='file ID in pac')
  917. parser.add_argument('-a', '--address', dest='address', type=auto_int, required=True,
  918. help='erase flash start address')
  919. parser.add_argument('-s', '--size', dest='size', type=auto_int, required=True,
  920. help='erase flash size')
  921. parser.add_argument('-n', '--nocheck', dest='nocheck', action='store_true',
  922. help='not check by default')
  923. def cfg_fmt_flash_args(sub_parsers):
  924. parser = sub_parsers.add_parser(
  925. 'cfg-fmt-flash', help='add format flash file system')
  926. parser.set_defaults(func=cfg_fmt_flash)
  927. parser.add_argument('-i', '--id', dest='id', required=True,
  928. help='file ID in pac')
  929. parser.add_argument('-b', '--block-device-name', dest='bname', required=True,
  930. help='flash block device name')
  931. parser.add_argument('-n', '--nocheck', dest='nocheck', action='store_true',
  932. help='not check by default')
  933. def cfg_del_appimg_args(sub_parsers):
  934. parser = sub_parsers.add_parser(
  935. 'cfg-del-appimg', help='add delete appimg file')
  936. parser.set_defaults(func=cfg_del_appimg)
  937. parser.add_argument('-i', '--id', dest='id', required=True,
  938. help='file ID in pac')
  939. def cfg_phase_check_args(sub_parsers):
  940. parser = sub_parsers.add_parser(
  941. 'cfg-phase-check', help='add phase check')
  942. parser.set_defaults(func=cfg_phase_check)
  943. def cfg_nv_args(sub_parsers):
  944. parser = sub_parsers.add_parser(
  945. 'cfg-nv', help='add NV download')
  946. parser.set_defaults(func=cfg_nv)
  947. parser.add_argument('-s', '--size', dest='size', type=auto_int, required=True,
  948. help='host fdl size')
  949. parser.add_argument('-p', '--path', dest='path', required=True,
  950. help='local host fdl image file path')
  951. parser.add_argument('-n', '--name', dest='name', default=None,
  952. help='host fdl image file name in pac')
  953. def cfg_pack_file_args(sub_parsers):
  954. parser = sub_parsers.add_parser(
  955. 'cfg-pack-file', help='add download one file or directory')
  956. parser.set_defaults(func=cfg_pack_file)
  957. parser.add_argument('-i', '--id', dest='id', required=True,
  958. help='file ID in pac')
  959. parser.add_argument('-d', '--desc', dest='desc', default=None,
  960. help='file description in pac')
  961. parser.add_argument('--can-omit', dest='can_omit',
  962. type=int, choices=[0, 1], default=0,
  963. help='file can omit flag in pac')
  964. parser.add_argument('--default-check', dest='default_check',
  965. type=int, choices=[0, 1], default=1,
  966. help='file default check flag in pac')
  967. parser.add_argument('--force-check', dest='force_check',
  968. type=int, choices=[0, 1], default=0,
  969. help='file force check flag in pac')
  970. parser.add_argument('-p', '--path', dest='path', required=True,
  971. help='local file or directory path')
  972. parser.add_argument('-n', '--name', dest='name', default=None,
  973. help='remote file or directory path')
  974. def cfg_pack_cpio_args(sub_parsers):
  975. parser = sub_parsers.add_parser(
  976. 'cfg-pack-cpio', help='add pre-generated cpio')
  977. parser.set_defaults(func=cfg_pack_cpio)
  978. parser.add_argument('-i', '--id', dest='id', required=True,
  979. help='file ID in pac')
  980. parser.add_argument('-d', '--desc', dest='desc', default=None,
  981. help='file description in pac')
  982. parser.add_argument('--can-omit', dest='can_omit',
  983. type=int, choices=[0, 1], default=0,
  984. help='file can omit flag in pac')
  985. parser.add_argument('--default-check', dest='default_check',
  986. type=int, choices=[0, 1], default=1,
  987. help='file default check flag in pac')
  988. parser.add_argument('--force-check', dest='force_check',
  989. type=int, choices=[0, 1], default=0,
  990. help='file force check flag in pac')
  991. parser.add_argument('-p', '--path', dest='path', required=True,
  992. help='cpio file or directory path')
  993. parser.add_argument('-n', '--name', dest='name', default=None,
  994. help='cpio file name in pac')
  995. def pac_gen_args(sub_parsers):
  996. parser = sub_parsers.add_parser(
  997. 'pac-gen', help='generate pac file')
  998. parser.set_defaults(func=pac_gen)
  999. parser.add_argument('--cfg', dest='cfg', default=None,
  1000. help='configuration file name')
  1001. parser.add_argument('fname', help='pac file name')
  1002. def dep_gen_args(sub_parsers):
  1003. parser = sub_parsers.add_parser(
  1004. 'dep-gen', help='generate dependency files')
  1005. parser.set_defaults(func=dep_gen)
  1006. parser.add_argument('--base', dest='base', default=None,
  1007. help='base directory of the dependency files')
  1008. parser.add_argument('target', help='target of dependency')
  1009. parser.add_argument('output', help='output dependency file')
  1010. def main(argv):
  1011. parser = argparse.ArgumentParser(description=DESCRIPTION,
  1012. formatter_class=argparse.RawDescriptionHelpFormatter)
  1013. sub_parsers = parser.add_subparsers(description="")
  1014. cfg_init_args(sub_parsers)
  1015. cfg_nvitem_args(sub_parsers)
  1016. cfg_host_fdl_args(sub_parsers)
  1017. cfg_fdl2_args(sub_parsers)
  1018. cfg_fdl_args(sub_parsers)
  1019. cfg_image_args(sub_parsers)
  1020. cfg_clear_nv_args(sub_parsers)
  1021. cfg_phase_check_args(sub_parsers)
  1022. cfg_nv_args(sub_parsers)
  1023. cfg_erase_flash_args(sub_parsers)
  1024. cfg_fmt_flash_args(sub_parsers)
  1025. cfg_del_appimg_args(sub_parsers)
  1026. cfg_pack_file_args(sub_parsers)
  1027. cfg_pack_cpio_args(sub_parsers)
  1028. pac_gen_args(sub_parsers)
  1029. dep_gen_args(sub_parsers)
  1030. if not argv:
  1031. parser.parse_args(["-h"])
  1032. return 0
  1033. cmdlist = list(sub_parsers.choices.keys())
  1034. def splitcmd(args):
  1035. subcmd = []
  1036. for arg in args:
  1037. if arg in cmdlist:
  1038. if subcmd:
  1039. yield subcmd
  1040. subcmd = [arg]
  1041. else:
  1042. subcmd.append(arg)
  1043. if subcmd:
  1044. yield subcmd
  1045. cmdlines = list(splitcmd(argv))
  1046. namespace = argparse.Namespace()
  1047. for cmdline in cmdlines:
  1048. args = parser.parse_args(cmdline, namespace=namespace)
  1049. if args.__contains__("func"):
  1050. ret = args.func(args)
  1051. if ret != 0:
  1052. return ret
  1053. else:
  1054. parser.parse_args(["-h"])
  1055. return 0
  1056. return 0
  1057. if __name__ == "__main__":
  1058. sys.exit(main(sys.argv[1:]))