update ErrorCode, status, lifecycle

This commit is contained in:
2026-07-06 15:55:14 +07:00
parent 323715eab0
commit 397b9ab3c5
12 changed files with 253 additions and 69 deletions

View File

@@ -41,10 +41,17 @@ target_link_libraries(my_app PRIVATE lidarlib::lidarlib)
lidarlib::LidarConfig c{"front", "192.168.1.10", 2368, "AUTO", false, "OLEI"};
std::unique_ptr<lidarlib::Lidar> lidar = lidarlib::make_lidar(c);
lidar->open();
lidarlib::ErrorCode err = lidar->open();
if (err != lidarlib::ErrorCode::Ok) {
fprintf(stderr, "open that bai: %s\n", lidarlib::to_string(err));
return 1;
}
lidarlib::ScanResult r;
lidar->recv_scan(r, 1000);
if (!lidar->recv_scan(r, 1000)) {
// Timeout / DeviceDisconnected / NotOpen — xem lidar->last_error()
}
// r.scan : LaserScan — format sensor_msgs/LaserScan của ROS, chung mọi lidar
// r.info : ExtraInfo — thông tin thêm tuỳ family/model
printf("%zu diem, model=%s\n", r.scan.ranges.size(), r.info.detected_model.c_str());
@@ -61,6 +68,33 @@ lidarlib::NanoScanDriver nano(lidarlib::MODEL_SICK_NANOSCAN3, "0.0.0.0", 6060);
Ngoài `recv_scan()` blocking còn có callback: `set_scan_callback()` +
`spin_once()` trong vòng lặp riêng.
### Error handling & lifecycle
`open()` trả về `lidarlib::ErrorCode` (header `lidarlib/error.hpp`,
`to_string()` để log). Các code chính:
| ErrorCode | Khi nào |
|---|---|
| `Ok` | Thành công |
| `AlreadyOpen` | Gọi `open()` khi đang mở — kết nối cũ giữ nguyên |
| `NotOpen` | Gọi `recv_scan()`/`spin_once()` khi chưa `open()` |
| `InvalidAddress` | Chuỗi IP không hợp lệ |
| `PortInUse` | Port local đã bị chiếm (bind `EADDRINUSE`/`EACCES`) |
| `BindFailed` / `SocketError` | Lỗi bind khác / không tạo được socket |
| `ConnectionRefused` / `ConnectionFailed` / `Timeout` | TCP connect (SICK TiM) bị từ chối / không tới được / quá 2s |
| `HandshakeFailed` | TCP nối được nhưng gửi `sEN LMDscandata 1` thất bại |
| `DeviceDisconnected` | Thiết bị đóng kết nối / lỗi recv giữa chừng |
Trạng thái instance:
- `is_open()` — socket đang mở hay không.
- `last_error()` — kết quả của lần `open()`/`recv_scan()`/`spin_once()` gần
nhất (`recv_scan()` trả `false` thì gọi hàm này để biết `Timeout` hay
`DeviceDisconnected`).
- Lifecycle chịu lỗi mọi thứ tự gọi: `close()` trước `open()` hoặc `close()`
hai lần là no-op; `open()` hai lần trả `AlreadyOpen` và không đụng kết nối
đang chạy; sau `close()` có thể `open()` lại (state scan dở được reset).
## Cấu hình (config.json)
`lidar_app` là app mẫu headless: đọc `config.json`, mở từng lidar bằng
@@ -150,6 +184,7 @@ parse datagram; **đích UDP phải cấu hình sẵn trong SICK Safety Designer
| File | Vai trò |
|---|---|
| `include/lidarlib/error.hpp` | `enum class ErrorCode` + `to_string()` |
| `include/lidarlib/lidar.hpp` | Data model, interface `Lidar`, driver OLEI, các `MODEL_*` OLEI |
| `include/lidarlib/sick_lidar.hpp` | `SickDriver`, `NanoScanDriver`, các `MODEL_SICK_*` |
| `include/lidarlib/config.hpp` | `LidarConfig`, load/save JSON, `make_lidar()` |
@@ -160,7 +195,35 @@ parse datagram; **đích UDP phải cấu hình sẵn trong SICK Safety Designer
## Ghi chú
- Nếu port UDP đã bị app khác giữ (không bật `SO_REUSEPORT`), `open()` sẽ thất
bại. Kiểm tra: `ss -lunp | grep 2368`.
- Nếu port UDP đã bị app khác giữ (không bật `SO_REUSEPORT`), `open()` trả
`ErrorCode::PortInUse`. Kiểm tra: `ss -lunp | grep 2368`.
- `inverted` đã verify bằng sniff sống: `false` góc tăng dần, `true` góc giảm
dần cùng bước.
## Changelog
### 2026-07-06 — Error handling & lifecycle API
- **Header mới `lidarlib/error.hpp`**: `enum class ErrorCode``Ok`,
`AlreadyOpen`, `NotOpen`, `SocketError`, `InvalidAddress`, `PortInUse`,
`BindFailed`, `ConnectionRefused`, `ConnectionFailed`, `HandshakeFailed`,
`Timeout`, `DeviceDisconnected` — kèm `to_string()` để log.
- **`open()` đổi chữ ký `bool``ErrorCode`** trên cả 3 driver (`Driver`,
`SickDriver`, `NanoScanDriver`). Lỗi phân loại từ `errno` thật: bind
`EADDRINUSE``PortInUse`, connect TCP bị từ chối → `ConnectionRefused`,
quá 2s → `Timeout`, gửi lệnh start-stream fail → `HandshakeFailed`,
IP sai format → `InvalidAddress`.
- **API trạng thái mới trên interface `Lidar`**:
- `is_open()` — socket đang mở hay không (cả 3 driver implement);
- `last_error()` — kết quả lần `open()`/`recv_scan()`/`spin_once()` gần
nhất; `recv_scan()` trả `false` thì gọi hàm này để biết `Timeout` hay
`DeviceDisconnected`.
- **Lifecycle chịu lỗi mọi thứ tự gọi**: `close()` trước `open()` hoặc gọi
hai lần là no-op; `open()` khi đang mở trả `AlreadyOpen` và không đụng kết
nối đang chạy; `recv_scan()`/`spin_once()` khi chưa mở trả `false` +
`NotOpen`; sau `close()` có thể `open()` lại (state scan dở được reset).
- **`NanoScanDriver` bỏ `SO_REUSEADDR`**: với UDP không có tác dụng (không có
TIME_WAIT) mà còn che mất lỗi trùng port — giờ `PortInUse` báo được thật.
- ⚠️ **Breaking change**: code cũ viết `if (!lidar->open())` bị đảo ngược
logic vì `ErrorCode::Ok == 0` — phải đổi thành
`if (lidar->open() != lidarlib::ErrorCode::Ok)`.