KY_SendIOCtrlWithChannel
功能描述:向已连接的设备发送自定义的控制指令(Command)和数据。这是实现 APP 对设备进行远程控制的核心接口。所有控制指令均需通过该接口发送,设备响应数据可通过
KY_DidReceiveIOCtrlWithUid回调接收。接口定义
- (void)KY_SendIOCtrlWithChannel:(NSInteger)channel
type:(ENUM_AVIOCTRL_MSGTYPE)type
data:(NSData * _Nonnull)data;
参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
| channel | NSInteger | 设备连线的通道号,默认值为 0 |
| type | ENUM_AVIOCTRL_MSGTYPE | 控制指令的类型(Command ID)。开发者需与设备端约定自定义指令值,或使用 SDK 预定义指令,相关定义在 AVIOCTRLDEFs.h 头文件中 |
| data | NSData * | 要发送给设备的具体指令数据。通常需将自定义 C 结构体转换为 NSData 对象传输 |
代码示例
// 假设 self.camera 是已完成连线的设备实例
// IOTYPE_USER_IPCAM_GET_PLAYBACK_REQ 为自定义指令类型
NSData *data = [self buildPlaybackRequestData]; // 构建自定义请求数据
[self.camera KY_SendIOCtrlWithChannel:0
type:IOTYPE_USER_IPCAM_GET_PLAYBACK_REQ
data:data];
协议封装示例
以下以「APP 获取设备端灯控开关状态」为例,详细说明自定义协议的定义、数据封装发送、响应接收解析全流程。该示例覆盖了控制指令交互的完整生命周期,可作为自定义协议开发的参考模板。
1. 定义协议及结构体
首先需在 APP 端和设备端统一约定指令 ID(Command ID)和数据结构体格式,确保双方数据解析逻辑一致。
// 1. 定义指令 ID (Command ID) - 需与设备端一致
#define IOTYPE_GET_LED_REQ 0x30000001 // APP -> 设备:获取灯控状态请求
#define IOTYPE_GET_LED_RESP 0x30000002 // 设备 -> APP:灯控状态响应
// 2. 定义指令对应的数据结构体
// (a) APP 发送给设备的请求结构体
typedef struct {
unsigned int channel; // 当前通道号,默认填 0
unsigned char reserved[4]; // 预留字段,用于内存对齐或扩展
} SMsgAVIoctrlGetLedReq;
// (b) 设备回复给 APP 的响应结构体
typedef struct {
int result; // 执行结果:0 成功,非0 失败(自定义错误码)
unsigned char isOnOff; // 灯控状态:0 关闭,1 开启
unsigned char reserved[3]; // 预留字段
} SMsgAVIoctrlGetLedResp;
2. 结构体封装与发送 (APP 端)
APP 端需将请求结构体转换为 NSData 格式,再通过 KY_SendIOCtrlWithChannel 接口发送至设备。
// 假设 self.camera 是已连接的设备实例
// (1) 初始化请求结构体
SMsgAVIoctrlGetLedReq reqData;
reqData.channel = 0; // 设置通道号
memset(reqData.reserved, 0, sizeof(reqData.reserved)); // 初始化预留字段
// (2) 将结构体转换为 NSData
NSData *sendData = [NSData dataWithBytes:&reqData length:sizeof(SMsgAVIoctrlGetLedReq)];
// (3) 发送控制指令
[self.camera KY_SendIOCtrlWithChannel:0
type:IOTYPE_GET_LED_REQ
data:sendData];
NSLog(@"已发送获取灯控状态请求,通道号:%d", 0);
3. 数据接收与解析 (APP 端)
设备处理完控制指令后,会返回响应数据。APP 端需实现 KY_DidReceiveIOCtrlWithUid 回调方法,接收并解析响应数据。
// 实现 KYCameraDelegate 协议的回调方法
- (void)KY_DidReceiveIOCtrlWithUid:(NSString * _Nonnull)uid
channel:(NSInteger)channel
type:(ENUM_AVIOCTRL_MSGTYPE)type
data:(NSData * _Nonnull)data {
// 过滤当前设备的响应数据
if (![uid isEqualToString:self.camera.uid]) return;
// 判断指令类型为灯控状态响应
if (type == IOTYPE_GET_LED_RESP) {
NSLog(@"收到设备 %@ 灯控状态响应", uid);
// 校验数据长度
if (data.length != sizeof(SMsgAVIoctrlGetLedResp)) {
NSLog(@"响应数据长度异常:实际 %lu,预期 %lu", (unsigned long)data.length, (unsigned long)sizeof(SMsgAVIoctrlGetLedResp));
return;
}
// 将 NSData 转换为结构体
SMsgAVIoctrlGetLedResp *respData = (SMsgAVIoctrlGetLedResp *)data.bytes;
// 解析响应数据
if (respData->result == 0) {
NSString *ledStatus = respData->isOnOff ? @"开启" : @"关闭";
NSLog(@"获取灯控状态成功:%@", ledStatus);
// 更新UI展示状态
self.ledStatusLabel.text = [NSString stringWithFormat:@"灯控状态:%@", ledStatus];
} else {
NSLog(@"获取灯控状态失败,错误码:%d", respData->result);
}
}
}
