Fix #7428
[opentx.git] / radio / util / build-firmware.py
blobe6528f692175f99fae95b718943d6f638c36608b
1 #!/usr/bin/env python
3 from __future__ import print_function
4 import os
5 import sys
6 import subprocess
7 import shutil
8 import filelock
9 from fwoptions import *
11 # Error codes
12 FIRMWARE_SIZE_TOO_BIG = 1
13 COMPILATION_ERROR = 4
14 INVALID_FIRMWARE = 5
15 INVALID_BOARD = 6
16 INVALID_LANGUAGE = 7
18 # Board types
19 BOARD_9X = 0
20 BOARD_GRUVIN9X = 1
21 BOARD_SKY9X = 2
22 BOARD_TARANIS = 3
23 BOARD_HORUS = 4
25 # Board families
26 BOARD_FAMILY_AVR = 0
27 BOARD_FAMILY_ARM = 1
29 if len(sys.argv) != 3:
30 exit(INVALID_FIRMWARE)
32 what = sys.argv[1]
33 directory, filename = os.path.split(sys.argv[2])
34 root, ext = os.path.splitext(filename)
35 options = root.split("-")
37 if len(options) < 2 or options[0] != "opentx":
38 exit(INVALID_FIRMWARE)
40 optcount = 1
41 command_options = {}
43 if options[optcount] == "9x":
44 command_options["PCB"] = "9X"
45 firmware_options = options_9x
46 maxsize = 65536
47 board = BOARD_9X
48 board_family = BOARD_FAMILY_AVR
49 elif options[optcount] == "9xr":
50 command_options["PCB"] = "9XR"
51 firmware_options = options_9x
52 maxsize = 65536
53 board = BOARD_9X
54 board_family = BOARD_FAMILY_AVR
55 elif options[optcount] == "9x128":
56 command_options["PCB"] = "9X128"
57 command_options["FRSKY_STICKS"] = "YES"
58 firmware_options = options_9x128
59 maxsize = 65536 * 2
60 board = BOARD_9X
61 board_family = BOARD_FAMILY_AVR
62 elif options[optcount] == "9xr128":
63 command_options["PCB"] = "9XR128"
64 command_options["FRSKY_STICKS"] = "YES"
65 firmware_options = options_9x128
66 maxsize = 65536 * 2
67 board = BOARD_9X
68 board_family = BOARD_FAMILY_AVR
69 elif options[optcount] == "gruvin9x":
70 command_options["PCB"] = "GRUVIN9X"
71 command_options["TELEMETRY"] = "FRSKY"
72 firmware_options = options_gruvin9x
73 maxsize = 65536 * 4
74 board = BOARD_GRUVIN9X
75 board_family = BOARD_FAMILY_AVR
76 elif options[optcount] == "mega2560":
77 command_options["PCB"] = "MEGA2560"
78 command_options["TELEMETRY"] = "FRSKY"
79 firmware_options = options_mega2560
80 maxsize = 65536 * 4
81 board = BOARD_GRUVIN9X
82 board_family = BOARD_FAMILY_AVR
83 elif options[optcount] == "sky9x":
84 command_options["PCB"] = "SKY9X"
85 firmware_options = options_sky9x
86 maxsize = 65536 * 4
87 board = BOARD_SKY9X
88 board_family = BOARD_FAMILY_ARM
89 elif options[optcount] == "9xrpro":
90 command_options["PCB"] = "9XRPRO"
91 command_options["SDCARD"] = "YES"
92 firmware_options = options_sky9x
93 maxsize = 65536 * 4
94 board = BOARD_SKY9X
95 board_family = BOARD_FAMILY_ARM
96 elif options[optcount] == "ar9x":
97 command_options["PCB"] = "AR9X"
98 command_options["SDCARD"] = "YES"
99 firmware_options = options_ar9x
100 maxsize = 65536 * 4
101 board = BOARD_SKY9X
102 board_family = BOARD_FAMILY_ARM
103 elif options[optcount] == "x7":
104 command_options["PCB"] = "X7"
105 firmware_options = options_taranisplus
106 maxsize = 65536 * 8
107 board = BOARD_TARANIS
108 board_family = BOARD_FAMILY_ARM
109 elif options[optcount] == "xlite":
110 command_options["PCB"] = "XLITE"
111 firmware_options = options_xlite
112 maxsize = 65536 * 8
113 board = BOARD_TARANIS
114 board_family = BOARD_FAMILY_ARM
115 elif options[optcount] == "x9d":
116 command_options["PCB"] = "X9D"
117 firmware_options = options_taranis
118 maxsize = 65536 * 8
119 board = BOARD_TARANIS
120 board_family = BOARD_FAMILY_ARM
121 elif options[optcount] == "x9d+":
122 command_options["PCB"] = "X9D+"
123 firmware_options = options_taranisplus
124 maxsize = 65536 * 8
125 board = BOARD_TARANIS
126 board_family = BOARD_FAMILY_ARM
127 elif options[optcount] == "x9e":
128 command_options["PCB"] = "X9E"
129 firmware_options = options_taranisx9e
130 maxsize = 65536 * 8
131 board = BOARD_TARANIS
132 board_family = BOARD_FAMILY_ARM
133 elif options[optcount] == "x10":
134 command_options["PCB"] = "X10"
135 firmware_options = options_x10
136 maxsize = 2 * 1024 * 1024
137 board = BOARD_HORUS
138 board_family = BOARD_FAMILY_ARM
139 elif options[optcount] == "x12s":
140 command_options["PCB"] = "X12S"
141 firmware_options = options_x12s
142 maxsize = 2 * 1024 * 1024
143 board = BOARD_HORUS
144 board_family = BOARD_FAMILY_ARM
145 else:
146 exit(INVALID_BOARD)
148 if what == "firmware":
149 if board_family == BOARD_FAMILY_ARM:
150 ext = ".bin"
151 else:
152 ext = ".hex"
153 target = "firmware" + ext
154 filename = "opentx"
155 elif what == "libsimulator":
156 ext = ".so"
157 target = "libopentx-" + options[optcount] + "-simulator.so"
158 filename = "libopentx"
159 else:
160 exit(INVALID_BOARD)
162 filename += "-" + options[optcount]
163 optcount += 1
165 # The firmware options
166 for opt, value in firmware_options.items():
167 found = False
168 for i in range(optcount, len(options)):
169 if options[i] == opt:
170 found = True
171 break
173 if found:
174 optvalue = value[1];
175 filename += "-" + opt;
176 else:
177 optvalue = value[2]
179 if optvalue is not None:
180 command_options[value[0]] = optvalue
182 # The firmware display language
183 language = ""
184 for key in languages:
185 if key == options[-1]:
186 language = key
187 if not language:
188 exit(INVALID_LANGUAGE)
189 command_options["TRANSLATIONS"] = language.upper()
191 filename += "-" + language + ext
192 path = os.path.join(directory, filename)
193 errpath = path + ".err"
195 def build_firmware(path):
196 srcdir = os.path.dirname(os.path.realpath(__file__)) + "/../.."
197 outpath = path + ".out"
199 # cmake 3.7.2 cannot work from / so we need to go into a subdir
200 os.mkdir("/build")
201 os.chdir("/build")
203 # Launch CMake
204 cmd = ["cmake"]
205 for opt, value in command_options.items():
206 cmd.append("-D%s=%s" % (opt, value))
207 if "OPENTX_VERSION_SUFFIX" in os.environ:
208 suffix = os.environ["OPENTX_VERSION_SUFFIX"]
209 cmd.append('-DVERSION_SUFFIX="%s"' % suffix)
210 if suffix.startswith("N"):
211 cmd.append('-DNIGHTLY_BUILD_WARNING=YES')
212 cmd.append(srcdir)
213 proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
214 output, error = proc.communicate()
215 if proc.returncode == 0:
216 file(outpath, "a").write("\n".join(cmd) + output + error)
217 else:
218 file(errpath, "w").write(output + error)
219 print(filename)
220 exit(COMPILATION_ERROR)
222 # Launch make
223 cmd = ["make", "-j2", what]
224 proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
225 output, error = proc.communicate()
226 if proc.returncode == 0:
227 file(outpath, "a").write(output + error)
228 else:
229 file(errpath, "w").write(output + error)
230 print(filename)
231 exit(COMPILATION_ERROR)
233 if what == "firmware":
234 # Check binary size
235 if board_family == BOARD_FAMILY_ARM:
236 size = os.stat(target).st_size
237 else:
238 size = subprocess.check_output('avr-size -A %s | grep Total | cut -f2- -d " "' % target, shell=True)
239 size = int(size.strip())
240 if size > maxsize:
241 exit(FIRMWARE_SIZE_TOO_BIG)
243 # Copy binary to the binaries directory
244 shutil.move(target, path)
246 if os.path.isfile(errpath):
247 print(filename)
248 exit(COMPILATION_ERROR)
250 if os.path.isfile(path):
251 print(filename)
252 exit(0)
254 lockpath = path + ".lock"
255 lock = filelock.FileLock(lockpath)
256 try:
257 with lock.acquire(timeout = 60*60):
258 if not os.path.isfile(path):
259 build_firmware(path)
260 except filelock.Timeout:
261 print(filename)
262 exit(COMPILATION_ERROR)
264 print(filename)
265 exit(0)