Skip to content

Commit bda4c92

Browse files
authored
Merge pull request #139 from ExpressLRS/fix-devices-with-spaces
Validate vendor and device JSON keys, fix "tunerc 2.4g nano pa rx" device name
2 parents 639edfe + dc405fd commit bda4c92

4 files changed

Lines changed: 51 additions & 38 deletions

File tree

.github/hardware.py

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ def validate(target, layout, device, type):
213213
for field in dict(filter(ignore_undef_pins, layout.items())):
214214
# Ensure that the layout field is a valid field from the hardware list
215215
if field not in hardware_fields.keys():
216-
print(f'device "{target}" has an unknown field name {field}')
216+
print(f'ERROR: device "{target}" has an unknown field name {field}')
217217
had_error = True
218218
else:
219219
had_error |= validate_pin_uniqueness(target, layout, field)
@@ -244,15 +244,15 @@ def validate_field_grouping(target, layout, field, field_group):
244244
if field in group[0]:
245245
for must in group[0] + group[1]:
246246
if must not in layout:
247-
print(f'device "{target}" because "{field}" is defined all other related fields must also be defined {must}')
247+
print(f'ERROR: device "{target}" because "{field}" is defined all other related fields must also be defined {must}')
248248
print(f'\t{group[0] + group[1]}')
249249
had_error = True
250250
found = True if group[2] == [] else False
251251
for one in group[2]:
252252
if one in layout:
253253
found = True
254254
if not found:
255-
print(f'device "{target}" because "{field}" is defined at least one of the following fields must also be {group[2]}')
255+
print(f'ERROR: device "{target}" because "{field}" is defined at least one of the following fields must also be {group[2]}')
256256
had_error = True
257257
return had_error
258258

@@ -267,7 +267,7 @@ def validate_pin_uniqueness(target, layout, field):
267267
if field in duplicate and used_pins[pin] in duplicate:
268268
allowed = True
269269
if not allowed:
270-
print(f'device "{target}" PIN {pin} "{field}" is already assigned to "{used_pins[pin]}"')
270+
print(f'ERROR: device "{target}" PIN {pin} "{field}" is already assigned to "{used_pins[pin]}"')
271271
had_error = True
272272
else:
273273
used_pins[pin] = field
@@ -284,32 +284,32 @@ def validate_power_config(target, layout):
284284
power_default = layout['power_default']
285285
power_high = layout['power_high']
286286
if power_min > power_max:
287-
print(f'device "{target}" power_min must be less than or equal to power_max')
287+
print(f'ERROR: device "{target}" power_min must be less than or equal to power_max')
288288
had_error = True
289289
if power_default < power_min or power_default > power_max:
290-
print(f'device "{target}" power_default must lie between power_min and power_max')
290+
print(f'ERROR: device "{target}" power_default must lie between power_min and power_max')
291291
had_error = True
292292
if power_high < power_min or power_high > power_max:
293-
print(f'device "{target}" power_high must lie between power_min and power_max')
293+
print(f'ERROR: device "{target}" power_high must lie between power_min and power_max')
294+
had_error = True
295+
if power_values and power_max - power_min + 1 > len(power_values):
296+
print(f'ERROR: device "{target}" power_values must have the correct number of entries to match all values from power_min to power_max')
297+
had_error = True
298+
if power_values_dual and power_max - power_min + 1 > len(power_values_dual):
299+
print(f'ERROR: device "{target}" power_values_dual must have the correct number of entries to match all values from power_min to power_max')
294300
had_error = True
295-
if power_values and power_max - power_min + 1 != len(power_values):
296-
print(f'device "{target}" power_values must have the correct number of entries to match all values from power_min to power_max')
297-
had_error = power_max - power_min + 1 > len(power_values)
298-
if power_values_dual and power_max - power_min + 1 != len(power_values_dual):
299-
print(f'device "{target}" power_values_dual must have the correct number of entries to match all values from power_min to power_max')
300-
had_error = power_max - power_min + 1 > len(power_values_dual)
301301
if layout['power_control'] == 3 and 'power_apc2' not in layout:
302-
print(f'device "{target}" defines power_control as DACWRITE and power_apc2 is undefined')
302+
print(f'ERROR: device "{target}" defines power_control as DACWRITE and power_apc2 is undefined')
303303
had_error = True
304304
if 'power_values2' in layout:
305305
if len(layout['power_values2']) != len(power_values):
306-
print(f'device "{target}" power_values2 must have the same number of entries as power_values')
306+
print(f'ERROR: device "{target}" power_values2 must have the same number of entries as power_values')
307307
had_error = True
308308
if layout['power_control'] != 3:
309-
print(f'device "{target}" power_values2 is defined so power_control must be set to 3 (DACWRITE)')
309+
print(f'ERROR: device "{target}" power_values2 is defined so power_control must be set to 3 (DACWRITE)')
310310
had_error = True
311311
if 'power_apc2' not in layout:
312-
print(f'device "{target}" power_values2 is defined so the power_apc2 pin must also be defined')
312+
print(f'ERROR: device "{target}" power_values2 is defined so the power_apc2 pin must also be defined')
313313
had_error = True
314314
return had_error
315315

@@ -318,10 +318,10 @@ def validate_backpack(target, layout):
318318
had_error = False
319319
if 'passthrough_baud' in layout:
320320
if layout['serial_rx'] == layout['serial_tx'] and layout['passthrough_baud'] != 230400:
321-
print(f'device "{target}" an external module with a backpack should set the baud rate to 230400')
321+
print(f'ERROR: device "{target}" an external module with a backpack should set the baud rate to 230400')
322322
had_error = True
323323
if layout['serial_rx'] != layout['serial_tx'] and layout['passthrough_baud'] != 460800:
324-
print(f'device "{target}" an internal module with a backpack should set the baud rate to 460800')
324+
print(f'ERROR: device "{target}" an internal module with a backpack should set the baud rate to 460800')
325325
had_error = True
326326
return had_error
327327

@@ -330,18 +330,18 @@ def validate_joystick(target, layout):
330330
had_error = False
331331
if 'joystick' in layout or 'joystick_values' in layout:
332332
if 'joystick' not in layout:
333-
print(f'device "{target}" joystick_values is defined so the joystick pin must also be defined')
333+
print(f'ERROR: device "{target}" joystick_values is defined so the joystick pin must also be defined')
334334
had_error = True
335335
elif 'joystick_values' not in layout:
336-
print(f'device "{target}" joystick is defined so the joystick_values must also be defined')
336+
print(f'ERROR: device "{target}" joystick is defined so the joystick_values must also be defined')
337337
had_error = True
338338
elif len(layout['joystick_values']) != 6:
339-
print(f'device "{target}" joystick_values must have 6 values defined')
339+
print(f'ERROR: device "{target}" joystick_values must have 6 values defined')
340340
had_error = True
341341
else:
342342
for value in layout['joystick_values']:
343343
if value < 0 or value > 4095:
344-
print(f'device "{target}" joystick_values must be between 0 and 4095 inclusive')
344+
print(f'ERROR: device "{target}" joystick_values must be between 0 and 4095 inclusive')
345345
had_error = True
346346
return had_error
347347

@@ -354,7 +354,7 @@ def validate_pwm_outputs(target, layout):
354354
field in layout and \
355355
layout[field] in layout['pwm_outputs'] and \
356356
field not in allowable_pwm_shared:
357-
print(f'device "{target}" pwm_output pin {layout[field]} is not allowed to be shared with {field}')
357+
print(f'ERROR: device "{target}" pwm_output pin {layout[field]} is not allowed to be shared with {field}')
358358
had_error = True
359359
return had_error
360360

@@ -363,10 +363,10 @@ def validate_pin_function(target, layout, field, platform):
363363
if hardware_fields[field].value > FieldType.PIN.value:
364364
function = get_pin_function(platform, layout[field])
365365
if function is None:
366-
print(f'device "{target}" has an invalid pin number for {field}, {layout[field]}')
366+
print(f'ERROR: device "{target}" has an invalid pin number for {field}, {layout[field]}')
367367
return True
368368
if hardware_fields[field] == FieldType.INPUT and not (function & 1):
369-
print(f'device "{target}" pin for {field} must be assigned to a pin that supports INPUT')
369+
print(f'ERROR: device "{target}" pin for {field} must be assigned to a pin that supports INPUT')
370370
return True
371371
return False
372372

@@ -375,5 +375,5 @@ def validate_vtx_amp_pwm(target, layout, platform):
375375
if platform == 'esp32' and 'vtx_amp_pwm' in layout:
376376
function = get_pin_function(platform, layout['vtx_amp_pwm'])
377377
if function is not None and function & 8 != 8:
378-
print(f'device "{target}" "vtx_amp_pwm" is preferred to be a DAC pin if possible, but PWM output is supported')
378+
print(f'NOTICE: device "{target}" "vtx_amp_pwm" is preferred to be a DAC pin if possible, but PWM output is supported')
379379
return False

.github/targets_validator.py

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,25 @@
33
import glob
44
import argparse
55
import hardware
6+
import re
67

78
hadError = False
89
warnEnabled = False
910
firmwares = set()
1011

12+
1113
def error(msg):
1214
global hadError
1315
hadError = True
14-
print(msg)
16+
print("ERROR: " + msg)
17+
1518

1619
def warn(msg):
1720
if warnEnabled:
1821
global hadError
1922
hadError = True
20-
print(msg)
23+
print("WARNING: " + msg)
24+
2125

2226
def validate_stm32(vendor, type, devname, device):
2327
for method in device['upload_methods']:
@@ -37,6 +41,7 @@ def validate_stm32(vendor, type, devname, device):
3741
error(f'The "stlink" attribute for target "{vendor}.{type}.{devname}" must have a valid "bootloader"')
3842
# could check the existence of the bootloader file
3943

44+
4045
def validate_esp(vendor, type, devname, device):
4146
if 'lua_name' not in device:
4247
error(f'device "{vendor}.{type}.{devname}" must have a "lua_name" child element')
@@ -80,21 +85,25 @@ def validate_esp(vendor, type, devname, device):
8085
if '_ESP8285_' not in device['firmware']:
8186
error(f'device "{vendor}.{type}.{devname}" firmware and platform MUST match')
8287

88+
8389
def validate_esp32(vendor, type, devname, device):
8490
for method in device['upload_methods']:
8591
if method not in ['uart', 'etx', 'wifi', 'betaflight']:
8692
error(f'Invalid upload method "{method}" for target "{vendor}.{type}.{devname}"')
8793
validate_esp(vendor, type, devname, device)
8894

95+
8996
def validate_esp8285(vendor, type, devname, device):
9097
for method in device['upload_methods']:
9198
if method not in ['uart', 'wifi', 'betaflight']:
9299
error(f'Invalid upload method "{method}" for target "{vendor}.{type}.{devname}"')
93100
validate_esp(vendor, type, devname, device)
94101

95102
def validate_devices(vendor, type, devname, device):
96-
if devname != devname.lower():
97-
error(f'device tag "{devname}" should be lowercase')
103+
allowed_json_key_characters = re.compile("^[a-z0-9_-]+$")
104+
if not allowed_json_key_characters.match(devname):
105+
error(f'device tag "{devname}" can only include lowercase a-z, 0-9, and underscores and dashes')
106+
98107
if 'product_name' not in device:
99108
error(f'device "{vendor}.{type}.{devname}" must have a "product_name" child element')
100109
if 'upload_methods' not in device:
@@ -132,19 +141,21 @@ def validate_devices(vendor, type, devname, device):
132141
error(f'features must contain one or more of [\'buzzer\', \'unlock-higher-power\', \'fan\', \'sbus-uart\'], if present in target "{vendor}.{type}.{devname}"')
133142

134143
def validate_vendor(name, types):
135-
if name != name.lower():
136-
error(f'vendor tag "{vendor}" should be lowercase')
144+
allowed_json_key_characters = re.compile("^[a-z0-9_-]+$")
145+
if not allowed_json_key_characters.match(name):
146+
error(f'vendor tag "{name}" can only include lowercase a-z, 0-9, and underscores and dashes')
137147

138148
if 'name' not in types:
139149
error(f'vendor "{vendor}" must have a "name" child element')
140150

141151
for type in types:
142152
if type not in ['rx_2400', 'rx_900', 'rx_dual', 'tx_2400', 'tx_900', 'tx_dual', 'name']:
143153
error(f'invalid tag "{type}" in "{vendor}"')
144-
if type in ['rx_2400', 'rx_900', 'rx_dual', 'tx_2400', 'tx_900', 'tx_dual']:
154+
if type in ['rx_2400', 'rx_900', 'rx_dual', 'tx_2400', 'tx_900', 'tx_dual']:
145155
for device in types[type]:
146156
validate_devices(name, type, device, types[type][device])
147157

158+
148159
if __name__ == '__main__':
149160
parser = argparse.ArgumentParser(description="Configure Binary Firmware")
150161
parser.add_argument("--warn", "-w", action='store_true', default=False, help="Print warnings")
@@ -175,7 +186,7 @@ def validate_vendor(name, types):
175186
target = line
176187
if line.startswith('board_config'):
177188
eq = line.find('=')
178-
board = line[eq+1:].strip()
189+
board = line[eq + 1:].strip()
179190
parts = board.split('.')
180191
if len(parts) != 3:
181192
error(f'{inifile}: board_config must have 3 parts')
@@ -191,4 +202,4 @@ def validate_vendor(name, types):
191202
error(f'{inifile}: targets.json "{vendor}.{type}" does not contain device {device}')
192203
if hadError:
193204
sys.exit(1)
194-
sys.exit(0)
205+
sys.exit(0)

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
.DS_Store
2+
.idea
3+
__pycache__

targets.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@
119119
"overlay": {
120120
"vbat_offset": 0,
121121
"vbat_scale": 908,
122-
"vbat_atten": 7
122+
"vbat_atten": 7
123123
},
124124
"upload_methods": ["uart", "wifi", "betaflight"],
125125
"min_version": "3.5.0",
@@ -3016,7 +3016,7 @@
30163016
"tunerc": {
30173017
"name": "TuneRC",
30183018
"rx_2400": {
3019-
"tunerc 2.4g nano pa rx": {
3019+
"tunerc_2400_nano_pa_rx": {
30203020
"product_name": "TuneRC 2.4G nano PA RX",
30213021
"lua_name": "TuneRC 2G4 nano",
30223022
"layout_file": "Generic C3 2400 PA.json",

0 commit comments

Comments
 (0)