API目錄
KY_SendIOCtrlWithChannel
功能描述:向已連接的設(shè)備發(fā)送自定義的控制指令(Command)和數(shù)據(jù)。這是實(shí)現(xiàn) APP 對(duì)設(shè)備進(jìn)行遠(yuǎn)程控制的核心接口。所有控制指令均需通過(guò)該接口發(fā)送,設(shè)備響應(yīng)數(shù)據(jù)可通過(guò)
KY_DidReceiveIOCtrlWithUid回調(diào)接收。接口定義
- (void)KY_SendIOCtrlWithChannel:(NSInteger)channel
type:(ENUM_AVIOCTRL_MSGTYPE)type
data:(NSData * _Nonnull)data;
參數(shù)說(shuō)明
| 參數(shù) | 類型 | 說(shuō)明 |
|---|---|---|
| channel | NSInteger | 設(shè)備連線的通道號(hào),默認(rèn)值為 0 |
| type | ENUM_AVIOCTRL_MSGTYPE | 控制指令的類型(Command ID)。開(kāi)發(fā)者需與設(shè)備端約定自定義指令值,或使用 SDK 預(yù)定義指令,相關(guān)定義在 AVIOCTRLDEFs.h 頭文件中 |
| data | NSData * | 要發(fā)送給設(shè)備的具體指令數(shù)據(jù)。通常需將自定義 C 結(jié)構(gòu)體轉(zhuǎn)換為 NSData 對(duì)象傳輸 |
代碼示例
// 假設(shè) self.camera 是已完成連線的設(shè)備實(shí)例
// IOTYPE_USER_IPCAM_GET_PLAYBACK_REQ 為自定義指令類型
NSData *data = [self buildPlaybackRequestData]; // 構(gòu)建自定義請(qǐng)求數(shù)據(jù)
[self.camera KY_SendIOCtrlWithChannel:0
type:IOTYPE_USER_IPCAM_GET_PLAYBACK_REQ
data:data];
協(xié)議封裝示例
以下以「APP 獲取設(shè)備端燈控開(kāi)關(guān)狀態(tài)」為例,詳細(xì)說(shuō)明自定義協(xié)議的定義、數(shù)據(jù)封裝發(fā)送、響應(yīng)接收解析全流程。該示例覆蓋了控制指令交互的完整生命周期,可作為自定義協(xié)議開(kāi)發(fā)的參考模板。
1. 定義協(xié)議及結(jié)構(gòu)體
首先需在 APP 端和設(shè)備端統(tǒng)一約定指令 ID(Command ID)和數(shù)據(jù)結(jié)構(gòu)體格式,確保雙方數(shù)據(jù)解析邏輯一致。
// 1. 定義指令 ID (Command ID) - 需與設(shè)備端一致
#define IOTYPE_GET_LED_REQ 0x30000001 // APP -> 設(shè)備:獲取燈控狀態(tài)請(qǐng)求
#define IOTYPE_GET_LED_RESP 0x30000002 // 設(shè)備 -> APP:燈控狀態(tài)響應(yīng)
// 2. 定義指令對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu)體
// (a) APP 發(fā)送給設(shè)備的請(qǐng)求結(jié)構(gòu)體
typedef struct {
unsigned int channel; // 當(dāng)前通道號(hào),默認(rèn)填 0
unsigned char reserved[4]; // 預(yù)留字段,用于內(nèi)存對(duì)齊或擴(kuò)展
} SMsgAVIoctrlGetLedReq;
// (b) 設(shè)備回復(fù)給 APP 的響應(yīng)結(jié)構(gòu)體
typedef struct {
int result; // 執(zhí)行結(jié)果:0 成功,非0 失?。ㄗ远x錯(cuò)誤碼)
unsigned char isOnOff; // 燈控狀態(tài):0 關(guān)閉,1 開(kāi)啟
unsigned char reserved[3]; // 預(yù)留字段
} SMsgAVIoctrlGetLedResp;
2. 結(jié)構(gòu)體封裝與發(fā)送 (APP 端)
APP 端需將請(qǐng)求結(jié)構(gòu)體轉(zhuǎn)換為 NSData 格式,再通過(guò) KY_SendIOCtrlWithChannel 接口發(fā)送至設(shè)備。
// 假設(shè) self.camera 是已連接的設(shè)備實(shí)例
// (1) 初始化請(qǐng)求結(jié)構(gòu)體
SMsgAVIoctrlGetLedReq reqData;
reqData.channel = 0; // 設(shè)置通道號(hào)
memset(reqData.reserved, 0, sizeof(reqData.reserved)); // 初始化預(yù)留字段
// (2) 將結(jié)構(gòu)體轉(zhuǎn)換為 NSData
NSData *sendData = [NSData dataWithBytes:&reqData length:sizeof(SMsgAVIoctrlGetLedReq)];
// (3) 發(fā)送控制指令
[self.camera KY_SendIOCtrlWithChannel:0
type:IOTYPE_GET_LED_REQ
data:sendData];
NSLog(@"已發(fā)送獲取燈控狀態(tài)請(qǐng)求,通道號(hào):%d", 0);
3. 數(shù)據(jù)接收與解析 (APP 端)
設(shè)備處理完控制指令后,會(huì)返回響應(yīng)數(shù)據(jù)。APP 端需實(shí)現(xiàn) KY_DidReceiveIOCtrlWithUid 回調(diào)方法,接收并解析響應(yīng)數(shù)據(jù)。
// 實(shí)現(xiàn) KYCameraDelegate 協(xié)議的回調(diào)方法
- (void)KY_DidReceiveIOCtrlWithUid:(NSString * _Nonnull)uid
channel:(NSInteger)channel
type:(ENUM_AVIOCTRL_MSGTYPE)type
data:(NSData * _Nonnull)data {
// 過(guò)濾當(dāng)前設(shè)備的響應(yīng)數(shù)據(jù)
if (![uid isEqualToString:self.camera.uid]) return;
// 判斷指令類型為燈控狀態(tài)響應(yīng)
if (type == IOTYPE_GET_LED_RESP) {
NSLog(@"收到設(shè)備 %@ 燈控狀態(tài)響應(yīng)", uid);
// 校驗(yàn)數(shù)據(jù)長(zhǎng)度
if (data.length != sizeof(SMsgAVIoctrlGetLedResp)) {
NSLog(@"響應(yīng)數(shù)據(jù)長(zhǎng)度異常:實(shí)際 %lu,預(yù)期 %lu", (unsigned long)data.length, (unsigned long)sizeof(SMsgAVIoctrlGetLedResp));
return;
}
// 將 NSData 轉(zhuǎn)換為結(jié)構(gòu)體
SMsgAVIoctrlGetLedResp *respData = (SMsgAVIoctrlGetLedResp *)data.bytes;
// 解析響應(yīng)數(shù)據(jù)
if (respData->result == 0) {
NSString *ledStatus = respData->isOnOff ? @"開(kāi)啟" : @"關(guān)閉";
NSLog(@"獲取燈控狀態(tài)成功:%@", ledStatus);
// 更新UI展示狀態(tài)
self.ledStatusLabel.text = [NSString stringWithFormat:@"燈控狀態(tài):%@", ledStatus];
} else {
NSLog(@"獲取燈控狀態(tài)失敗,錯(cuò)誤碼:%d", respData->result);
}
}
}
