Comments 17
Чтобы не припаивать провод прямо на кнопку, можно развести пятаки под диагностический разъем.
То, чего все больше всего боялись — свершилось. Continuous Integration добралась до FW.
Все таки ежедневные сборки прошивки — это пока еще дичайшая дичь. Чтобы полностью проверить прошивку, надо бы тестовый стенд по сложности в 2 раза сложнее, чем подопытное устройство.
Чтобы полностью проверить прошивку, надо бы тестовый стенд по сложности в 2 раза сложнее, чем подопытное устройство.
Ок. А разве CI на стенде запрещает обычную человеческую проверку?
И даже стенд
P.S. есть идеи выложить фремворк в паблик, но как-то не заморачивался думая что мало кто в эмбеде по CI упарывается
«Железячные тестовые стенды» и тестируемые приборы, в отличии от «тестирования кодом кода», часто не совсем детерминированные — взаимные наводки, плохие контакты, помехи, коты и всякое такое, поэтому:
— принцип KISS на первом плане — чем меньше мы навесим тестовой обвязки — тем лучше, стараемся максимально снять инфы по визуальному каналу (вебкамера смотрит на экран тестируемых приборов и их светодиоды), там где можно тестировать демоборды или что-то с питанием от USB — берем USB хаб управляющий питанием по каждому порту (например Dlink H7 в сером корпусе) — $20 за 7 каналов управления питанием и проброса UART-или-что-там-на-борде в систему
— никаких плат разложенных по столам/полкам стендов — во первых коты, во вторых маппинг экранов/светодиодов в пиксели видеокамеры будет слетать. Например, собираем тестовые «лотки» из корпусов от старых CD приводов, и вставляем их в старый ATX корпус, где напротив них стационарно висит вебкамера (см фото). На веб-камеру стоит нацепить полярик, и не особо совать все это под солнечный свет (цвета пикселей будут уходить)
— только качественные и короткие USB провода
О фреймворке (точнее сборки из NodeJS+Redis c легаси и велосипедами) — он состоит из серверной части и самих тестов. Серверная часть выставляет веб-морду, из которой можно запустить любой тест и смотреть его прогресс и видеокамеру. (планировалась еще интерактивность, пробросить кнопки прибора в кнопки на морде, но руки пока не дошли). Так-же серверная часть обрабатывает вебкамеру, захватывая кадры через OpenCV, выделяя интересующую область и публикуя ее в Redis-канал для приема на стороне теста, и в вебсокеты UI клиентам.
На стороне теста «фреймворк» выставляет Promise обертки над всякими командами «поуправлять питанием портов USB хаба» и над i2c периферией, которая «нажимает кнопки» 16-канальным PWM драйвером, им-же эмулирует аналоговые сигналы (например, один из наших приборов {реле защиты} измеряет напряжение в сети и от него все действия, PWM хоть и точностью +-3 вольта, но эмулит пере/недо-напряжения)
const {
wait ,
waitForUart ,
waitForPixel ,
timeLabel ,
infoLabel ,
buttonPress ,
buttonUnpress,
sendPWM ,
powerCycle
} = require('./test-framework');
const Stage = require('./stage-config');
const PowerLedX = 34;
const PowerLedY = 236;
const PowerReadyLedX = 53;
const PowerReasyLedY = 274;
Promise.resolve(true)
//
// turn on PWM driver
.then(timeLabel("init-section","START"))
.then(infoLabel("включаем PWM,устанавливаем напряжение входа VP16"))
.then(powerCycle(true,Stage.PWM))
.then(wait(500))
// set input voltage at VP16
.then(sendPWM(0,220/Stage.VP16.UCONST,Stage.VP16.UINP))
.then(wait(500))
.then(timeLabel("init-section","PASS"))
.catch(timeLabel("init-section","FAIL"))
.then(infoLabel("включаем VP16"))//
.then(wait(500))
.then(timeLabel("pwr-ready-test","START"))
.then(powerCycle(true,Stage.VP16))
//.then(powerCycle(true,Stage.TR16))
.then(infoLabel("ждем готовности по напряжению"))
.then(waitForPixel(PowerReadyLedX,PowerReasyLedY,(r,g,b,a)=>(r>200 || ((r > (g+b)*2)&&(r>30)) )))
.then(timeLabel("pwr-ready-test","PASS"))
.catch(timeLabel("pwr-ready-test","FAIL"))
.then(wait(2000))
.then(timeLabel("pwr-button-on-test","START"))
.then(infoLabel("нажимаем среднюю кнопку"))
.then(buttonPress(Stage.VP16.BUTTON2))
.then(waitForPixel(PowerLedX,PowerLedY,(r,g,b,a)=>r>230))
.then(timeLabel("pwr-button-on-test","PASS"))
.catch(timeLabel("pwr-button-on-test","FAIL"))
.then(infoLabel("отпускаем среднюю кнопку"))
.then(buttonUnpress(Stage.VP16.BUTTON2))
.then(wait(2000))
.then(timeLabel("pwr-overvoltage-test","START"))
.then(infoLabel("имитируем овервольтаж"))
.then(sendPWM(0,310/Stage.VP16.UCONST,Stage.VP16.UINP))
.then(waitForPixel(PowerLedX,PowerLedY,(r,g,b,a)=>r<230))
.then(timeLabel("pwr-overvoltage-test","PASS"))
.catch(timeLabel("pwr-overvoltage-test","FAIL"))
.then(wait(2000))
.then(infoLabel("ждем восстановления"))
.then(wait(500))
.then(timeLabel("pwr-overvoltage-return-test","START"))
.then(sendPWM(0,220/Stage.VP16.UCONST,Stage.VP16.UINP))
.then(waitForPixel(PowerLedX,PowerLedY,(r,g,b,a)=>r>230))
.then(timeLabel("pwr-overvoltage-return-test","PASS"))
.catch(timeLabel("pwr-overvoltage-return-test","FAIL"))
.then(wait(2000))
.then(infoLabel("выключаем приборы"))
.then(powerCycle(false,Stage.VP16))
.then(wait(500))
.then(powerCycle(false,Stage.TR16))
.then(wait(500))
.then(powerCycle(false,Stage.PWM))
.then(wait(1000))
//.then(powerCycle(false,Stage.TR16))
.then(timeLabel("final-section","PASS"))
.catch(timeLabel("final-section","FAIL"))
.then(()=>process.exit());
const Stage = {
"PWM" : {
id: "PWM",
usb: "8.7",
power_hub_port: 7,
serial: undefined
},
"VP16": {
id: "VP16",
usb: "8.1",
power_hub_port: 1,
serial: undefined,
// voltage calibration
UCONST : 0.2980,
// pwm shield port map
UINP : 0, // U input emulation
BUTTON1 : 2, // buttons...
BUTTON2 : 1, //
BUTTON3 : 3, //
},
"TR16": {
id: "TR16",
usb: "8.6",
power_hub_port: 6,
serial: undefined,
},
"FLASHER" : {
id: "FLASHER",
usb: "8.2",
power_hub_port: 2,
serial: undefined
},
};
module.exports = Stage;
Тест можно запускать из-под UI вручную, можно из cmd-line для интеграции пайплайнов да и просто с IDE по SSH (у меня CLion скриптом собирает бинарь, scp его на стенд, ssh туда, выгрузка на плату и запуск теста при необходимости — получается эмбед писать с ноута удаленно от стенда и проводов). При запуске из командной строки вывод и вэбка все-равно транслируются в UI для стороннего контроля.
Крутится все это на i5 под убунтой, жрет CPU 10..15% (в основном вэбка и ее данные по шине Redis, там не особо оптимизировать успел)
В целом получается что-то типа сильно упрощенного Redd от EasyLy ( habr.com/ru/post/440156 ) только «мясом вовнутрь» и за шапку сухарей.
Для начала масштаб проблемы. У нас пяток классов устройств, у каждого — своя система. Одновременно для каждой системы ведется разработка над текущим релизом, следующим мажорным релизом и опционально следующим мажорным релизом + 1. Помимо этого есть минорные релизы, над котороыми работа может начаться одновременно с мажорным. Плюс специальные ветки для бета-версий, фиксов безопасности и отдельные ветки для фабрик, чтобы не показывать им весь софт до релиза. Это все дает примерно с десяток активных каналов разработки для каждого класса устройств. Примерно каждый год выходит несколько новых моделей почти во всех классах, поддержка старых осуществляется в течение нескольких лет. Это дает до нескольких десятков поддерживаемых моделей устройств на класс. У каждой системы есть несколько вариантов, для пользователей, для фабричного тестирования, для разработчиков, etc. Итого мы ежедневно получаем примерно 30-50 сборок систем в день и примерно 100 моделей устройств, на которых нужно проверить, что интересующие нас варианты систем хотя бы базово работают. Сейчас у нас больше 250 устройств, которые висят подключенными на почти трех десятках серверов и работают в CI. Осложняется дело необходимым на все это временем. Сборка всех изменений за сутки занимает примерно 6-8 часов, сборка всего — 13 часов. Еще 2-4 часа на то, чтобы смастерить образы системы для всех вариантов и для всех устройств. Отдельная история про построение OTA патчей и загрузку всего этого дела в архив, это идет в фоне и может занимать до суток. erase-install на одно устройство занимает примерно полчаса. Минимальный набор тестов еще минут 15.
Всем вышеописанным занимается наш отдел. Все что можно автоматизировать — автоматизируется, в том числе и проверка на железе. Без этого с ума бы сходили. Старожили еще помнят, как делали все это вручную, но тогда было меньше классов устройств, выпущенных моделей и параллельных каналов разработки.
Сложно сказать, что сложнее, стенд или устройства. В качестве стенда выступает сервер, к которому подключается десяток устройств. На интерфейсном кабеле устройств висят специальные умные девайсы, которые через тот же кабель снимают с устройства serial, умеют нажимать на кнопки, сбрасывать устройство, насильно менять его текущий режим работы и отлаживать в случае паники. Управляет этим всем жуткая мешанина проприетарных технологий специально разработанных для работы с нашими устройствами и тестирования софта на них. Наша скромная высокоуровневая автоматизация и тесты пишутся на питоне и боле-менее справляется с задачей.
Ну и да, мы единственная команда, которая проверяет все поддерживаемые устройства. Правда и набор тестов у нас скудный. Чтобы его пройти образ должен успешно установиться на устройство, не жрать 100% cpu, не крешиться в цикле, а процесс UI должен запуститься и не падать. Мы буквально отвечаем на вопрос «а пригоден ли билд к дальнейшему тестированию?», зато для всего.
У других команд есть всевозможные автотесты на функциональность, они работают на том же технологическом стеке, но на другом пулле устройств и они проверяют, как правило, одну модель для каждого SoC. Полностью же покрыть весь софт автотестами не реально — слишком быстро происходят изменения. В ручную тестируется просто большая часть системы.
Мы буквально отвечаем на вопрос «а пригоден ли билд к дальнейшему тестированию?», зато для всего.
В том-то и дело, что при этом по аналогии с софтом может возникнуть ложная уверенность, что раз CI "дала добро", можно смело начинать выкатывать OTA на пользовательские устройства, хотя это на самом деле только самый базовый уровень тестирования и в реале экономит не так уж много времени, если думать об "успешно установиться на устройство, не жрать 100% cpu, не крешиться в цикле, а процесс UI должен запуститься и не падать" еще на этапе архитектуры, а не кодирования.
— «способен ли новый билд посредством OTA откатиться на старый» должен быть автоматизирован в пайплайне
И вот у меня почему-то на 99% уверенности, что комментатор выше это не тестирует на своей CI ферме. :-)
Автоматизация аппаратного тестирования Embedded Систем