air640w.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  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['air640w'] = {
  15. # ============================================================
  16. # 不要修改PLAT_ROOT!不要修改PLAT_ROOT!不要修改PLAT_ROOT!
  17. # PLAT_ROOT仅供SDK源码开发者使用!!!!
  18. # 不要把PLAT_ROOT指向任何存在的路径!!!!!
  19. "PLAT_ROOT" : "D:\\github\\air640w\\sdk\\PLAT\\",
  20. # ============================================================
  21. "FTC_PATH" : ".\\",
  22. "EC_PATH" : ".\\air640w_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" : "COM28"
  30. }
  31. if os.path.exists("local.ini") :
  32. config.read("local.ini")
  33. if os.path.exists(config["air640w"]["PLAT_ROOT"]):
  34. PLAT_ROOT = os.path.abspath(config["air640w"]["PLAT_ROOT"]) + os.sep # 源码地址
  35. else:
  36. PLAT_ROOT = config["air640w"]["PLAT_ROOT"]
  37. FTC_PATH = os.path.abspath(config["air640w"]["FTC_PATH"]) + os.sep # FlashToolCLI刷机工具的目录
  38. EC_PATH = os.path.abspath(config["air640w"]["EC_PATH"]) # EC后缀的固件路径
  39. USER_PATH = os.path.abspath(config["air640w"]["USER_PATH"]) + os.sep # 用户脚本所在的目录
  40. LIB_PATH = os.path.abspath(config["air640w"]["LIB_PATH"]) + os.sep # 用户脚本所在的目录
  41. DEMO_PATH = os.path.abspath(config["air640w"]["DEMO_PATH"]) + os.sep # 用户脚本所在的目录
  42. MAIN_LUA_DEBUG = config["air640w"]["MAIN_LUA_DEBUG"] == "true"
  43. LUA_DEBUG = config["air640w"]["LUA_DEBUG"] == "true"
  44. COM_PORT = config["air640w"]["COM_PORT"]
  45. TOOLS_PATH = os.path.abspath(config["air640w"]["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 air640w.py [action]
  64. lfs - 编译文件系统
  65. dlrom - 下载底层固件
  66. dlfs - 下载lua脚本(即整个文件系统)
  67. dlfull- 下载底层和lua脚本
  68. pkg - 生成发布用的压缩包
  69. build - 构建源码(仅内部使用)
  70. 用例1, 生成文件系统并下载到开发板
  71. python air640w.py lfs dlfs
  72. 用例2, 生成文件系统,并下载固件和文件系统到开发板
  73. python air640w.py lfs dlfull
  74. 用例3, 仅下载底层固件
  75. python air640w.py dlrom
  76. 用例四, 编译,打包,构建文件系统,全量下载
  77. python air640w.py build lfs pkg dlfull
  78. ''')
  79. '''
  80. 执行打包程序,内部使用
  81. '''
  82. def _pkg():
  83. # TODO 扩展为用户可用的打包ec固件的工具
  84. if os.path.exists("tmp"):
  85. shutil.rmtree("tmp")
  86. _tag = time.strftime("%Y%m%d%H%M%S", time.localtime())
  87. _tag = _tag + "-" + get_git_revision_short_hash().decode()
  88. os.mkdir("tmp")
  89. # 拷贝固件文件
  90. if os.path.exists("../w60x/Bin/rtthread_1M.FLS") :
  91. shutil.copy("../w60x/Bin/rtthread_1M.FLS", "tmp/LuatOS_Air640W_V0002.FLS")
  92. # 拷贝库文件和demo
  93. shutil.copytree(LIB_PATH, "tmp/lib")
  94. shutil.copytree(DEMO_PATH, "tmp/demo")
  95. shutil.copytree(TOOLS_PATH, "tmp/tools")
  96. #拷贝自身
  97. shutil.copy(sys.argv[0], "tmp/air640w.py")
  98. shutil.copy("README.md", "tmp/README.md")
  99. shutil.copy("YModem.py", "tmp/YModem.py")
  100. shutil.copy("YMTask.py", "tmp/YMTask.py")
  101. if os.path.exists("userdoc") :
  102. shutil.copytree("userdoc", "tmp/userdoc")
  103. if os.path.exists("../../docs/api/lua"):
  104. shutil.copytree("../../docs/api/lua", "tmp/userdoc/api")
  105. if os.path.exists(USER_PATH):
  106. shutil.copytree(USER_PATH, "tmp/user")
  107. with open("tmp/文档在userdoc目录.txt", "w") as f:
  108. f.write("QQ群: 1061642968")
  109. # 写入默认配置文件
  110. with open("tmp/local.ini", "w") as f:
  111. f.write('''
  112. [air640w]
  113. USER_PATH = user\\
  114. LIB_PATH = lib\\
  115. DEMO_PATH = demo\\
  116. TOOLS_PATH = tools\\
  117. MAIN_LUA_DEBUG = false
  118. LUA_DEBUG = false
  119. COM_PORT = COM56
  120. ''')
  121. pkg_name = "air640w_V0002_"+_tag + ".zip"
  122. shutil.make_archive("air640w_V0002_"+_tag, 'zip', "tmp")
  123. print("ALL DONE===================================================")
  124. print("Package Name", pkg_name)
  125. '''
  126. 下载底层或脚本
  127. '''
  128. def _dl(tp, _path=None):
  129. if tp == "fs":
  130. import serial
  131. from YModem import YModem
  132. serial_io = serial.Serial()
  133. serial_io.port = COM_PORT
  134. serial_io.baudrate = "115200"
  135. serial_io.parity = "N"
  136. serial_io.bytesize = 8
  137. serial_io.stopbits = 1
  138. serial_io.timeout = 2
  139. try:
  140. serial_io.open()
  141. except Exception as e:
  142. raise Exception("Failed to open serial port!")
  143. def sender_getc(size):
  144. return serial_io.read(size) or None
  145. def sender_putc(data, timeout=15):
  146. return serial_io.write(data)
  147. serial_io.write("reboot\r\n".encode())
  148. for k in range(10) :
  149. serial_io.write("reinit\r\n".encode())
  150. resp = serial_io.read_until()
  151. try :
  152. print(resp.decode(), )
  153. if "DONE!" in resp.decode() :
  154. print("格式化完成")
  155. break
  156. except:
  157. pass
  158. time.sleep(0.03) # 50ms
  159. for k in range(10) :
  160. resp = serial_io.read_until()
  161. time.sleep(1)
  162. print(">> 开始ymodem发送文件")
  163. os.chdir("disk")
  164. for root, dirs, files in os.walk(".", topdown=False):
  165. for name in files:
  166. serial_io.write("ry\r\n".encode())
  167. serial_io.read_until()
  168. sender = YModem(sender_getc, sender_putc)
  169. _path = os.path.join(root, name)
  170. sent = sender.send_file(_path, retry=1)
  171. #print (">>" + sent)
  172. serial_io.close()
  173. '''
  174. 生成文件系统镜像
  175. '''
  176. def _lfs(_path=None):
  177. _disk = FTC_PATH + "disk"
  178. if os.path.exists(_disk) :
  179. shutil.rmtree(_disk)
  180. os.mkdir(_disk)
  181. if not _path:
  182. _path = USER_PATH
  183. # 收集需要处理的文件列表
  184. _paths = []
  185. # 首先,遍历lib目录
  186. if os.path.exists(LIB_PATH) :
  187. for name in os.listdir(LIB_PATH) :
  188. _paths.append(LIB_PATH + name)
  189. # 然后遍历user目录
  190. for name in os.listdir(_path) :
  191. _paths.append(_path + name)
  192. TAG_PROJECT = ""
  193. TAG_VERSION = ""
  194. for name in _paths :
  195. # 如果是lua文件, 编译之
  196. if name.endswith(".lua") :
  197. cmd = [TOOLS_PATH + "luac_536_32bits.exe"]
  198. print ("Using Lua 32bits!!!")
  199. if name.endswith("main.lua") :
  200. if not MAIN_LUA_DEBUG :
  201. cmd += ["-s"]
  202. with open(name, "rb") as f :
  203. for line in f.readlines() :
  204. if line :
  205. line = line.strip().decode()
  206. if line.startswith("PROJECT =") :
  207. TAG_PROJECT = line[line.index("\"") + 1:][:-1]
  208. elif line.startswith("VERSION =") :
  209. TAG_VERSION = line[line.index("\"") + 1:][:-1]
  210. elif not LUA_DEBUG :
  211. cmd += ["-s"]
  212. else:
  213. print("LUA_DEBUG", LUA_DEBUG, "False" == LUA_DEBUG)
  214. cmd += ["-o", FTC_PATH + "disk/" + os.path.basename(name) + "c", os.path.basename(name)]
  215. print("CALL", " ".join(cmd))
  216. subprocess.check_call(cmd, cwd=os.path.dirname(name))
  217. # 其他文件直接拷贝
  218. else:
  219. print("COPY", name, FTC_PATH + "disk/" + os.path.basename(name))
  220. shutil.copy(name, FTC_PATH + "disk/" + os.path.basename(name))
  221. if TAG_PROJECT == "" or TAG_VERSION == "" :
  222. print("!!!!!!!miss PROJECT or/and VERSION!!!!!!!!!!")
  223. for root, dirs, files in os.walk("disk", topdown=False):
  224. import struct
  225. print("write flashx.bin", root)
  226. with open("disk/flashx.bin", "wb") as f :
  227. # 写入文件头
  228. f.write(struct.pack("<HHI", 0x1234, 0x00, 0x00))
  229. for name in files:
  230. # 写入文件名
  231. f.write(struct.pack("<HHI", 0x0101, 0x00, len(name)))
  232. f.write(name.encode())
  233. # 写入文件内容
  234. _path = os.path.join(root, name)
  235. _size = os.path.getsize(_path)
  236. f.write(struct.pack("<HHI", 0x0202, 0x00, _size))
  237. with open(_path, "rb") as f2 :
  238. shutil.copyfileobj(f2, f, _size)
  239. if TAG_PROJECT != "" and TAG_VERSION != "":
  240. # otademo_1.2.7_LuatOS_V0003_w60x
  241. TAG_NAME = "%s_%s_LuatOS_V0003_w60x.bin" % (TAG_PROJECT, TAG_VERSION)
  242. print("update bin --> " + TAG_NAME)
  243. shutil.copy("disk/flashx.bin", TAG_NAME)
  244. def main():
  245. argc = 1
  246. while len(sys.argv) > argc :
  247. if sys.argv[argc] == "build" :
  248. print("Action Build ----------------------------------")
  249. #subprocess.check_call([PLAT_ROOT + "KeilBuild.bat"], cwd=PLAT_ROOT)
  250. elif sys.argv[argc] == "lfs" :
  251. print("Action mklfs ----------------------------------")
  252. _lfs()
  253. elif sys.argv[argc] == "pkg" :
  254. print("Action pkg ------------------------------------")
  255. _pkg()
  256. # elif sys.argv[argc] == "dlrom": #下载底层
  257. # print("Action download ROM ---------------------------")
  258. # if len(sys.argv) > argc + 1 and sys.argv[argc+1].startsWith("-path="):
  259. # _dl("rom", sys.argv[argc+1][6:])
  260. # argc += 1
  261. # else:
  262. # _dl("rom")
  263. elif sys.argv[argc] == "dlfs":
  264. print("Action download FS ---------------------------")
  265. if len(sys.argv) > argc + 1 and sys.argv[argc+1].startsWith("-path="):
  266. _dl("fs", sys.argv[argc+1][6:])
  267. argc += 1
  268. else:
  269. _dl("fs")
  270. # elif sys.argv[argc] == "dlfull":
  271. # if len(sys.argv) > argc + 1 and sys.argv[argc+1].startsWith("-path="):
  272. # _dl("full", sys.argv[argc+1][6:])
  273. # argc += 1
  274. # else:
  275. # _dl("full")
  276. elif sys.argv[argc] == "clean":
  277. if os.path.exists("tmp"):
  278. shutil.rmtree("tmp")
  279. if os.path.exists(FTC_PATH + "disk"):
  280. shutil.rmtree(FTC_PATH + "disk")
  281. else:
  282. usage()
  283. return
  284. argc += 1
  285. print("============================================================================")
  286. print("every done, bye")
  287. if len(sys.argv) == 1 :
  288. usage()
  289. else :
  290. main()