feat(config,diagnostics): explicit transport in DeviceConfig, vendor-neutral diagnostics
DeviceConfig now carries an optional transport (serial/udp/tcp) instead of
the ESPE-only use_udp bool. Plugins validate it in create_driver_instance:
a fixed-transport driver configured with the wrong transport fails open()
with InvalidConfig (via InvalidConfigDriver — the plugin ABI forbids
returning nullptr) rather than silently ignoring the setting. Selectable
drivers (ESPE) switch TCP/UDP through the same field. config.json
load/save round-trips "transport" for every transport, including serial,
and migrates legacy use_udp:true entries.
Diagnostics drops the per-vendor accessors (espe_fault, rplidar_fault,
monitor_fault, sick_error, pollution_*, contamination_*, manipulation) for
one common shape: a list of DiagnosticIssue{severity, code, detail} with
cross-vendor codes, plus a raw map of vendor passthrough values and
to_json() for hosts that prefer a string. Vendor bit decoding now lives in
one place (decode_diagnostics); has_fault/has_warning/healthy keep their
meaning, so is_ready()/wait_ready() are unchanged.
Also: README regains the model/protocol and ExtraInfo tables lost in the
lidarlib->xlidar refactor (verified against current code), and the empty
xlocd/ tree left by a stray sync run is gone.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -74,8 +74,10 @@ an toàn kiểu safety-scanner). Các trường chẩn đoán (port từ driver
|
||||
| `[44-47]` | u32 LE | `status_flags` | Cờ trạng thái tổng — bit map chưa có tài liệu |
|
||||
|
||||
Vì bit map chưa xác minh, driver **truyền nguyên giá trị raw** qua
|
||||
`Diagnostics` (các trường `std::optional`) thay vì decode sai. Khi có tài
|
||||
liệu V3 chính thức hoặc thiết bị GS1-5 để thử, bổ sung decode tại
|
||||
`Diagnostics::raw` (key `"olei.scan_frequency"`, `"olei.input_status"`,
|
||||
`"olei.output_status"`, `"olei.field_status"`, `"olei.status_flags"`,
|
||||
`"olei.distance_ratio"`) thay vì decode sai thành issue. Khi có tài liệu V3
|
||||
chính thức hoặc thiết bị GS1-5 để thử, bổ sung decode tại
|
||||
`decode_diagnostics()` trong `include/lidar_interface.hpp` (và bảng field trong `plugins/driver_olei/olei_driver.cpp`).
|
||||
|
||||
## 4. SICK TiM (TCP/CoLa-A — telegram `LMDscandata`)
|
||||
@@ -93,8 +95,11 @@ Khác OLEI, TiM có **hai đường** lấy chẩn đoán:
|
||||
| `0 2` | Pollution warning — kính bắt đầu bẩn, vẫn đo được |
|
||||
| `0 4` | Pollution error — kính bẩn nặng, phải lau |
|
||||
|
||||
Driver ghép cặp này vào `info.sick_device_status` (`(word0<<8)|word1`) và
|
||||
decode qua `sick_error()` / `pollution_warning()` / `pollution_error()`.
|
||||
Driver ghép cặp này vào `info.sick_device_status` (`(word0<<8)|word1`);
|
||||
`decode_diagnostics()` biến nó thành issue chung: bit error →
|
||||
`{fault, device_error}`, pollution warning → `{warning, optics_dirty}`,
|
||||
pollution error → `{fault, optics_dirty}` (raw giữ ở
|
||||
`raw["sick.device_status"]`).
|
||||
Ngoài ra telegram còn mang input/output số (`input_status`/`output_status`)
|
||||
và tần số quét (`scan_frequency_raw`, đơn vị 1/100 Hz).
|
||||
**Chưa verify trên TiM781S thật với kính bẩn** — cần che/bôi bẩn kính để
|
||||
@@ -121,8 +126,10 @@ offset/size. Block **General System State** (offset tại header `[32]`, size
|
||||
| 4 | `0x10` | Reference contour status |
|
||||
| 5 | `0x20` | Manipulation — nghi bị che/can thiệp cố ý |
|
||||
|
||||
Driver đọc byte này vào `info.nano_general_state`, decode qua
|
||||
`contamination_warning()` / `contamination_error()` / `manipulation()`.
|
||||
Driver đọc byte này vào `info.nano_general_state`; `decode_diagnostics()`
|
||||
biến nó thành issue chung: contamination warning → `{warning, optics_dirty}`,
|
||||
contamination error → `{fault, optics_dirty}`, manipulation →
|
||||
`{fault, manipulation}` (raw giữ ở `raw["nano.general_state"]`).
|
||||
Lưu ý: block này **chỉ có mặt nếu được tick chọn** trong cấu hình data output
|
||||
của Safety Designer — thiếu block thì trường giữ `nullopt`.
|
||||
|
||||
@@ -134,8 +141,9 @@ RPLIDAR không nhúng chẩn đoán trong stream điểm quét; thay vào đó S
|
||||
**một lần lúc `open()`** — status Error thì `open()` trả `DeviceError` và
|
||||
không dùng thiết bị; Warning vẫn chạy nhưng để lại dấu.
|
||||
|
||||
- Snapshot health nằm ở `Diagnostics::rplidar_health_status` /
|
||||
`rplidar_error_code`, decode qua `rplidar_fault()` / `rplidar_warning()`.
|
||||
- Snapshot health nằm ở `raw["rplidar.health_status"]` /
|
||||
`raw["rplidar.error_code"]`; `decode_diagnostics()` sinh issue chung:
|
||||
health Error → `{fault, device_error}`, Warning → `{warning, device_warning}`.
|
||||
- `Diagnostics::model` (`slamtec-0xNN` từ device info) và
|
||||
`Diagnostics::firmware` (`fw M.mm hw H`) được tự nhận lúc `open()`.
|
||||
- Chẩn đoán runtime chủ yếu là gián tiếp: `recv_scan()` timeout / mất kết
|
||||
@@ -183,6 +191,19 @@ if (!lidar->is_ready()) { /* mất dữ liệu hoặc thiết bị báo fault */
|
||||
|
||||
## 9. API
|
||||
|
||||
API chung cho mọi hãng — không có hàm decode riêng từng vendor. Mỗi vấn đề
|
||||
thiết bị là một `DiagnosticIssue{severity, code, detail}`; bảng map từ wire
|
||||
sang code chung:
|
||||
|
||||
| Nguồn wire | Issue (severity, code) |
|
||||
|---|---|
|
||||
| OLEI Family A bit monitor / voltage / temp | fault `motor` / `voltage` / `temperature` |
|
||||
| OLEI Family A bit 3-7 (reserved) ≠ 0 | fault `device_error` |
|
||||
| SICK TiM device error / pollution warning / pollution error | fault `device_error` / warning `optics_dirty` / fault `optics_dirty` |
|
||||
| nanoScan3 contamination warning / error / manipulation | warning `optics_dirty` / fault `optics_dirty` / fault `manipulation` |
|
||||
| ESPE fault word ≠ 0 | fault `device_error` (detail kèm giá trị hex) |
|
||||
| RPLIDAR health Warning / Error | warning `device_warning` / fault `device_error` |
|
||||
|
||||
```cpp
|
||||
#include "lidar_manager.hpp"
|
||||
|
||||
@@ -192,23 +213,19 @@ if (lidar->recv_scan(r, 1000)) {
|
||||
|
||||
if (!d.valid) {
|
||||
// chưa có scan nào được decode
|
||||
} else if (d.has_fault()) {
|
||||
// Family A: đọc từng bit
|
||||
if (d.voltage_fault()) /* điện áp bất thường */;
|
||||
if (d.temperature_fault()) /* nhiệt độ bất thường */;
|
||||
if (d.monitor_fault()) /* motor/giám sát bất thường */;
|
||||
printf("lidar fault: %s\n", xlidar::to_string(d).c_str());
|
||||
}
|
||||
|
||||
// SICK: cảnh báo kính bẩn — chưa phải fault nhưng nên lên lịch lau
|
||||
if (d.has_warning()) {
|
||||
d.pollution_warning(); // TiM
|
||||
d.contamination_warning(); // nanoScan3
|
||||
for (const xlidar::DiagnosticIssue& issue : d.issues) {
|
||||
printf("[%s] %s — %s\n", xlidar::to_string(issue.severity),
|
||||
issue.code.c_str(), issue.detail.c_str());
|
||||
}
|
||||
if (d.manipulation()) /* nanoScan3: nghi bị che/can thiệp */;
|
||||
if (d.has_fault()) { /* dừng tin dữ liệu */ }
|
||||
if (d.has_warning()) { /* lên lịch bảo trì */ }
|
||||
|
||||
// Family C raw (nullopt nếu không phải GS1-5)
|
||||
if (d.status_flags) printf("status_flags=0x%08X\n", *d.status_flags);
|
||||
// Giá trị thô của hãng (chỉ có khi wire mang nó), VD Family C raw:
|
||||
if (auto it = d.raw.find("olei.status_flags"); it != d.raw.end())
|
||||
printf("status_flags=0x%08X\n", it->second);
|
||||
|
||||
printf("%s\n", xlidar::to_json(d).c_str()); // JSON cho REST/telemetry
|
||||
}
|
||||
```
|
||||
|
||||
@@ -217,10 +234,11 @@ if (lidar->recv_scan(r, 1000)) {
|
||||
- `decode_diagnostics(const ExtraInfo&)` — hàm free, decode trực tiếp từ
|
||||
`ScanResult::info` nếu app muốn gắn chẩn đoán với đúng scan cụ thể.
|
||||
- `to_string(Diagnostics)` — chuỗi log 1 dòng: `no data` / `ok` /
|
||||
`WARN: pollution` / `FAULT: voltage temperature`.
|
||||
- `has_fault()` gộp mọi nguồn lỗi (OLEI byte lỗi, TiM device/pollution error,
|
||||
nano contamination error/manipulation); `has_warning()` gộp các mức cảnh
|
||||
báo kính bẩn.
|
||||
`WARN: optics_dirty` / `FAULT: voltage temperature | WARN: optics_dirty`.
|
||||
- `to_json(Diagnostics)` — chuỗi JSON đầy đủ (`valid`, `model`, `firmware`,
|
||||
`healthy`, `issues[]`, `raw{}`) cho host nào muốn nhận string thay struct.
|
||||
- `has_fault()` / `has_warning()` quét `issues` theo severity;
|
||||
`healthy()` = `valid && !has_fault()`.
|
||||
|
||||
## 10. Hướng mở rộng
|
||||
|
||||
|
||||
Reference in New Issue
Block a user