forked from ExpressLRS/ExpressLRS
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathUnifiedConfiguration.py
More file actions
157 lines (132 loc) · 5.71 KB
/
UnifiedConfiguration.py
File metadata and controls
157 lines (132 loc) · 5.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#!/usr/bin/python
import argparse
import json
import struct
import sys
from external import jmespath
def findFirmwareEnd(f):
f.seek(0, 0)
(magic, segments, _, _, _) = struct.unpack('<BBBBI', f.read(8))
if magic != 0xe9:
sys.stderr.write('The file provided does not the right magic for a firmware file!\n')
exit(1)
is8285 = False
if segments == 2: # we have to assume it's an ESP8266/85
f.seek(0x1000, 0)
(magic, segments, _, _, _) = struct.unpack('<BBBBI', f.read(8))
is8285 = True
else:
f.seek(24, 0)
for _ in range(segments):
(_, size) = struct.unpack('<II', f.read(8))
f.seek(size, 1)
pos = f.tell()
pos = (pos + 16) & ~15
if not is8285:
pos = pos + 32
return pos
def appendToFirmware(firmware_file, product_name, lua_name, defines, config, layout_file):
product = (product_name.encode() + (b'\0' * 128))[0:128]
device = (lua_name.encode() + (b'\0' * 16))[0:16]
end = findFirmwareEnd(firmware_file)
firmware_file.seek(end, 0)
firmware_file.write(product)
firmware_file.write(device)
defines = (defines.encode() + (b'\0' * 512))[0:512]
firmware_file.write(defines)
if layout_file is not None:
try:
with open(layout_file) as h:
hardware = json.load(h)
if 'overlay' in config:
hardware.update(config['overlay'])
layout = (json.JSONEncoder().encode(hardware).encode() + (b'\0' * 2048))[0:2048]
firmware_file.write(layout)
except EnvironmentError:
sys.stderr.write(f'Error opening file "{layout_file}"\n')
exit(1)
else:
firmware_file.write(b'\0' * 2048)
if config is not None and 'logo_file' in config:
logo_file = f"hardware/logo/{config['logo_file']}"
with open(logo_file, 'rb') as f:
firmware_file.write(f.read())
if config is not None and 'prior_target_name' in config:
firmware_file.write(b'\xBE\xEF\xCA\xFE')
firmware_file.write(config['prior_target_name'].upper().encode())
firmware_file.write(b'\0')
def doConfiguration(file, defines, config, moduletype, frequency, platform, device_name):
product_name = "Unified"
lua_name = "Unified"
layout = None
targets = {}
with open('hardware/targets.json') as f:
targets = json.load(f)
if config is not None:
config ='.'.join(map(lambda s: f'"{s}"', config.split('.')))
config = jmespath.search(config, targets)
elif not sys.stdin.isatty():
print('Not running in an interactive shell, leaving the firmware "bare".\n')
print('The current compile options (user defines) have been included.')
print('You will be able to configure the hardware via the web UI on the device.')
else:
products = []
i = 0
for k in jmespath.search(f'[*."{moduletype}_{frequency}".*][][?platform==`{platform}`][].product_name', targets):
i += 1
products.append(k)
print(f"{i}) {k}")
print('Choose a configuration to load into the firmware file (press enter to leave bare)')
choice = input()
if choice != "":
config = products[int(choice)-1]
config = jmespath.search(f'[*."{moduletype}_{frequency}".*][][?product_name==`{config}`][]', targets)[0]
if config is not None:
product_name = config['product_name']
lua_name = config['lua_name']
dir = 'TX' if moduletype == 'tx' else 'RX'
layout = f"hardware/{dir}/{config['layout_file']}"
lua_name = lua_name if device_name is None else device_name
appendToFirmware(file, product_name, lua_name, defines, config, layout)
def appendConfiguration(source, target, env):
target_name = env.get('PIOENV', '').upper()
device_name = env.get('DEVICE_NAME', None)
config = env.GetProjectOption('board_config', None)
if 'UNIFIED_' not in target_name and config is None:
return
moduletype = ''
frequency = ''
if config is not None:
moduletype = 'tx' if '.tx_' in config else 'rx'
frequency = '2400' if '_2400.' in config else '900'
else:
moduletype = 'tx' if '_TX_' in target_name else 'rx'
frequency = '2400' if '_2400_' in target_name else '900'
if env.get('PIOPLATFORM', '') == 'espressif32':
platform = 'esp32'
if 'esp32-s3' in env.get('BOARD', ''):
platform = 'esp32-s3'
else:
platform = 'esp8285'
print(platform)
defines = json.JSONEncoder().encode(env['OPTIONS_JSON'])
with open(str(target[0]), "r+b") as firmware_file:
doConfiguration(firmware_file, defines, config, moduletype, frequency, platform, device_name)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Configure Unified Firmware")
parser.add_argument("--target", type=str, help="Path into 'targets.json' file for hardware configuration")
parser.add_argument("--options", type=str, help="JSON document with configuration options")
parser.add_argument("file", type=argparse.FileType("r+b"), help="The firmware file to configure")
args = parser.parse_args()
targets = {}
with open('hardware/targets.json') as f:
targets = json.load(f)
moduletype = 'tx' if '.tx_' in args.target else 'rx'
config ='.'.join(map(lambda s: f'"{s}"', args.target.split('.')))
config = jmespath.search(config, targets)
if config is not None:
product_name = config['product_name']
lua_name = config['lua_name']
dir = 'TX' if moduletype == 'tx' else 'RX'
layout = f"hardware/{dir}/{config['layout_file']}"
appendToFirmware(args.file, product_name, lua_name, args.options, config, layout)