air302.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. #!/usr/bin/python3
  2. # -*- coding: UTF-8 -*-
  3. import os.path
  4. import shutil
  5. import zipfile
  6. import time
  7. import subprocess
  8. import sys
  9. import json
  10. #------------------------------------------------------------------
  11. # 读取配置信息
  12. import configparser
  13. config = configparser.ConfigParser()
  14. config['air302'] = {
  15. # ============================================================
  16. # 不要修改PLAT_ROOT!不要修改PLAT_ROOT!不要修改PLAT_ROOT!
  17. # PLAT_ROOT仅供SDK源码开发者使用!!!!
  18. # 不要把PLAT_ROOT指向任何存在的路径!!!!!
  19. "PLAT_ROOT" : "D:\\github\\air302\\sdk\\PLAT\\",
  20. # ============================================================
  21. "FTC_PATH" : ".\\FlashToolCLI\\",
  22. "EC_PATH" : ".\\Air302_dev.ec",
  23. "USER_PATH": ".\\user\\",
  24. "LIB_PATH" : ".\\lib\\",
  25. "DEMO_PATH": ".\\demo\\",
  26. "TOOLS_PATH": ".\\tools\\",
  27. "MAIN_LUA_DEBUG" : "false",
  28. "LUA_DEBUG" : "false",
  29. "COM_PORT" : "COM56"
  30. }
  31. if os.path.exists("local.ini") :
  32. config.read("local.ini")
  33. if os.path.exists(config["air302"]["PLAT_ROOT"]):
  34. PLAT_ROOT = os.path.abspath(config["air302"]["PLAT_ROOT"]) + os.sep # 源码地址
  35. else:
  36. PLAT_ROOT = config["air302"]["PLAT_ROOT"]
  37. FTC_PATH = os.path.abspath(config["air302"]["FTC_PATH"]) + os.sep # FlashToolCLI刷机工具的目录
  38. EC_PATH = os.path.abspath(config["air302"]["EC_PATH"]) # EC后缀的固件路径
  39. USER_PATH = os.path.abspath(config["air302"]["USER_PATH"]) + os.sep # 用户脚本所在的目录
  40. LIB_PATH = os.path.abspath(config["air302"]["LIB_PATH"]) + os.sep # 用户脚本所在的目录
  41. DEMO_PATH = os.path.abspath(config["air302"]["DEMO_PATH"]) + os.sep # 用户脚本所在的目录
  42. MAIN_LUA_DEBUG = config["air302"]["MAIN_LUA_DEBUG"] == "true"
  43. LUA_DEBUG = config["air302"]["LUA_DEBUG"] == "true"
  44. COM_PORT = config["air302"]["COM_PORT"]
  45. TOOLS_PATH = os.path.abspath(config["air302"]["TOOLS_PATH"]) + os.sep
  46. # TODO 从环境变量获取上述参数
  47. '''
  48. 获取git库的当前版本号,为一个hash值
  49. '''
  50. def get_git_revision_short_hash():
  51. try :
  52. if os.path.exists(PLAT_ROOT):
  53. return subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD'], cwd=PLAT_ROOT).strip()
  54. else:
  55. return subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD']).strip()
  56. except:
  57. return ""
  58. '''
  59. 打印帮助信息
  60. '''
  61. def usage():
  62. print('''
  63. python air302.py [action]
  64. lfs - 编译文件系统
  65. dlrom - 下载底层固件
  66. dlfs - 下载lua脚本(即整个文件系统)
  67. dlfull- 下载底层和lua脚本
  68. pkg - 生成发布用的压缩包
  69. build - 构建源码(仅内部使用)
  70. 用例1, 生成文件系统并下载到开发板
  71. python air302.py lfs dlfs
  72. 用例2, 生成文件系统,并下载固件和文件系统到开发板
  73. python air302.py lfs dlfull
  74. 用例3, 仅下载底层固件
  75. python air302.py dlrom
  76. 用例四, 编译,打包,构建文件系统,全量下载
  77. python air302.py build lfs pkg dlfull
  78. ''')
  79. '''
  80. FlashToolCLI所需要的配置信息
  81. '''
  82. FTC_CNF_TMPL = '''
  83. [config]
  84. line_0_com = ${COM}
  85. agbaud = 921600
  86. ;bootloader.bin file infomation
  87. [bootloader]
  88. blpath = .\\image\\bootloader.bin
  89. blloadskip = 0
  90. ;system.bin file infomation
  91. [system]
  92. syspath = .\\system.bin
  93. sysloadskip = 0
  94. ;control such as reset before download
  95. [control]
  96. reset = 0
  97. [flexfile0]
  98. filepath = .\\rfCaliTb\\MergeRfTable.bin
  99. burnaddr = 0x3A4000
  100. [flexfile1]
  101. filepath = .\\rfCaliTb\\MergeRfTable.bin
  102. burnaddr = 0x16000
  103. [flexfile2]
  104. filepath = .\\disk.fs
  105. burnaddr = 0x350000
  106. '''.replace("${COM}", COM_PORT)
  107. '''
  108. 执行打包程序,内部使用
  109. '''
  110. def _pkg():
  111. # TODO 扩展为用户可用的打包ec固件的工具
  112. if os.path.exists("tmp"):
  113. shutil.rmtree("tmp")
  114. _tag = time.strftime("%Y%m%d%H%M%S", time.localtime())
  115. _tag = _tag + "-" + get_git_revision_short_hash().decode()
  116. os.mkdir("tmp")
  117. os.mkdir("tmp/ec")
  118. # 拷贝固件文件
  119. if os.path.exists(PLAT_ROOT) :
  120. shutil.copy(PLAT_ROOT + "out/ec616_0h00/air302/air302.bin", "tmp/ec/luatos.bin")
  121. shutil.copy(PLAT_ROOT + "out/ec616_0h00/air302/comdb.txt", "tmp/ec/comdb.txt")
  122. shutil.copy(FTC_PATH + "image/bootloader.bin", "tmp/ec/bootloader.bin")
  123. shutil.copy(FTC_PATH + "image/bootloader_head.bin", "tmp/ec/bootloader_head.bin")
  124. elif os.path.exists(EC_PATH) and EC_PATH.endswith(".ec") :
  125. with zipfile.ZipFile(EC_PATH) as zip :
  126. zip.extractall(path="tmp/ec/")
  127. # 拷贝库文件和demo
  128. shutil.copytree(LIB_PATH, "tmp/lib")
  129. shutil.copytree(DEMO_PATH, "tmp/demo")
  130. shutil.copytree(TOOLS_PATH, "tmp/tools")
  131. #拷贝自身
  132. shutil.copy(sys.argv[0], "tmp/air302.py")
  133. # 写入默认配置文件
  134. with open("tmp/local.ini", "w") as f:
  135. f.write('''
  136. [air302]
  137. FTC_PATH = FlashToolCLI\\
  138. EC_PATH = ${EC}
  139. USER_PATH = user\\
  140. LIB_PATH = lib\\
  141. DEMO_PATH = demo\\
  142. TOOLS_PATH = tools\\
  143. MAIN_LUA_DEBUG = false
  144. LUA_DEBUG = false
  145. COM_PORT = COM56
  146. '''.replace("${EC}", "Air302_V0002_"+_tag+".ec"))
  147. if os.path.exists("userdoc") :
  148. shutil.copytree("userdoc", "tmp/userdoc")
  149. if os.path.exists("../../docs/api/lua"):
  150. shutil.copytree("../../docs/api/lua", "tmp/userdoc/api")
  151. if os.path.exists(USER_PATH):
  152. shutil.copytree(USER_PATH, "tmp/user")
  153. with open("tmp/文档在userdoc目录.txt", "w") as f:
  154. f.write("QQ群: 1061642968")
  155. with zipfile.ZipFile("tmp/Air302_V0002_"+_tag+".ec", mode="w", compression=zipfile.ZIP_DEFLATED, compresslevel=9) as zip :
  156. zip.write("tmp/ec/luatos.bin", "luatos.bin") # 底层固件
  157. zip.write("tmp/ec/comdb.txt", "comdb.txt") # uart0输出的unilog所需要的数据库文件,备用
  158. zip.write("tmp/ec/bootloader.bin", "bootloader.bin") # bootloader,备用
  159. zip.write("tmp/ec/bootloader_head.bin", "bootloader_head.bin") # bootloader_header,备用
  160. zip.write(FTC_PATH + "disk.fs", "disk.bin") # 默认磁盘镜像
  161. shutil.rmtree("tmp/ec/")
  162. if os.path.exists(FTC_PATH):
  163. shutil.copytree(FTC_PATH, "tmp/FlashToolCLI")
  164. pkg_name = "Air302_V0002_"+_tag + ".zip"
  165. shutil.make_archive("Air302_V0002_"+_tag, 'zip', "tmp")
  166. ## 拷贝一份固定路径的
  167. shutil.copy("tmp/Air302_V0002_"+_tag+".ec", "tmp/Air302_dev.ec")
  168. print("ALL DONE===================================================")
  169. print("Package Name", pkg_name)
  170. '''
  171. 下载底层或脚本
  172. '''
  173. def _dl(tp, _path=None):
  174. with open(FTC_PATH + "config.ini", "w") as f :
  175. f.write(FTC_CNF_TMPL)
  176. cmd = [FTC_PATH + "FlashToolCLI.exe", "-p", COM_PORT, "burnbatch", "--imglist"]
  177. if tp == "rom" or tp == "full":
  178. if os.path.exists(PLAT_ROOT + "out/ec616_0h00/air302/air302.bin") :
  179. shutil.copy(PLAT_ROOT + "out/ec616_0h00/air302/air302.bin", FTC_PATH + "system.bin")
  180. elif EC_PATH.endswith(".ec") :
  181. import zipfile
  182. with zipfile.ZipFile(EC_PATH) as zip :
  183. with open(FTC_PATH + "system.bin", "wb") as f:
  184. f.write(zip.read("luatos.bin"))
  185. elif EC_PATH.endswith(".bin"):
  186. shutil.copy(EC_PATH, FTC_PATH + "system.bin")
  187. else:
  188. print("Bad EC_PATH")
  189. return
  190. cmd += ["system"]
  191. if tp == "fs" or tp == "full" :
  192. cmd += ["flexfile2"]
  193. print("CALL", " ".join(cmd))
  194. subprocess.check_call(cmd, cwd=FTC_PATH)
  195. '''
  196. 生成文件系统镜像
  197. '''
  198. def _lfs(_path=None):
  199. _disk = FTC_PATH + "disk"
  200. if os.path.exists(_disk) :
  201. shutil.rmtree(_disk)
  202. os.mkdir(_disk)
  203. if not _path:
  204. _path = USER_PATH
  205. # 收集需要处理的文件列表
  206. _paths = []
  207. # 首先,遍历lib目录
  208. if os.path.exists(LIB_PATH) :
  209. for name in os.listdir(LIB_PATH) :
  210. _paths.append(LIB_PATH + name)
  211. # 然后遍历user目录
  212. for name in os.listdir(_path) :
  213. _paths.append(_path + name)
  214. TAG_PROJECT = ""
  215. TAG_VERSION = ""
  216. for name in _paths :
  217. # 如果是lua文件, 编译之
  218. if name.endswith(".lua") :
  219. cmd = [TOOLS_PATH + "luac_536_32bits.exe"]
  220. if name.endswith("main.lua") :
  221. if not MAIN_LUA_DEBUG :
  222. cmd += ["-s"]
  223. with open(name, "rb") as f :
  224. for line in f.readlines() :
  225. if line :
  226. line = line.strip().decode()
  227. if line.startswith("PROJECT =") :
  228. TAG_PROJECT = line[line.index("\"") + 1:][:-1]
  229. elif line.startswith("VERSION =") :
  230. TAG_VERSION = line[line.index("\"") + 1:][:-1]
  231. elif not LUA_DEBUG :
  232. cmd += ["-s"]
  233. else:
  234. print("LUA_DEBUG", LUA_DEBUG, "False" == LUA_DEBUG)
  235. cmd += ["-o", FTC_PATH + "disk/" + os.path.basename(name) + "c", os.path.basename(name)]
  236. print("CALL", " ".join(cmd))
  237. subprocess.check_call(cmd, cwd=os.path.dirname(name))
  238. # 其他文件直接拷贝
  239. else:
  240. print("COPY", name, FTC_PATH + "disk/" + os.path.basename(name))
  241. shutil.copy(name, FTC_PATH + "disk/" + os.path.basename(name))
  242. if TAG_PROJECT == "" or TAG_VERSION == "" :
  243. print("!!!!!!!miss PROJECT or/and VERSION!!!!!!!!!!")
  244. for root, dirs, files in os.walk(FTC_PATH + "disk", topdown=False):
  245. import struct
  246. print("write flashx.tlv", root)
  247. with open(FTC_PATH + "disk/flashx.tlv", "wb") as f :
  248. # 写入文件头
  249. f.write(struct.pack("<HHI", 0x1234, 0x00, 0x00))
  250. for name in files:
  251. # 写入文件名
  252. f.write(struct.pack("<HHI", 0x0101, 0x00, len(name)))
  253. f.write(name.encode())
  254. # 写入文件内容
  255. _path = os.path.join(root, name)
  256. _size = os.path.getsize(_path)
  257. f.write(struct.pack("<HHI", 0x0202, 0x00, _size))
  258. with open(_path, "rb") as f2 :
  259. shutil.copyfileobj(f2, f, _size)
  260. if TAG_PROJECT != "" and TAG_VERSION != "":
  261. # otademo_1.2.7_LuatOS_V0003_ec616
  262. TAG_NAME = "%s_%s_LuatOS_V0003_ec616.bin" % (TAG_PROJECT, TAG_VERSION)
  263. shutil.copy(FTC_PATH + "disk/flashx.bin", TAG_NAME)
  264. print("CALL mklfs for disk.fs")
  265. subprocess.check_call([TOOLS_PATH + "mklfs.exe"], cwd=FTC_PATH)
  266. def main():
  267. argc = 1
  268. while len(sys.argv) > argc :
  269. if sys.argv[argc] == "build" :
  270. print("Action Build ----------------------------------")
  271. subprocess.check_call([PLAT_ROOT + "KeilBuild.bat"], cwd=PLAT_ROOT)
  272. elif sys.argv[argc] == "lfs" :
  273. print("Action mklfs ----------------------------------")
  274. _lfs()
  275. elif sys.argv[argc] == "pkg" :
  276. print("Action pkg ------------------------------------")
  277. _pkg()
  278. elif sys.argv[argc] == "dlrom": #下载底层
  279. print("Action download ROM ---------------------------")
  280. if len(sys.argv) > argc + 1 and sys.argv[argc+1].startsWith("-path="):
  281. _dl("rom", sys.argv[argc+1][6:])
  282. argc += 1
  283. else:
  284. _dl("rom")
  285. elif sys.argv[argc] == "dlfs":
  286. print("Action download FS ---------------------------")
  287. if len(sys.argv) > argc + 1 and sys.argv[argc+1].startsWith("-path="):
  288. _dl("fs", sys.argv[argc+1][6:])
  289. argc += 1
  290. else:
  291. _dl("fs")
  292. elif sys.argv[argc] == "dlfull":
  293. if len(sys.argv) > argc + 1 and sys.argv[argc+1].startsWith("-path="):
  294. _dl("full", sys.argv[argc+1][6:])
  295. argc += 1
  296. else:
  297. _dl("full")
  298. elif sys.argv[argc] == "clean":
  299. if os.path.exists("tmp"):
  300. shutil.rmtree("tmp")
  301. if os.path.exists(PLAT_ROOT) :
  302. subprocess.call([PLAT_ROOT + "KeilBuild.bat", "clall"], cwd=PLAT_ROOT)
  303. else:
  304. usage()
  305. return
  306. argc += 1
  307. print("============================================================================")
  308. print("every done, bye")
  309. if len(sys.argv) == 1 :
  310. usage()
  311. else :
  312. main()