AdvancedControllerRemoteCPP/docs/REMOTE_API_EN.txt

313 lines
16 KiB
Text

AdvancedController - remote control over RS485. Protocol description and integration
=====================================================================================
Firmware version: r7.2.6. Russian version: REMOTE_API_RU.txt.
1. PHYSICAL LAYER
-----------------
Controller port: INPUT (RS485, the connector next to the power connector).
Inside: USART2, PD5 TX, PD6 RX, PD7 = transceiver direction.
Line settings: 9600 baud, 8 data bits, no parity, 1 stop bit (9600 8N1).
Half duplex, two-wire A/B line. On the PC side: a USB-RS485 adapter with
automatic direction control (virtual COM port). 120 ohm termination at the
ends of a long line as usual for RS485.
Only the PC must be on this bus: the controller never transmits on its own,
it only answers commands.
2. FRAME AND EXCHANGE RULES
---------------------------
Request from the PC: CMD [ARG1 [ARG2]]<CR><LF>
- ASCII text, case-insensitive (br 12 = BR 12);
- arguments separated by a space; terminator CR, LF or CR+LF;
- at most 64 characters without the terminator.
Reply of the controller to EVERY request:
OK<CR><LF> command executed
OK <data><CR><LF> command executed, data follows (VER, STATUS)
ERR <code> <text><CR><LF> command not executed (section 5)
Stop-and-wait: the PC sends the next command only after the reply arrived (or
the timeout expired). The controller handles one line per pass of its main
loop; lines that arrive earlier wait in a 256-byte buffer.
Line turnaround: after a reply wait at least 5 ms before the next request.
The controller switches its RS485 transceiver back to receiving about 2 ms
after the end of its reply; bytes sent earlier are lost and the controller
answers ERR 1 UNKNOWN or ERR 5 CHECKSUM to the damaged line. RemoteClient
(lib/remoteclient.cpp) keeps this pause by itself.
Timeouts on the PC side (recommendation):
ordinary commands 0.5 s
PRESET LOAD/SAVE, KEY LOAD*/SAVE* 3 s
KEY XH1/XH2, KEY UP/DOWN/LEFT/RIGHT while a crosshair is being edited 2-3 s
RESET, FOCUS, KEY CAMRESET, KEY FOCUS 10 s
The reply to a long command comes AFTER it has completed (RESET ~6 s, FOCUS
~5 s). While a long command runs the controller does not parse new lines;
they are not lost and are handled afterwards (replies arrive late).
Late reply: when the PC gave up waiting (timeout) the reply still comes later
and would be taken for the reply to the next request. Drop such lines before
the next request (RemoteClient does it by itself: after a timeout it waits
for 0.3 s of silence and clears the receive buffer).
Retries: when no reply arrives, repeat only idempotent commands (PING, VER,
STATUS, CAM, BR, AGC, ZOOM, FLIP, MIR, TEMP, LED). Never repeat KEY, RESET,
FOCUS or PRESET automatically - a repetition repeats the action.
Resynchronisation: a pause of more than 100 ms between the bytes of a line
drops the partial line without a reply. A line longer than 64 characters is
answered with ERR 4 after its terminator.
Checksum (optional): a request may end with "*hh", hh being the XOR of all
characters before '*' in hexadecimal (NMEA style):
PING*10<CR><LF> -> OK PONG ADVCTRL*48<CR><LF>
When the request carries a checksum the controller verifies it (mismatch ->
ERR 5) and appends a checksum to the reply. Without '*' there is no checksum
in either direction.
3. COMMANDS
-----------
All commands with values act on the CURRENT camera (see CAM and STATUS).
Command Arguments Action / reply
------------------- ----------------- -------------------------------------------
PING - OK PONG ADVCTRL. Link check and controller
detection (signature "PONG ADVCTRL").
VER - OK r7.2.6. Firmware version.
ID - OK ADVCTRL FW=r7.2.6 CAMS=4 UID=<24 hex>.
Identification: firmware, number of
cameras, unique MCU id.
STATUS - OK CAM=.. BR=.. ... (section 4).
LEDS - OK <6 hex>. State of the 24 keyboard
leds as the device shows them
(section 4a).
CAM n 1..4 Select camera n (like the CAM SELECT
button, the selection leds follow).
BR n 0..20 Camera brightness.
AGC n 0..20 Camera AGC.
ZOOM n 0..16 Camera digital zoom.
FLIP 0|1 - Image flip off/on.
MIR 0|1 - Mirror off/on.
TEMP 0|1 - Temperature on the camera OSD off/on.
LED n 0..3 Backlight level: 0 off, 1 = 25 %,
2 = 75 %, 3 = 100 %. Ends AUTO mode.
LED AUTO 0|1 - Automatic backlight from the 0-10 V
input off/on (all channels).
PRESET LOAD 1|2 - Load a user preset of the camera.
PRESET SAVE 1|2 - Save the camera settings to a preset.
RESET - Default settings to all cameras
(CAM RESET button, ~6 s).
FOCUS - Crosshair initialisation of the current
camera (FOCUS button, ~5 s).
KEY <name> section 6 Virtual keyboard button.
IDENTIFY - The gear led blinks fast for 3 s - to
see which controller the PC talks to.
Example session (terminal, 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 FIELDS
----------------
CAM current camera 1..4
BR brightness 0..20 AGC 0..20 ZOOM 0..16
FLIP 0/1 MIR 0/1 TOSD temperature on OSD 0/1
LED backlight level 0..3 (manual) AUTO automatic backlight 0/1
CT temperature of camera 1, C (sent by the camera; 25 until the first message)
CT2 temperature of camera 2, C (last field of the STATUS line)
PT temperature of the controller CPU, C (internal sensor, approximate)
LT light tower: G - normal (green), R - camera overheated (red)
XH1, XH2 crosshair 1 / 2 shown 0/1
BR/AGC/ZOOM/FLIP/MIR/TOSD/LED are stored in the controller per camera and
reflect both PC commands and keyboard presses. The camera's own values after
PRESET LOAD are unknown to the controller (camera limitation): after loading a
preset set the wanted values explicitly with BR/AGC/ZOOM.
4a. LEDS - LED BITS
-------------------
The reply is a 24-bit mask as 6 hexadecimal digits (bit = 1: led on).
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
The virtual panel (bin/AdvancedControllerPanel) polls LEDS 5 times a
second and mirrors the device indication. CAM1SEL/CAM2SEL are the two leds of
the camera-select button: camera 1 = 1/0, 2 = 0/1, 3 = 1/1, 4 = 0/0.
5. ERROR CODES
--------------
ERR 1 UNKNOWN unknown command
ERR 2 ARG wrong number or format of arguments
ERR 3 RANGE argument out of range
ERR 4 TOOLONG line longer than 64 characters
ERR 5 CHECKSUM checksum mismatch
6. VIRTUAL BUTTONS (KEY)
------------------------
KEY reproduces a press of the membrane keyboard and goes through the same
handler as the real button: same modes, leds and interlocks. OK is returned
after the press has been executed.
ENTER LONGENTER (long press - open the camera OSD menu)
UP DOWN LEFT RIGHT arrows (act in the active mode)
FLIP MIRROR toggle flip / mirror
ZOOM BRIGHT AGC enter/leave the arrow-adjust mode
XH1 XH2 show/hide crosshair 1 / 2
XH1LONG XH2LONG crosshair edit mode (arrows move the lines)
CAMRESET reset of all cameras (= RESET); the "three
sliders" button, its led blinks during the reset
TEMP temperature on the camera OSD on/off
LEDON manual backlight mode on/off (arrows change the level)
LEDAUTO automatic backlight on/off
LOAD1 LOAD2 SAVE1 SAVE2 camera presets
SYSRESET leave all active adjust modes; the gear button
(its led = remote-control sign, section 7)
CAMSEL next camera (1->2->3->4->1)
FOCUS crosshair initialisation (= FOCUS)
Modality: ZOOM, BRIGHT, AGC, LEDON, XH1LONG, XH2LONG and LONGENTER enter a
mode in which UP/DOWN/LEFT/RIGHT change the corresponding parameter. Only one
adjust mode is active at a time. PC software should prefer the direct
commands (BR, AGC, ZOOM, LED, CAM) and use KEY for what has no direct command
(crosshairs, OSD menu).
7. BEHAVIOUR AND LIMITS
-----------------------
- The controller keyboard keeps working next to the PC. A real press wins:
a virtual press is executed in the next loop pass.
- Changes made with the buttons are visible to the PC through STATUS.
- Camera 4 is connected to the controller by its backlight (PWM) only;
camera commands with camera 4 selected go nowhere (the INPUT port is the PC's).
- During RESET/FOCUS the controller is busy for up to 6 s; the watchdog does
not trip.
- The controller sends nothing on its own.
Poll STATUS, e.g. once per second, to display the state.
- Operator indication: while commands keep coming from the PC
the gear-button led on the device blinks twice with a 2 s pause; it goes
off 5 s after the last command. The firmware does this; the PC software
does nothing for it (bit 22 SYSRESET in LEDS = the gear led; bit 7 CAMMENU
is the led of the "three sliders" button).
The IDENTIFY command makes the same led blink fast for 3 s (100 ms on /
100 ms off) - that is how one finds out which of several controllers is
connected to a given port; the normal indication resumes afterwards.
8. INTEGRATION GUIDELINES FOR CLIENT SOFTWARE
---------------------------------------------
1. One thread (or one queue) per port: strictly stop-and-wait, at least 5 ms
between the end of a reply and the next request (section 2).
2. After opening the port: wait 100 ms, clear the input buffer, then
CONTROLLER DETECTION: PING with a 0.3 s timeout, up to 2 attempts. A reply
starting with "OK PONG ADVCTRL" means "controller detected"; any other
reply or silence means "controller not detected" (another device or
nothing on that port). After the detection: ID (firmware version, number
of cameras, MCU UID - it tells several controllers apart).
Finding the right port among many: run the same procedure on every COM
port (RemoteClient::detect(), RemoteClient::findController();
remote_test --scan / --detect).
3. Wait for each command up to the timeout of section 2; ignore lines that do
not start with OK/ERR (link test, garbage at power-on).
4. Repeat only idempotent commands on timeout (list in section 2); drop the
late reply before the repeat (section 2).
5. ERR is not a link failure: show it to the user and continue.
6. Synchronise the PC user interface from STATUS (once per second or after
each command), not from an assumed state.
7. No reply to 3 consecutive PINGs = link lost: reopen the port.
8. Enable the checksum in industrial environments (long line, noise).
C++ / Qt 6 - blocking client (lib/remoteclient.h), for a console program or a
worker thread:
#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"); // show crosshair 1
if (!rc.brightness(99)) // the controller answers ERR 3 RANGE
qDebug() << "controller said" << rc.lastReply().code << rc.lastReply().text;
C++ / Qt 6 - GUI application (lib/controllerlink.h): the client runs in its own
thread, the results arrive as signals in the GUI thread:
#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 led bits */ });
link->open("/dev/ttyUSB0");
link->send("CAM 2");
link->send("BR 12");
The virtual panel (panel/deviceview.cpp) is a complete example of ControllerLink.
Build: in your CMake project find Qt (find_package(Qt6 REQUIRED COMPONENTS Core
SerialPort) and qt_standard_project_setup()), then add_subdirectory(<path>/lib)
and target_link_libraries(<your target> PRIVATE AdvancedControllerRemote) - or
add the four files of lib/ to your target.
C# example (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); // line turnaround (section 2)
sp.ReadTimeout = timeoutMs; sp.DiscardInBuffer();
sp.WriteLine(line);
while (true) { // skip lines that are not replies
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));
Pseudo code for C / embedded hosts:
wait_ms(5); /* line turnaround after the previous reply */
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. FILES IN THIS FOLDER
-----------------------
build.sh builds the project and puts binaries into bin/
run.sh starts the virtual front panel (bin/AdvancedControllerPanel)
CMakeLists.txt CMake project: lib, panel, tools
lib/ client library to embed into your software:
remoteclient.h/.cpp RemoteClient - blocking, one port
controllerlink.h/.cpp ControllerLink - RemoteClient in its own
thread, results as Qt signals (GUI)
panel/ virtual front panel (Qt Widgets): the device buttons, the leds
mirror the real ones (LEDS)
tools/remote_test.cpp test tool (bin/remote_test): --list, --scan, --detect,
--monitor, -c CMD, --selftest, interactive
docs/ this document (RU/EN) and the panel button guide (PANEL_HELP.txt)
The panel works with three controllers at once: tabs CONTROLLER 1..3, each
with its own port, OPEN/CLOSE and indicator (grey - port closed, red - port
open but no answer, green - connected).
Requirements: Linux, Qt 6.5 or later with Qt Serial Port, GCC or Clang (C++17),
CMake 3.16 or later. Ports like /dev/ttyUSB0; the user must be in the dialout
group (sudo usermod -a -G dialout $USER).