| 1.0.0 | 初始版本 | 梁振营 | 2024-03-8 |\r
| 1.0.1 | 鼠标按键指令修改 | 梁振营 | 2024-03-18 |\r
| 1.0.2 | 鉴权流程修改,只有鉴权成功了,SDK相关功能才可以使用 | 梁振营 | 2024-03-19 |\r
+| 1.0.3 | 支持USB通讯 | 梁振营 | 2024-04-01 |\r
\r
\r
\r
\r
## 相关权限配置\r
\r
-因为sdk用到蓝牙权限,所以需要在info.plist进行相关配置\r
+因为sdk用到蓝牙权限、网络、语音等功能,info.plist和沙盒需要进行相关权限设置\r
\r
```xml\r
<!-- 蓝牙 --> \r
<key>NSBluetoothAlwaysUsageDescription</key> \r
-<string>App需要您的同意,才能访问蓝牙</string> \r
-```\r
+<string>要打开蓝牙才能使用AI功能哦</string> \r
+\r
+<key>Privacy - Microphone Usage Description</key> \r
+<string>要打开麦克风才能使用AI功能哦</string> \r
\r
+```\r
\r
+\r
\r
## SDK相关接口\r
\r
```objective-c\r
+/// 单利\r
++(AiMouse *)shared;\r
+\r
+/// 切换连接类型\r
+/// - Parameter type: 连接类型\r
+- (void)switchConnect:(AiMouseConnectType)type;\r
+\r
/// 开始鉴权\r
/// - Parameter finished: 鉴权结果回调\r
- (void)startAuthentication:(void (^)(AiMouseAuthState state))finished;\r
\r
/// 鼠标按键指令回调\r
/// - Parameter data: 数据。\r
-/// M 键 短按0x42;长按按下(开始录音)0x25, 长按抬起(结束录音) 0x26;\r
-/// AI键 短按0x43 ,长按按下(开始录音)0x27, 长按抬起(结束录音) 0x28;\r
-/// 语音键 按下(开始录音) 0x31,弹起(结束录音)0x32;\r
+/// 前 第一次单击31(开始录音), 第二次单击32(结束录音) , 按下21(开始录音)抬起22(结束录音)\r
+/// 中 单击42, 按下25(开始录音)抬起26(结束录音)\r
+/// 后 单击43,按下27(开始录音)抬起28(结束录音)\r
/// 其他未定义\r
- (void)aiMouseSendCmdData:(NSData *)data;\r
\r
- (void)aiMouseSendRecordData:(NSData *)data;\r
```\r
\r
-## 示例\r
-\r
-- 蓝牙服务特征\r
-\r
- ```objective-c\r
- // 服务id\r
- #define kServiceUUID @"FFF1"\r
- //ai特征\r
- #define kAiUUID @"0783B03E-8535-B5A0-7140-A304D2194CB8"\r
- //鉴权特征\r
- #define kAuthUUID @"0783B73E-8535-B5A0-7140-A304D2194CB7"\r
- //设备信息特征\r
- #define kDeviceInfoUUID @"0783B63E-8535-B5A0-7140-A304D2495CB6"\r
- ```\r
- \r
- \r
-\r
-\r
-\r
-1. 设置代理\r
-\r
- ```objective-c\r
- [AiMouse shared].delegate = self;\r
- ```\r
-\r
-2. 查找对应特征,订阅\r
-\r
- ```\r
- // 发现特征\r
- - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {\r
- for (CBCharacteristic *characteristic in service.characteristics){\r
- if ([characteristic.UUID.UUIDString isEqualToString:kAuthUUID]) {\r
- //鉴权特征\r
- self.authCha = characteristic;\r
- [peripheral setNotifyValue:YES forCharacteristic:characteristic];\r
- //找到鉴权特征后,一定要调用鉴权接口开始鉴权。只有鉴权通过了,sdk相关功能才可以使用\r
- [[AiMouse shared] startAuthentication:^(AiMouseAuthState state) {\r
- [self showLog:[NSString stringWithFormat:@"鉴权结果 = %@",@(state)]];\r
- if(self.authCallBack){\r
- self.authCallBack(state == AiMouseAuthState_Success);\r
- }\r
- }];\r
- }\r
- else if ([characteristic.UUID.UUIDString isEqualToString:kAiUUID]) {\r
- //AI特征\r
- self.aiCha = characteristic;\r
- [peripheral setNotifyValue:YES forCharacteristic:characteristic];\r
- }\r
- else if ([characteristic.UUID.UUIDString isEqualToString:kDeviceInfoUUID]) {\r
- //设备信息特征\r
- self.deviceInfoCha = characteristic;\r
- [peripheral setNotifyValue:YES forCharacteristic:characteristic];\r
- }\r
- }\r
- }\r
- ```\r
-\r
- \r
-\r
-3. 收到设备传输过来的数据,传给sdk处理\r
-\r
- ```objective-c\r
- //收到蓝牙数据\r
- - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {\r
- NSData *data = characteristic.value;\r
- [self showLog:[NSString stringWithFormat:@"[receive] %@",[AiMouseTools dataToHexString:data]]];\r
- if([characteristic.UUID.UUIDString isEqualToString:kAuthUUID]){\r
- //鉴权数据\r
- [[AiMouse shared] sendAuthDataToSdk:data];\r
- }\r
- else if([characteristic.UUID.UUIDString isEqualToString:kAiUUID]){\r
- //AI数据\r
- [[AiMouse shared] sendAiDataToSdk:data];\r
- }\r
- else if([characteristic.UUID.UUIDString isEqualToString:kDeviceInfoUUID]){\r
- //设备信息数据\r
- [[AiMouse shared] sendDeviceDataToSdk:data];\r
- }\r
- }\r
- \r
- ```\r
-\r
- sdk代理回调\r
-\r
- ```objective-c\r
- /// 鉴权数据回调,需要将此数据转发给蓝牙设备\r
- /// - Parameter data: 数据\r
- - (void)aiMouseSendAuthData:(NSData *)data{\r
- [self showLog:[NSString stringWithFormat:@"[send] %@",[AiMouseTools dataToHexString:data]]];\r
- [self.connectPeripheral writeValue:data forCharacteristic:self.authCha type:CBCharacteristicWriteWithoutResponse];\r
- }\r
- \r
- \r
- /// 设备信息数据回调,需要将此数据通过设备信息特征转发给蓝牙设备\r
- /// - Parameter data: 数据\r
- -(void)aiMouseSendDeviceInfoData:(NSData *)data{\r
- [self showLog:[NSString stringWithFormat:@"[send] %@",[AiMouseTools dataToHexString:data]]];\r
- [self.connectPeripheral writeValue:data forCharacteristic:self.deviceInfoCha type:CBCharacteristicWriteWithoutResponse];\r
- }\r
- \r
- /// 鼠标按键指令回调\r
- /// - Parameter data: 数据。\r
- /// M 键 短按0x42;长按按下(开始录音)0x25, 长按抬起(结束录音) 0x26;\r
- /// AI键 短按0x43 ,长按按下(开始录音)0x27, 长按抬起(结束录音) 0x28;\r
- /// 语音键 按下(开始录音) 0x31,弹起(结束录音)0x32;\r
- /// 其他未定义\r
- - (void)aiMouseSendCmdData:(NSData *)data{\r
- uint8 cmd;\r
- [data getBytes:&cmd length:1];\r
- if(cmd == 0x25){\r
- [self showLog:@"M键开始录音"];\r
- self.recordData = [[NSMutableData alloc] init];\r
- }\r
- else if(cmd == 0x26){\r
- [self showLog:@"M键结束录音"];\r
- [self finishRecored:self.recordData];\r
- }\r
- else if(cmd == 0x27){\r
- [self showLog:@"AI键开始录音"];\r
- self.recordData = [[NSMutableData alloc] init];\r
- }\r
- else if(cmd == 0x28){\r
- [self showLog:@"AI键结束录音"];\r
- [self finishRecored:self.recordData];\r
- }\r
- else if(cmd == 0x31){\r
- [self showLog:@"语音键开始录音"];\r
- self.recordData = [[NSMutableData alloc] init];\r
- }\r
- else if(cmd == 0x32){\r
- [self showLog:@"语音键结束录音"];\r
- [self finishRecored:self.recordData];\r
- }\r
- else{\r
- [self showLog:@"未定义指令!!!!!!!!"];\r
- }\r
- }\r
- /// 录音回调\r
- /// - Parameter data: pcm格式语音数据\r
- - (void)aiMouseSendRecordData:(NSData *)data{\r
- [self.recordData appendData:data];\r
- }\r
- ```\r
-\r
- 获取设备信息\r
-\r
-- 获取设备信息\r
-\r
- ```\r
- [[AiMouse shared] getDeviceInfo:^(AiMouseDeviceInfo *deviceInfo, NSError *error) {\r
- \r
- }];\r
- ```\r
-\r
- \r
-\r
-- 设置PCI\r
-\r
- ```\r
- [[AiMouse shared] setCPI:1000 completation:^(BOOL isSuccess, NSError *error) {\r
- \r
- }];\r
- ```\r
-\r
- \r
+\r
+\r
+## 蓝牙示例\r
+\r
+```objective-c\r
+ //\r
+// BleManager.m\r
+// AliIotSdkDemo\r
+//\r
+// Created by incar on 2024/1/30.\r
+//\r
+\r
+#import "BleManager.h"\r
+#import <AiMouseSdk/AiMouseSdk.h>\r
+#import "Config.h"\r
+\r
+// 服务id\r
+#define kServiceUUID @"FFF1"\r
+//ai特征\r
+#define kAiUUID @"0783B03E-8535-B5A0-7140-A304D2194CB8"\r
+//鉴权特征\r
+#define kAuthUUID @"0783B73E-8535-B5A0-7140-A304D2194CB7"\r
+//设备信息特征\r
+#define kDeviceInfoUUID @"0783B63E-8535-B5A0-7140-A304D2495CB6"\r
+\r
+@interface BleManager ()<CBCentralManagerDelegate,CBPeripheralDelegate,AiMouseDelegate>\r
+@property(nonatomic, strong) CBCentralManager *centralManager;///蓝牙管理\r
+@property(nonatomic, strong) CBPeripheral *connectPeripheral;//连接的设备\r
+@property(nonatomic, strong) CBCharacteristic *authCha;//鉴权特征\r
+@property(nonatomic, strong) CBCharacteristic *aiCha;//ai特征\r
+@property(nonatomic, strong) CBCharacteristic *deviceInfoCha;//设备信息特征\r
+@property (nonatomic,strong) NSMutableData *recordData;//录音的数据\r
+@end\r
+\r
+@implementation BleManager\r
++(BleManager *)shared{\r
+ static BleManager *manager = nil;\r
+ static dispatch_once_t oncePredicate;\r
+ dispatch_once(&oncePredicate, ^{\r
+ manager = [[BleManager alloc]init];\r
+ });\r
+ return manager;\r
+}\r
+\r
+- (instancetype)init{\r
+ self = [super init];\r
+ if (self) {\r
+ self.centralManager = [[CBCentralManager alloc]initWithDelegate:self queue:nil];\r
+ }\r
+ return self;\r
+}\r
+\r
+#pragma mark - CBCentralManagerDelegate\r
+- (void)centralManagerDidUpdateState:(nonnull CBCentralManager *)central {\r
+ [self showLog:[NSString stringWithFormat:@"蓝牙状态 = %@",@(central.state)]];\r
+ switch (central.state) {\r
+ case CBManagerStateUnknown:\r
+ \r
+ break;\r
+ case CBManagerStateResetting:\r
+ \r
+ break;\r
+ case CBManagerStateUnsupported:\r
+ \r
+ break;\r
+ case CBManagerStateUnauthorized:\r
+ \r
+ break;\r
+ case CBManagerStatePoweredOff:\r
+ \r
+ break;\r
+ case CBManagerStatePoweredOn:\r
+ [self autoConnectDevice];\r
+ break;\r
+ }\r
+}\r
+\r
+- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{\r
+// [self showLog:[NSString stringWithFormat:@"扫描到设备 = %@, data = %@",peripheral,advertisementData]];\r
+ if(self.discoverDevice){\r
+ self.discoverDevice(peripheral);\r
+ }\r
+}\r
+\r
+- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{\r
+ [self showLog:[NSString stringWithFormat:@"连接成功 name = %@",peripheral.name]];\r
+ if(self.didConnectDevice){\r
+ self.didConnectDevice(peripheral);\r
+ }\r
+ peripheral.delegate = self;\r
+ [peripheral discoverServices:nil];\r
+ \r
+ [[NSNotificationCenter defaultCenter] postNotificationName:kDidConnectBleNotification object:nil];\r
+}\r
+-(void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{\r
+ [self showLog:[NSString stringWithFormat:@"断开连接。。。%@",error.description]];\r
+ [[NSNotificationCenter defaultCenter] postNotificationName:kDidDisconnectBleNotification object:nil];\r
+ if(self.didDisConnectDevice){\r
+ self.didDisConnectDevice(peripheral);\r
+ }\r
+ [self autoConnectDevice];\r
+}\r
+- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error{\r
+ [self showLog:[NSString stringWithFormat:@"连接失败。。。%@",error.description]];\r
+}\r
+#pragma mark - CBPeripheralDelegate\r
+//发现服务\r
+- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {\r
+ for (CBService *service in peripheral.services){\r
+ [peripheral discoverCharacteristics:nil forService:service];\r
+ }\r
+}\r
+\r
+// 发现特征\r
+- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {\r
+ for (CBCharacteristic *characteristic in service.characteristics){\r
+ if ([characteristic.UUID.UUIDString isEqualToString:kAuthUUID]) {\r
+ //鉴权特征\r
+ self.authCha = characteristic;\r
+ [peripheral setNotifyValue:YES forCharacteristic:characteristic];\r
+ //切换代理\r
+ [AiMouse shared].delegate = self;\r
+ //切换当前连接类型\r
+ [[AiMouse shared] switchConnect:AiMouseConnectType_bluetooth];\r
+ //找到鉴权特征后,一定要调用鉴权接口开始鉴权。只有鉴权通过了,sdk相关功能才可以使用\r
+ [[AiMouse shared] startAuthentication:^(AiMouseAuthState state) {\r
+ [self showLog:[NSString stringWithFormat:@"鉴权结果 = %@",@(state)]];\r
+ if(self.authCallBack){\r
+ self.authCallBack(state == AiMouseAuthState_Success);\r
+ }\r
+ }];\r
+ }\r
+ else if ([characteristic.UUID.UUIDString isEqualToString:kAiUUID]) {\r
+ //AI特征\r
+ self.aiCha = characteristic;\r
+ [peripheral setNotifyValue:YES forCharacteristic:characteristic];\r
+ }\r
+ else if ([characteristic.UUID.UUIDString isEqualToString:kDeviceInfoUUID]) {\r
+ //设备信息特征\r
+ self.deviceInfoCha = characteristic;\r
+ [peripheral setNotifyValue:YES forCharacteristic:characteristic];\r
+ }\r
+ }\r
+}\r
+//收到蓝牙数据\r
+- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {\r
+ NSData *data = characteristic.value;\r
+ [self showLog:[NSString stringWithFormat:@"[receive] %@",[AiMouseTools dataToHexString:data]]];\r
+ if([characteristic.UUID.UUIDString isEqualToString:kAuthUUID]){\r
+ //鉴权数据\r
+ [[AiMouse shared] sendAuthDataToSdk:data];\r
+ }\r
+ else if([characteristic.UUID.UUIDString isEqualToString:kAiUUID]){\r
+ //AI数据\r
+ [[AiMouse shared] sendAiDataToSdk:data];\r
+ }\r
+ else if([characteristic.UUID.UUIDString isEqualToString:kDeviceInfoUUID]){\r
+ //设备信息数据\r
+ [[AiMouse shared] sendDeviceDataToSdk:data];\r
+ }\r
+}\r
+\r
+#pragma mark - AiDelegate\r
+/// 鉴权数据回调,需要将此数据转发给蓝牙设备\r
+/// - Parameter data: 数据\r
+- (void)aiMouseSendAuthData:(NSData *)data{\r
+ [self showLog:[NSString stringWithFormat:@"[send] %@",[AiMouseTools dataToHexString:data]]];\r
+ [self.connectPeripheral writeValue:data forCharacteristic:self.authCha type:CBCharacteristicWriteWithoutResponse];\r
+}\r
+\r
+\r
+/// 设备信息数据回调,需要将此数据通过设备信息特征转发给蓝牙设备\r
+/// - Parameter data: 数据\r
+-(void)aiMouseSendDeviceInfoData:(NSData *)data{\r
+ [self showLog:[NSString stringWithFormat:@"[send] %@",[AiMouseTools dataToHexString:data]]];\r
+ [self.connectPeripheral writeValue:data forCharacteristic:self.deviceInfoCha type:CBCharacteristicWriteWithoutResponse];\r
+}\r
+\r
+/// 鼠标按键指令回调\r
+/// - Parameter data: 数据。\r
+/// 前 第一次单击31(开始录音), 第二次单击32(结束录音) , 按下21(开始录音)抬起22(结束录音)\r
+/// 中 单击42, 按下25(开始录音)抬起26(结束录音)\r
+/// 后 单击43,按下27(开始录音)抬起28(结束录音)\r
+/// 其他未定义\r
+- (void)aiMouseSendCmdData:(NSData *)data{\r
+ uint8 cmd;\r
+ [data getBytes:&cmd length:1];\r
+ [self showLog:[NSString stringWithFormat:@"收到指令 = %X",cmd]];\r
+ \r
+ if(cmd == 0x31 || cmd == 0x21 || cmd == 0x25 ||cmd == 0x27){\r
+ [self showLog:@"开始录音"];\r
+ self.recordData = [[NSMutableData alloc] init];\r
+ }\r
+ else if(cmd == 0x32 || cmd == 0x22 || cmd == 0x26 ||cmd == 0x28){\r
+ [self showLog:@"结束录音"];\r
+ [self finishRecored:self.recordData];\r
+ }\r
+}\r
+\r
+/// 录音回调\r
+/// - Parameter data: pcm格式语音数据\r
+- (void)aiMouseSendRecordData:(NSData *)data{\r
+ [self.recordData appendData:data];\r
+}\r
+\r
+#pragma mark - public\r
+/// 连接设备\r
+- (void)startScanDevice{\r
+ [self.centralManager scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey : [NSNumber numberWithBool:NO]}];\r
+}\r
+\r
+/// 扫描设备\r
+- (void)stopScanDevice{\r
+ [self.centralManager stopScan];\r
+}\r
+\r
+/// 连接设备\r
+- (void)connectPeripheral:(CBPeripheral *)peripheral{\r
+ self.connectPeripheral = peripheral;\r
+ [self.centralManager connectPeripheral:peripheral options:@{CBConnectPeripheralOptionNotifyOnConnectionKey : [NSNumber numberWithBool:YES]}];\r
+}\r
+\r
+/// 获取设备信息\r
+- (void)getDeviceInfo:(void (^)(AiMouseDeviceInfo * _Nonnull, NSError * _Nonnull))completation{\r
+ [[AiMouse shared] getDeviceInfo:completation];\r
+}\r
+#pragma mark - other\r
+//自动连接,获取已配对的蓝牙,取第一个连接\r
+- (void)autoConnectDevice{\r
+ //如果是已连接或者正在连接,则不再重连\r
+ if (self.connectPeripheral && (self.connectPeripheral.state == CBPeripheralStateConnected || self.connectPeripheral.state == CBPeripheralStateConnecting)) {\r
+ return;\r
+ }\r
+ NSArray<CBPeripheral *> *devices = [self.centralManager retrieveConnectedPeripheralsWithServices:@[[CBUUID UUIDWithString:kServiceUUID]]];\r
+ if (devices.count > 0) {\r
+ CBPeripheral *peripheral = devices[0];\r
+ [self showLog:[NSString stringWithFormat:@"匹配过的设备%@",peripheral.name]];\r
+ [self connectPeripheral:peripheral];\r
+ }\r
+ // 10s自动重连\r
+ [self performSelector:@selector(autoConnectDevice) withObject:nil afterDelay:10];\r
+}\r
+- (void)showLog:(NSString *)log{\r
+ NSLog(@"%@",log);\r
+}\r
+\r
+//将录音数据保存\r
+- (void)finishRecored:(NSData *)data{\r
+ NSString *doc = NSTemporaryDirectory();\r
+ NSString *fullPath = [NSString stringWithFormat:@"%@1.pcm",doc];\r
+ NSError *err;\r
+ [data writeToFile:fullPath options:NSDataWritingAtomic error:&err];\r
+ if (err) {\r
+ [self showLog:[NSString stringWithFormat:@"录音保存失败 %@",err.description]];\r
+ }\r
+ else{\r
+ [self showLog:[NSString stringWithFormat:@"录音保存成功 path = %@",fullPath]];\r
+ }\r
+}\r
+@end\r
+\r
+```\r
+\r
+\r
+\r
+## USB示例\r
+\r
+ \r
+\r
+```objective-c\r
+//\r
+// HidManager.m\r
+// MouseSdk\r
+//\r
+// Created by incar on 2024/3/26.\r
+//\r
+\r
+#import "HidManager.h"\r
+#include <IOKit/hid/IOHIDLib.h>\r
+#include <IOKit/hid/IOHIDKeys.h>\r
+#import <AiMouseSdk/AiMouseSdk.h>\r
+#import "Config.h"\r
+\r
+//供应商id\r
+const long vendorID = 0x248a;\r
+//产品id\r
+const long productID = 0xca08;\r
+\r
+@interface HidManager ()<AiMouseDelegate>\r
+\r
+@property(nonatomic, assign) IOHIDManagerRef hidManager;///hid管理\r
+@property(nonatomic, assign) IOHIDDeviceRef authCha;//鉴权通道\r
+@property(nonatomic, assign) IOHIDDeviceRef aiCha;//ai通道\r
+@property(nonatomic, assign) IOHIDDeviceRef deviceInfoCha;//设备信息通道\r
+@property (nonatomic,strong) NSMutableData *recordData;//录音的数据\r
+@end\r
+\r
+@implementation HidManager\r
++(HidManager *)shared{\r
+ static HidManager *manager = nil;\r
+ static dispatch_once_t oncePredicate;\r
+ dispatch_once(&oncePredicate, ^{\r
+ manager = [[HidManager alloc]init];\r
+ });\r
+ return manager;\r
+}\r
+\r
+- (instancetype)init{\r
+ self = [super init];\r
+ if (self) {\r
+ [self initHid];\r
+ [self open];\r
+ }\r
+ return self;\r
+}\r
+\r
+- (void)initHid{\r
+\r
+}\r
+\r
+- (void)open{\r
+ self.hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);\r
+ IOHIDManagerScheduleWithRunLoop(self.hidManager, CFRunLoopGetMain(), kCFRunLoopDefaultMode);\r
+ IOReturn ret = IOHIDManagerOpen(self.hidManager, 0L);\r
+ if (ret != kIOReturnSuccess) {\r
+ NSLog(@"打开设备失败!");\r
+ }else{\r
+ NSLog(@"打开设备成功!");\r
+ }\r
+ //设置匹配设备\r
+ NSMutableDictionary* dict= [NSMutableDictionary dictionary];\r
+ [dict setValue:[NSNumber numberWithLong:productID] forKey:[NSString stringWithCString:kIOHIDProductIDKey encoding:NSUTF8StringEncoding]];\r
+ [dict setValue:[NSNumber numberWithLong:vendorID] forKey:[NSString stringWithCString:kIOHIDVendorIDKey encoding:NSUTF8StringEncoding]];\r
+ IOHIDManagerSetDeviceMatching(self.hidManager, (__bridge CFMutableDictionaryRef)dict);\r
+ //设置匹配到设备回调\r
+ IOHIDManagerRegisterDeviceMatchingCallback(self.hidManager, &hidAppearDevice, NULL);\r
+ //设置移除设备回调\r
+ IOHIDManagerRegisterDeviceRemovalCallback(self.hidManager, &hidDisAppearDevice, NULL);\r
+}\r
+\r
+- (void)close{\r
+ IOReturn ret = IOHIDManagerClose(self.hidManager, 0);\r
+ if (ret != kIOReturnSuccess) {\r
+ NSLog(@"关闭设备失败!");\r
+ }else{\r
+ NSLog(@"关闭设备成功!");\r
+ }\r
+}\r
+\r
+#pragma mark - Hid CallBack\r
+/// 匹配到设备回调\r
+static void hidAppearDevice(void *inContext,IOReturn inResult,void *inSender,IOHIDDeviceRef inIOHIDDeviceRef) {\r
+ uint32_t vid = IOHIDDevGetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDVendorIDKey));\r
+ uint32_t pid = IOHIDDevGetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDProductIDKey));\r
+ uint32_t PrimaryUsagePage = IOHIDDevGetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDPrimaryUsagePageKey));\r
+ uint32_t PrimaryUsage = IOHIDDevGetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDPrimaryUsageKey));\r
+ NSLog(@"vid = %u, pid = %u, PrimaryUsagePage = %u, PrimaryUsage = %u,",vid,pid,PrimaryUsagePage,PrimaryUsage);\r
+ NSLog(@"发现设备 %@\n ",inIOHIDDeviceRef);\r
+ \r
+ // PrimaryUsagePage=1 PrimaryUsage=0,设备信息\r
+ // PrimaryUsagePage=1 PrimaryUsage=6,鉴权\r
+ // PrimaryUsagePage=65283 PrimaryUsage=0,ai\r
+ if(PrimaryUsagePage == 1 && PrimaryUsage == 0){\r
+ //设备信息\r
+ [HidManager shared].deviceInfoCha = inIOHIDDeviceRef;\r
+ //鉴权\r
+ [HidManager shared].authCha = inIOHIDDeviceRef;\r
+ //开始鉴权\r
+ [[HidManager shared] startAuthentication];\r
+ }\r
+ else if(PrimaryUsagePage == 65283 && PrimaryUsage == 0){\r
+ //ai\r
+ [HidManager shared].aiCha = inIOHIDDeviceRef;\r
+ }\r
+ //注册消息回调\r
+ unsigned char InputBuffer[128];\r
+ IOHIDDeviceRegisterInputReportCallback(inIOHIDDeviceRef, InputBuffer, sizeof(InputBuffer), hidReceiveData, NULL);\r
+}\r
+\r
+/// 设备移除回调\r
+static void hidDisAppearDevice(void *inContext,IOReturn inResult,void *inSender,IOHIDDeviceRef inIOHIDDeviceRef) {\r
+ NSLog(@"拔出设备 %@ ",inIOHIDDeviceRef);\r
+ uint32_t PrimaryUsagePage = IOHIDDevGetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDPrimaryUsagePageKey));\r
+ uint32_t PrimaryUsage = IOHIDDevGetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDPrimaryUsageKey));\r
+\r
+ if(PrimaryUsagePage == 1 && PrimaryUsage == 0){\r
+ [HidManager shared].connectStateCallBack(false);\r
+ }\r
+}\r
+\r
+static void hidReceiveData(void* context, IOReturn result, void* sender, IOHIDReportType type, uint32_t reportID, uint8_t *report,CFIndex reportLength){\r
+ \r
+ [[HidManager shared] showLog:[NSString stringWithFormat:@"[receive] 处理前 %@",[AiMouseTools dataToHexString:[[NSData alloc] initWithBytes:report length:reportLength]]]];\r
+ \r
+ NSInteger len = get_data_len(report, reportLength);\r
+ NSData *data = [[NSData alloc] initWithBytes:report length:len];\r
+ [[HidManager shared] showLog:[NSString stringWithFormat:@"[receive] 处理后 %@",[AiMouseTools dataToHexString:data]]];\r
+ \r
+ uint32_t PrimaryUsagePage = IOHIDDevGetUInt32Property(sender, CFSTR(kIOHIDPrimaryUsagePageKey));\r
+ uint32_t PrimaryUsage = IOHIDDevGetUInt32Property(sender, CFSTR(kIOHIDPrimaryUsageKey));\r
+\r
+ if(PrimaryUsagePage == 1 && PrimaryUsage == 0){\r
+ [[HidManager shared] showLog:@"device数据"];\r
+ [[AiMouse shared] sendDeviceDataToSdk:data];\r
+ }\r
+ else if(PrimaryUsagePage == 65283 && PrimaryUsage == 0){\r
+ [[HidManager shared] showLog:@"AI数据"];\r
+ [[AiMouse shared] sendAiDataToSdk:data];\r
+ }\r
+}\r
+#pragma mark - AiDelegate\r
+/// 鉴权数据回调,需要将此数据转发给蓝牙设备\r
+/// - Parameter data: 数据\r
+- (void)aiMouseSendAuthData:(NSData *)data{\r
+ [self sendData:data toDevice:self.authCha];\r
+}\r
+\r
+/// 设备信息数据回调,需要将此数据通过设备信息特征转发给蓝牙设备\r
+/// - Parameter data: 数据\r
+-(void)aiMouseSendDeviceInfoData:(NSData *)data{\r
+ [self sendData:data toDevice:self.deviceInfoCha];\r
+}\r
+\r
+/// 鼠标按键指令回调\r
+/// - Parameter data: 数据。\r
+/// 前 第一次单击31(开始录音), 第二次单击32(结束录音) , 按下21(开始录音)抬起22(结束录音)\r
+/// 中 单击42, 按下25(开始录音)抬起26(结束录音)\r
+/// 后 单击43,按下27(开始录音)抬起28(结束录音)\r
+/// 其他未定义\r
+- (void)aiMouseSendCmdData:(NSData *)data{\r
+ uint8 cmd;\r
+ [data getBytes:&cmd length:1];\r
+ [self showLog:[NSString stringWithFormat:@"收到指令 = %X",cmd]];\r
+ \r
+ if(cmd == 0x31 || cmd == 0x21 || cmd == 0x25 ||cmd == 0x27){\r
+ [self showLog:@"开始录音"];\r
+ self.recordData = [[NSMutableData alloc] init];\r
+ }\r
+ else if(cmd == 0x32 || cmd == 0x22 || cmd == 0x26 ||cmd == 0x28){\r
+ [self showLog:@"结束录音"];\r
+ [self finishRecored:self.recordData];\r
+ }\r
+}\r
+/// 录音回调\r
+/// - Parameter data: pcm格式语音数据\r
+- (void)aiMouseSendRecordData:(NSData *)data{\r
+ [self.recordData appendData:data];\r
+}\r
+\r
+#pragma mark - public\r
+-(void)startAuthentication{\r
+ //连上设备\r
+ [HidManager shared].connectStateCallBack(true);\r
+ //设置代理\r
+ [AiMouse shared].delegate = self;\r
+ //切换当前连接类型\r
+ [[AiMouse shared] switchConnect:AiMouseConnectType_hid];\r
+ //找到鉴权特征后,一定要调用鉴权接口开始鉴权。只有鉴权通过了,sdk相关功能才可以使用\r
+ [self showLog:@"开始鉴权"];\r
+ [[AiMouse shared] startAuthentication:^(AiMouseAuthState state) {\r
+ [self showLog:[NSString stringWithFormat:@"鉴权结果 = %@",@(state)]];\r
+ if(self.authCallBack){\r
+ self.authCallBack(state == AiMouseAuthState_Success);\r
+ }\r
+ }];\r
+}\r
+/// 获取设备信息\r
+- (void)getDeviceInfo:(void (^)(AiMouseDeviceInfo * _Nonnull, NSError * _Nonnull))completation{\r
+ [[AiMouse shared] getDeviceInfo:completation];\r
+}\r
+\r
+/// 发送数据给设备\r
+-(void)sendData:(NSData *)data toDevice:(IOHIDDeviceRef)device{\r
+ if(device == nil){\r
+ [self showLog:@"请先连上设备"];\r
+ return;\r
+ }\r
+ [self showLog:[NSString stringWithFormat:@"开始发送[send] %@\n%@",[AiMouseTools dataToHexString:data],[AiMouseTools dataToUtf8String:data]]];\r
+ \r
+ IOReturn ret = IOHIDDeviceSetReport(device, kIOHIDReportTypeOutput, 0, data.bytes, data.length);\r
+ if (ret != kIOReturnSuccess) {\r
+ [self showLog:[NSString stringWithFormat:@"发送失败! code = %d",ret]];\r
+ }else{\r
+ [self showLog:@"发送成功!"];\r
+ }\r
+}\r
+//将录音数据保存\r
+- (void)finishRecored:(NSData *)data{\r
+ NSString *doc = NSTemporaryDirectory();\r
+ NSString *fullPath = [NSString stringWithFormat:@"%@1.pcm",doc];\r
+ NSError *err;\r
+ [data writeToFile:fullPath options:NSDataWritingAtomic error:&err];\r
+ if (err) {\r
+ [self showLog:[NSString stringWithFormat:@"录音保存失败 %@",err.description]];\r
+ }\r
+ else{\r
+ [self showLog:[NSString stringWithFormat:@"录音保存成功 path = %@",fullPath]];\r
+ }\r
+}\r
+- (void)showLog:(NSString *)log{\r
+ NSLog(@"%@",log);\r
+}\r
+\r
+/// 实际到数据长度\r
+static inline int get_data_len(uint8_t *buf, u_long len) {\r
+ if (len <= 0 ) return 0;\r
+ int url_len = 0;\r
+ while (buf[url_len] != 0x00) url_len++;\r
+ return url_len;\r
+}\r
+\r
+/// 获取对应属性值\r
+static uint32_t IOHIDDevGetUInt32Property(IOHIDDeviceRef inIOHIDDeviceRef, CFStringRef inKey) {\r
+ uint32_t outValue = 0;\r
+ if (inIOHIDDeviceRef != NULL) {\r
+ CFTypeRef tCFTypeRef = IOHIDDeviceGetProperty(inIOHIDDeviceRef, inKey);\r
+ if (tCFTypeRef != NULL && (CFNumberGetTypeID() == CFGetTypeID(tCFTypeRef)) ) {\r
+ Boolean result = CFNumberGetValue((CFNumberRef) tCFTypeRef, kCFNumberSInt32Type, &outValue);\r
+ if (!result) {\r
+ NSLog(@"get %@ failed.", inKey);\r
+ }\r
+ }\r
+ }\r
+ return outValue;\r
+}\r
+@end\r
+\r
+```\r
\r
\r
\r
## 注意事项\r
\r
-- 鉴权数据使用的是鉴权特征,走鉴权接口;设备信息数据使用的是设备信息特征,走设备信息接口;AI数据使用的是AI特征,走AI接口。\r
-- 只有鉴权成功了以后,AI相关功能才可用。authState鉴权状态,默认是Unknow。所以必须在连上蓝牙设备找到鉴权特征后,需要主动调用startAuthentication方法去鉴权。(只有鉴权成功,AI键,语音键、M键才可用)\r
+- 鉴权数据使用的是鉴权,走鉴权接口;设备信息数据使用的是设备信息通道,走设备信息接口;AI数据使用的是AI通道,走AI接口。\r
+- 只有鉴权成功了以后,AI相关功能才可用。authState鉴权状态,默认是Unknow。所以必须在连上蓝牙设备找到鉴权特征后,需要主动调用startAuthentication方法去鉴权。(只有鉴权成功,AI功能才可用)\r
- SDK只封装了蓝牙相关数据处理,APP自己维护蓝牙设备的扫描连接。蓝牙设备一段时间没有任何操作的话,会自动断开连接。APP可以在检测到断开后重连。\r
+- 当切换蓝牙或者USB,需要调用switchConnect切换连接类型。\r
\r
#import "HidManager.h"
#include <IOKit/hid/IOHIDLib.h>
#include <IOKit/hid/IOHIDKeys.h>
-
#import <AiMouseSdk/AiMouseSdk.h>
#import "Config.h"
+//供应商id
+const long vendorID = 0x248a;
+//产品id
+const long productID = 0xca08;
+
@interface HidManager ()<AiMouseDelegate>
@property(nonatomic, assign) IOHIDManagerRef hidManager;///hid管理
-@property(nonatomic, assign) IOHIDDeviceRef authCha;//鉴权特征
-@property(nonatomic, assign) IOHIDDeviceRef aiCha;//ai特征
-@property(nonatomic, assign) IOHIDDeviceRef deviceInfoCha;//设备信息特征
+@property(nonatomic, assign) IOHIDDeviceRef authCha;//鉴权通道
+@property(nonatomic, assign) IOHIDDeviceRef aiCha;//ai通道
+@property(nonatomic, assign) IOHIDDeviceRef deviceInfoCha;//设备信息通道
@property (nonatomic,strong) NSMutableData *recordData;//录音的数据
@end
}else{
NSLog(@"打开设备成功!");
}
-
- const long vendorID = 0x248a;
- const long productID = 0xca08;
+ //设置匹配设备
NSMutableDictionary* dict= [NSMutableDictionary dictionary];
[dict setValue:[NSNumber numberWithLong:productID] forKey:[NSString stringWithCString:kIOHIDProductIDKey encoding:NSUTF8StringEncoding]];
[dict setValue:[NSNumber numberWithLong:vendorID] forKey:[NSString stringWithCString:kIOHIDVendorIDKey encoding:NSUTF8StringEncoding]];
IOHIDManagerSetDeviceMatching(self.hidManager, (__bridge CFMutableDictionaryRef)dict);
-
+ //设置匹配到设备回调
IOHIDManagerRegisterDeviceMatchingCallback(self.hidManager, &hidAppearDevice, NULL);
+ //设置移除设备回调
IOHIDManagerRegisterDeviceRemovalCallback(self.hidManager, &hidDisAppearDevice, NULL);
}
}
#pragma mark - Hid CallBack
+/// 匹配到设备回调
static void hidAppearDevice(void *inContext,IOReturn inResult,void *inSender,IOHIDDeviceRef inIOHIDDeviceRef) {
uint32_t vid = IOHIDDevGetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDVendorIDKey));
uint32_t pid = IOHIDDevGetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDProductIDKey));
[HidManager shared].deviceInfoCha = inIOHIDDeviceRef;
//鉴权
[HidManager shared].authCha = inIOHIDDeviceRef;
+ //开始鉴权
[[HidManager shared] startAuthentication];
}
- else if(PrimaryUsagePage == 1 && PrimaryUsage == 6){
-// //鉴权
-// [HidManager shared].authCha = inIOHIDDeviceRef;
-// [[HidManager shared] startAuthentication];
- }
else if(PrimaryUsagePage == 65283 && PrimaryUsage == 0){
//ai
[HidManager shared].aiCha = inIOHIDDeviceRef;
}
-
+ //注册消息回调
unsigned char InputBuffer[128];
IOHIDDeviceRegisterInputReportCallback(inIOHIDDeviceRef, InputBuffer, sizeof(InputBuffer), hidReceiveData, NULL);
}
+/// 设备移除回调
static void hidDisAppearDevice(void *inContext,IOReturn inResult,void *inSender,IOHIDDeviceRef inIOHIDDeviceRef) {
NSLog(@"拔出设备 %@ ",inIOHIDDeviceRef);
uint32_t PrimaryUsagePage = IOHIDDevGetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDPrimaryUsagePageKey));
}
static void hidReceiveData(void* context, IOReturn result, void* sender, IOHIDReportType type, uint32_t reportID, uint8_t *report,CFIndex reportLength){
+
+ [[HidManager shared] showLog:[NSString stringWithFormat:@"[receive] 处理前 %@",[AiMouseTools dataToHexString:[[NSData alloc] initWithBytes:report length:reportLength]]]];
+
NSInteger len = get_data_len(report, reportLength);
NSData *data = [[NSData alloc] initWithBytes:report length:len];
- [[HidManager shared] showLog:[NSString stringWithFormat:@"[receive] = %@",[AiMouseTools dataToHexString:data]]];
+ [[HidManager shared] showLog:[NSString stringWithFormat:@"[receive] 处理后 %@",[AiMouseTools dataToHexString:data]]];
uint32_t PrimaryUsagePage = IOHIDDevGetUInt32Property(sender, CFSTR(kIOHIDPrimaryUsagePageKey));
uint32_t PrimaryUsage = IOHIDDevGetUInt32Property(sender, CFSTR(kIOHIDPrimaryUsageKey));
[[AiMouse shared] sendAiDataToSdk:data];
}
}
-
-static uint32_t IOHIDDevGetUInt32Property(IOHIDDeviceRef inIOHIDDeviceRef, CFStringRef inKey) {
- uint32_t outValue = 0;
- if (inIOHIDDeviceRef != NULL) {
- CFTypeRef tCFTypeRef = IOHIDDeviceGetProperty(inIOHIDDeviceRef, inKey);
- if (tCFTypeRef != NULL && (CFNumberGetTypeID() == CFGetTypeID(tCFTypeRef)) ) {
- Boolean result = CFNumberGetValue((CFNumberRef) tCFTypeRef, kCFNumberSInt32Type, &outValue);
- if (!result) {
- NSLog(@"get %@ failed.", inKey);
- }
- }
- }
-
- return outValue;
-}
#pragma mark - AiDelegate
/// 鉴权数据回调,需要将此数据转发给蓝牙设备
/// - Parameter data: 数据
[self sendData:data toDevice:self.authCha];
}
-
/// 设备信息数据回调,需要将此数据通过设备信息特征转发给蓝牙设备
/// - Parameter data: 数据
-(void)aiMouseSendDeviceInfoData:(NSData *)data{
#pragma mark - public
-(void)startAuthentication{
+ //连上设备
[HidManager shared].connectStateCallBack(true);
+ //设置代理
[AiMouse shared].delegate = self;
//切换当前连接类型
[[AiMouse shared] switchConnect:AiMouseConnectType_hid];
[[AiMouse shared] getDeviceInfo:completation];
}
+/// 发送数据给设备
-(void)sendData:(NSData *)data toDevice:(IOHIDDeviceRef)device{
if(device == nil){
[self showLog:@"请先连上设备"];
NSLog(@"%@",log);
}
+/// 实际到数据长度
static inline int get_data_len(uint8_t *buf, u_long len) {
if (len <= 0 ) return 0;
int url_len = 0;
return url_len;
}
+/// 获取对应属性值
+static uint32_t IOHIDDevGetUInt32Property(IOHIDDeviceRef inIOHIDDeviceRef, CFStringRef inKey) {
+ uint32_t outValue = 0;
+ if (inIOHIDDeviceRef != NULL) {
+ CFTypeRef tCFTypeRef = IOHIDDeviceGetProperty(inIOHIDDeviceRef, inKey);
+ if (tCFTypeRef != NULL && (CFNumberGetTypeID() == CFGetTypeID(tCFTypeRef)) ) {
+ Boolean result = CFNumberGetValue((CFNumberRef) tCFTypeRef, kCFNumberSInt32Type, &outValue);
+ if (!result) {
+ NSLog(@"get %@ failed.", inKey);
+ }
+ }
+ }
+ return outValue;
+}
@end