fbuild 1.2.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fbuild/__init__.py +390 -0
- fbuild/assets/example.txt +1 -0
- fbuild/build/__init__.py +117 -0
- fbuild/build/archive_creator.py +186 -0
- fbuild/build/binary_generator.py +444 -0
- fbuild/build/build_component_factory.py +131 -0
- fbuild/build/build_info_generator.py +624 -0
- fbuild/build/build_state.py +325 -0
- fbuild/build/build_utils.py +93 -0
- fbuild/build/compilation_executor.py +422 -0
- fbuild/build/compiler.py +165 -0
- fbuild/build/compiler_avr.py +574 -0
- fbuild/build/configurable_compiler.py +664 -0
- fbuild/build/configurable_linker.py +637 -0
- fbuild/build/flag_builder.py +214 -0
- fbuild/build/library_dependency_processor.py +185 -0
- fbuild/build/linker.py +708 -0
- fbuild/build/orchestrator.py +67 -0
- fbuild/build/orchestrator_avr.py +651 -0
- fbuild/build/orchestrator_esp32.py +878 -0
- fbuild/build/orchestrator_rp2040.py +719 -0
- fbuild/build/orchestrator_stm32.py +696 -0
- fbuild/build/orchestrator_teensy.py +580 -0
- fbuild/build/source_compilation_orchestrator.py +218 -0
- fbuild/build/source_scanner.py +516 -0
- fbuild/cli.py +717 -0
- fbuild/cli_utils.py +314 -0
- fbuild/config/__init__.py +16 -0
- fbuild/config/board_config.py +542 -0
- fbuild/config/board_loader.py +92 -0
- fbuild/config/ini_parser.py +369 -0
- fbuild/config/mcu_specs.py +88 -0
- fbuild/daemon/__init__.py +42 -0
- fbuild/daemon/async_client.py +531 -0
- fbuild/daemon/client.py +1505 -0
- fbuild/daemon/compilation_queue.py +293 -0
- fbuild/daemon/configuration_lock.py +865 -0
- fbuild/daemon/daemon.py +585 -0
- fbuild/daemon/daemon_context.py +293 -0
- fbuild/daemon/error_collector.py +263 -0
- fbuild/daemon/file_cache.py +332 -0
- fbuild/daemon/firmware_ledger.py +546 -0
- fbuild/daemon/lock_manager.py +508 -0
- fbuild/daemon/logging_utils.py +149 -0
- fbuild/daemon/messages.py +957 -0
- fbuild/daemon/operation_registry.py +288 -0
- fbuild/daemon/port_state_manager.py +249 -0
- fbuild/daemon/process_tracker.py +366 -0
- fbuild/daemon/processors/__init__.py +18 -0
- fbuild/daemon/processors/build_processor.py +248 -0
- fbuild/daemon/processors/deploy_processor.py +664 -0
- fbuild/daemon/processors/install_deps_processor.py +431 -0
- fbuild/daemon/processors/locking_processor.py +777 -0
- fbuild/daemon/processors/monitor_processor.py +285 -0
- fbuild/daemon/request_processor.py +457 -0
- fbuild/daemon/shared_serial.py +819 -0
- fbuild/daemon/status_manager.py +238 -0
- fbuild/daemon/subprocess_manager.py +316 -0
- fbuild/deploy/__init__.py +21 -0
- fbuild/deploy/deployer.py +67 -0
- fbuild/deploy/deployer_esp32.py +310 -0
- fbuild/deploy/docker_utils.py +315 -0
- fbuild/deploy/monitor.py +519 -0
- fbuild/deploy/qemu_runner.py +603 -0
- fbuild/interrupt_utils.py +34 -0
- fbuild/ledger/__init__.py +52 -0
- fbuild/ledger/board_ledger.py +560 -0
- fbuild/output.py +352 -0
- fbuild/packages/__init__.py +66 -0
- fbuild/packages/archive_utils.py +1098 -0
- fbuild/packages/arduino_core.py +412 -0
- fbuild/packages/cache.py +256 -0
- fbuild/packages/concurrent_manager.py +510 -0
- fbuild/packages/downloader.py +518 -0
- fbuild/packages/fingerprint.py +423 -0
- fbuild/packages/framework_esp32.py +538 -0
- fbuild/packages/framework_rp2040.py +349 -0
- fbuild/packages/framework_stm32.py +459 -0
- fbuild/packages/framework_teensy.py +346 -0
- fbuild/packages/github_utils.py +96 -0
- fbuild/packages/header_trampoline_cache.py +394 -0
- fbuild/packages/library_compiler.py +203 -0
- fbuild/packages/library_manager.py +549 -0
- fbuild/packages/library_manager_esp32.py +725 -0
- fbuild/packages/package.py +163 -0
- fbuild/packages/platform_esp32.py +383 -0
- fbuild/packages/platform_rp2040.py +400 -0
- fbuild/packages/platform_stm32.py +581 -0
- fbuild/packages/platform_teensy.py +312 -0
- fbuild/packages/platform_utils.py +131 -0
- fbuild/packages/platformio_registry.py +369 -0
- fbuild/packages/sdk_utils.py +231 -0
- fbuild/packages/toolchain.py +436 -0
- fbuild/packages/toolchain_binaries.py +196 -0
- fbuild/packages/toolchain_esp32.py +489 -0
- fbuild/packages/toolchain_metadata.py +185 -0
- fbuild/packages/toolchain_rp2040.py +436 -0
- fbuild/packages/toolchain_stm32.py +417 -0
- fbuild/packages/toolchain_teensy.py +404 -0
- fbuild/platform_configs/esp32.json +150 -0
- fbuild/platform_configs/esp32c2.json +144 -0
- fbuild/platform_configs/esp32c3.json +143 -0
- fbuild/platform_configs/esp32c5.json +151 -0
- fbuild/platform_configs/esp32c6.json +151 -0
- fbuild/platform_configs/esp32p4.json +149 -0
- fbuild/platform_configs/esp32s3.json +151 -0
- fbuild/platform_configs/imxrt1062.json +56 -0
- fbuild/platform_configs/rp2040.json +70 -0
- fbuild/platform_configs/rp2350.json +76 -0
- fbuild/platform_configs/stm32f1.json +59 -0
- fbuild/platform_configs/stm32f4.json +63 -0
- fbuild/py.typed +0 -0
- fbuild-1.2.8.dist-info/METADATA +468 -0
- fbuild-1.2.8.dist-info/RECORD +121 -0
- fbuild-1.2.8.dist-info/WHEEL +5 -0
- fbuild-1.2.8.dist-info/entry_points.txt +5 -0
- fbuild-1.2.8.dist-info/licenses/LICENSE +21 -0
- fbuild-1.2.8.dist-info/top_level.txt +2 -0
- fbuild_lint/__init__.py +0 -0
- fbuild_lint/ruff_plugins/__init__.py +0 -0
- fbuild_lint/ruff_plugins/keyboard_interrupt_checker.py +158 -0
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
"""
|
|
2
|
+
PlatformIO.ini configuration parser.
|
|
3
|
+
|
|
4
|
+
This module provides functionality to parse platformio.ini files and extract
|
|
5
|
+
environment configurations for building embedded projects.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import configparser
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Dict, List, Optional
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class PlatformIOConfigError(Exception):
|
|
14
|
+
"""Exception raised for platformio.ini configuration errors."""
|
|
15
|
+
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class PlatformIOConfig:
|
|
20
|
+
"""
|
|
21
|
+
Parser for platformio.ini configuration files.
|
|
22
|
+
|
|
23
|
+
This class handles parsing of PlatformIO-style INI files, extracting
|
|
24
|
+
environment configurations, and validating required fields.
|
|
25
|
+
|
|
26
|
+
Example platformio.ini:
|
|
27
|
+
[env:uno]
|
|
28
|
+
platform = atmelavr
|
|
29
|
+
board = uno
|
|
30
|
+
framework = arduino
|
|
31
|
+
|
|
32
|
+
Usage:
|
|
33
|
+
config = PlatformIOConfig(Path("platformio.ini"))
|
|
34
|
+
envs = config.get_environments()
|
|
35
|
+
uno_config = config.get_env_config("uno")
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
REQUIRED_FIELDS = {"platform", "board", "framework"}
|
|
39
|
+
|
|
40
|
+
def __init__(self, ini_path: Path):
|
|
41
|
+
"""
|
|
42
|
+
Initialize the parser with a platformio.ini file.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
ini_path: Path to the platformio.ini file
|
|
46
|
+
|
|
47
|
+
Raises:
|
|
48
|
+
PlatformIOConfigError: If the file doesn't exist or cannot be parsed
|
|
49
|
+
"""
|
|
50
|
+
self.ini_path = ini_path
|
|
51
|
+
|
|
52
|
+
if not ini_path.exists():
|
|
53
|
+
raise PlatformIOConfigError(f"Configuration file not found: {ini_path}")
|
|
54
|
+
|
|
55
|
+
# Use interpolation=None to disable Python's built-in interpolation.
|
|
56
|
+
# PlatformIO uses a different syntax: ${env:section.key} instead of ${section:key}
|
|
57
|
+
# We handle this manually in get_env_config() with a custom regex-based interpolation.
|
|
58
|
+
self.config = configparser.ConfigParser(allow_no_value=True, interpolation=None)
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
self.config.read(ini_path, encoding="utf-8")
|
|
62
|
+
except configparser.Error as e:
|
|
63
|
+
raise PlatformIOConfigError(f"Failed to parse {ini_path}: {e}") from e
|
|
64
|
+
|
|
65
|
+
def get_environments(self) -> List[str]:
|
|
66
|
+
"""
|
|
67
|
+
Get list of all environment names defined in the config.
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
List of environment names (e.g., ['uno', 'mega', 'nano'])
|
|
71
|
+
|
|
72
|
+
Example:
|
|
73
|
+
For [env:uno], [env:mega], returns ['uno', 'mega']
|
|
74
|
+
"""
|
|
75
|
+
envs = []
|
|
76
|
+
for section in self.config.sections():
|
|
77
|
+
if section.startswith("env:"):
|
|
78
|
+
env_name = section.split(":", 1)[1]
|
|
79
|
+
envs.append(env_name)
|
|
80
|
+
return envs
|
|
81
|
+
|
|
82
|
+
def get_env_config(self, env_name: str, _visited: Optional[set] = None, _validate: bool = True) -> Dict[str, str]:
|
|
83
|
+
"""
|
|
84
|
+
Get configuration for a specific environment with inheritance support.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
env_name: Name of the environment (e.g., 'uno')
|
|
88
|
+
_visited: Internal parameter for circular dependency detection
|
|
89
|
+
_validate: Internal parameter to control validation (default: True)
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
Dictionary of configuration key-value pairs
|
|
93
|
+
|
|
94
|
+
Raises:
|
|
95
|
+
PlatformIOConfigError: If environment not found, missing required fields,
|
|
96
|
+
or circular dependency detected
|
|
97
|
+
|
|
98
|
+
Example:
|
|
99
|
+
config.get_env_config('uno')
|
|
100
|
+
# Returns: {'platform': 'atmelavr', 'board': 'uno', 'framework': 'arduino'}
|
|
101
|
+
"""
|
|
102
|
+
# Initialize visited set for circular dependency detection
|
|
103
|
+
if _visited is None:
|
|
104
|
+
_visited = set()
|
|
105
|
+
|
|
106
|
+
# Check for circular dependency
|
|
107
|
+
if env_name in _visited:
|
|
108
|
+
chain = " -> ".join(_visited) + f" -> {env_name}"
|
|
109
|
+
raise PlatformIOConfigError(f"Circular dependency detected in environment inheritance: {chain}")
|
|
110
|
+
|
|
111
|
+
_visited.add(env_name)
|
|
112
|
+
|
|
113
|
+
section = f"env:{env_name}"
|
|
114
|
+
|
|
115
|
+
if section not in self.config:
|
|
116
|
+
available = ", ".join(self.get_environments())
|
|
117
|
+
raise PlatformIOConfigError(f"Environment '{env_name}' not found. " + f"Available environments: {available or 'none'}")
|
|
118
|
+
|
|
119
|
+
# Collect all key-value pairs from the environment section
|
|
120
|
+
# Use raw=True to avoid interpolation errors when referencing parent environments
|
|
121
|
+
env_config = {}
|
|
122
|
+
for key in self.config[section]:
|
|
123
|
+
value = self.config[section].get(key, raw=True)
|
|
124
|
+
# Handle multi-line values (like lib_deps)
|
|
125
|
+
env_config[key] = value.strip() if value else ""
|
|
126
|
+
|
|
127
|
+
# Also check if there's a base [env] section to inherit from
|
|
128
|
+
if "env" in self.config:
|
|
129
|
+
base_config = {}
|
|
130
|
+
for key in self.config["env"]:
|
|
131
|
+
value = self.config["env"].get(key, raw=True)
|
|
132
|
+
base_config[key] = value.strip() if value else ""
|
|
133
|
+
# Environment-specific values override base values
|
|
134
|
+
env_config = {**base_config, **env_config}
|
|
135
|
+
|
|
136
|
+
# Handle 'extends' directive for environment inheritance
|
|
137
|
+
if "extends" in env_config:
|
|
138
|
+
parent_ref = env_config["extends"].strip()
|
|
139
|
+
# Parse parent reference (can be "env:parent" or just "parent")
|
|
140
|
+
parent_name = parent_ref.replace("env:", "").strip()
|
|
141
|
+
|
|
142
|
+
# Recursively get parent config (don't validate parent, it might be abstract)
|
|
143
|
+
parent_config = self.get_env_config(parent_name, _visited, _validate=False)
|
|
144
|
+
|
|
145
|
+
# Merge: parent values first, then child overrides
|
|
146
|
+
merged_config = parent_config.copy()
|
|
147
|
+
for key, value in env_config.items():
|
|
148
|
+
if key == "extends":
|
|
149
|
+
# Remove 'extends' key from final config
|
|
150
|
+
continue
|
|
151
|
+
merged_config[key] = value
|
|
152
|
+
|
|
153
|
+
env_config = merged_config
|
|
154
|
+
|
|
155
|
+
# Now perform manual variable interpolation for cross-environment references
|
|
156
|
+
# This handles ${env:parent.key} syntax
|
|
157
|
+
import re
|
|
158
|
+
|
|
159
|
+
interpolated_config = {}
|
|
160
|
+
for key, value in env_config.items():
|
|
161
|
+
# Look for ${env:name.key} patterns
|
|
162
|
+
pattern = r"\$\{env:([^}]+)\}"
|
|
163
|
+
matches = re.findall(pattern, value)
|
|
164
|
+
|
|
165
|
+
interpolated_value = value
|
|
166
|
+
for match in matches:
|
|
167
|
+
# Parse the reference: "env:parent.build_flags"
|
|
168
|
+
parts = match.split(".")
|
|
169
|
+
if len(parts) == 2:
|
|
170
|
+
ref_env = parts[0]
|
|
171
|
+
ref_key = parts[1]
|
|
172
|
+
|
|
173
|
+
# Get the referenced environment's config
|
|
174
|
+
# Create a new visited set to avoid false circular dependency detection
|
|
175
|
+
# Don't validate the referenced environment (it might be an abstract base)
|
|
176
|
+
ref_config = self.get_env_config(ref_env, set(), _validate=False)
|
|
177
|
+
|
|
178
|
+
if ref_key in ref_config:
|
|
179
|
+
# Replace the variable reference with the actual value
|
|
180
|
+
interpolated_value = interpolated_value.replace(f"${{env:{match}}}", ref_config[ref_key])
|
|
181
|
+
|
|
182
|
+
interpolated_config[key] = interpolated_value
|
|
183
|
+
|
|
184
|
+
env_config = interpolated_config
|
|
185
|
+
|
|
186
|
+
# Validate required fields (only if validation is enabled)
|
|
187
|
+
if _validate:
|
|
188
|
+
missing_fields = self.REQUIRED_FIELDS - set(env_config.keys())
|
|
189
|
+
if missing_fields:
|
|
190
|
+
raise PlatformIOConfigError(f"Environment '{env_name}' is missing required fields: " + f"{', '.join(sorted(missing_fields))}")
|
|
191
|
+
|
|
192
|
+
return env_config
|
|
193
|
+
|
|
194
|
+
def get_build_flags(self, env_name: str) -> List[str]:
|
|
195
|
+
"""
|
|
196
|
+
Parse and return build flags for an environment.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
env_name: Name of the environment
|
|
200
|
+
|
|
201
|
+
Returns:
|
|
202
|
+
List of build flags
|
|
203
|
+
|
|
204
|
+
Example:
|
|
205
|
+
For build_flags = -DDEBUG -DVERSION=1.0
|
|
206
|
+
Returns: ['-DDEBUG', '-DVERSION=1.0']
|
|
207
|
+
"""
|
|
208
|
+
env_config = self.get_env_config(env_name)
|
|
209
|
+
build_flags_str = env_config.get("build_flags", "")
|
|
210
|
+
|
|
211
|
+
if not build_flags_str:
|
|
212
|
+
return []
|
|
213
|
+
|
|
214
|
+
# Split on whitespace and newlines, filter empty strings
|
|
215
|
+
raw_flags = build_flags_str.split()
|
|
216
|
+
flags = []
|
|
217
|
+
|
|
218
|
+
# Handle cases like "-D FLAG" which should become "-DFLAG"
|
|
219
|
+
# PlatformIO allows "-D FLAG=value" format (space after -D)
|
|
220
|
+
i = 0
|
|
221
|
+
while i < len(raw_flags):
|
|
222
|
+
flag = raw_flags[i]
|
|
223
|
+
if flag == "-D" and i + 1 < len(raw_flags):
|
|
224
|
+
# Next token is the define name/value
|
|
225
|
+
next_token = raw_flags[i + 1]
|
|
226
|
+
# Only combine if next token doesn't start with dash
|
|
227
|
+
if not next_token.startswith("-"):
|
|
228
|
+
flags.append(f"-D{next_token}")
|
|
229
|
+
i += 2
|
|
230
|
+
continue
|
|
231
|
+
if flag:
|
|
232
|
+
flags.append(flag)
|
|
233
|
+
i += 1
|
|
234
|
+
|
|
235
|
+
return flags
|
|
236
|
+
|
|
237
|
+
def get_lib_deps(self, env_name: str) -> List[str]:
|
|
238
|
+
"""
|
|
239
|
+
Parse and return library dependencies for an environment.
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
env_name: Name of the environment
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
List of library dependencies
|
|
246
|
+
|
|
247
|
+
Example:
|
|
248
|
+
For lib_deps =
|
|
249
|
+
SPI
|
|
250
|
+
Wire
|
|
251
|
+
Returns: ['SPI', 'Wire']
|
|
252
|
+
"""
|
|
253
|
+
env_config = self.get_env_config(env_name)
|
|
254
|
+
lib_deps_str = env_config.get("lib_deps", "")
|
|
255
|
+
|
|
256
|
+
if not lib_deps_str:
|
|
257
|
+
return []
|
|
258
|
+
|
|
259
|
+
# Split on newlines and commas, strip whitespace, filter empty
|
|
260
|
+
deps = []
|
|
261
|
+
for line in lib_deps_str.split("\n"):
|
|
262
|
+
for dep in line.split(","):
|
|
263
|
+
dep = dep.strip()
|
|
264
|
+
if dep:
|
|
265
|
+
deps.append(dep)
|
|
266
|
+
return deps
|
|
267
|
+
|
|
268
|
+
def has_environment(self, env_name: str) -> bool:
|
|
269
|
+
"""
|
|
270
|
+
Check if an environment exists in the configuration.
|
|
271
|
+
|
|
272
|
+
Args:
|
|
273
|
+
env_name: Name of the environment to check
|
|
274
|
+
|
|
275
|
+
Returns:
|
|
276
|
+
True if environment exists, False otherwise
|
|
277
|
+
"""
|
|
278
|
+
return f"env:{env_name}" in self.config
|
|
279
|
+
|
|
280
|
+
def get_default_environment(self) -> Optional[str]:
|
|
281
|
+
"""
|
|
282
|
+
Get the default environment from platformio.ini.
|
|
283
|
+
|
|
284
|
+
Returns:
|
|
285
|
+
Default environment name, or first available environment, or None
|
|
286
|
+
|
|
287
|
+
Example:
|
|
288
|
+
If [platformio] section has default_envs = uno, returns 'uno'
|
|
289
|
+
Otherwise returns the first environment found
|
|
290
|
+
"""
|
|
291
|
+
# Check for explicit default_envs in [platformio] section
|
|
292
|
+
if "platformio" in self.config:
|
|
293
|
+
default_envs = self.config["platformio"].get("default_envs", "").strip()
|
|
294
|
+
if default_envs:
|
|
295
|
+
# Can be comma-separated, take the first one
|
|
296
|
+
return default_envs.split(",")[0].strip()
|
|
297
|
+
|
|
298
|
+
# Fall back to first environment
|
|
299
|
+
envs = self.get_environments()
|
|
300
|
+
return envs[0] if envs else None
|
|
301
|
+
|
|
302
|
+
def get_src_dir(self) -> Optional[str]:
|
|
303
|
+
"""
|
|
304
|
+
Get source directory override from [platformio] section.
|
|
305
|
+
|
|
306
|
+
Returns:
|
|
307
|
+
Source directory path relative to project root, or None if not specified
|
|
308
|
+
|
|
309
|
+
Example:
|
|
310
|
+
If [platformio] section has src_dir = examples/Blink, returns 'examples/Blink'
|
|
311
|
+
"""
|
|
312
|
+
if "platformio" in self.config:
|
|
313
|
+
src_dir = self.config["platformio"].get("src_dir", "").strip()
|
|
314
|
+
# Remove inline comments (everything after ';')
|
|
315
|
+
if ";" in src_dir:
|
|
316
|
+
src_dir = src_dir.split(";")[0].strip()
|
|
317
|
+
return src_dir if src_dir else None
|
|
318
|
+
return None
|
|
319
|
+
|
|
320
|
+
def get_platformio_config(self, key: str, default: Optional[str] = None) -> Optional[str]:
|
|
321
|
+
"""
|
|
322
|
+
Get a configuration value from the [platformio] section.
|
|
323
|
+
|
|
324
|
+
Args:
|
|
325
|
+
key: Configuration key to retrieve
|
|
326
|
+
default: Default value if key not found
|
|
327
|
+
|
|
328
|
+
Returns:
|
|
329
|
+
Configuration value or default
|
|
330
|
+
|
|
331
|
+
Example:
|
|
332
|
+
build_cache_dir = config.get_platformio_config('build_cache_dir', '.pio/build_cache')
|
|
333
|
+
"""
|
|
334
|
+
if "platformio" in self.config:
|
|
335
|
+
value = self.config["platformio"].get(key, "").strip()
|
|
336
|
+
return value if value else default
|
|
337
|
+
return default
|
|
338
|
+
|
|
339
|
+
def get_board_overrides(self, env_name: str) -> Dict[str, str]:
|
|
340
|
+
"""
|
|
341
|
+
Get board build and upload overrides from environment configuration.
|
|
342
|
+
|
|
343
|
+
Extracts all board_build.* and board_upload.* settings from the
|
|
344
|
+
environment configuration.
|
|
345
|
+
|
|
346
|
+
Args:
|
|
347
|
+
env_name: Name of the environment
|
|
348
|
+
|
|
349
|
+
Returns:
|
|
350
|
+
Dictionary of board override settings (e.g., {'flash_mode': 'dio', 'flash_size': '4MB'})
|
|
351
|
+
|
|
352
|
+
Example:
|
|
353
|
+
For board_build.flash_mode = dio and board_build.flash_size = 4MB
|
|
354
|
+
Returns: {'flash_mode': 'dio', 'flash_size': '4MB'}
|
|
355
|
+
"""
|
|
356
|
+
env_config = self.get_env_config(env_name)
|
|
357
|
+
overrides = {}
|
|
358
|
+
|
|
359
|
+
for key, value in env_config.items():
|
|
360
|
+
if key.startswith("board_build."):
|
|
361
|
+
# Extract the override key (e.g., "flash_mode" from "board_build.flash_mode")
|
|
362
|
+
override_key = key.replace("board_build.", "")
|
|
363
|
+
overrides[override_key] = value
|
|
364
|
+
elif key.startswith("board_upload."):
|
|
365
|
+
# Also handle upload overrides
|
|
366
|
+
override_key = "upload_" + key.replace("board_upload.", "")
|
|
367
|
+
overrides[override_key] = value
|
|
368
|
+
|
|
369
|
+
return overrides
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MCU specifications for various embedded platforms.
|
|
3
|
+
|
|
4
|
+
This module centralizes hardware specifications like flash size and RAM
|
|
5
|
+
for different microcontrollers, making it easier to maintain and extend.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from typing import Optional
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class MCUSpec:
|
|
14
|
+
"""Hardware specifications for a microcontroller."""
|
|
15
|
+
|
|
16
|
+
mcu_id: str
|
|
17
|
+
max_flash: int # Maximum flash size in bytes
|
|
18
|
+
max_ram: int # Maximum RAM size in bytes
|
|
19
|
+
bootloader_size: int = 0 # Bootloader size in bytes (subtracted from flash)
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def usable_flash(self) -> int:
|
|
23
|
+
"""Get usable flash after accounting for bootloader."""
|
|
24
|
+
return self.max_flash - self.bootloader_size
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
# AVR MCU specifications
|
|
28
|
+
AVR_SPECS = {
|
|
29
|
+
"atmega328p": MCUSpec(
|
|
30
|
+
mcu_id="atmega328p",
|
|
31
|
+
max_flash=32768, # 32KB
|
|
32
|
+
max_ram=2048, # 2KB
|
|
33
|
+
bootloader_size=512, # 512B bootloader
|
|
34
|
+
),
|
|
35
|
+
"atmega2560": MCUSpec(
|
|
36
|
+
mcu_id="atmega2560",
|
|
37
|
+
max_flash=262144, # 256KB
|
|
38
|
+
max_ram=8192, # 8KB
|
|
39
|
+
bootloader_size=8192, # 8KB bootloader
|
|
40
|
+
),
|
|
41
|
+
"atmega32u4": MCUSpec(
|
|
42
|
+
mcu_id="atmega32u4",
|
|
43
|
+
max_flash=32768, # 32KB
|
|
44
|
+
max_ram=2560, # 2.5KB
|
|
45
|
+
bootloader_size=4096, # 4KB bootloader
|
|
46
|
+
),
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def get_mcu_spec(mcu_id: str) -> Optional[MCUSpec]:
|
|
51
|
+
"""
|
|
52
|
+
Get MCU specifications by ID.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
mcu_id: MCU identifier (e.g., 'atmega328p')
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
MCUSpec if found, None otherwise
|
|
59
|
+
"""
|
|
60
|
+
return AVR_SPECS.get(mcu_id.lower())
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def get_max_flash(mcu_id: str) -> Optional[int]:
|
|
64
|
+
"""
|
|
65
|
+
Get maximum usable flash for an MCU (after bootloader).
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
mcu_id: MCU identifier
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
Usable flash size in bytes, or None if MCU not found
|
|
72
|
+
"""
|
|
73
|
+
spec = get_mcu_spec(mcu_id)
|
|
74
|
+
return spec.usable_flash if spec else None
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def get_max_ram(mcu_id: str) -> Optional[int]:
|
|
78
|
+
"""
|
|
79
|
+
Get maximum RAM for an MCU.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
mcu_id: MCU identifier
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
RAM size in bytes, or None if MCU not found
|
|
86
|
+
"""
|
|
87
|
+
spec = get_mcu_spec(mcu_id)
|
|
88
|
+
return spec.max_ram if spec else None
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""
|
|
2
|
+
fbuild Daemon - Concurrent Deploy and Monitor Management
|
|
3
|
+
|
|
4
|
+
This package provides a singleton daemon for managing concurrent deploy and monitor
|
|
5
|
+
operations with proper locking and process tree tracking.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from fbuild.daemon.client import (
|
|
9
|
+
ensure_daemon_running,
|
|
10
|
+
get_daemon_status,
|
|
11
|
+
request_build,
|
|
12
|
+
request_deploy,
|
|
13
|
+
request_install_dependencies,
|
|
14
|
+
request_monitor,
|
|
15
|
+
stop_daemon,
|
|
16
|
+
)
|
|
17
|
+
from fbuild.daemon.messages import (
|
|
18
|
+
BuildRequest,
|
|
19
|
+
DaemonState,
|
|
20
|
+
DaemonStatus,
|
|
21
|
+
DeployRequest,
|
|
22
|
+
InstallDependenciesRequest,
|
|
23
|
+
MonitorRequest,
|
|
24
|
+
OperationType,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
"BuildRequest",
|
|
29
|
+
"DaemonState",
|
|
30
|
+
"DaemonStatus",
|
|
31
|
+
"DeployRequest",
|
|
32
|
+
"InstallDependenciesRequest",
|
|
33
|
+
"MonitorRequest",
|
|
34
|
+
"OperationType",
|
|
35
|
+
"ensure_daemon_running",
|
|
36
|
+
"get_daemon_status",
|
|
37
|
+
"request_build",
|
|
38
|
+
"request_deploy",
|
|
39
|
+
"request_install_dependencies",
|
|
40
|
+
"request_monitor",
|
|
41
|
+
"stop_daemon",
|
|
42
|
+
]
|