init commit
This commit is contained in:
@@ -0,0 +1,634 @@
|
||||
# DoorMission 使用手册
|
||||
|
||||
## 目录
|
||||
- [概述](#概述)
|
||||
- [基本功能](#基本功能)
|
||||
- [启动与停止](#启动与停止)
|
||||
- [配置管理](#配置管理)
|
||||
- [门控逻辑](#门控逻辑)
|
||||
- [站点配置](#站点配置)
|
||||
- [UI界面](#ui界面)
|
||||
- [参数说明](#参数说明)
|
||||
- [故障排查](#故障排查)
|
||||
- [附录](#附录)
|
||||
|
||||
---
|
||||
|
||||
## 概述
|
||||
|
||||
`DoorMission` 是一个门控进程类,用于管理多个门控制器及其关联的门。它提供了以下核心功能:
|
||||
- 多门控制器管理(支持不同类型)
|
||||
- 自动门控逻辑(根据小车位置自动开关门)
|
||||
- 手动控制功能(支持临时手动控制,优先级高于自动控制)
|
||||
- 车辆占用管理(跟踪和清空门区域的车辆占用)
|
||||
- 配置文件动态监控(支持热更新)
|
||||
- 线程安全的门状态读写
|
||||
- 可视化的配置和监控界面
|
||||
|
||||
### 架构特点
|
||||
- **抽象化设计**:门控制器通过抽象基类 `BasicDoorController` 实现,支持扩展不同类型的控制器
|
||||
- **线程安全**:门状态读取和控制写入分离,所有通信操作在门控制器内部线程完成
|
||||
- **事件驱动**:与交通控制系统集成,响应小车进入/离开站点事件
|
||||
- **热更新支持**:配置文件每10秒自动检查更新,无需重启任务
|
||||
- **控制仲裁机制**:手动控制优先级高于自动控制,手动控制过期后自动恢复自动模式
|
||||
|
||||
---
|
||||
|
||||
## 基本功能
|
||||
|
||||
### 1. 门控制器管理
|
||||
|
||||
#### 1.1 门控制器类型
|
||||
门控制器通过 `DoorTypeAttribute` 标记类型,系统会自动识别并创建实例。当前支持:
|
||||
- **ModbusDoorController**:基于 Modbus TCP 的门控制器
|
||||
|
||||
#### 1.2 门控制器配置
|
||||
每个门控制器包含以下配置:
|
||||
- **Index**:控制器索引(唯一标识)
|
||||
- **Ip**:IP地址
|
||||
- **Port**:端口号(默认502)
|
||||
- **Type**:控制器类型(通过 `DoorTypeAttribute.Name` 指定)
|
||||
- **Doors**:门列表
|
||||
|
||||
#### 1.3 门配置
|
||||
每个门包含以下配置:
|
||||
- **Index**:门索引(在控制器内唯一)
|
||||
- **ControlAddress**:开关控制信号地址(Modbus 线圈地址)
|
||||
- **OpenStatusAddress**:开到位信号地址(Modbus 离散输入地址)
|
||||
|
||||
### 2. 自动门控逻辑
|
||||
|
||||
#### 2.1 门开启条件
|
||||
门会在以下情况自动开启:
|
||||
1. **小车即将进入区域**:当小车到达站点且站点的 `EnterDoor` 字段匹配时,门会在锁定前开启
|
||||
2. **小车在区域内**:当小车已进入并锁定站点时,门保持开启状态
|
||||
|
||||
#### 2.2 门关闭条件
|
||||
门会在以下情况自动关闭:
|
||||
- 小车离开区域后,门自动关闭
|
||||
|
||||
#### 2.3 门标识符格式
|
||||
站点配置中的门标识符格式为:**控制器索引.门索引**
|
||||
|
||||
**示例**:
|
||||
```
|
||||
"EnterDoor": "1.2" // 表示控制器索引1,门索引2
|
||||
"LeaveDoor": "2.3" // 表示控制器索引2,门索引3
|
||||
```
|
||||
|
||||
### 3. 配置文件动态监控
|
||||
|
||||
系统每10秒自动检查 `DoorConfig.json` 文件,并根据配置变化:
|
||||
- **添加**:新增的门控制器会自动创建并连接
|
||||
- **删除**:已移除的门控制器会自动断开并移除
|
||||
- **修改**:已修改的门控制器会自动更新(IP、端口、类型或门配置变化)
|
||||
|
||||
---
|
||||
|
||||
## 启动与停止
|
||||
|
||||
### 1. 启动任务
|
||||
|
||||
```csharp
|
||||
var doorMission = new DoorMission();
|
||||
doorMission.Execute(); // 执行"启动进程"
|
||||
```
|
||||
|
||||
**启动流程**:
|
||||
1. 设置数据文件路径(`DoorConfig.json`)
|
||||
2. 订阅交通控制事件(`BeforeLock`、`AfterLeave`、`OnLockAcquired`)
|
||||
3. 立即加载一次配置(避免监控界面在首次轮询前无数据)
|
||||
4. 启动配置监控任务(每10秒检查一次)
|
||||
5. 启动门控逻辑监控任务(每500毫秒检查一次)
|
||||
|
||||
### 2. 停止任务
|
||||
|
||||
```csharp
|
||||
doorMission.Stop(); // 执行"停止进程"
|
||||
```
|
||||
|
||||
**停止流程**:
|
||||
1. 取消事件订阅
|
||||
2. 取消所有后台任务
|
||||
3. 断开所有门控制器连接
|
||||
4. 等待任务完成(最多等待5秒)
|
||||
|
||||
### 3. 公共方法
|
||||
|
||||
#### 3.1 读取门状态
|
||||
```csharp
|
||||
bool isOpen = doorMission.GetDoorState(controllerIndex, doorIndex);
|
||||
```
|
||||
- **参数**:
|
||||
- `controllerIndex`:门控制器索引
|
||||
- `doorIndex`:门索引
|
||||
- **返回值**:`true`=打开,`false`=关闭
|
||||
|
||||
#### 3.2 设置门控制目标(自动模式)
|
||||
```csharp
|
||||
doorMission.SetDoorControlTarget(controllerIndex, doorIndex, open);
|
||||
```
|
||||
- **参数**:
|
||||
- `controllerIndex`:门控制器索引
|
||||
- `doorIndex`:门索引
|
||||
- `open`:`true`=打开,`false`=关闭
|
||||
|
||||
**注意**:此方法仅设置目标控制状态,实际通信由门控制器内部线程完成,确保线程安全。此方法会立即生效,但可能被手动控制覆盖。
|
||||
|
||||
#### 3.3 设置手动控制目标
|
||||
```csharp
|
||||
bool success = doorMission.SetManualDoorControl(controllerIndex, doorIndex, open, holdSeconds);
|
||||
```
|
||||
- **参数**:
|
||||
- `controllerIndex`:门控制器索引
|
||||
- `doorIndex`:门索引
|
||||
- `open`:`true`=打开,`false`=关闭
|
||||
- `holdSeconds`:手动保持秒数(可选,默认10秒)
|
||||
- **返回值**:`true`=成功,`false`=失败(当有车辆占用且尝试关闭时返回false)
|
||||
|
||||
**功能说明**:
|
||||
- 手动控制优先级高于自动控制
|
||||
- 手动控制会在指定时间后自动过期,恢复自动模式
|
||||
- **安全保护**:当门区域内有车辆占用时,禁止手动关闭门
|
||||
- 手动控制过期后,系统自动恢复自动控制逻辑
|
||||
|
||||
#### 3.4 清除手动控制
|
||||
```csharp
|
||||
doorMission.ClearManualDoorControl(controllerIndex, doorIndex);
|
||||
```
|
||||
- **参数**:
|
||||
- `controllerIndex`:门控制器索引
|
||||
- `doorIndex`:门索引
|
||||
|
||||
**功能说明**:立即清除手动控制请求,恢复自动控制模式。
|
||||
|
||||
#### 3.5 清空车辆占用
|
||||
```csharp
|
||||
doorMission.ClearCarsInArea(controllerIndex, doorIndex);
|
||||
```
|
||||
- **参数**:
|
||||
- `controllerIndex`:门控制器索引
|
||||
- `doorIndex`:门索引
|
||||
|
||||
**功能说明**:清空指定门的车辆占用记录。清空后,如果门处于打开状态且没有其他小车需要进入,门会自动关闭。
|
||||
|
||||
#### 3.6 获取门控制状态
|
||||
```csharp
|
||||
var status = doorMission.GetDoorControlStatus(controllerIndex, doorIndex);
|
||||
```
|
||||
- **参数**:
|
||||
- `controllerIndex`:门控制器索引
|
||||
- `doorIndex`:门索引
|
||||
- **返回值**:`DoorControlStatus` 对象,包含:
|
||||
- `Target`:当前目标状态(true=打开,false=关闭)
|
||||
- `Source`:控制来源(`ControlSource.Auto` 或 `ControlSource.Manual`)
|
||||
- `ManualRemainingSeconds`:手动控制剩余秒数(仅当Source=Manual时有效)
|
||||
- `CarsInArea`:车辆占用列表
|
||||
|
||||
#### 3.7 获取车辆占用情况
|
||||
```csharp
|
||||
var cars = doorMission.GetCarsInArea(controllerIndex, doorIndex);
|
||||
```
|
||||
- **参数**:
|
||||
- `controllerIndex`:门控制器索引
|
||||
- `doorIndex`:门索引
|
||||
- **返回值**:车辆ID列表(`IReadOnlyList<int>`)
|
||||
|
||||
---
|
||||
|
||||
## 配置管理
|
||||
|
||||
### 1. 配置文件格式
|
||||
|
||||
配置文件 `DoorConfig.json` 位于程序根目录,格式如下:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"Index": 1,
|
||||
"Ip": "192.168.1.100",
|
||||
"Port": 502,
|
||||
"Type": "ModbusDoorController",
|
||||
"Doors": [
|
||||
{
|
||||
"Index": 1,
|
||||
"ControlAddress": 0,
|
||||
"OpenStatusAddress": 0
|
||||
},
|
||||
{
|
||||
"Index": 2,
|
||||
"ControlAddress": 1,
|
||||
"OpenStatusAddress": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Index": 2,
|
||||
"Ip": "192.168.1.101",
|
||||
"Port": 502,
|
||||
"Type": "ModbusDoorController",
|
||||
"Doors": [
|
||||
{
|
||||
"Index": 1,
|
||||
"ControlAddress": 0,
|
||||
"OpenStatusAddress": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### 2. 配置界面
|
||||
|
||||
通过调用 `DoorMission.OpenViewer()` 打开门控制器管理界面,可以:
|
||||
- 添加、删除、修改门控制器
|
||||
- 为每个门控制器添加、删除、修改门配置
|
||||
- 保存配置到 `DoorConfig.json`
|
||||
|
||||
**打开配置界面**:
|
||||
```csharp
|
||||
DoorMission.OpenViewer();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 门控逻辑
|
||||
|
||||
### 1. 事件响应流程
|
||||
|
||||
#### 1.1 BeforeLock 事件
|
||||
当小车即将锁定站点时触发:
|
||||
1. 检查站点的 `EnterDoor` 字段
|
||||
2. 检查小车当前站点的 `PreEnterDoor` 字段是否匹配
|
||||
3. 如果匹配,设置 `_needOpen[(controllerIndex, doorIndex)] = true`
|
||||
4. 返回门的当前状态(如果门已打开则允许锁定)
|
||||
|
||||
#### 1.2 OnLockAcquired 事件
|
||||
当小车成功锁定站点时触发:
|
||||
1. 检查站点的 `EnterDoor` 字段
|
||||
2. 检查小车当前站点的 `PreEnterDoor` 字段是否匹配
|
||||
3. 如果匹配,将小车ID添加到 `carsInAreas[(controllerIndex, doorIndex)]`
|
||||
4. 设置 `_needOpen[(controllerIndex, doorIndex)] = false`
|
||||
|
||||
#### 1.3 AfterLeave 事件
|
||||
当小车离开站点时触发:
|
||||
1. 检查站点的 `LeaveDoor` 字段
|
||||
2. 检查小车当前站点的 `RearLeaveDoor` 字段是否匹配
|
||||
3. 如果匹配,从 `carsInAreas[(controllerIndex, doorIndex)]` 中移除小车ID
|
||||
|
||||
### 2. 门控状态监控与仲裁
|
||||
|
||||
`MonitorDoorLogicAsync` 任务每500毫秒执行一次,检查每个门的控制逻辑并进行仲裁:
|
||||
|
||||
```csharp
|
||||
// 自动目标:有车或需要打开
|
||||
var needOpen = _needOpen.TryGetValue(key, out var open) && open;
|
||||
var hasCarsInArea = carsInAreas.TryGetValue(key, out var cars) && cars.Count > 0;
|
||||
var autoTarget = needOpen || hasCarsInArea;
|
||||
|
||||
// 手动请求仲裁:优先级 Manual > Auto,手动过期后自动恢复
|
||||
bool finalTarget = autoTarget;
|
||||
if (_manualRequests.TryGetValue(key, out var manual))
|
||||
{
|
||||
if (manual.ExpireAt <= DateTime.Now)
|
||||
{
|
||||
_manualRequests.Remove(key); // 手动控制过期,移除
|
||||
}
|
||||
else
|
||||
{
|
||||
finalTarget = manual.Target; // 手动控制有效,使用手动目标
|
||||
}
|
||||
}
|
||||
|
||||
// 设置门的目标控制状态
|
||||
controller.SetDoorControlTarget(doorIndex, finalTarget);
|
||||
```
|
||||
|
||||
**逻辑说明**:
|
||||
- **自动目标计算**:
|
||||
- 如果 `_needOpen[key] = true`,门需要打开(小车即将进入)
|
||||
- 如果 `carsInAreas[key]` 中有小车,门需要保持打开(小车在区域内)
|
||||
- 其他情况,自动目标为关闭
|
||||
- **控制仲裁**:
|
||||
- 手动控制优先级高于自动控制
|
||||
- 如果存在有效的手动控制请求(未过期),使用手动目标
|
||||
- 手动控制过期后,自动移除并恢复自动控制
|
||||
- 最终目标写入门控制器的 `DoorControlTargets` 字段
|
||||
|
||||
---
|
||||
|
||||
## 站点配置
|
||||
|
||||
### 1. 站点字段说明
|
||||
|
||||
站点需要配置以下字段以实现门控功能:
|
||||
|
||||
| 字段名 | 类型 | 说明 | 示例 |
|
||||
|--------|------|------|------|
|
||||
| `EnterDoor` | string | 进站门标识符(格式:控制器索引.门索引) | `"1.2"` |
|
||||
| `LeaveDoor` | string | 离站门标识符(格式:控制器索引.门索引) | `"2.3"` |
|
||||
|
||||
### 2. 小车站点字段说明
|
||||
|
||||
小车当前站点需要配置以下字段:
|
||||
|
||||
| 字段名 | 类型 | 说明 | 示例 |
|
||||
|--------|------|------|------|
|
||||
| `PreEnterDoor` | string | 前方进站门标识符(与目标站点的 `EnterDoor` 匹配) | `"1.2"` |
|
||||
| `RearLeaveDoor` | string | 后方离站门标识符(与目标站点的 `LeaveDoor` 匹配) | `"2.3"` |
|
||||
|
||||
### 3. 配置示例
|
||||
|
||||
**站点配置**:
|
||||
```json
|
||||
{
|
||||
"id": 100,
|
||||
"name": "站点A",
|
||||
"fields": {
|
||||
"EnterDoor": "1.2",
|
||||
"LeaveDoor": "2.3"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**小车站点配置**:
|
||||
```json
|
||||
{
|
||||
"id": 50,
|
||||
"name": "小车当前位置",
|
||||
"fields": {
|
||||
"PreEnterDoor": "1.2",
|
||||
"RearLeaveDoor": "2.3"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**工作流程**:
|
||||
1. 小车从站点50驶向站点100
|
||||
2. 到达站点100时,触发 `BeforeLock` 事件
|
||||
3. 系统检查站点100的 `EnterDoor`(`"1.2"`)是否与站点50的 `PreEnterDoor`(`"1.2"`)匹配
|
||||
4. 如果匹配,设置控制器1的门2为打开状态
|
||||
5. 门打开后,小车锁定站点100
|
||||
6. 触发 `OnLockAcquired` 事件,门保持打开状态
|
||||
7. 小车离开站点100时,触发 `AfterLeave` 事件
|
||||
8. 系统检查站点100的 `LeaveDoor`(`"2.3"`)是否与站点50的 `RearLeaveDoor`(`"2.3"`)匹配
|
||||
9. 如果匹配,从区域内小车列表中移除该小车
|
||||
10. 如果没有其他小车在区域内,门自动关闭
|
||||
|
||||
---
|
||||
|
||||
## UI界面
|
||||
|
||||
### 1. 配置管理界面
|
||||
|
||||
**打开方式**:
|
||||
```csharp
|
||||
DoorMission.OpenViewer();
|
||||
```
|
||||
|
||||
**功能**:
|
||||
- 门控制器列表管理(添加、删除、修改)
|
||||
- 门列表管理(为每个控制器添加、删除、修改门)
|
||||
- 类型选择(自动识别所有带 `DoorTypeAttribute` 的控制器类型)
|
||||
- 配置保存到 `DoorConfig.json`
|
||||
|
||||
### 2. 监控界面
|
||||
|
||||
**打开方式**:
|
||||
```csharp
|
||||
DoorMission.OpenMonitor();
|
||||
```
|
||||
|
||||
**功能**:
|
||||
- 实时显示所有门的状态
|
||||
- 显示控制器索引、门索引、当前状态、控制目标、车辆占用
|
||||
- 显示控制来源和手动控制剩余时间
|
||||
- 显示控制地址和开到位信号地址
|
||||
- 手动控制门开关(打开/关闭,带安全保护)
|
||||
- 清空车辆占用记录
|
||||
- 自动刷新(默认1秒刷新间隔)
|
||||
|
||||
**显示信息**:
|
||||
| 列名 | 说明 |
|
||||
|------|------|
|
||||
| 控制器编码 | 门控制器索引 |
|
||||
| 门编码 | 门索引 |
|
||||
| 当前状态 | 门的当前状态(开/关,带颜色标识:绿色=打开,红色=关闭) |
|
||||
| 控制目标 | 门的目标控制状态(开/关,带颜色标识:绿色=开,红色=关) |
|
||||
| 车辆占用 | 门区域内的小车ID列表(多个ID用逗号分隔,无车辆显示"无") |
|
||||
| 控制来源 | 当前控制来源(自动/手动) |
|
||||
| 手动剩余(s) | 手动控制剩余秒数(仅当控制来源=手动时显示,自动时显示"-") |
|
||||
| 控制地址 | Modbus 线圈地址 |
|
||||
| 开到位地址 | Modbus 离散输入地址 |
|
||||
|
||||
**手动控制功能**:
|
||||
- **打开按钮**:设置手动打开控制,默认保持10秒
|
||||
- **关闭按钮**:设置手动关闭控制,默认保持10秒
|
||||
- **安全保护**:当门区域内有车辆占用时,关闭按钮自动禁用,无法执行关闭操作
|
||||
- 必须先清空车辆占用,才能手动关闭门
|
||||
- **清空占用按钮**:清空选中门的车辆占用记录
|
||||
- 清空后,如果门处于打开状态且没有其他小车需要进入,门会自动关闭
|
||||
- 清空占用后,可以执行手动关闭操作
|
||||
|
||||
**控制优先级说明**:
|
||||
- 手动控制优先级高于自动控制
|
||||
- 手动控制会在指定时间(默认10秒)后自动过期,恢复自动模式
|
||||
- 可以通过"清空占用"按钮清空车辆占用,然后手动关闭门
|
||||
|
||||
---
|
||||
|
||||
## 参数说明
|
||||
|
||||
### 1. 监控间隔
|
||||
|
||||
| 参数 | 默认值 | 说明 |
|
||||
|------|--------|------|
|
||||
| 配置监控间隔 | 10秒 | 检查配置文件的间隔 |
|
||||
| 门控逻辑监控间隔 | 500毫秒 | 检查门控逻辑的间隔(已优化) |
|
||||
| 监控界面刷新间隔 | 1秒 | 监控界面自动刷新间隔 |
|
||||
| 手动控制默认保持时间 | 10秒 | 手动控制请求的默认过期时间 |
|
||||
|
||||
### 2. 线程安全说明
|
||||
|
||||
- **门状态读取**:通过 `controller.DoorStates` 字典访问,所有读写操作受锁保护
|
||||
- **门控制写入**:通过 `controller.SetDoorControlTarget()` 设置目标状态,实际通信由门控制器内部线程完成
|
||||
- **配置同步**:配置变更时使用锁保护,确保线程安全
|
||||
- **控制仲裁**:手动控制请求和自动控制逻辑的仲裁在同一锁内完成,确保线程安全
|
||||
- **车辆占用管理**:车辆占用的增删改查操作均受锁保护
|
||||
|
||||
### 3. 控制仲裁机制
|
||||
|
||||
系统采用**控制仲裁机制**来协调手动控制和自动控制:
|
||||
|
||||
- **优先级**:手动控制 > 自动控制
|
||||
- **手动控制过期**:手动控制请求会在指定时间(默认10秒)后自动过期,过期后恢复自动控制
|
||||
- **安全保护**:当门区域内有车辆占用时,禁止手动关闭门,确保安全
|
||||
- **仲裁流程**:
|
||||
1. 计算自动目标(基于车辆占用和需要打开标志)
|
||||
2. 检查是否存在有效的手动控制请求
|
||||
3. 如果手动控制未过期,使用手动目标;否则使用自动目标
|
||||
4. 将最终目标写入门控制器的 `DoorControlTargets` 字段
|
||||
|
||||
---
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 问题1:门控制器无法连接
|
||||
|
||||
**排查步骤**:
|
||||
1. 检查配置文件中的 IP 和端口是否正确
|
||||
2. 检查网络连接是否正常
|
||||
3. 查看诊断日志中的错误信息
|
||||
4. 确认门控制器硬件是否在线
|
||||
|
||||
**诊断命令**:
|
||||
```csharp
|
||||
var controllers = doorMission.GetDoorControllers();
|
||||
foreach (var controller in controllers)
|
||||
{
|
||||
Console.WriteLine($"控制器{controller.Index}: IP={controller.Ip}, Port={controller.Port}, State={controller.State}, Error={controller.ErrorMessage}");
|
||||
}
|
||||
```
|
||||
|
||||
### 问题2:门不自动开启
|
||||
|
||||
**排查步骤**:
|
||||
1. 确认 `DoorMission` 任务已启动
|
||||
2. 检查站点的 `EnterDoor` 字段是否配置正确
|
||||
3. 检查小车站点的 `PreEnterDoor` 字段是否与目标站点的 `EnterDoor` 匹配
|
||||
4. 查看门控制器的连接状态是否为 `Online`
|
||||
5. 检查门的状态是否正确读取
|
||||
|
||||
**诊断命令**:
|
||||
```csharp
|
||||
// 检查门状态
|
||||
bool isOpen = doorMission.GetDoorState(1, 2);
|
||||
Console.WriteLine($"控制器1门2的状态: {(isOpen ? "打开" : "关闭")}");
|
||||
|
||||
// 检查门控制器状态
|
||||
var controllers = doorMission.GetDoorControllers();
|
||||
var controller = controllers.FirstOrDefault(c => c.Index == 1);
|
||||
if (controller != null)
|
||||
{
|
||||
Console.WriteLine($"控制器状态: {controller.State}");
|
||||
Console.WriteLine($"是否在线: {controller.IsOnline}");
|
||||
Console.WriteLine($"错误信息: {controller.ErrorMessage}");
|
||||
}
|
||||
```
|
||||
|
||||
### 问题3:配置文件更新后不生效
|
||||
|
||||
**排查步骤**:
|
||||
1. 确认配置文件格式正确(JSON格式)
|
||||
2. 检查配置文件是否保存成功
|
||||
3. 等待最多10秒,系统会自动检测更新
|
||||
4. 查看诊断日志中的配置同步信息
|
||||
|
||||
### 问题4:监控界面无数据
|
||||
|
||||
**排查步骤**:
|
||||
1. 确认 `DoorMission` 任务已启动
|
||||
2. 检查是否有配置的门控制器
|
||||
3. 查看门控制器是否成功连接
|
||||
4. 检查监控界面的刷新间隔设置
|
||||
|
||||
### 问题5:手动关闭按钮无法点击
|
||||
|
||||
**原因**:
|
||||
- 门区域内有车辆占用,系统安全保护机制禁止手动关闭
|
||||
|
||||
**解决方法**:
|
||||
1. 先点击"清空占用"按钮,清空车辆占用记录
|
||||
2. 清空后,关闭按钮会自动启用
|
||||
3. 然后可以执行手动关闭操作
|
||||
|
||||
### 问题6:手动控制不生效
|
||||
|
||||
**排查步骤**:
|
||||
1. 检查手动控制是否已过期(默认10秒)
|
||||
2. 查看"控制来源"列,确认是否为"手动"
|
||||
3. 查看"手动剩余(s)"列,确认剩余时间
|
||||
4. 如果已过期,手动控制会自动恢复为自动模式
|
||||
5. 可以通过监控界面重新设置手动控制
|
||||
|
||||
---
|
||||
|
||||
## 附录
|
||||
|
||||
### A. 门标识符解析
|
||||
|
||||
门标识符格式:`控制器索引.门索引`
|
||||
|
||||
**解析规则**:
|
||||
- 必须包含一个点号(`.`)
|
||||
- 点号前后必须为整数
|
||||
- 解析失败时返回 `null`
|
||||
|
||||
**示例**:
|
||||
- `"1.2"` → `(controllerIndex: 1, doorIndex: 2)` ✅
|
||||
- `"10.5"` → `(controllerIndex: 10, doorIndex: 5)` ✅
|
||||
- `"1"` → `null` ❌(缺少点号)
|
||||
- `"1.2.3"` → `null` ❌(多个点号)
|
||||
- `"a.2"` → `null` ❌(非数字)
|
||||
|
||||
### B. 诊断日志说明
|
||||
|
||||
系统会在以下情况记录诊断日志:
|
||||
- 门控制器连接成功/失败
|
||||
- 门控制器配置变更
|
||||
- 门状态读取失败
|
||||
- 门控制写入失败
|
||||
- 配置加载失败
|
||||
|
||||
**日志位置**:系统诊断日志
|
||||
|
||||
### C. 类结构关系图
|
||||
|
||||
```
|
||||
DoorMission (门控进程)
|
||||
│
|
||||
├── BasicDoorController (抽象基类)
|
||||
│ │
|
||||
│ └── ModbusDoorController (Modbus 实现)
|
||||
│
|
||||
├── DoorManager (配置界面)
|
||||
│
|
||||
├── DoorMonitor (监控界面)
|
||||
│
|
||||
└── DoorModel (配置模型)
|
||||
```
|
||||
|
||||
### D. 控制来源枚举
|
||||
|
||||
```csharp
|
||||
public enum ControlSource
|
||||
{
|
||||
Auto = 0, // 自动控制
|
||||
Manual = 1 // 手动控制
|
||||
}
|
||||
```
|
||||
|
||||
### E. 门控制状态结构
|
||||
|
||||
```csharp
|
||||
public class DoorControlStatus
|
||||
{
|
||||
public bool Target { get; set; } // 当前目标状态(true=打开,false=关闭)
|
||||
public ControlSource Source { get; set; } // 控制来源(Auto/Manual)
|
||||
public double? ManualRemainingSeconds { get; set; } // 手动控制剩余秒数(仅当Source=Manual时有效)
|
||||
public IReadOnlyList<int> CarsInArea { get; set; } // 车辆占用列表
|
||||
}
|
||||
```
|
||||
|
||||
### F. 版本历史
|
||||
|
||||
| 版本 | 日期 | 主要更新 |
|
||||
|------|------|----------|
|
||||
| 1.0 | 2025-01 | 初始版本,支持 Modbus 门控制器 |
|
||||
| 1.1 | 2025-01 | 新增门控仲裁机制,支持手动控制与自动控制协调 |
|
||||
| 1.2 | 2025-01 | 新增车辆占用管理功能,监控界面显示车辆占用情况 |
|
||||
| 1.3 | 2025-01 | 优化门控逻辑监控间隔至500ms,新增安全保护机制(占用时禁止手动关闭) |
|
||||
|
||||
---
|
||||
|
||||
**文档更新时间**:2025-01-21
|
||||
Reference in New Issue
Block a user