fix(espidf): recuperar esp_camera.h — se perdio al migrar a arduino-esp32 3.x
Los dos ejemplos de camara (esp32cam-lcd-preview y esp32cam-webcam-demo) morian con "esp_camera.h: No such file or directory". No es que el ejemplo estuviera mal: es una regresion de la migracion. El arbol viejo /opt/arduino-esp32 (2.x) traia un SDK precompilado con esp32-camera dentro, en tools/sdk/<target>/include/esp32-camera/, para esp32, c3, s2 y s3. El componente 3.x que usamos ahora NO lo trae, y su idf_component.yml tampoco depende de el, asi que el header simplemente dejo de existir. Por eso funcionaba antes y dejo de funcionar sin que nadie tocara el ejemplo. Mezclar los headers de la 2.x en este build no es opcion — vienen con su SDK precompilado y aqui compilamos contra IDF 5. Lo correcto en el mundo 3.x es pedirle el componente al gestor: la plantilla no traia idf_component.yml, asi que todo lo gestionado llegaba de rebote por el manifiesto de arduino-esp32, y lo que el no arrastra hay que pedirlo explicitamente. _detect_camera_usage() ve el include y _add_managed_components() escribe main/idf_component.yml con espressif/esp32-camera. Verificado en el contenedor sobre el mismo directorio que fallaba: el gestor descarga 2.1.7, el configure termina con esp32-camera en la lista de componentes, y sketch.ino.cpp compila.
This commit is contained in:
parent
a13eb3e7e2
commit
119aa5982e
|
|
@ -487,6 +487,65 @@ class ESPIDFCompiler:
|
|||
return True
|
||||
return any(v in f for v in ('nano_nora', 'm5stack_cardputer', 'm5stack_stamps3', 'm5stamp_s3'))
|
||||
|
||||
# Cache: boards.txt is a few hundred KB and never changes at runtime.
|
||||
_variant_cache: dict = {}
|
||||
|
||||
def _arduino_variant(self, board_fqbn: str, idf_target: str) -> str:
|
||||
"""The Arduino VARIANT for this FQBN, from arduino-esp32's boards.txt.
|
||||
|
||||
Without this every board builds against ``variants/<chip>/``, i.e. as a
|
||||
generic dev-kit, and the board's own pin names never exist: a XIAO
|
||||
sketch dies on ``D1``, an M5 sketch on its silk names. Since those are
|
||||
exactly the sketches people copy from vendor wikis, the emulator has to
|
||||
get this right to be believable.
|
||||
|
||||
boards.txt is the authority (``<board>.build.variant=<variant>``), so it
|
||||
is read rather than guessed; anything not found falls back to the chip,
|
||||
which is the previous behaviour.
|
||||
"""
|
||||
board_id = board_fqbn.split(':')[-1].split('?')[0].strip()
|
||||
if not board_id:
|
||||
return idf_target
|
||||
key = (board_id, idf_target)
|
||||
if key in self._variant_cache:
|
||||
return self._variant_cache[key]
|
||||
|
||||
variant = idf_target
|
||||
# The 3.x core first: it is the one the IDF5 targets build against.
|
||||
roots = [
|
||||
r
|
||||
for r in (
|
||||
os.environ.get('ARDUINO_ESP32_V3_PATH', '/opt/arduino-esp32-3'),
|
||||
os.environ.get('ARDUINO_ESP32_PATH', '/opt/arduino-esp32'),
|
||||
)
|
||||
if r
|
||||
]
|
||||
for root in roots:
|
||||
boards_txt = Path(root) / 'boards.txt'
|
||||
if not boards_txt.is_file():
|
||||
continue
|
||||
try:
|
||||
text = boards_txt.read_text(encoding='utf-8', errors='ignore')
|
||||
except OSError:
|
||||
continue
|
||||
needle = f'{board_id}.build.variant='
|
||||
for line in text.splitlines():
|
||||
if line.startswith(needle):
|
||||
found = line.split('=', 1)[1].strip()
|
||||
if found:
|
||||
variant = found
|
||||
break
|
||||
if variant != idf_target:
|
||||
break
|
||||
|
||||
if variant == idf_target and board_id != idf_target:
|
||||
logger.info(
|
||||
f'[espidf] no build.variant for {board_id} in boards.txt; '
|
||||
f'falling back to {idf_target}'
|
||||
)
|
||||
self._variant_cache[key] = variant
|
||||
return variant
|
||||
|
||||
def _idf_target(self, board_fqbn: str) -> str:
|
||||
"""Map FQBN to IDF_TARGET."""
|
||||
if self._is_esp32c3(board_fqbn):
|
||||
|
|
@ -498,6 +557,39 @@ class ESPIDFCompiler:
|
|||
# Default to esp32 (Xtensa LX6) for the original ESP32 / ESP32-S2
|
||||
return 'esp32'
|
||||
|
||||
def _add_managed_components(self, project_dir: Path, deps: dict) -> None:
|
||||
"""Declare extra ESP-IDF managed components for the `main` component.
|
||||
|
||||
The template ships no idf_component.yml, so every managed component the
|
||||
build sees today arrives transitively through arduino-esp32's own
|
||||
manifest. Anything it does not depend on has to be asked for explicitly;
|
||||
the component manager then fetches it into managed_components/ during the
|
||||
cmake configure and caches it in the build dir for later runs.
|
||||
"""
|
||||
if not deps:
|
||||
return
|
||||
manifest = project_dir / 'main' / 'idf_component.yml'
|
||||
lines = ['# Auto-generated by Velxio — components the sketch needs that the',
|
||||
'# Arduino core does not pull in by itself.',
|
||||
'dependencies:']
|
||||
for name, version in deps.items():
|
||||
lines.append(f' {name}: "{version}"')
|
||||
manifest.write_text('\n'.join(lines) + '\n', encoding='utf-8')
|
||||
logger.info(
|
||||
'[espidf] Declared managed components: %s', ', '.join(sorted(deps))
|
||||
)
|
||||
|
||||
def _detect_camera_usage(self, code: str) -> bool:
|
||||
"""Does the sketch use the ESP32 camera driver?
|
||||
|
||||
`esp_camera.h` does NOT ship with the Arduino core: it lives in the
|
||||
`espressif/esp32-camera` managed component, which arduino-esp32's own
|
||||
idf_component.yml does not depend on. So a camera sketch compiles fine
|
||||
everywhere else and dies here with "esp_camera.h: No such file or
|
||||
directory" — which is exactly what both ESP32-CAM examples did.
|
||||
"""
|
||||
return bool(re.search(r'#include\s*[<"]esp_camera\.h[">]', code))
|
||||
|
||||
def _detect_wifi_usage(self, code: str) -> bool:
|
||||
"""Check if sketch uses WiFi."""
|
||||
return bool(re.search(r'#include\s*[<"]WiFi\.h[">]|WiFi\.begin\(', code))
|
||||
|
|
@ -2170,6 +2262,7 @@ class ESPIDFCompiler:
|
|||
'ARDUHAL_LOG_LEVEL': str(
|
||||
self._DEBUG_LEVEL_NUMBER[normalized['coreDebugLevel']]
|
||||
),
|
||||
'ARDUINO_VARIANT': normalized.get('arduinoVariant') or idf_target,
|
||||
'ARDUINO_RUNNING_CORE': str(normalized['arduinoRunsOnCore']),
|
||||
'ARDUINO_EVENT_RUNNING_CORE': str(normalized['eventsRunOnCore']),
|
||||
}
|
||||
|
|
@ -2881,6 +2974,22 @@ class ESPIDFCompiler:
|
|||
|
||||
cmake_path.write_text(cmake_text, encoding='utf-8')
|
||||
logger.info('[espidf] Patched main CMakeLists: REQUIRES += user_libs_all, INCLUDE_DIRS += user_libs_all')
|
||||
|
||||
# esp_camera.h used to come free: arduino-esp32 2.x shipped a precompiled
|
||||
# SDK with esp32-camera bundled under tools/sdk/<target>/include. The 3.x
|
||||
# component does NOT, and its manifest does not depend on it either, so the
|
||||
# move to 3.x silently broke every camera sketch with "esp_camera.h: No such
|
||||
# file or directory". Ask for it explicitly; the component manager fetches it
|
||||
# during the cmake configure and caches it in the build dir.
|
||||
sketch_src = '\n'.join(
|
||||
f.get('content', '') for f in files if str(f.get('name', '')).endswith(
|
||||
('.ino', '.cpp', '.c', '.h', '.hpp')
|
||||
)
|
||||
)
|
||||
if self._detect_camera_usage(sketch_src):
|
||||
self._add_managed_components(
|
||||
project_dir, {'espressif/esp32-camera': '^2.0.4'}
|
||||
)
|
||||
else:
|
||||
# Pure ESP-IDF mode (no Arduino component usable for this
|
||||
# target). Remove Arduino main.cpp to avoid conflict.
|
||||
|
|
|
|||
Loading…
Reference in New Issue