Замечание: на момент написания этого перевода [1] это все еще экспериментальная фича, так что стабильность API не гарантируется. Однако будет очень полезной обратная связь через репозиторий ESP-IDF GitHub или на форуме ESP32, и она может помочь повлиять на будущее разработки серверных приложений ESP-IDF.
В этой статье (перевод документации [1]) дан обзор методов запуска приложений ESP-IDF на операционной системе Linux, а также типов приложений ESP-IDF, которые обычно могут быть запущены на Linux.
Обычно приложение ESP-IDF разрабатывается и строится (кросс-компиляцией) на хосте PC, затем выгружаетсяu (т. е. прошивается) в память чипа ESP для выполнения, и может осуществляться мониторинг лога приложения на хосте через порт UART/USB. Однако выполнение приложения ESP-IDF непосредственно на чипе ESP может вводить ограничения в различных сценариях процесса разработки/применения/тестирования.
Имеется возможность для приложения ESP-IDF, чтобы оно было собрано и запущено полностью на хосте разработки Linux (далее это будет упоминаться как "запуск (или работа) приложения на хосте"). Запуск приложения ESP-IDF хосте имеет несколько преимуществ:
• Не требуется перепрошивать чип. • Ускоренное выполнение теста на машине хоста, по сравнению с работой программы на чипе ESP. • Нет требований к какому-либо конкретному оборудованию, кроме самого хоста разработки. • Упрощается автоматизация и настройка для тестирования программного обеспечения. • Существует множество инструментов для анализа кода и поведения программы runtime, например Valgrind [2].
Valgrind — это фреймворк для набора инструментов, который используется для создания динамического анализа программ, в основном на Linux. Простыми словами это инструмент, который запускает вашу программу в специальной виртуальной среде и проверяет её поведение в реальном времени, помогая находить ошибки, которые сложно обнаружить при обычной компиляции и запуске.
[Что конкретно умеет Valgrind?]
Valgrind сам по себе является "платформой", и его функциональность зависит от того, какой конкретный инструмент (Tool) вы используете. Наиболее распространённые из них:
• Memcheck (самый популярный): детектор ошибок памяти. Он проверяет, не обращается ли ваша программа к невыделенной или уже освобождённой памяти, не использует ли неинициализированные переменные, а также обнаруживает утечки памяти (memory leaks). Для проектов на C/C++ (включая ESP-IDF) это критически важно. • Helgrind / DRD: детекторы ошибок потоков. Они помогают находить состояния гонки (race conditions) и неправильное использование блокировок в многопоточных программах. • Cachegrind / Callgrind: инструменты профилирования. Они анализируют, насколько эффективно программа использует кэш процессора и какие функции выполняются дольше всего, что помогает оптимизировать скорость работы. • Massif: профайлер кучи (heap profiler). Показывает, сколько памяти ваша программа использует в разные моменты времени, помогая найти избыточное потребление памяти.
[Почему Valgrind упоминается в документации ESP-IDF?]
В документации ESP-IDF Valgrind упоминается именно в контексте тестирования на хосте (Host-based testing). Поскольку при таком подходе ваша программа компилируется и запускается как обычный Linux-исполняемый файл (а не как прошивка для ESP32), вы можете использовать все стандартные инструменты разработки Linux, включая Valgrind.
Это позволяет вам до прошивки на реальную плату проверить логику вашего кода на наличие утечек памяти или ошибок работы с памятью, которые в среде микроконтроллера (с ограниченным объёмом RAM) могут привести к непредсказуемым сбоям.
Многие компоненты ESP-IDF имеют зависимости от определенного оборудования/MCU (chip-specific hardware). Эти аппаратные зависимости должны быть заменены или смоделированы (mocked) при запуске приложения на хосте. В настоящее время ESP-IDF поддерживает следующие подходы mocking и симуляции:
1. Использование FreeRTOS POSIX/Linux simulator, который симулирует работу планировщика RTOS (FreeRTOS scheduling). Поверх этой симуляции при работе на хосте также симулируются или реализуются другие интерфейсы API.
2. Используется CMock для подмены всех зависимостей и запуска кода в полной изоляции от оборудования.
Стоит отметить, что несмотря на свое название "FreeRTOS POSIX/Linux simulator", он в настоящее время также работает и на macOS. Также имейте в виду, что несмотря на частое использование запуска приложений ESP-IDF на хост-машинах с целью тестирования, моделирование окружения и mock-подмена зависимостей не полностью представляют целевое устройство. Таким образом, тестирование на целевом устройстве по-прежнему необходимо, хотя и с другим фокусом, который обычно придает больший вес интеграции и системному тестированию.
Примечание: другая альтернативная возможность запуска приложений на хосте - использование QEMU simulator [3]. Однако интеграция QEMU для приложений ESP-IDF все еще находится в разработке, и пока не документирована.
Запуск приложения ESP-IDF на основе CMock. Этот подход использует фреймворк CMock [4] для решения проблемы отсутствующего оборудования и программных зависимостей. Приложения на базе CMock, работающие на хост-машине, получают дополнительное преимущество в том, что они обычно компилируют только необходимый код, то есть зависимости (в основном подменяемые mock) вместо всей системы. Общие сведения о Mocks, их настройке и использовании в ESP-IDF см. в разделе Mocks документации по юнит-тестированию приложений ESP-IDF, например [5].
Запуск приложения ESP-IDF на основе POSIX/Linux Simulator. FreeRTOS POSIX/Linux simulator уже доступен на ESP-IDF в качестве превью (preview target). Этот симулятор позволяет реализовать компоненты ESP-IDF на хосте, делая их доступными для приложений ESP-IDF при их работе на хосте.
В настоящее время только ограниченное количество компонентов готово к сборке на Linux. Кроме того, функциональность каждого компонента, портированного на Linux, может быть также ограничено или иметь другое поведение в сравнении с функционалом компонента, когда его сборка осуществляется для запуска на целевом чипе. Дополнительные сведения о том, поддерживаются ли требуемые компоненты в Linux, см. раздел "Обзор поддержки компонентов Linux/Mock" в конце статьи.
Обратите внимание, что этот симулятор в значительной степени полагается на сигналы POSIX и обработчики сигналов для управления потоками. Следовательно, он имеет следующие ограничения:
• Следует избегать использования в коде not async-signal-safe функций, например printf(). В частности, их вызов из различных задач/потоков может привести к падению кода и зацикливанию (crashes, deadlocks). • Запрещен запуск любых FreeRTOS примитивов из потоков, которые не были созданы API-функциями FreeRTOS. • Задачи FreeRTOS, использующие любой собственный механизм блокировки/ожидания (например, select()), могут восприниматься смоделированным планировщиком FreeRTOS как готовые к запуску (ready) и как следствие могут быть запланированы на выполнение, даже если они фактически заблокированы. Это происходит потому, что симулируемый планировщик FreeRTOS распознаёт как ожидающие только те задачи, которые заблокированы на каком-либо API-вызове FreeRTOS. • API, которые могут быть прерваны сигналами, будут постоянно получать сигналы, имитирующие прерывания тика FreeRTOS, при вызове из выполняющейся симулированной задачи FreeRTOS. Следовательно, код, вызывающий эти API, должен быть спроектирован так, чтобы обрабатывать потенциальные прерывающие сигналы, либо сам API должен быть обёрнут на уровне линкера.
Поскольку эти ограничения не очень практичны, в частности для тестирования и разработки, разработчики ESP-IDF настоящее время изучают возможности найти лучшее решение для запуска приложений ESP-IDF на хост-машине.
Кроме того, имейте в виду, что если вы используете mock-компонент FreeRTOS из ESP-IDF (tools/mocks/freertos), эти ограничения не применяются. Но этот mock-компонент также не выполняет никакого планирования.
Замечание: FreeRTOS POSIX/Linux симулятор позволяет настроить версию Amazon SMP FreeRTOS. Однако симуляция по-прежнему выполняется в однопоточном режиме (single-core). Основная причина, по которой допускается использование Amazon SMP FreeRTOS — обеспечить совместимость API с приложениями ESP-IDF, написанными для Amazon SMP FreeRTOS.
[Требования для использования Mocks]
• Установлена ESP-IDF, включая все, что для неё необходимо. • Установлены требуемые системные пакеты (libbsd, libbsd-dev). • Достаточно свежая версия Linux или macOS, и компилятор GCC. • Все компоненты, от которых зависит приложения, поддерживаются на Linux target (Linux/POSIX simulator), или обладают их mock-заменой.
Приложение, которое запущено на Linux target, должно иметь переменную COMPONENTS, установленную в main, в файле CMakeLists.txt корневой директории приложения:
set(COMPONENTS main)
Это предотвращает автоматическое включение всех компонентов из ESP-IDF в процесс сборки, которое в противном случае выполняется для удобства.
Если используется любой mock, то также требуется Ruby.
[Сборка и запуск]
Для сборки приложения на Linux должен быть настроен target на значение linux, после чего приложение может быть собрано и запущено:
idf.py --preview set-target linux idf.py build idf.py monitor
[Troubleshooting]
Поскольку приложения компилируются для хоста, они могут отлаживаться инструментами того же хоста. Например, на Linux это могут быть GDB [7] и Valgrind [2]. В тех случаях, когда отладчик не подключен, обработчики ошибок сегментации (segmentation fault) и сигналов прерывания выполнения (Abort signal) настраиваются для печати дополнительной информации для пользователя и повышения совместимости с инструментами ESP-IDF.
Следующие фичи ни в коем случае не заменяют запуск приложения в отладчике. Он предназначен только для предоставления некоторой дополнительной информации, например, если батарея тестов запускается на Linux в системе CI/CD, где собираются только журналы приложений. Чтобы отследить фактическую проблему в большинстве случаев вам нужно будет воспроизвести ее с прикрепленным отладчиком. Отладчик тоже намного удобнее, потому что, например, не нужно преобразовывать адреса в номера строк.
Segmentation Faults. В Linux приложения печатают сообщение об ошибке и рудиментарный стек обратной трассировки вызовов (backtrace), как только он сталкивается с ошибкой сегментации. Эта информация может использоваться для поиска номеров строк в исходном коде, где возникла проблема. Ниже приведен пример сбоя сегментации в приложении Hello-World:
Обратите внимание, что адреса (+0x...) являются относительными двоичными адресами, которые все еще должны быть преобразованы в номера строк исходного кода (см. далее).
Кроме того, обратите внимание, что backtrace (трассировка стека) создаётся из обработчика сигнала, а это означает, что два самых верхних кадра стека не представляют интереса. Вместо этого третья строка является самым верхним кадром стека, где произошла проблема:
Чтобы узнать действительную строку исходного кода, где произошла ошибка, необходимо вызвать утилиту addr2line с именем файла и относительным адресом (в этом примере +0x6198):
С этого момента вы должны использовать уточняющие средства отладки, доступные на хосте, для дальнейшего отслеживания проблемы. Для получения дополнительной информации об addr2line и его вызове см. справочную страницу addr2line [8].
Aborts. При вызове abort() будет выведена следующая строка:
ERROR: Aborted
[Обзор поддержки компонентов Linux/Mock]
Обратите внимание, что любое «Да» здесь не обязательно означает полную реализацию или полное mock-замещение. Это также может означать частичную реализацию или частичное mock-замещение функциональности. Обычно реализация или mock-замещение выполняется до той степени, при которой обеспечивается достаточный объём функциональности для сборки и запуска тестового приложения.
Компонент
Mock
Simulation
cmock
No
Yes
driver
Yes
No
esp_app_format
No
Yes
esp_common
No
Yes
esp_event
Yes
Yes
esp_http_client
Yes
Yes
esp_http_server
No
Yes
esp_https_server
No
Yes
esp_hw_support
Yes
Yes
esp_netif
Yes
Yes
esp_netif_stack
No
Yes
esp_partition
Yes
Yes
esp_rom
No
Yes
esp_system
No
Yes
esp_timer
Yes
No
esp_tls
Yes
Yes
fatfs
No
Yes
freertos
Yes
Yes
hal
No
Yes
heap
No
Yes
http_parser
Yes
Yes
json
No
Yes
linux
No
Yes
log
No
Yes
lwip
Yes
Yes
mbedtls
No
Yes
mqtt
No
Yes
nvs_flash
No
Yes
partition_table
No
Yes
protobuf-c
No
Yes
pthread
No
Yes
soc
No
Yes
spiffs
No
Yes
spi_flash
Yes
No
tcp_transport
Yes
No
unity
No
Yes
[Ссылки]
1. Running ESP-IDF Applications on Host site:docs.espressif.com. 2. Valgrind User Manual site:valgrind.org. 3. QEMU site:qemu.org. 4. CMock site:throwtheswitch.org. 5. Unit Testing in ESP32-S3 site:docs.espressif.com. 6. Symmetric Multiprocessing (SMP) with FreeRTOS site:freertos.org. 7. gdb(1) Linux manual page site:man7.org. 8. addr2line(1) Linux man page site:linux.die.net.