Skip to content

Commit e147c52

Browse files
committed
modifications
1 parent 76958e5 commit e147c52

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+3032
-1283
lines changed

builder/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,13 @@ def generate_manifest(
256256
)
257257
]
258258

259+
toml_gen_driver = f'{script_dir}/build/display.py'
260+
if os.path.exists(toml_gen_driver):
261+
print(toml_gen_driver)
262+
file_path, file_name = os.path.split(toml_gen_driver)
263+
entry = f"freeze('{file_path}', '{file_name}')"
264+
manifest_files.append(entry)
265+
259266
for file in frozen_manifest_files:
260267
if not os.path.exists(file):
261268
raise RuntimeError(f'File not found "{file}"')

builder/toml_reader.py

Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
import os
2+
3+
try:
4+
import tomlib as toml
5+
except ImportError:
6+
try:
7+
import toml
8+
except ImportError:
9+
raise RuntimeError(
10+
'A "toml" library is needed to read a .toml file\n'
11+
'One is included with Python 3.11+ or you can install \n'
12+
'into your current version of Python using the following command:\n'
13+
'\n'
14+
'pip3 install toml'
15+
)
16+
17+
18+
class TOMLMeta(type):
19+
20+
def __call__(cls, name, parent=None, **kwargs):
21+
children = {}
22+
for key, value in list(kwargs.items()):
23+
if isinstance(value, dict):
24+
children[key] = value
25+
del kwargs[key]
26+
27+
instance = super().__call__(name, parent=parent, **kwargs)
28+
29+
for child_name, child_data in children.items():
30+
child = TOMLObject(child_name, parent=instance, **child_data)
31+
instance.add_child(child)
32+
33+
return instance
34+
35+
36+
class TOMLObject(metaclass=TOMLMeta):
37+
38+
def __init__(self, name, parent=None, **kwargs):
39+
40+
if parent is not None and parent.name == 'MCU':
41+
self.build_args = kwargs
42+
43+
self.name = name
44+
self.parent = parent
45+
self.__kwargs = kwargs
46+
self.__children = []
47+
self.imports = []
48+
self.mcu = None
49+
50+
def add_child(self, child):
51+
if self.name == 'MCU':
52+
self.__dict__.update(child.__dict__)
53+
self.board = child.name
54+
self.name = 'MCU'
55+
elif self.parent is None and child.name == 'MCU':
56+
self.mcu = TOMLmcu(child)
57+
else:
58+
self.__children.append(child)
59+
60+
def __getattr__(self, item):
61+
if item in self.__dict__:
62+
return self.__dict__[item]
63+
64+
if item in self.__kwargs:
65+
return self.__kwargs[item]
66+
67+
raise AttributeError(item)
68+
69+
@property
70+
def fqn(self):
71+
if self.__kwargs:
72+
if 'params' in self.__kwargs or 'value' in self.__kwargs:
73+
return self.parent.fqn + '.' + self.name
74+
75+
return self.name + ' = ' + self.parent.fqn
76+
77+
if self.name == 'I2C':
78+
return 'i2c.I2C'
79+
80+
if self.name == 'SPI':
81+
return 'machine.SPI'
82+
83+
if self.name == 'SDCard':
84+
return 'machine.SDCard'
85+
86+
if self.name.lower() in display_drivers:
87+
return self.name.lower() + '.' + self.name
88+
89+
if self.name.lower() in indev_drivers:
90+
return self.name.lower() + '.' + self.name
91+
92+
if self.name.lower() in io_expanders:
93+
return self.name.lower() + '.' + self.name
94+
95+
if self.name in ('I80Bus', 'SPIBus', 'I2CBus', 'RGBBus'):
96+
return 'lcd_bus.' + self.name
97+
98+
if self.parent is None:
99+
return None
100+
101+
if self.parent.name:
102+
return self.parent.fqn + '.' + self.name
103+
104+
return self.name
105+
106+
@property
107+
def var_names(self):
108+
if self.__kwargs:
109+
fqn = self.fqn
110+
111+
if '=' in fqn:
112+
return [fqn.split('=')[0].strip()]
113+
114+
return []
115+
116+
var_names = []
117+
118+
for child in self.__children:
119+
var_names.extend(child.var_names)
120+
121+
return var_names
122+
123+
@property
124+
def constants(self):
125+
res = []
126+
127+
if not self.__children:
128+
for key, value in list(self.__kwargs.items()):
129+
if not isinstance(value, int) or key == 'value':
130+
continue
131+
132+
name = self.name.upper()
133+
134+
key_upper = key.upper()
135+
if name not in key_upper:
136+
key_upper = name + '_' + key_upper
137+
138+
res.append(f'_{key_upper} = const({value})')
139+
self.__kwargs[key] = f'_{key_upper}'
140+
else:
141+
for child in self.__children:
142+
res.extend(child.constants)
143+
144+
return res
145+
146+
def __str__(self):
147+
if self.parent is None:
148+
var_names = self.var_names
149+
150+
output = []
151+
output.extend(self.constants)
152+
153+
for child in self.__children:
154+
if child.name not in var_names:
155+
module = child.fqn.split('.')[0]
156+
if module not in self.imports:
157+
self.imports.append(module)
158+
output.extend(['', f'import {module}', ''])
159+
160+
output.append(str(child))
161+
162+
if output:
163+
output = [
164+
'from micropython import const',
165+
'import lvgl as lv',
166+
'',
167+
''
168+
] + output
169+
170+
return '\n'.join(output)
171+
172+
if self.__children and not self.__kwargs:
173+
output = [str(child) for child in self.__children]
174+
return '\n'.join(output)
175+
176+
fqn = self.fqn
177+
178+
if len(self.__kwargs) == 1:
179+
key = list(self.__kwargs.keys())[0]
180+
if key == 'params':
181+
params = ', '.join(str(itm) for itm in self.__kwargs[key])
182+
return f'{fqn}({params})'
183+
elif key == 'value':
184+
return f'{fqn} = ' + str(self.__kwargs[key])
185+
else:
186+
return f'{fqn}({key}={str(self.__kwargs[key])})'
187+
else:
188+
params = ',\n'.join(f' {k}={str(v)}' for k, v in self.__kwargs.items() if not isinstance(v, dict))
189+
if params:
190+
output = [f'{fqn}(\n{params}\n)', '']
191+
else:
192+
raise RuntimeError
193+
194+
for child in self.__children:
195+
output.append(self.name + '.' + str(child).split('.', 2)[-1])
196+
197+
if len(output) > 2:
198+
output.append('')
199+
200+
return '\n'.join(output)
201+
202+
203+
class TOMLmcu:
204+
205+
def __init__(self, mcu):
206+
name = mcu.board
207+
build_args = mcu.build_args
208+
209+
command = [name]
210+
for arg, value in build_args.items():
211+
if arg.islower():
212+
build_arg = '--' + arg.replace('_', '-')
213+
if isinstance(value, bool) and not value:
214+
raise SyntaxError(
215+
'optionless build commands must be set to "true"\n'
216+
f'if they are used in the toml file. ({arg} = {repr(value)})'
217+
)
218+
else:
219+
build_arg = arg
220+
221+
if not isinstance(value, bool):
222+
build_arg = f'{build_arg}={value}'
223+
224+
command.append(build_arg)
225+
226+
self.build_command = command
227+
228+
229+
base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
230+
231+
display_driver_path = os.path.join(base_path, 'api_drivers/common_api_drivers/display')
232+
indev_driver_path = os.path.join(base_path, 'api_drivers/common_api_drivers/indev')
233+
io_expander_path = os.path.join(base_path, 'api_drivers/common_api_drivers/io_expander')
234+
235+
236+
display_drivers = [file for file in os.listdir(display_driver_path) if not file.endswith('.wip') and not file.endswith('.py')]
237+
indev_drivers = [file[:-3] for file in os.listdir(indev_driver_path) if file.endswith('.py')]
238+
io_expanders = [file[:-3] for file in os.listdir(io_expander_path) if file.endswith('.py')]
239+
240+
241+
def run(toml_path, output_file):
242+
243+
if not os.path.exists(toml_path):
244+
raise RuntimeError(f'inable to locate .toml ({toml_path})')
245+
246+
try:
247+
with open(toml_path, 'r') as f:
248+
toml_data = toml.load(f)
249+
250+
toml_obj = TOMLObject('', **toml_data)
251+
252+
t_data = str(toml_obj)
253+
254+
if t_data:
255+
with open(output_file, 'w') as f:
256+
f.write(t_data)
257+
258+
displays = [f'DISPLAY={item}' for item in toml_obj.imports if item in display_drivers]
259+
indevs = [f'INDEV={item}' for item in toml_obj.imports if item in indev_drivers]
260+
expanders = [f'EXPANDER={item}' for item in toml_obj.imports if item in io_expanders]
261+
262+
if toml_obj.mcu is None:
263+
build_command = []
264+
else:
265+
build_command = toml_obj.build_command
266+
267+
for display in displays[:]:
268+
if display not in build_command:
269+
build_command.append(display)
270+
271+
for indev in indevs[:]:
272+
if indev not in build_command:
273+
build_command.append(indev)
274+
275+
for expander in expanders[:]:
276+
if expander not in build_command:
277+
build_command.append(expander)
278+
279+
return build_command
280+
281+
except OSError as err:
282+
raise RuntimeError(f'Unable to write data to {output_file}') from err
283+
except Exception as err: # NOQA
284+
raise SyntaxError(f'Unable to parse .toml file ({toml_path})') from err
285+
286+

example_build_toml.toml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
2+
[MCU.esp32]
3+
BOARD = "ESP32_GENERIC_S3"
4+
BOARD_VARIANT = "SPIRAM_OCT"
5+
octal_flash = true
6+
flash_size = 16
7+
enable_jtag_repl = 'n'
8+
enable_cdc_repl = 'n'
9+
enable_uart_repl = 'y'
10+
uart_repl_bitrate = 115200
11+
12+
13+
14+
[I80Bus.display_bus]
15+
data0 = 9
16+
data1 = 46
17+
data2 = 3
18+
data3 = 8
19+
data4 = 18
20+
data5 = 17
21+
data6 = 16
22+
data7 = 15
23+
dc = 0
24+
wr = 47
25+
cs = -1
26+
freq = 20000000
27+
28+
29+
[I2C.Bus.i2c_bus]
30+
host = 0
31+
scl = 5
32+
sda = 6
33+
freq = 100000
34+
35+
36+
[I2C.Device.indev_device]
37+
bus = "i2c_bus"
38+
dev_id = "ft6x36.I2C_ADDR"
39+
reg_bits = "ft6x36.BITS"
40+
41+
42+
[ST7796.display]
43+
data_bus = "display_bus"
44+
display_width = 320
45+
display_height = 480
46+
backlight_pin = 45
47+
color_byte_order = "st7789.BYTE_ORDER_BGR"
48+
color_space = "lv.COLOR_FORMAT.RGB565"
49+
rgb565_byte_swap = true
50+
51+
[ST7796.display.init]
52+
params = []
53+
54+
[FT6x36.indev]
55+
device = "indev_device"
56+
57+
[display.set_color_inversion]
58+
params = [true]
59+
60+
[display.set_rotation]
61+
params = ["lv.DISPLAY_ROTATION._90"]
62+
63+
[display.set_backlight]
64+
params = [100]
65+
66+
[task_handler.TaskHandler]
67+
params=[]

0 commit comments

Comments
 (0)