air302.py 15 KB

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