在开发硬件设备相关的软件时,例如:
工业控制设备
智能硬件
机器人设备
测试仪器
IoT 设备
上位机通常需要向设备发送各种控制指令。
例如:
开启设备
设置参数
获取状态
执行校准
固件升级
但是在实际通信过程中,并不是所有指令都可以立即发送。
很多设备通信协议都有类似限制:
同一时间只能执行一条指令
上一条指令需要等待设备返回结果
指令需要按照顺序执行
某些指令需要超时重试
如果直接在业务代码中处理这些逻辑,代码很容易变得混乱。
因此,可以设计一个简单的设备指令队列管理器(Command Queue Manager),统一管理设备指令发送流程。
本文将使用 C# 实现一个简单版本的设备指令队列管理器。
一、为什么需要指令队列
假设现在有一个设备,需要执行以下操作:
1. 设置设备参数
2. 启动设备
3. 获取运行状态
4. 停止设备
最简单的写法可能是:
SendCommand("SET_PARAM");
SendCommand("START");
SendCommand("GET_STATUS");
SendCommand("STOP");
但是设备实际处理速度可能没有这么快。
例如:
发送 SET_PARAM
↓
等待设备响应
↓
收到 OK
↓
发送 START
↓
等待设备响应
如果程序连续发送:
SET_PARAM
START
GET_STATUS
STOP
设备可能无法正确处理。
因此需要一个中间管理层:
业务层
↓
指令队列
↓
通信模块
↓
硬件设备
业务层只负责添加指令。
队列负责控制发送顺序。
二、设计一个简单的指令模型
首先定义一个设备指令对象。
public class DeviceCommand
{
public string Name { get; set; }
public byte[] Data { get; set; }
public int Timeout { get; set; }
public Action<bool> Callback { get; set; }
}
其中:
Name:
表示指令名称。
例如:
START_DEVICE
Data:
表示实际发送的数据。
例如:
AA 01 00 FF
Timeout:
表示等待设备响应时间。
Callback:
用于通知执行结果。
例如:
command.Callback(true);
表示执行成功。
三、实现指令队列管理器
创建一个管理类:
public class DeviceCommandQueue
{
private Queue<DeviceCommand> commandQueue
= new Queue<DeviceCommand>();
private bool isExecuting = false;
}
其中:
Queue 用于保存等待执行的指令。
isExecuting:
表示当前是否正在执行。
避免多个指令同时发送。
添加指令方法:
public void AddCommand(DeviceCommand command)
{
commandQueue.Enqueue(command);
ExecuteNext();
}
当添加新指令后:
自动尝试执行下一条。
四、实现指令顺序执行
核心逻辑:
private async void ExecuteNext()
{
if(isExecuting)
return;
if(commandQueue.Count == 0)
return;
isExecuting = true;
DeviceCommand command = commandQueue.Dequeue();
Console.WriteLine(
"发送指令:" + command.Name);
bool result = await SendCommand(command);
command.Callback?.Invoke(result);
isExecuting = false;
ExecuteNext();
}
执行流程:
取出第一条指令
↓
发送设备
↓
等待结果
↓
回调通知
↓
执行下一条
这样可以保证:
任何时候只有一个指令正在执行。
五、模拟设备通信过程
实际项目中:
SendCommand 通常会连接:
串口
TCP
蓝牙
USB
这里简单模拟。
private async Task<bool> SendCommand(
DeviceCommand command)
{
Console.WriteLine(
"发送数据");
await Task.Delay(1000);
Console.WriteLine(
"设备返回成功");
return true;
}
调用:
var queue = new DeviceCommandQueue();
queue.AddCommand(
new DeviceCommand
{
Name = "启动设备",
Data = new byte[]
{
0xAA,
0x01
},
Callback = result =>
{
Console.WriteLine(
"执行结果:" + result);
}
});
queue.AddCommand(
new DeviceCommand
{
Name = "读取状态"
});
执行结果:
发送指令:启动设备
等待设备响应
设备返回成功
执行结果:true
发送指令:读取状态
等待设备响应
设备返回成功
六、实际项目中可以继续扩展的方向
上面的实现只是一个基础版本。
在真实设备项目中,通常还会增加更多功能。
1. 指令超时处理
例如:
设备 3 秒没有响应。
自动失败:
Task.Delay(timeout)
超过时间:
Command Timeout
然后执行下一条。
2. 指令重试机制
例如:
WiFi 通信不稳定。
第一次失败:
发送失败
↓
重新发送
↓
最多3次
可以增加:
RetryCount
字段。
3. 优先级队列
有些指令优先级更高。
例如:
紧急停止:
STOP
应该优先于:
读取数据
可以将 Queue 改为 PriorityQueue。
4. 指令状态管理
例如:
Waiting
↓
Sending
↓
Success
↓
Failed
方便日志记录和问题排查。
对于上位机开发来说,一个稳定的指令队列管理器是比较常见的基础模块。
无论是串口设备、网络设备,还是工业控制设备,只要涉及“发送指令 → 等待响应 → 继续执行”的通信模式,都可以使用类似的设计方式。