Привет, меня зовут Олег Герасимов, я директор центра компетенций IT-кластера Ростелекома. Наша команда среди многих задач разрабатывает прошивки камер видеонаблюдения для B2B и B2C-сервисов. В предыдущей статье я рассказывал, как мы научились самостоятельно разрабатывать софт и прошивки для IP-камер, в том числе и недорогих, и подключать их к облаку.
За прошедшее время камеры с нашей прошивкой уже появились на рынке, и, судя по данным Яндекс.Маркета, — на полках магазинов цены на них начинаются от 1500 рублей. И это уже не дешевый «ноунэйм», а качественные камеры ведущих мировых брендов: Hikvision, Dahua и Uniview. На мой взгляд, это отличный результат!
Когда мы начинали работать с прошивками, количество поддерживаемых моделей камер было небольшим. В процессе разработки общих компонентов мы самостоятельно реализовывали поддержку новых моделей камер.
Тогда у нас была возможность самим выбирать, какие модели интегрировать в первую очередь, а какие нет, исходя из технических соображений.
Например, если в камере используется сенсор, под который в SDK процессора нет драйвера, то драйвер сенсора придется разработать самим. Это очень трудоемкий процесс, требующий сложной разработки и отладки. Сенсор — технически сложный компонент, и на одно изучение технического описания (Datasheet) сенсора могут уйти недели. Это, на секундочку, сотни страниц с описанием тысяч регистров, влияющих на работу сенсора, и логики взаимодействия с ними.
Первое время мы обходили стороной камеры с незнакомыми сенсорами, чтобы не застрять в деталях настройки конкретного железа, а сосредоточиться на разработке общих компонентов, которые будут использоваться в большинстве камер. Иногда нам удавалось найти уже готовые драйверы сенсора в оригинальной прошивке камеры, но это было скорее счастливым исключением из правил. Работая в таком режиме, мы поддержали около десятка моделей камер на нескольких наиболее популярных чипсетах, делая упор не на количество моделей, а на функциональность.
Следующий этап разработки прошивок для камер совпал с объявлением тендера на закупку камер. Это уже серьезное событие. Ростелеком закупал сотни тысяч камер на открытом тендере, в который могли войти любые вендоры камер, соответствующих по своим ТТХ продуктовым и техническим требованиям.
Одно из ключевых требований к поставщикам — предоставление технической информации о схемотехнике камер, например, о GPIO-выводах, к которым подключены светодиоды, кнопки, ИК фильтры и т.д. Кроме этой информации, мы просили вендоров предоставить специфичные для оборудования патчи ядра/загрузчика и исходные тексты драйверов устройств, в первую очередь, сенсоров и WI-FI чипов.
Такой подход существенно облегчил нашу задачу по поддержке новых камер. Вместо данных, добытых реверс-инжинирингом, у нас появились официальные спецификации и исходники драйверов от вендоров.
Однако по-прежнему много времени уходило на подготовку прошивок, даже когда вендоры стали делиться информацией: данные в спецификациях были неточными, драйверы не хотели заводиться на железе, а то и вовсе отказывались собираться.
Самостоятельно найти ошибку в спецификациях или драйверах получалось не всегда, да и искать ошибки в стороннем коде — небыстрое занятие. Поэтому чаще для решения проблемы приходилось обращаться к вендорам. Как правило разработчики, которые могут ответить на вопросы о схемотехнике, найти
и поправить ошибки в драйверах, находятся в Китае. А это сразу замедляет коммуникацию — одна итерация «вопрос-ответ» может занимать несколько дней, а исправление ошибок и того дольше.
Пока поток новых камер был небольшим такой режим устраивал, но со временем запросы от маркетологов выросли. Возникла потребность в интеграции большего количества линеек: уличные камеры с Wi-Fi, домашние с PTZ, с сиреной и т.д. Но с другой стороны, по мере развития облачного видеонаблюдения увеличивалось количество вендоров, желающих работать с нами.
В этот момент мы поняли, что силами команды с возросшим в разы количеством новых камер уже не справиться. Всё время разработки
будет занимать исключительно интеграция новых камер, а на разработку новых фич и улучшения времени не останется. Нужно было найти новый подход.
Мы начали анализировать узкие места процесса. Они оказались на поверхности: больше всего времени уходило на итерации получения патчей и драйверов, багрепорты в сторону вендоров и ожидание исправлений.
Логичная мысль: дать вендорам возможность самим собирать нашу прошивку с драйверами их оборудования и конфигурациями, проверять результаты и отлаживать работу у себя, не тратя драгоценное время на переписку.
Техническое решение, с одной стороны, очевидное: сделать SDK для сборки нашей прошивки. Но есть ряд требований:
- SDK должен уметь собирать прошивки под все типы поддерживаемых SoC. На сегодня это больше 10 чипсетов от Hisilicon, Ambarella, MStar и Fullhan.
- Нельзя передавать компоненты прошивок от одного вендора другим, потому что это интеллектуальная собственность. Мы подписываем NDA, в котором обязуемся не раскрывать передаваемую информацию.
- Результаты интеграции, полученные от вендора, нужно уметь замерджить в общее дерево исходников прошивки в нашем Git.
- У вендора должна быть возможность вносить патчи и дополнения во все компоненты: ядро, загрузчик, SoC SDK и прочие.
- Нужно иметь гибкую структуру настроек, в которой будут учитываться максимальное количество возможных конфигураций оборудования.
- Для каждой пары «вендор-SoC» должна собираться универсальная прошивка, поддерживающая все камеры вендора на базе этого процессора.
- Сборка должна работать автономно и не требовать доступа в Интернет. Да, большинство разработчиков ПО для камер в Китае не имеют доступа в Интернет на рабочих местах.
Структура системы сборки, в тот момент, была не готова к такому подходу. Например, в некоторых файлах конфигурации были совмещены настройки камер от нескольких вендоров, а для сборки прошивки и загрузки пакетов требовался доступ к нашим внутренним репозиториям. Да и некоторые места системы сборки (чего греха таить) не предполагали такого масштабирования: их разработали в то время, когда поддерживался один тип процессора и две модели камеры...
Другая проблема: под каждый процессор поставляется отдельный SDK от его производителя, с уникальным набором системных компонентов: своя версия и набор патчей ядра, toolchain, uboot, системная библиотека (где-то uclibc, а может быть glibc). Под эти факторы приходится подстраивать систему сборки, а местами и код приложений. Для наглядности масштабов фрагментации вот табличка со списком версий компонентов:
Процессор | Версия Linux | Версия gcc |
---|---|---|
Hisilicon 3516a/d | 3.4.y | gcc 4.9 |
Hisilicon 3518ev100 | 3.0.y | gcc 4.4 |
Hisilicon 3518ev200 | 3.4.y | gcc 4.9 |
Hisilicon 3516cv300 | 3.18.y | gcc 4.9 |
Hisilicon 3518ev300/3516ev200/ev300 | 4.9.y | gcc 6.3 |
Hisilicon 3516cv500/dv300 | 4.9.y | gcc 6.3 |
mStar i3 | 3.18 | gcc 4.8 |
mStar i6 | 4.9 | gcc 8.2 |
Ambarella s2l | 3.10 | gcc 4.9 |
Ambarella s3l | 3.10 | gcc 5.2 |
Fullhan fh8632 | 3.0.y | gcc 4.3 |
Как видно, разброс огромный: от легаси десятилетней давности до относительно свежих ревизий.
С такими вводными нам предстоял рефакторинг системы сборки прошивок: выделить общие патчи и драйвера, которые будут доступны для всех вендоров, повторить это для 10+ поддерживаемых моделей SoC, полностью переосмыслить систему конфигурации наших компонентов. Заодно выпилить специфичные для камер костыли из init-скриптов, сделав общие и универсальные решения.
В результате мы пришли к структуре, в которой все специфичные для конкретных моделей настройки/конфигурации/makefile/патчи собраны в папках, структурированную по иерархии "Вендор → SoC → Модель камеры". Такая иерархия позволила автоматизировать сборку SDK с разделением сборок по вендорам. Вот пример, драйверы и конфигурации для камер от выдуманного вендора Megatech на чипсете Hisilicon.
Драйверы
drivers
+ megatech/ -> драйвера и конфиги для вендора 'megatech'
| + hi3518ev200/ -> чипсет hisilicon hi3518ev200
| | + 1421 -> конфигурации модели камеры с кодом оборудования 1421
| | | | + ipcdb.1421.yml -> общая конфигурация
| | | | + mpi/entry.1421.yml -> конфигурация видеозахвата
| | | | + ptz/entry.1421.yml -> конфигурация PTZ
| | + motor -> драйверы моторов управления PTZ
| | | + bu24036_motor -> драйвер шагового мотора на чипе bu24036
| | | | gpio_motor -> драйвер шагового мотора управляемый GPIO выводами
| | + wlan -> драйверы wi-fi чипов
| | | + Makefile -> скрипт сборки
| | + sensor -> драйверы сенсоров
| | | + Makefile -> скрипт сборки
Патчи ядра
kernel
+ megatech/
| + hi3518ev200/
| | + mmc_hotplug.patch
| | + kernel-config.patch
Патчи uboot
uboot
+ megatech/
| + hi3518ev200/
| | + uboot-mmc.patch
| | + uboot-spi.patch
Все файлы конфигурации камер перевели в формат YAML, как самый удобный для ручного редактирования, и разделили по компонентам:
- Настройки оборудования модели камеры (GPIO, наличие и тип Wi-Fi, сенсора, флаги наличия микрофонов, динамиков, дополнительные скрипты инициализации).
1421:
vendor: megatech
model: Model A
soc: 3518ev2
ethernet: 0
wlan: rtl8188eu
sensor: ov9732
leds:
ir:
gpio: 23
inverse: true
red:
gpio: 10
power:
gpio: 10
green:
gpio: 2
net:
gpio: 2
keys:
wps:
gpio: 16
reset:
gpio: 16
peri-out:
pwdn:
gpio: 1
inverse: true
ircut.p:
gpio: 57
ircut.n:
gpio: 60
wifi_pwr:
gpio: 7
flash: spi
misc:
microphone: true
speaker: true
mic_hpf_level: 3
mic_anr_level: 4
scripts:
insert-sns:
- himm 0x200f0040 0x2; # I2C0_SCL
- himm 0x2003002c 0xc4001; # sensor unreset, clk 24MHz, VI 99MHz
init-wlan:
- insmod 8188eu.ko
- Настройки видеоприложения для конкретной модели (тип сенсора, поддерживаемые разрешения, режимы синхронизации и видеозахвата, подстройки алгоритмов).
1421:
sensor:
type: ov9732
lib: libsns_ov9732.so
resolutions:
- targets:
- { width: 1280, height: 720, maxrate: 30 }
- { width: 640, height: 480, maxrate: 30 }
- { width: 640, height: 360, maxrate: 30 }
- { width: 320, height: 240, maxrate: 30 }
channels:
- main
source: { width: 1280, height: 720, rates: [30, 25] }
combo_dev_attr:
input_mode: CMOS_33V
vi_dev_attr:
interface_mode: DIGITAL_CAMERA
component_mask: [67043328, 0]
syn_cfg:
vsync: field
vsync_neg: high
hsync: valid_signal
hsync_neg: high
vsync_valid: valid_signal
vsync_valid_neg: high
timing_blank: [ 370, 1280, 0, 6, 720, 6, 0, 0, 0 ]
isp_image_attr:
bayer_format: BGGR
- Настройки PTZ (тип чипа, тайминги работы шаговых драйверов).
1421:
type: pan_controller_and_tilt_gpio_generic
interrupt_gpio: 50
absolute: true
pan:
park_ccw: false
continuous: [-20, 20]
relative: [-7.9, 7.9]
absolute: [0, 355]
channel: 0
min_wait: 100
max_step: 140
max_speed: 375
unity: 430
tilt:
park_ccw: true
continuous: [-20, 20]
relative: [-3.5, 3.5]
absolute: [0, 90]
max_step: 2000
unity: 157
Выбор способа сборки дистрибуции SDK был очевидным. Docker оказался вне конкуренции, с его помощью можно легко передать подготовленную среду.
Мы использовали Docker практически с самого начала разработки, как в CI, так и для локальной отладки на компьютерах разработчиков.
Процесс сборки полностью автоматизирован. Docker-образы с нашим SDK собираются в общем CI под матрицу сочетаний «SoC-вендор».
Исходно у нас было два основных репозитория:
- build-tools — в нем хранятся Dockerfile, скрипты установки SoC SDK и скрипты сборки общих библиотек для поддерживаемых аппаратных платформ. В CI этого репозитория собираются Docker-образы со всем необходимым для сборки прошивки и софта под целевую платформу.
- vc-firmware — здесь хранится система сборки прошивки и компонент. К этому же репозиторию как git-submodule подключены репозитории с исходниками наших компонентов: видеоприложение, облачный агент, модуль обновления). Результатом работы CI в этом репозитории являются сами прошивки камер.
Для нового SDK добавили еще один репозиторий, vc-sdk, к которому подключили vc-firmware и build-tools как git-submodule. В CI этого репозитория сборка разделена на этапы:
- подготовка базового Docker-образа по аналогии с репозиторием build-tools;
- сборка пакетов с компонентами (видеоприложение, облачный агент, модуль обновления);
- загрузка пакетов с общими компонентами (публичные библиотеки, драйверы Wi-Fi и т.д.)
- копирование каталогов с драйверами и патчами, специфичными для вендора
В результате работы CI получается автономный Docker-образ, рассчитанный на сборку прошивок для камер на выбранном чипе вендором. Он загружался
в общий registry образов, из которого вендор может скачать свой образ.
Следующий объемный фронт работ — разработка документации. Документацию мы писали поэтапно, собирая обратную связь от вендоров и учитывая замечания. Кстати, для документации использовался наш инструмент Foliant. Про него наши ребята уже рассказывали на митапе «Write the Docs Moscow» (https://habr.com/ru/post/431210/).
Заключение
За этот год уже 8 вендоров освоило использование нашего SDK, с его помощью добавили поддержку работы с видеонаблюдением Ростелекома в нескольких десятков новых моделей камер. Некоторые из этих камер уже продаются.
Важно, что выбранный подход — разработка собственной прошивки на базе SDK — работает на потребителей: интеграция камер таким способом позволила организовать честную конкуренцию при тендере на закупку камер. Победители выявляются по объективным показателям: качеству оборудования и наименьшей стоимости.
Наконец, если раньше количество поддерживаемых моделей камер было ограничено силами и ресурсами команды, то сегодня эта проблема ушла в прошлое. Теперь вендоры камер могут сами добавлять поддержку новых моделей через облако РТК.