317 lines
24 KiB
Text
317 lines
24 KiB
Text
AdvancedController — удалённое управление по RS485. Описание протокола и интеграция
|
||
=====================================================================================
|
||
Версия прошивки: r7.2.6. Английская версия: REMOTE_API_EN.txt.
|
||
|
||
|
||
1. ФИЗИЧЕСКИЙ УРОВЕНЬ
|
||
---------------------
|
||
Порт контроллера: INPUT (RS485, разъём у разъёма питания). Внутри: USART2,
|
||
PD5 TX, PD6 RX, PD7 — управление направлением приёмопередатчика.
|
||
Параметры линии: 9600 бод, 8 бит данных, без чётности, 1 стоп-бит (9600 8N1).
|
||
Полудуплекс, двухпроводная линия A/B. На стороне ПК — адаптер USB-RS485 с
|
||
автоматическим управлением направлением (виртуальный COM-порт). Согласующий
|
||
резистор 120 Ом на концах длинной линии по правилам RS485.
|
||
На этой шине должен быть только ПК: контроллер сам ничего не передаёт, кроме
|
||
ответов на команды.
|
||
|
||
|
||
2. КАДР И ПРАВИЛА ОБМЕНА
|
||
------------------------
|
||
Запрос от ПК: CMD [ARG1 [ARG2]]<CR><LF>
|
||
- текст ASCII, регистр не важен (br 12 = BR 12);
|
||
- разделитель аргументов — пробел; терминатор — CR, LF или CR+LF;
|
||
- длина строки без терминатора не более 64 символов.
|
||
Ответ контроллера на КАЖДЫЙ запрос:
|
||
OK<CR><LF> команда выполнена
|
||
OK <данные><CR><LF> команда выполнена, есть данные (VER, STATUS)
|
||
ERR <код> <текст><CR><LF> команда не выполнена (см. п. 5)
|
||
|
||
Стоп-и-жди: ПК отправляет следующую команду только после получения ответа
|
||
(или истечения таймаута). Контроллер обрабатывает одну строку за проход
|
||
главного цикла; строки, пришедшие раньше, ждут в буфере (256 байт).
|
||
|
||
Разворот линии: после ответа выдержите не меньше 5 мс перед следующим
|
||
запросом. Контроллер переключает приёмопередатчик RS485 обратно на приём
|
||
примерно через 2 мс после конца своего ответа; байты, отправленные раньше,
|
||
теряются, и на испорченную строку контроллер отвечает ERR 1 UNKNOWN или
|
||
ERR 5 CHECKSUM. RemoteClient (lib/remoteclient.cpp) выдерживает эту паузу сам.
|
||
|
||
Таймауты на стороне ПК (рекомендация):
|
||
обычные команды 0,5 с
|
||
PRESET LOAD/SAVE, KEY LOAD*/SAVE* 3 с
|
||
KEY XH1/XH2, KEY UP/DOWN/LEFT/RIGHT в режиме редактирования перекрестья 2–3 с
|
||
RESET, FOCUS, KEY CAMRESET, KEY FOCUS 10 с
|
||
Ответ на долгие команды приходит ПОСЛЕ их выполнения (RESET ≈ 6 с, FOCUS ≈ 5 с).
|
||
Во время выполнения долгой команды контроллер не обрабатывает новые строки;
|
||
они не теряются и будут обработаны после (ответы придут с задержкой).
|
||
Поздний ответ: если ПК не дождался ответа (таймаут), ответ всё равно придёт
|
||
позже и может быть принят за ответ на следующую команду. Перед следующей
|
||
командой такие строки нужно отбросить (RemoteClient делает это сам: после
|
||
таймаута выдерживает 0,3 с тишины и очищает буфер приёма).
|
||
|
||
Повторы: при отсутствии ответа повторяйте только идемпотентные команды
|
||
(PING, VER, STATUS, CAM, BR, AGC, ZOOM, FLIP, MIR, TEMP, LED). Команды KEY,
|
||
RESET, FOCUS, PRESET повторять автоматически нельзя — повторная отправка
|
||
даст повторное действие.
|
||
|
||
Ресинхронизация: если между байтами строки пауза больше 100 мс, недостроенная
|
||
строка отбрасывается без ответа. Строка длиннее 64 символов — ответ ERR 4
|
||
после её терминатора.
|
||
|
||
Контрольная сумма (необязательно): к запросу можно добавить «*hh», где hh —
|
||
XOR всех символов до «*» в шестнадцатеричном виде (стиль NMEA):
|
||
PING*10<CR><LF> → OK PONG ADVCTRL*48<CR><LF>
|
||
Если запрос содержит сумму, контроллер её проверяет (несовпадение → ERR 5) и
|
||
добавляет сумму к ответу. Без «*» суммы нет ни в запросе, ни в ответе.
|
||
|
||
|
||
3. КОМАНДЫ
|
||
----------
|
||
Все команды со значениями действуют на ТЕКУЩУЮ камеру (см. CAM и STATUS).
|
||
|
||
Команда Аргументы Действие / ответ
|
||
------------------- ----------------- -------------------------------------------
|
||
PING — OK PONG ADVCTRL. Проверка связи и опознание
|
||
контроллера (сигнатура «PONG ADVCTRL»).
|
||
VER — OK r7.2.6. Версия прошивки.
|
||
ID — OK ADVCTRL FW=r7.2.6 CAMS=4 UID=<24 hex>.
|
||
Опознание: прошивка, число камер,
|
||
уникальный номер микроконтроллера.
|
||
STATUS — OK CAM=.. BR=.. ... (см. п. 4).
|
||
LEDS — OK <6 hex>. Состояние 24 светодиодов
|
||
клавиатуры, как их показывает
|
||
устройство (см. п. 4а).
|
||
CAM n 1..4 Выбрать камеру n (как кнопка CAM SELECT,
|
||
светодиоды выбора обновляются).
|
||
BR n 0..20 Яркость камеры.
|
||
AGC n 0..20 AGC камеры.
|
||
ZOOM n 0..16 Цифровой зум камеры.
|
||
FLIP 0|1 — Переворот изображения выкл/вкл.
|
||
MIR 0|1 — Зеркало выкл/вкл.
|
||
TEMP 0|1 — Показ температуры на OSD камеры выкл/вкл.
|
||
LED n 0..3 Уровень подсветки: 0 выкл, 1 = 25 %,
|
||
2 = 75 %, 3 = 100 %. Выключает режим AUTO.
|
||
LED AUTO 0|1 — Автоматическая подсветка по входу 0–10 В
|
||
выкл/вкл (для всех каналов).
|
||
PRESET LOAD 1|2 — Загрузить пользовательский пресет камеры.
|
||
PRESET SAVE 1|2 — Сохранить текущие настройки камеры в пресет.
|
||
RESET — Сброс всех камер к настройкам по умолчанию
|
||
(кнопка CAM RESET, ≈ 6 с).
|
||
FOCUS — Инициализация перекрестий текущей камеры
|
||
(кнопка FOCUS, ≈ 5 с).
|
||
KEY <имя> см. п. 6 Виртуальное нажатие кнопки клавиатуры.
|
||
IDENTIFY — Светодиод шестерёнки быстро мигает 3 с —
|
||
чтобы найти глазами, с каким из
|
||
контроллеров работает ПК.
|
||
|
||
Пример сеанса (терминал, 9600 8N1, CR+LF):
|
||
> PING < OK PONG ADVCTRL
|
||
> VER < OK r7.2.6
|
||
> ID < OK ADVCTRL FW=r7.2.6 CAMS=4 UID=3A0032000E51383433353839
|
||
> CAM 2 < OK
|
||
> BR 12 < OK
|
||
> STATUS < OK CAM=2 BR=12 AGC=4 ZOOM=0 FLIP=0 MIR=0 TOSD=0 LED=3 AUTO=0 CT=41 PT=36 LT=G XH1=0 XH2=0 CT2=40
|
||
> BR 99 < ERR 3 RANGE
|
||
> HELLO < ERR 1 UNKNOWN
|
||
|
||
|
||
4. ПОЛЯ STATUS
|
||
--------------
|
||
CAM номер текущей камеры 1..4
|
||
BR яркость 0..20 AGC 0..20 ZOOM 0..16
|
||
FLIP 0/1 MIR 0/1 TOSD температура на OSD 0/1
|
||
LED уровень подсветки 0..3 (ручной) AUTO автоподсветка 0/1
|
||
CT температура камеры 1, °C (приходит от камеры; до первого сообщения 25)
|
||
CT2 температура камеры 2, °C (поле в конце строки STATUS)
|
||
PT температура процессора контроллера, °C (внутренний датчик, ориентировочно)
|
||
LT состояние световой колонны: G — норма (зелёный), R — перегрев камеры (красный)
|
||
XH1, XH2 перекрестья 1 и 2 показаны 0/1
|
||
Значения BR/AGC/ZOOM/FLIP/MIR/TOSD/LED хранятся в контроллере отдельно для
|
||
каждой камеры и отражают как команды с ПК, так и нажатия кнопок. Значения
|
||
самой камеры после PRESET LOAD контроллеру неизвестны (ограничение камеры):
|
||
после загрузки пресета задайте нужные величины командами BR/AGC/ZOOM явно.
|
||
|
||
|
||
4а. LEDS — БИТЫ СВЕТОДИОДОВ
|
||
---------------------------
|
||
Ответ — 24-битная маска в виде 6 шестнадцатеричных цифр (бит = 1: горит).
|
||
0 TEMP 1 XH2 2 XH1 3 SAVE2 4 SAVE1 5 LOAD2
|
||
6 LOAD1 7 CAMMENU 8 FOCUS 9 FLIP 10 MIRROR 11 ZOOM
|
||
12 CAM1SEL 13 UP 14 DOWN 15 RIGHT 16 LEFT 17 ENTER
|
||
18 BRIGHT 19 AGC 20 LEDAUTO 21 LEDON 22 SYSRESET 23 CAM2SEL
|
||
Пример: OK 00A000 -> биты 13 (UP), 15 (RIGHT), 17 (ENTER)... считать по маске.
|
||
Виртуальная панель (bin/AdvancedControllerPanel) опрашивает LEDS 5 раз в
|
||
секунду и повторяет индикацию устройства. CAM1SEL/CAM2SEL — два светодиода
|
||
кнопки выбора камеры: камера 1 = 1/0, 2 = 0/1, 3 = 1/1, 4 = 0/0.
|
||
|
||
|
||
5. КОДЫ ОШИБОК
|
||
--------------
|
||
ERR 1 UNKNOWN неизвестная команда
|
||
ERR 2 ARG неверное число или формат аргументов
|
||
ERR 3 RANGE аргумент вне диапазона
|
||
ERR 4 TOOLONG строка длиннее 64 символов
|
||
ERR 5 CHECKSUM контрольная сумма не совпала
|
||
|
||
|
||
6. ВИРТУАЛЬНЫЕ КНОПКИ (KEY)
|
||
---------------------------
|
||
KEY воспроизводит нажатие кнопки мембранной клавиатуры и проходит через тот же
|
||
обработчик, что и реальная кнопка: те же режимы, светодиоды, блокировки.
|
||
Ответ OK приходит после выполнения нажатия.
|
||
|
||
ENTER LONGENTER (долгое — открыть OSD-меню камеры)
|
||
UP DOWN LEFT RIGHT стрелки (действуют в активном режиме)
|
||
FLIP MIRROR переключить переворот / зеркало
|
||
ZOOM BRIGHT AGC включить/выключить режим регулировки стрелками
|
||
XH1 XH2 показать/скрыть перекрестье 1 / 2
|
||
XH1LONG XH2LONG режим редактирования перекрестья (стрелки двигают линии)
|
||
CAMRESET сброс всех камер (= RESET); кнопка «три ползунка»,
|
||
её светодиод мигает во время сброса
|
||
TEMP температура на OSD камеры вкл/выкл
|
||
LEDON ручной режим подсветки вкл/выкл (стрелки меняют уровень)
|
||
LEDAUTO автоподсветка вкл/выкл
|
||
LOAD1 LOAD2 SAVE1 SAVE2 пресеты камеры
|
||
SYSRESET выключить все активные режимы регулировки;
|
||
кнопка-шестерёнка (её светодиод = признак
|
||
удалённого управления, п. 7)
|
||
CAMSEL следующая камера (1→2→3→4→1)
|
||
FOCUS инициализация перекрестий (= FOCUS)
|
||
|
||
Модальность: кнопки ZOOM, BRIGHT, AGC, LEDON, XH1LONG, XH2LONG, LONGENTER
|
||
включают режим, в котором стрелки UP/DOWN/LEFT/RIGHT меняют соответствующий
|
||
параметр. Одновременно активен один режим регулировки. Для ПО ПК проще
|
||
использовать прямые команды (BR, AGC, ZOOM, LED, CAM), а KEY — для того,
|
||
чего нет в прямых командах (перекрестья, OSD-меню).
|
||
|
||
|
||
7. ПОВЕДЕНИЕ И ОГРАНИЧЕНИЯ
|
||
--------------------------
|
||
- Клавиатура контроллера работает параллельно с ПК. Реальное нажатие имеет
|
||
приоритет: виртуальное нажатие выполнится в следующем проходе цикла.
|
||
- Изменения, сделанные кнопками, видны ПК через STATUS.
|
||
- Камера 4 подключена к контроллеру только подсветкой (ШИМ); команды камере
|
||
при выбранной камере 4 никуда не отправляются (порт INPUT занят ПК).
|
||
- Во время RESET/FOCUS контроллер занят до 6 с; сторожевой таймер при этом
|
||
не срабатывает.
|
||
- Контроллер не шлёт ничего по своей инициативе.
|
||
Для отображения состояния опрашивайте STATUS, например раз в секунду.
|
||
- Индикация оператору: пока с ПК приходят команды, светодиод
|
||
кнопки-шестерёнки на устройстве мигает двумя короткими вспышками с паузой
|
||
2 с; гаснет через 5 с после последней команды. Это делает прошивка;
|
||
ПО ПК ничего для этого не делает (в LEDS это бит 22 SYSRESET — светодиод
|
||
шестерёнки; бит 7 CAMMENU — светодиод кнопки «три ползунка»).
|
||
Команда IDENTIFY заставляет тот же светодиод быстро мигать 3 с (100 мс
|
||
вкл / 100 мс выкл) — так находят, какой из нескольких контроллеров
|
||
подключён к данному порту; потом обычная индикация возобновляется.
|
||
|
||
|
||
8. РЕКОМЕНДАЦИИ ПО ИНТЕГРАЦИИ В ПО КЛИЕНТА
|
||
------------------------------------------
|
||
1. Один поток (или одна очередь) обмена на порт: строго стоп-и-жди, между
|
||
концом ответа и следующим запросом не меньше 5 мс (см. п. 2).
|
||
2. После открытия порта: подождать 100 мс, очистить входной буфер, затем
|
||
ОБНАРУЖЕНИЕ КОНТРОЛЛЕРА: PING с таймаутом 0,3 с, до 2 попыток. Ответ,
|
||
начинающийся с «OK PONG ADVCTRL», означает «контроллер обнаружен»; любой
|
||
другой ответ или тишина — «контроллер не обнаружен» (на порту другое
|
||
устройство или ничего). После обнаружения — ID (версия прошивки, число
|
||
камер, UID микроконтроллера — по нему различают несколько контроллеров).
|
||
Поиск нужного порта среди многих: перебрать все COM-порты той же
|
||
процедурой (RemoteClient::detect(), RemoteClient::findController();
|
||
remote_test --scan / --detect).
|
||
3. Каждую команду ждать до таймаута из п. 2; строки, не начинающиеся с OK/ERR,
|
||
игнорировать (тест связи, мусор при включении).
|
||
4. Повторять по таймауту только идемпотентные команды (список в п. 2);
|
||
перед повтором отбросить поздний ответ (см. п. 2).
|
||
5. ERR — не обрыв связи: показать пользователю и продолжать.
|
||
6. Состояние интерфейса ПК синхронизировать по STATUS (раз в 1 с или после
|
||
каждой команды), а не по «предполагаемому» состоянию.
|
||
7. При отсутствии ответа на 3 PING подряд — считать связь потерянной,
|
||
переоткрыть порт.
|
||
8. Контрольную сумму включать в промышленных условиях (длинная линия, помехи).
|
||
|
||
C++ / Qt 6 — блокирующий клиент (lib/remoteclient.h), для консольной
|
||
программы или рабочего потока:
|
||
#include "remoteclient.h"
|
||
AdvCtrl::RemoteClient rc;
|
||
if (!rc.open("/dev/ttyUSB0")) {
|
||
qWarning() << rc.errorString();
|
||
return;
|
||
}
|
||
if (rc.detect()) {
|
||
AdvCtrl::Fields id;
|
||
if (rc.identify(&id))
|
||
qDebug() << id.value("FW") << id.value("UID");
|
||
}
|
||
rc.cam(2);
|
||
rc.brightness(12);
|
||
rc.led(3);
|
||
AdvCtrl::Fields st;
|
||
if (rc.status(&st))
|
||
qDebug() << "BR =" << st.value("BR").toInt();
|
||
rc.key("XH1"); // показать перекрестье 1
|
||
if (!rc.brightness(99)) // контроллер ответит ERR 3 RANGE
|
||
qDebug() << "controller said" << rc.lastReply().code << rc.lastReply().text;
|
||
|
||
C++ / Qt 6 — приложение с окном (lib/controllerlink.h): клиент работает в
|
||
своём потоке, результаты приходят сигналами в поток интерфейса:
|
||
#include "controllerlink.h"
|
||
auto *link = new AdvCtrl::ControllerLink(this);
|
||
connect(link, &AdvCtrl::ControllerLink::stateChanged, this,
|
||
[](AdvCtrl::ControllerLink::State s) { /* Closed, NoLink, Link */ });
|
||
connect(link, &AdvCtrl::ControllerLink::reply, this,
|
||
[](const QString &command, const QString &result) { /* "OK", "ERR 3 RANGE", "!! ..." */ });
|
||
connect(link, &AdvCtrl::ControllerLink::leds, this, [](quint32 mask) { /* 24 бита светодиодов */ });
|
||
link->open("/dev/ttyUSB0");
|
||
link->send("CAM 2");
|
||
link->send("BR 12");
|
||
Полный пример использования ControllerLink — виртуальная панель (panel/deviceview.cpp).
|
||
Сборка: в своём CMake-проекте найти Qt (find_package(Qt6 REQUIRED COMPONENTS Core
|
||
SerialPort) и qt_standard_project_setup()), затем add_subdirectory(<путь>/lib) и
|
||
target_link_libraries(<ваша цель> PRIVATE AdvancedControllerRemote) — или
|
||
добавить четыре файла из lib/ в свою цель.
|
||
|
||
Пример на C# (System.IO.Ports.SerialPort):
|
||
var sp = new SerialPort("/dev/ttyUSB0", 9600, Parity.None, 8, StopBits.One);
|
||
sp.NewLine = "\r\n"; sp.ReadTimeout = 500; sp.Open();
|
||
Thread.Sleep(100); sp.DiscardInBuffer();
|
||
string Cmd(string line, int timeoutMs = 500) {
|
||
Thread.Sleep(5); // разворот линии (п. 2)
|
||
sp.ReadTimeout = timeoutMs; sp.DiscardInBuffer();
|
||
sp.WriteLine(line);
|
||
while (true) { // пропускаем строки, не являющиеся ответом
|
||
string r = sp.ReadLine().Trim();
|
||
if (r.StartsWith("OK") || r.StartsWith("ERR")) return r;
|
||
}
|
||
}
|
||
Console.WriteLine(Cmd("VER"));
|
||
Cmd("BR 12");
|
||
Console.WriteLine(Cmd("STATUS"));
|
||
Console.WriteLine(Cmd("RESET", 10000));
|
||
|
||
Псевдокод для C/встроенных систем:
|
||
wait_ms(5); /* разворот линии после предыдущего ответа */
|
||
send("BR 12\r\n"); line = read_line(timeout);
|
||
if (starts_with(line, "OK")) ... else if (starts_with(line, "ERR")) code = atoi(line+4);
|
||
|
||
|
||
9. ФАЙЛЫ В ЭТОЙ ПАПКЕ
|
||
---------------------
|
||
build.sh сборка проекта и установка исполняемых файлов в bin/
|
||
run.sh запуск виртуальной передней панели (bin/AdvancedControllerPanel)
|
||
CMakeLists.txt проект CMake: lib, panel, tools
|
||
lib/ библиотека-клиент для встраивания в ПО:
|
||
remoteclient.h/.cpp RemoteClient — блокирующий, один порт
|
||
controllerlink.h/.cpp ControllerLink — RemoteClient в своём
|
||
потоке, результаты сигналами Qt (окна)
|
||
panel/ виртуальная передняя панель (Qt Widgets): кнопки как на
|
||
устройстве, светодиоды повторяют реальные (LEDS)
|
||
tools/remote_test.cpp утилита (bin/remote_test): --list, --scan, --detect,
|
||
--monitor, -c CMD, --selftest, интерактив
|
||
docs/ этот документ (RU/EN) и справка по кнопкам панели (PANEL_HELP.txt)
|
||
Панель работает с тремя контроллерами одновременно: вкладки CONTROLLER 1..3,
|
||
у каждой свой порт, OPEN/CLOSE и индикатор (серый — порт закрыт, красный —
|
||
порт открыт, контроллер не отвечает, зелёный — связь есть).
|
||
Требуется: Linux, Qt 6.5 или новее с модулем Qt Serial Port, компилятор C++17
|
||
(GCC или Clang), CMake 3.16 или новее. Порты вида /dev/ttyUSB0, пользователь
|
||
должен состоять в группе dialout (sudo usermod -a -G dialout $USER).
|