Обсуждая реализацию автотестирования в нашей компании, была предложена идея визуализации результатов с помощью светофора. Данный инструмент прост и понятен каждому, да и к тому же производит небольшой вау эффект. Под катом будет история внедрения светофора в нашу систему автотестов.
Поиск и покупка светофора
В интернете огромное количество предложений по покупке светофора. Мы не стали заморачиваться и собирать свой, а сразу купили готовый.
• Рабочее напряжение питания: 220В переменного тока, в соответствии с ГОСТ 13109. По испытаниям, электрическая прочность изоляции выдерживает напряжение не менее 1500В с частотой 50Гц без пробоев в течении 1 мин;
• Гарантия от производителя 3 года. Срок службы светофоров не менее 12 лет. Используются долговечные энергосберегающие светодиодные излучатели (СИД).Средний срок службы светодиодов – 100 000 часов;
• Диапазон рабочих температур светодиодных светофоров: от – 60 С до +60 С;
• Светотехнические параметры светофоров, осевая сила света излучателей дорожных светофоров в соответствии с ГОСТ Р 52282-2004;
• Малый вес светофора не более 8 кг;
Светофор стоит недешево. Данная модель обошлась нам почти в 13000 р. Большим плюсом такого светофора является его компактность. Толщина светофора, включая козырьки, составляет 275 мм. Без козырьков 138 мм. Длина 840 мм. В комплекте идут кронштейны, с помощью которых мы повесили его на….шкаф.
Электроника
Для управления светофором решили использовать плату дискретных входов-выходов «Quartech – Jackpot – USB», разработанную нашими друзьями.
Плата управления размещена в корпусе светофора и управляет тремя твердотельными реле COSMO, обеспечивающими с большим запасом не только гальваническую развязку, но и необходимую нагрузочную способность (при желании через них можно управлять не одним десятком таких светофоров).
Был разработан и реализован расширяемый протокол управления, позволяющий при помощи этой платы управлять не только светофором, но и множеством других периферийных устройств (питание камер наблюдения, системы управления освещением, различные кнопки и датчики на демонстрационных макетах).
Физический уровень
Полнодуплексный обмен по USB через виртуальный COM-порт, открытый на скорости 9600кб/c.
Транспортный уровень
Обмен между любыми устройствами происходит в режиме прямого подключения. Все сообщения на транспортном уровне имеют стандартизированный формат:
Поле | Стартовый байт | Размер команды (номер + данные) | Текущий статус | Номер команды | Данные команды | Контрольная сумма |
Размер | 1 | 1 | 1 | 1 | 0-254 | 1 |
Значение | 0x7E | 1 — 255
0 — ошибка |
Битовое поле, определяющее текущее состояние каждого типа устройств | 1 — 255
0 — ошибка |
Определяется командой | Cумма всех предыдущих полей сообщения, включая стартовый байт |
Битовое поле текущего статуса имеет следующие поля:
бит 0: 0 — нормальная работа, 1 — ошибка
бит 1: 0 — режим ожидания запроса, 1 — режим потоковой выдачи данных
Командный уровень.
Каждая команда состоит из поля «Номер команды» и опционального поля «Данные команды». Четные номера команд — запросы, нечетные — ответы.
Номер команды | Описание команды | Данные |
0x01 | Запрос типа устройства | нет |
0x02 | Ответ типа устройства | 1 байт:
0 — ошибка 1 — измерительная часть 2 — интерфейсная часть 3 — ПК |
0x03 | Запрос серийного номера | нет |
0x04 | Ответ серийного номера | 2 байта |
0x05 | Запрос версии софта | нет |
0x06 | Ответ версии софта | 2 байта |
0x07 | Запрос версии железа | нет |
0x08 | Ответ версии железа | 2 байта |
0x0A | Установка состояния порта | 1 байт |
0x0B | Запрос состояния порта | нет |
0x0C | Ответ состояния порта | 1 байт |
0x0D | Включить пищалку, мс | 1-2 байта |
0x0E | Запрос состояния джамперов | нет |
0x0F | Ответ состояния джамперов | 1 байт |
0x10 | Запрос состояния входов (оптопар) | нет |
0x11 | Ответ состояния входов | 1 байт |
0х12 | Запрос количества фронтов входов | 1 байт (номер входа) |
0х13 | Ответ количества фронтов входов | 5 байт:
1-й байт — номер входа 2-3 байты — количество передних фронтов 4-5 байты — количество задних фронтов |
0х14 | Пакетный запрос состояния входов и счетчиков количества фронтов | нет |
0х15 | Ответ на пакетный запрос состояния входов и счетчиков количества фронтов | 33 байта:
1-й байт — состояние входов 2-17 байты — количество передних фронтов по 2 байта на вход начиная с нулевого 18-33 байты — количество задних фронтов по 2 байта на вход начиная с нулевого |
0х16 | Сброс счетчиков фронтов | Нет (в ответ выдается команда 0х15 с нулевыми значениями счетчиков) |
0х20 | Установка битов автоматического мигания выходов | 1 байт |
0х21 | Запрос установленных битов мигания выходов | нет |
0х22 | Ответ установленных битов мигания выходов | 1 байт |
0х23 | Установка периода мигания выхода | 3 байта:
1-й байт — номер выхода 2-3 байты — период в мс По умолчанию период равен 500мс. Если байты 2-3 равны 0, то устанавливается период по-умолчанию |
0х24 | Ответ периода мигания выхода | 3 байта (аналогично команде 0х23) |
Если ответ на команду не получен в течение защитного интервала, то подключенное устройство считается потерянным.
Пример:
Управление выходными линиями платы.
В виртуальный COM-порт необходимо послать команду 0х0A с данными, соответствующими требуемому состоянию выходных линий. Если требуется подать сигнал только на нулевую линию, то в байте данных команд необходимо передать 0х01. Таким образом, вся команда будет иметь следующий вид:
0х7Е 0х02 0х00 0х0А 0х01 0x8B
в ответ на эту команду при возможности её выполнения плата ответит командой 0х0С с данными, соответствующими состоянию установленных выходных линий:
0х7Е 0х02 0х00 0х0С 0х01 0x8D
либо, при невозможности выполнения, сообщит об ошибке:
0х7Е 0х00 0х01 0x7F
Система тестирования
Система автоматического тестирования написана на языке python3. С периодичностью в одну минуту проверяется наличие новой ревизии в репозитории. Если такая присутствует, она выкачивается, и на нее «натравливаются» тесты. Тесты — это отдельные скрипты на все том же python3, между которыми есть зависимости. Благодаря зависимостям тесты выстраиваются в определенную последовательность: сначала запускается тест, осуществляющий сборку проекта; следом за ним — «быстрые» тесты; в последнюю очередь — все остальные. Результаты выполнения тестов помещаются в базу данных (sqlite).
Отдельный скрипт реализует web-сервер, который визуализирует результаты выполнения тестов.
Этот же web-сервер научили формировать сводку по совокупности тестов. Данная возможность используется для управления светофором.
#! /usr/bin/env python3
import sys, os, termios, threading, time, http.client
if len(sys.argv)<=1:
sys.exit("Usage: {0} CONFIG-FILE".format(sys.argv[0]))
exec(open(sys.argv[1], "rt").read())
portfd=os.open(serialport, os.O_RDWR)
# Configure serial port - make it "raw", set 9600 baud rate and 8N1
iflag,oflag,cflag,lflag,ispeed,ospeed,cc=tuple(termios.tcgetattr(portfd))
iflag&=~(termios.IGNBRK|termios.BRKINT|termios.PARMRK|termios.ISTRIP|termios.INLCR|termios.IGNCR|termios.ICRNL|termios.IXON)
oflag&=~(termios.OPOST)
lflag&=~(termios.ECHO|termios.ECHONL|termios.ICANON|termios.ISIG|termios.IEXTEN)
cflag&=~(termios.CSIZE|termios.PARENB|termios.CSTOPB)
cflag|=termios.CS8
ispeed=termios.B9600
ospeed=termios.B9600
termios.tcsetattr(portfd, termios.TCSANOW, [iflag, oflag, cflag, lflag, ispeed, ospeed, cc])
# Current state of traffic light:
# 0 - fail (red light)
# 1 - success (green light)
# 2 - in progress (yellow light)
# 3 - no data (blinking yellow)
state=3
RED=0
YELLOW=1
GREEN=2
def trafficLightControl(light):
cmd=[0x7E, 0x02, 0xFF, 0x0A]
if light==RED:
cmd.append(1)
elif light==YELLOW:
cmd.append(2)
elif light==GREEN:
cmd.append(4)
else:
cmd.append(0)
cmd.append(sum(cmd)&0xFF)
os.write(portfd, bytes(cmd))
def controlThreadProc():
while True:
if state==0:
trafficLightControl(RED)
elif state==1:
trafficLightControl(GREEN)
elif state==2:
trafficLightControl(YELLOW)
else:
trafficLightControl(YELLOW)
time.sleep(1.5)
trafficLightControl(None)
time.sleep(1.5)
controlThread=threading.Thread(target=controlThreadProc)
controlThread.start()
def pollThreadProc():
global state
connection=None
while True:
try:
if connection is None:
connection=http.client.HTTPConnection(server)
connection.request("GET", "/{0}/status?test={1}".format(project, ",".join(tests)))
r=connection.getresponse().readall()
state=int(r.decode("ascii"))
except:
state=3
connection=None
time.sleep(5)
pollThread=threading.Thread(target=pollThreadProc)
pollThread.start()
В конфигурационном файле указывается адрес сервера и список тестов, за которыми будет следить светофор.
server="192.168.2.245"
project="tvz-win-trunk"
tests=['build', 'xmlcheck', 'qdebug', 'runss', 'runssc', 'tr_en', 'trcyr_en', 'warning1', 'warning10', 'warning100', 'xmldeps', 'issue16683a', 'issue17071', 'issue16796', 'runmain', 'issue17319', 'issue17318', 'issue17396a', 'smartstation_su', 'xmlrpcdoc_ss', 'src_encoding', 'issue17241', 'issue17228']
serialport="/dev/ttyUSB0"
Логика работы светофора в системе тестов очень проста:
- Красный – тест провален
- Желтый – идёт прогон тестов или перепроверка теста
- Зеленый – все тесты успешно завершились
- Мигание желтым – отсутствует соединение с сервером
Итоги
Светофор был размещен перед выходом из офиса. Это дает достаточно ощутимый психологический эффект: горит зеленый сигнал светофора – путь свободен (можно смело идти домой), красный – надо исправлять ошибку.
Автор: Nordavind