Increase maximum number of Lua params (#2207)
[ExpressLRS.git] / src / python / targets_validator.py
blob77aa822f5ba7a803ec4a34bc9f3e9e8d507e3446
1 import os, sys
2 import json
3 import glob
5 hadError = False
6 firmwares = set()
8 def error(msg):
9 global hadError
10 hadError = True
11 print(msg)
13 def validate_stm32(vendor, type, devname, device):
14 for method in device['upload_methods']:
15 if method not in ['stlink', 'dfu', 'uart', 'wifi', 'betaflight']:
16 error(f'Invalid upload method "{method}" for target "{vendor}.{type}.{devname}"')
17 if 'stlink' not in device['upload_methods']:
18 error(f'STM32 based devices must always have "stlink" as an upload_method for target "{vendor}.{type}.{devname}"')
19 if 'stlink' not in device:
20 error(f'STM32 based devices must always have "stlink" attribute for target "{vendor}.{type}.{devname}"')
21 else:
22 stlink = device['stlink']
23 if 'cpus' not in stlink:
24 error(f'The "stlink" attribute for target "{vendor}.{type}.{devname}" must have a list of valid "cpus"')
25 if 'offset' not in stlink:
26 error(f'The "stlink" attribute for target "{vendor}.{type}.{devname}" must have a valid "offset"')
27 if 'bootloader' not in stlink:
28 error(f'The "stlink" attribute for target "{vendor}.{type}.{devname}" must have a valid "bootloader"')
29 # could check the existence of the bootloader file
31 def validate_esp(vendor, type, devname, device):
32 if 'lua_name' not in device:
33 error(f'device "{vendor}.{type}.{devname}" must have a "lua_name" child element')
34 if len(device['lua_name']) > 16:
35 error(f'device "{vendor}.{type}.{devname}" must have a "lua_name" of 16 characters or less')
36 # validate layout_file
37 if 'layout_file' not in device:
38 error(f'device "{vendor}.{type}.{devname}" must have a "layout_file" child element')
39 else:
40 dir = 'hardware/' + ('RX/' if type.startswith('rx') else 'TX/')
41 if not os.path.isfile(dir + device['layout_file']):
42 layout_file = device['layout_file']
43 error(f'File specified by layout_file "{layout_file}" in target "{vendor}.{type}.{devname}", does not exist')
44 # could validate overlay
46 def validate_esp32(vendor, type, devname, device):
47 for method in device['upload_methods']:
48 if method not in ['uart', 'etx', 'wifi', 'betaflight']:
49 error(f'Invalid upload method "{method}" for target "{vendor}.{type}.{devname}"')
50 validate_esp(vendor, type, devname, device)
52 def validate_esp8285(vendor, type, devname, device):
53 for method in device['upload_methods']:
54 if method not in ['uart', 'wifi', 'betaflight']:
55 error(f'Invalid upload method "{method}" for target "{vendor}.{type}.{devname}"')
56 validate_esp(vendor, type, devname, device)
58 def validate_devices(vendor, type, devname, device):
59 if devname != devname.lower():
60 error(f'device tag "{devname}" should be lowercase')
61 if 'product_name' not in device:
62 error(f'device "{vendor}.{type}.{devname}" must have a "product_name" child element')
63 if 'upload_methods' not in device:
64 error(f'device "{vendor}.{type}.{devname}" must have a "upload_methods" child element')
66 if 'firmware' not in device:
67 error(f'device "{vendor}.{type}.{devname}" must have a "firmware" child element')
68 else:
69 firmware = device['firmware']
70 if firmware not in firmwares:
71 error(f'device "{vendor}.{type}.{devname}" has an invalid firmware file "{firmware}"')
72 elif (firmware.endswith('_TX') and 'tx_' not in type):
73 error(f'device "{vendor}.{type}.{devname}" has an invalid firmware file "{firmware}", it must be a TX target firmware')
74 elif (firmware.endswith('_RX') and 'rx_' not in type):
75 error(f'device "{vendor}.{type}.{devname}" has an invalid firmware file "{firmware}", it must be an RX target firmware')
77 if 'platform' not in device:
78 error(f'device "{vendor}.{type}.{devname}" must have a "platform" child element')
79 else:
80 platform = device['platform']
81 if platform == 'stm32':
82 validate_stm32(vendor, type, devname, device)
83 elif platform == 'esp32':
84 validate_esp32(vendor, type, devname, device)
85 elif platform == 'esp8285':
86 validate_esp8285(vendor, type, devname, device)
87 else:
88 error(f'invalid platform "{platform}" in device "{vendor}.{type}.{devname}"')
90 if 'features' in device:
91 for feature in device['features']:
92 if feature not in ['buzzer', 'unlock-higher-power', 'fan', 'sbus-uart']:
93 error(f'features must contain one or more of [\'buzzer\', \'unlock-higher-power\', \'fan\', \'sbus-uart\'], if present in target "{vendor}.{type}.{devname}"')
95 def validate_vendor(name, types):
96 if name != name.lower():
97 error(f'vendor tag "{vendor}" should be lowercase')
99 if 'name' not in types:
100 error(f'vendor "{vendor}" must have a "name" child element')
102 for type in types:
103 if type not in ['rx_2400', 'rx_900', 'tx_2400', 'tx_900', 'name']:
104 error(f'invalid tag "{type}" in "{vendor}"')
105 if type in ['rx_2400', 'rx_900', 'tx_2400', 'tx_900']:
106 for device in types[type]:
107 validate_devices(name, type, device, types[type][device])
109 if __name__ == '__main__':
110 targets = {}
111 with open('hardware/targets.json') as f:
112 targets = json.load(f)
114 for inifile in glob.iglob('targets/*.ini'):
115 with open(inifile) as ini:
116 for line in ini:
117 if line.startswith('[env:'):
118 try:
119 firmware_file = line[5:line.index('_via_')]
120 firmwares.add(firmware_file)
121 except ValueError:
122 print(line)
123 None
125 for vendor in targets:
126 validate_vendor(vendor, targets[vendor])
128 for inifile in glob.iglob('targets/*.ini'):
129 with open(inifile) as ini:
130 for line in ini:
131 if line.startswith('[env:'):
132 target = line
133 if line.startswith('board_config'):
134 eq = line.find('=')
135 board = line[eq+1:].strip()
136 parts = board.split('.')
137 if len(parts) != 3:
138 error(f'{inifile}: board_config must have 3 parts')
139 else:
140 vendor = parts[0]
141 type = parts[1]
142 device = parts[2]
143 if vendor not in targets:
144 error(f'{inifile}: targets.json file does not contain vendor {vendor}')
145 elif type not in targets[vendor]:
146 error(f'{inifile}: targets.json "{vendor}" does not contain type {type}')
147 elif device not in targets[vendor][type]:
148 error(f'{inifile}: targets.json "{vendor}.{type}" does not contain device {device}')
149 if hadError:
150 sys.exit(1)
151 sys.exit(0)