Часто слышал мнение, что в embedded программировании в принципе не может быть никакого DevOps(а).  Якобы вот есть GUI(ня) в IAR и там надо много мышкой водить. "Ты же не будешь ставить шаговые двигатели для сдвигания мышки" и т. п.

В этом тексте я намерен пофантазировать каким мог бы быть абстрактный процесс разработки firmware с точки зрения DevOps. И перечислить атрибуты такого процесса.

1. Репозиторий с кодом (репа)

Это может быть. Git, SVN, Mercurial, ClearCase, Perforce. Репозиторий нужен не только для хранения, распространения кодовой базы среди разработчиков, но и в случае поломки сборок репозиторий позволит откатиться в истории на прежние версии кода, когда все было относительно хорошо. Можно восстановить случайно удаленные файлы. Репозиторий позволяет распределить работу среди нескольких вкладчиков. Контроль версий запоминает все шаги. С репозиторием намного спокойнее работать.  

Плохие примеры когда код в компании передают через DropBox, USB-Flash(ку) или архивом в электронном письме. В этом случае нет никаких гарантий, что у каждого разработчика та же версия, что у остальных.

2. Код-генерация

В firmware проектах часто много повторяющегося кода. Это синтаксический разбор содержимого payload бинарных пакетов (например CAN, RS485 и пр.). Синтаксический разбор регистров каких-н умных навороченных периферийных SPI, I2C, MDIO микросхем (драйверы сенсорных экранов, внешние ADC, трансиверы, драйверы исполнительных механизмов, интеллектуальное управление питанием и пр.). Для автоматизации написания кода синтаксического разбора можно прибегнуть к созданию простых консольных утилит код-генераторов. На основе текстовых файликов структуры пакета при помощи код генераторов можно мгновенно сформировать огромные *.c *.h файлы. Код генератор повысит гибкость проекта, уменьшит вероятность ошибки, ускорит внесение изменений.

3. Проект должен собираться из скриптов

Многие IDE(IAR, Code Composer Studio) могут запускать сборки из командной строки Windows. Запускать сборки со скриптов полезно еще и по той причине, что окна GUI(ни) в IDE IAR часто зависают. А в окно лога сборки в CCS не помещается весь текст 6 минут работы компилятора и теряются сообщения о критических предупреждениях. Если вы собираете проект из скриптов, то у вас останется log файл  компилятора и вы сможете проанализировать все сообщения.

4. Сборок должно быть много

Чтобы создать хорошую модульную базу с полной изоляцией компонентов надо собирать проект по частям. Например если это IoT устройство то надо подготовить сборку только с GNSS, сборку только с LTE модемом. Сборку для проверки качества пайки платы. Загрузчик, Приложение. Сборка с тестами. Также полезно сделать сборку для какого-н другого микроконтроллера (ESP32, STM, TI). Это даст гарантию, что код переносимый. Если каждая сборка собирается без ошибок, то это значит, что код достаточно модульный.

5. Проект собирать из Make файлов

Если Make файлы являются для вас исходниками, то вы можете делать супер модульный код. Буквально одной строчкой в make добавлять и исключать компоненты из сборок. Если же вы привыкли пользоваться IDE, то вам для добавления одного компонента придется в одной вкладке IDE добавить пути к include(ам) в другом окне добывать переменные препроцессора, в третьем окне IDE добавлять сами исходники и так для всех 55 сборок. И это все мышковозня. В Make это будет 1 строка.

IDE хороши в основном для прототипирования. Разработчики, которые пользуются только IDE не догадываются даже какой путь проходит код от написания до попадания в Flash. Не догадываются о существовании *.i, *.asm, *.o, файлах и прочее.

В промышленном подходе надо готовить Make файлы.

6. Статические анализаторы

После компиляции код следует подвергать статическому анализу. Можно воспользоваться бесплатным CppCheck. Это позволит выявить и исправить еще некоторые критические ошибки.

7. Автосборки 

Можно клонировать код из репозитория и выяснить, что он уже как полгода не собирается и никто об этом не догадывался так как код собирался только локально на DeskTop(е) разработчика. Забыли подвергнуть версионному контролю какие-то файлики.

Кодовая база в репозитории должна быть валидной каждый день. То есть сборки должны собираться без ошибок и без предупреждений компилятора из кода, что в репозитории. Кто за этим будет следить? Когда есть репозиторий и скрипты сборки можно автоматизировать запуск сборок при помощи бесплатной программы Jenkins. Это утилита с Web интерфейсом, которая запускает скрипты. Когда работает Jenkins, то можно не только удостовериться, что код синтаксически правильный, но и всегда каждый день брать свежие артефакты. Там есть удобная навигация и сортировка по категориям Job(ов). Можно даже открыть доступ Jenkins(у) клиентам продукта и они не будут беспокоить разработчиков вопросами, где же нам взять прошивку. Клиенты сами смогут взять ту прошивку, которая им нужна из Jenkins.

8. Сервер сборки

Настроить Jenkins это весьма кропотливая работа и много мышковозни. Запускать CI на каждом компьютере каждого разработчика это еще и бессмысленная повторная работа. Плюс нагрузка LapTop(а), лишний шум во время работы от кулера. Но это достаточно сделать 1 раз для всех разработчиков. Нужен какой-то общий компьютер. Можно задействовать дешевенький Win(довый) NetTop PC (Зомбик). Запустить на нем Jenkins и оставить работать 24/7. За ночь он соберет все сборки. Когда кому-то понадобился артефакт, то он подключается по Win Remote Desktop Connection или TeamViewer к зомбику и скачивает себе артефакт, посмотрит все ли в порядке с остальными сборками и в случае поломки сделает коммиты, чтобы починить код.

9. Модульные тесты (скрепы)

То что код собирается в репе это еще ни о чем не говорит. Код может собираться без единого предупреждения, а при загрузке на target плата будет бесконечно Reset(тся). Код должен корректно стартовать и исполняться. Как это проверить автоматически? Это можно сделать при помощи модульных тестов. Модульные тесты это просто функции, которые запускают другие функции и проверяют output. Должна быть сборка для тестирования программы изнутри (методом белого ящика). В идеале надо тестировать все нетривиальные функции. В каждом firmware проекте есть hardware зависимый  код и hardware независимый код (математика, строки, абстрактные структуры данных). Часть кода, который не зависит от железа можно собирать, запускать и тестировать прямо на x86-64. Памяти на PC много  и все тесты поместятся. В Jenkins должен быть отдельный Job для запуска тестов на PC.

Если же в MCU не хватает достаточно NorFlash памяти для сборки проекта с модульными тестами, то можно задействовать отладочную плату с чипом того же семейства но с большим объёмом NorFlash. Подключив нужную периферию перемычками получится прототип тестируемого устройства.

10. Hardware In The Loop (HIL) стенд 

Остаются аппаратно-зависимые тесты. Их надо запускать и выполнять прямо на target(е). Чтобы это автоматизировать надо минимум 3 вещи. Устройство, загрузчик и CLI. Соединив Target c NetTop компьютером по UART получится HIL стенд. Загрузчик позволит автоматически обновлять прошивку по тому же UART. CLI позволит подключиться к target по UART и запустить тесты, вычитать лог и сохранить отчет. Все это можно упаковать в отдельные Job(ы) на Jenkins. 

11. Code Coverage (advanсed)

Как понять, что составлено достаточно модульных тестов? Может случится, что какие-то строки протестированы 100 раз а другие ни разу. Ответить на этот вопрос можно только если как-то считать по каким строкам код прошил во время тестов, а какой код является недостижимым. Для этого есть специальные проприетарные Tool(ы) например Testwell CTC++.  

  1. Ежедневные планерки

Когда несколько разработчиков делают одну кодовую базу надо как-то координировать действия, переоценивать трудоемкость задач, расставлять приоритеты, сообщать от том что сделано, какие есть загвоздки и что каждый собирается делать. Для этого надо собираться каждый день в первой половина на 5...7 минут и устно проговаривать. Так можно исключить ситуации, когда одно и то же сделано несколько раз каждым разработчиком.

Еще раз хочу отметить, что все перечисленные 12 DevOps атрибутов всего на всего плоды моей фантазии. И если кто-то увидит в этом какие-то корреляции с реальностью, то это всего лишь совпадение.

Вывод

При налаженном DevOps можно организовать полностью удаленную работу даже для процесса разработки firmware. Разработчику достаточно делать коммиты в репозиторий и анализировать Job(ы) Jenkins(а) и изредка подключаться к HIL стенду. В теории не обязательно даже локально устанавливать ToolChain, ничего кроме своего любимого текстового редактора и браузера. Так 1 человек может контролировать до 20 сборок. Надеюсь этот текст поможет кому-нибудь автоматизировать свои проекты. Если есть дополнения, то предлагаю обсудить их в комментариях.

Links:

CI/CD прошивок для микроконтроллеров в Wiren Board (Начало на 25:50)
https://www.youtube.com/watch?v=HEEVxZ4rBCo&t=366s

Конвеерум #30: Эволюция рабочего окружения для embedded разработки
https://www.youtube.com/watch?v=vmuO4bHjTSo&list=WL&index=1

17 атрибутов хорошей PCB
https://habr.com/ru/post/655879/

9 атрибутов хорошего firmware
https://habr.com/ru/post/655641/

Комментарии (15)


  1. Sap_ru
    19.03.2022 02:25
    +7

    Не нужно фантазировать. Есть нормальные процессы разработки под железо. И тестирование, и тестирование на железе и жизненные циклы. Пишутся имитаторы окружения, имитаторы железа, делаются тестовые стенды, делается изоляция модулей программы, прогоняются анализаторы кода - это всё есть. Это совсем не так как Web и достаточно сильно отличается от десктопных плюсов, но всё уже давно есть и используется в серьёзных проектах.
    А то, что 90% российских разработчиков софта под железо - "ардуинщики" или лабают а Keil MDK, так это особенности деградации отрасли и низкий уровень оплаты. Если платить 30 т.р. разработчику под STM, то естественно получишь ардуинщика, Keil, и хаос вместо нормального процесса разработки.

    И, кстати, я пока не видел, чтобы Jenkins использовали - специфика несколько иная. Хотя, можно, наверное. Но после того как написана своя сборка - а она совершенно всегда требуется, так как контрольные суммы, нестандартная упаковка бинарников, внедрение ресурсов, гарантия уникальности версии, загрузки и т.д, - всё это сделать из IDE и стандартные make-файлов или невозможно или очень криво получается. И почти всегда нужно делать какие-то дополнительные нестандартные телодвижения для автоматизации процесса релизной сборки. После того, как создано ПО для прошивки и тестирования, ПО для массового производства, массовой проверки ремонта, наладки/калибровки, и т.п. то оказывается, что автоматизация сборки это наиболее простая и наименее трудоёмкая задача из всего и она уже решена каким-то образом в ходе выполнения остальных работ.


    1. Siddthartha
      19.03.2022 10:37
      +1

      для IoT вполне актуальная схема. вот на одном из проектов запускал в продакшн: само приложение бэкенд и мобильные клиенты, но есть устройства (шлагбаумы), отдельная команда разработки и их прошивка до недавнего времени была даже не в репе!) вобщем, внедрили -- положили в реп, завели постоянный тестовый стенд, к которому дев-сервер приложения обращается, и даже выдали сваггер с этого стенда. смогли тестировать целиком наконец-то. варианты включения сборки и аплоада прошивок в общий процесс CI/CD -- сейчас как раз ресерчим и что-то похожее собираемся "изобрести". )


    1. Zifix
      19.03.2022 20:29
      +1

      А где-то можно прочитать про лучшие практики, чтобы не изобретать велосипеды?


      1. aabzel Автор
        19.03.2022 21:13

        Лучшие практики формируются во время работы. Надо походить по граблям.

        Можно почитать ISO26262 части 5 и 6
        Part 5: Product development at the hardware level
        Part 6: Product development at the software level


        1. Zifix
          19.03.2022 21:38
          +2

          В какой-то мере придется по ним ходить в любом случае, но хотелось бы это минимизировать. Просто Sap_ru сказал, что не нужно фантазировать и всё уже давно отработано, вот мне бы и хотелось почитать где-нибудь про подход, который он предлагает.

          Но вам тоже спасибо за статьи и ссылки.


      1. aabzel Автор
        19.03.2022 21:15
        -2

        Есть 2 таких текста

        17 атрибутов хорошей PCB
        https://habr.com/ru/post/655879/

        9 атрибутов хорошего firmware
        https://habr.com/ru/post/655641/


  1. lamerok
    19.03.2022 07:11
    +1

    Используем ClearCase, make, cmake, Gdb для отладки, Nunit, Clion для редактирования кода.

    Нет только сервера сборки, но спасибо за наводку.


    1. unsignedchar
      19.03.2022 08:44
      -3

      А затем отдельный сервер? У вас сборка идёт несколько часов? КМК достаточно настроить сборку в контролируемом окружении (виртуальная машина, docker), чтобы результаты были воспроизводимы.


      1. lamerok
        19.03.2022 09:25
        +1

        Да, сборка идет долго. Сама сборка минут 40 (на дебаг и релиз), юнит тесты час примерно и еще проверка статическим анализатором минут 40. Итого, около двух часов. Там конечно если распараллелить на 8 потоков, быстрее получается, но в целом меньше часа не получается.

        Долгая сборка идет по причине использования спец тулов, например clearmake, вместо обычного make. Он дополнительно собирает информацию о том, какие версии файлов, с каких меток были собраны в этой сборке. Потом можно делать аудит и собственно полностью воспроизвести сборку для этой версии.


        1. unsignedchar
          19.03.2022 09:54
          +1

          Тогда, конечно, сервер с ночными сборками просто необходим.


      1. aabzel Автор
        19.03.2022 12:54

        У нас 55 сборок и каждая 5 минут. Чтобы пересобрать артефакты после 1 комита надо 4 ч 30 мин.


  1. evgeny_boger
    20.03.2022 03:38
    +2

    Вот тут рассказывал, как это организовано у нас в wirenboard: https://www.youtube.com/watch?v=HEEVxZ4rBCo&t=1510s


  1. F0iL
    20.03.2022 03:50
    +4

    Делаем прошивки для разных железок, предназначенных для диагностики, измерений и удаленного управления/мониторинга другими железками. Все разбито на модули, каждый модуль (например, реализация какого-то коммуникационного протокола, логика аварийной защиты, работа с архивами, и т.д.) делается в виде отдельной библиотеки - пишутся юнит-тесты, и код пишется кросс-платформенно, так, чтобы тесты можно было гонять в том числе и на десктопе/сервере. Само собой, настроен CI, без код-ревью, зелёных тестов, достаточного уровня покрытия кода, положительных результатов от статических анализаторов (используем cppcheck и coverity) смержить PR не выйдет. При сборке итоговой прошивки: модули собираются в соответствии с указанными версиями/ревизиями, прошивка подписывается, и сразу с билд-сервера можно отправить ее на интеграционные тесты: есть стенд из нескольких железок, к которым подключена сеть, консоль, эмуляторы устройств на внешних интерфейсах, и интеграционные/регрессионные тесты на Python, при которых железка автоматически прошивается свежей прошивкой, а потом или эмулируется различное состояние внешних устройств и проверяется реакция железки не них, или наоборот, подаётся команда на железку и смотрится, как она будет работать с внешними устройствами, и т.д. - итого несколько сотен тестов выполняются примерно за час (вручную такое тестировать нужно день-два).

    Да, у нас Embedded Linux, но ровно подобное я видел и у чуваков, писавших под bare metal и FreeRTOS. Так что все эти "в embedded DevOps невозможен" - это такие же байки от дедов из НИИ как "в embedded невозможны/бесполезны юнит-тесты" и прочее "здесь так принято" во имя говнокода.


    1. aabzel Автор
      20.03.2022 12:01

      О том что "в embedded DevOps невозможен" мне доказывали не только "очень опытные инженеры" из всяких НИИ “РосПил” но и 28...35 летние Team Lead(ы) некоторых московских контор.


  1. DarkTiger
    20.03.2022 11:53
    -1

    Про OpenBMC почитайте. Там сборка под Yocto (ну и гадость эта ваша заливная рыба).
    С учетом того, что OpenBMC поддерживают Facebook, Microsoft, Intel и много кто еще - выборка может получиться куда более репрезентативной.
    Но очень высокий порог входа туда. Средств отладки в Yocto практически нет. Подключить gdb можно, но столько танцев с саблями придется сделать... То же для IDE - можно, но десять раз вспотеешь.