M8蓝牙调试
authorliangzhenying <867174124@qq.com>
Thu, 17 Apr 2025 09:46:14 +0000 (17:46 +0800)
committerliangzhenying <867174124@qq.com>
Thu, 17 Apr 2025 09:46:14 +0000 (17:46 +0800)
22 files changed:
Document/新/21744613056_.pic.jpg [new file with mode: 0644]
Document/新/Mouse_Dongle通信协议_v1.3.pdf [new file with mode: 0644]
Document/新/WX20250416-114056.png [new file with mode: 0644]
Document/新/m8_log.txt [new file with mode: 0644]
Document/新/朱国巧鼠标.docx [new file with mode: 0644]
Document/新/语音鼠标蓝牙通信接口v2.0.3.docx [new file with mode: 0644]
MouseSdk/AiMouseSdk/AiMouseSdk.xcodeproj/project.pbxproj
MouseSdk/AiMouseSdk/AiMouseSdk.xcodeproj/xcuserdata/yaozuopan.xcuserdatad/xcschemes/xcschememanagement.plist
MouseSdk/AiMouseSdk/M8/M8MouseInfo.h [new file with mode: 0644]
MouseSdk/AiMouseSdk/M8/M8MouseInfo.m [new file with mode: 0644]
MouseSdk/AiMouseSdk/M8/M8MouseSdk.h [new file with mode: 0644]
MouseSdk/AiMouseSdk/M8/M8MouseSdk.m [new file with mode: 0644]
MouseSdk/AiMouseSdk/Manager/BleManager.h
MouseSdk/AiMouseSdk/Manager/BleManager.m
MouseSdk/AiMouseSdk/Manager/DeviceManger.h
MouseSdk/AiMouseSdk/Manager/DeviceManger.m
MouseSdk/AiMouseSdk/Manager/HidManager.m
MouseSdk/AiMouseSdk/Manager/TimerManager.m
MouseSdk/MouseSdk.xcworkspace/xcuserdata/yaozuopan.xcuserdatad/UserInterfaceState.xcuserstate
MouseSdk/MouseSdk.xcworkspace/xcuserdata/yaozuopan.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
MouseSdk/MouseSdk/ViewController.m
MouseSdk/Pods/Pods.xcodeproj/xcuserdata/yaozuopan.xcuserdatad/xcschemes/xcschememanagement.plist

diff --git a/Document/新/21744613056_.pic.jpg b/Document/新/21744613056_.pic.jpg
new file mode 100644 (file)
index 0000000..087f622
Binary files /dev/null and "b/Document/\346\226\260/21744613056_.pic.jpg" differ
diff --git a/Document/新/Mouse_Dongle通信协议_v1.3.pdf b/Document/新/Mouse_Dongle通信协议_v1.3.pdf
new file mode 100644 (file)
index 0000000..3ce7cd7
Binary files /dev/null and "b/Document/\346\226\260/Mouse_Dongle\351\200\232\344\277\241\345\215\217\350\256\256_v1.3.pdf" differ
diff --git a/Document/新/WX20250416-114056.png b/Document/新/WX20250416-114056.png
new file mode 100644 (file)
index 0000000..74da006
Binary files /dev/null and "b/Document/\346\226\260/WX20250416-114056.png" differ
diff --git a/Document/新/m8_log.txt b/Document/新/m8_log.txt
new file mode 100644 (file)
index 0000000..9d7b0ff
--- /dev/null
@@ -0,0 +1,45 @@
+12:04:56.2000: connected in underlying BLE layer.
+12:05:02.2080: discovered services: (
+    "Device Information",
+    "Human Interface Device",
+    AE00,
+    AE40,
+    Battery,
+    FF00
+)
+12:05:02.3330: discovered characteristics for service 180A: (
+    "Manufacturer Name String",
+    "Model Number String",
+    "Serial Number String",
+    "Hardware Revision String",
+    "Firmware Revision String",
+    "Software Revision String",
+    "System ID",
+    "IEEE Regulatory Certification",
+    "PnP ID"
+)
+12:05:02.4490: discovered characteristics for service 180F: (
+    "Battery Level"
+)
+12:05:02.5110: discovered characteristics for service AE40: (
+    AE41,
+    AE42
+)
+12:05:02.5690: discovered characteristics for service FF00: (
+    FF01,
+    FF02,
+    FF03
+)
+12:05:02.6300: discovered characteristics for service AE00: (
+    AE01,
+    AE02
+)
+12:05:02.6300: state changed to 'Connected'.
+12:05:03.0050: updated subscription state for characteristic 2A19___180F: subscribed
+12:05:03.0340: received update from characteristic 2A19___180F: <3c>
+12:05:03.0640: received update from characteristic 2A25___180A: <5342544a 30313445 31453030 30303030 4136>
+12:05:03.3290: received update from characteristic 2A23___180A: <00000000 00000000>
+12:05:03.4490: received update from characteristic 2A27___180A: <312e302e 30>
+12:05:03.5610: received update from characteristic 2A28___180A: <4d38>
+12:05:03.6340: received update from characteristic 2A29___180A: <4a594420 5368656e 5a68656e>
+12:05:03.6640: received update from characteristic 2A24___180A: <42542d30 574d4f2d 74623732 2d323430 34313830 315458>
\ No newline at end of file
diff --git a/Document/新/朱国巧鼠标.docx b/Document/新/朱国巧鼠标.docx
new file mode 100644 (file)
index 0000000..bf28c09
Binary files /dev/null and "b/Document/\346\226\260/\346\234\261\345\233\275\345\267\247\351\274\240\346\240\207.docx" differ
diff --git a/Document/新/语音鼠标蓝牙通信接口v2.0.3.docx b/Document/新/语音鼠标蓝牙通信接口v2.0.3.docx
new file mode 100644 (file)
index 0000000..cfd9653
Binary files /dev/null and "b/Document/\346\226\260/\350\257\255\351\237\263\351\274\240\346\240\207\350\223\235\347\211\231\351\200\232\344\277\241\346\216\245\345\217\243v2.0.3.docx" differ
index 78fe40c..8b758b5 100644 (file)
                3FCF53502D1A5C97007EC52F /* LogManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FCF534D2D1A5C97007EC52F /* LogManager.h */; };
                3FCF53512D1A5C97007EC52F /* LogManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FCF534D2D1A5C97007EC52F /* LogManager.h */; };
                3FCF53522D1A5C97007EC52F /* LogManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FCF534E2D1A5C97007EC52F /* LogManager.m */; };
+               3FF3D7372DAE442C008EBA5D /* M8MouseSdk.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FF3D7352DAE442C008EBA5D /* M8MouseSdk.h */; };
+               3FF3D7382DAE442C008EBA5D /* M8MouseSdk.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FF3D7362DAE442C008EBA5D /* M8MouseSdk.m */; };
+               3FF3D7392DAE442C008EBA5D /* M8MouseSdk.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FF3D7352DAE442C008EBA5D /* M8MouseSdk.h */; };
+               3FF3D73A2DAE442C008EBA5D /* M8MouseSdk.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FF3D7362DAE442C008EBA5D /* M8MouseSdk.m */; };
+               3FF3D75C2DAFA0BC008EBA5D /* M8MouseInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FF3D75B2DAFA0BC008EBA5D /* M8MouseInfo.m */; };
+               3FF3D75D2DAFA0BC008EBA5D /* M8MouseInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FF3D75A2DAFA0BC008EBA5D /* M8MouseInfo.h */; };
+               3FF3D75E2DAFA0BC008EBA5D /* M8MouseInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FF3D75A2DAFA0BC008EBA5D /* M8MouseInfo.h */; };
+               3FF3D75F2DAFA0BC008EBA5D /* M8MouseInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FF3D75B2DAFA0BC008EBA5D /* M8MouseInfo.m */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
                3F5CE3E62D1E7BCA00A5628A /* libAiMouseSdk copy.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libAiMouseSdk copy.a"; sourceTree = BUILT_PRODUCTS_DIR; };
                3FCF534D2D1A5C97007EC52F /* LogManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LogManager.h; sourceTree = "<group>"; };
                3FCF534E2D1A5C97007EC52F /* LogManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LogManager.m; sourceTree = "<group>"; };
+               3FF3D7352DAE442C008EBA5D /* M8MouseSdk.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = M8MouseSdk.h; sourceTree = "<group>"; };
+               3FF3D7362DAE442C008EBA5D /* M8MouseSdk.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = M8MouseSdk.m; sourceTree = "<group>"; };
+               3FF3D75A2DAFA0BC008EBA5D /* M8MouseInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = M8MouseInfo.h; sourceTree = "<group>"; };
+               3FF3D75B2DAFA0BC008EBA5D /* M8MouseInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = M8MouseInfo.m; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
                180E7A9D2BD7BB12008558E8 = {
                        isa = PBXGroup;
                        children = (
+                               3FF3D7562DAFA058008EBA5D /* M8 */,
                                18E0C5842D0FF84A0093BA8F /* ByteDance */,
                                1899600D2CEAD78B0042505F /* Keyboard */,
                                18D579FF2C91733E003D5714 /* NMouseSdk */,
                        path = TlwMouseSdk;
                        sourceTree = "<group>";
                };
+               3FF3D7562DAFA058008EBA5D /* M8 */ = {
+                       isa = PBXGroup;
+                       children = (
+                               3FF3D7352DAE442C008EBA5D /* M8MouseSdk.h */,
+                               3FF3D7362DAE442C008EBA5D /* M8MouseSdk.m */,
+                               3FF3D75A2DAFA0BC008EBA5D /* M8MouseInfo.h */,
+                               3FF3D75B2DAFA0BC008EBA5D /* M8MouseInfo.m */,
+                       );
+                       path = M8;
+                       sourceTree = "<group>";
+               };
 /* End PBXGroup section */
 
 /* Begin PBXHeadersBuildPhase section */
                                180E7C982BD8FC4E008558E8 /* rational.h in Headers */,
                                18EF7B022C7603E800AC5223 /* TlwTools.h in Headers */,
                                180E7CF82BD8FC4F008558E8 /* codec_id.h in Headers */,
+                               3FF3D75E2DAFA0BC008EBA5D /* M8MouseInfo.h in Headers */,
                                180E7C9B2BD8FC4E008558E8 /* avconfig.h in Headers */,
                                180E7CDA2BD8FC4E008558E8 /* avassert.h in Headers */,
                                180E7CCA2BD8FC4E008558E8 /* channel_layout.h in Headers */,
                                180E7CDB2BD8FC4E008558E8 /* hash.h in Headers */,
                                180E7B562BD7BD83008558E8 /* AiMouseConfig.h in Headers */,
                                180E7CF42BD8FC4F008558E8 /* codec.h in Headers */,
+                               3FF3D7392DAE442C008EBA5D /* M8MouseSdk.h in Headers */,
                                180E7C8D2BD8FC4E008558E8 /* detection_bbox.h in Headers */,
                                180E7CEF2BD8FC4F008558E8 /* videotoolbox.h in Headers */,
                                180E7CFF2BD8FC4F008558E8 /* version.h in Headers */,
                                18862B452C806BD900D3564D /* version.h in Headers */,
                                18862B462C806BD900D3564D /* ffversion.h in Headers */,
                                18862B472C806BD900D3564D /* intreadwrite.h in Headers */,
+                               3FF3D75D2DAFA0BC008EBA5D /* M8MouseInfo.h in Headers */,
                                18862B482C806BD900D3564D /* AFURLRequestSerialization.h in Headers */,
                                18862B492C806BD900D3564D /* buffer.h in Headers */,
                                18862B4A2C806BD900D3564D /* twofish.h in Headers */,
                                18862B8E2C806BD900D3564D /* AiMouseSdk.h in Headers */,
                                18862B8F2C806BD900D3564D /* qsv.h in Headers */,
                                18862B902C806BD900D3564D /* hmac.h in Headers */,
+                               3FF3D7372DAE442C008EBA5D /* M8MouseSdk.h in Headers */,
                                18862B912C806BD900D3564D /* AFNetworking.h in Headers */,
                                18862B922C806BD900D3564D /* threadmessage.h in Headers */,
                                18862B932C806BD900D3564D /* adpcm.h in Headers */,
                                180E7BE72BD7BD84008558E8 /* AiAudioManager.m in Sources */,
                                18EF7AFB2C7603E800AC5223 /* TlwTools.m in Sources */,
                                18EF7AFA2C7603E800AC5223 /* TlwMouseSdk.m in Sources */,
+                               3FF3D73A2DAE442C008EBA5D /* M8MouseSdk.m in Sources */,
                                18862A282C8064E300D3564D /* BleManager.m in Sources */,
                                188814C42C85C2BB009299A9 /* AESCBCHelper.m in Sources */,
+                               3FF3D75F2DAFA0BC008EBA5D /* M8MouseInfo.m in Sources */,
                                180E7BDF2BD7BD84008558E8 /* AiMouseConfig.m in Sources */,
                                18EF7AFC2C7603E800AC5223 /* AiConnectManager.m in Sources */,
                                181CE5C22C6EED9900EF8D07 /* AiAliAuthManager.m in Sources */,
                                188814C52C85C2BB009299A9 /* AESCBCHelper.m in Sources */,
                                18862BC62C806BD900D3564D /* AiMouseConfig.m in Sources */,
                                18862BC72C806BD900D3564D /* AiConnectManager.m in Sources */,
+                               3FF3D7382DAE442C008EBA5D /* M8MouseSdk.m in Sources */,
                                18862BC82C806BD900D3564D /* AiAliAuthManager.m in Sources */,
                                18862BC92C806BD900D3564D /* AFSecurityPolicy.m in Sources */,
+                               3FF3D75C2DAFA0BC008EBA5D /* M8MouseInfo.m in Sources */,
                                18862BCA2C806BD900D3564D /* DeviceManger.m in Sources */,
                                18862BCB2C806BD900D3564D /* AiAudioDecoder.m in Sources */,
                                18862BCC2C806BD900D3564D /* AiDeviceInfoManager.m in Sources */,
index 27157b9..64bd978 100644 (file)
@@ -7,7 +7,7 @@
                <key>AiMouseSdk copy.xcscheme_^#shared#^_</key>
                <dict>
                        <key>orderHint</key>
-                       <integer>4</integer>
+                       <integer>2</integer>
                </dict>
                <key>AiMouseSdk.xcscheme_^#shared#^_</key>
                <dict>
diff --git a/MouseSdk/AiMouseSdk/M8/M8MouseInfo.h b/MouseSdk/AiMouseSdk/M8/M8MouseInfo.h
new file mode 100644 (file)
index 0000000..2a7ab5d
--- /dev/null
@@ -0,0 +1,17 @@
+//
+//  M8MouseInfo.h
+//  AiMouseSdk
+//
+//  Created by liangshi on 2025/4/16.
+//
+
+#import <Foundation/Foundation.h>
+
+@interface M8MouseInfo : NSObject
+@property (nonatomic, strong) NSString *battery_power;/// 电池百分百电量,0-100
+@property (nonatomic, strong) NSString *version;///软件版本
+@property (nonatomic, strong) NSString *brand;/// 品牌名称
+@property (nonatomic, strong) NSString *sn;/// 设备序列号
+///
++(M8MouseInfo *)shared;
+@end
diff --git a/MouseSdk/AiMouseSdk/M8/M8MouseInfo.m b/MouseSdk/AiMouseSdk/M8/M8MouseInfo.m
new file mode 100644 (file)
index 0000000..34de1cc
--- /dev/null
@@ -0,0 +1,28 @@
+//
+//  M8MouseInfo.m
+//  AiMouseSdk
+//
+//  Created by liangshi on 2025/4/16.
+//
+
+#import "M8MouseInfo.h"
+
+@implementation M8MouseInfo
+
++(M8MouseInfo *)shared{
+    static M8MouseInfo *manager = nil;
+    static dispatch_once_t oncePredicate;
+    dispatch_once(&oncePredicate, ^{
+        manager = [[M8MouseInfo alloc]init];
+    });
+    return manager;
+}
+
+- (instancetype)init{
+    self = [super init];
+    if (self) {
+        
+    }
+    return self;
+}
+@end
diff --git a/MouseSdk/AiMouseSdk/M8/M8MouseSdk.h b/MouseSdk/AiMouseSdk/M8/M8MouseSdk.h
new file mode 100644 (file)
index 0000000..12c289b
--- /dev/null
@@ -0,0 +1,81 @@
+//
+//  M8MouseSdk.h
+//  AiMouseSdk
+//
+//  Created by liangshi on 2025/4/15.
+//
+
+#import <Foundation/Foundation.h>
+#import "AiMouseSdk.h"
+@protocol M8MouseSdkDelegate <NSObject>
+
+/// 设备连接状态
+/// - Parameter connected: 是否连接
+- (void)m8MouseConnectStateDidChange:(BOOL)connected;
+
+
+/// 设备信息数据回调,需要将此数据通过设备信息特征转发给蓝牙设备
+/// - Parameter data: 数据
+- (void)m8MouseSendDeviceInfoData:(NSData *)data;
+
+/// 鼠标按键指令回调
+/// - Parameter data: 数据。
+//EF AA 0B 00 02 E1 00 E3  语音键单击开始
+//EF AA 0C 00 02 E1 00 E3  语音键单击结束
+//EF AA 05 00 02 E1 00 E3  语音键长按
+//EF AA 06 00 02 E1 00 E3  语音键长按松开
+//
+//
+//EF AA 09 00 02 E1 00 E3  M键单击
+//EF AA 01 00 02 E1 00 E3  M键长按松开
+//EF AA 02 00 02 E1 00 E3  M键长按松开
+//
+//EF AA 0A 00 02 E1 00 E3  AI键单击
+//EF AA 03 00 02 E1 00 E3  AI键长按松开
+//EF AA 04 00 02 E1 00 E3  AI键长按松开
+//
+//EF AA 0D 00 02 E1 00 E3  翻译键单击开始
+//EF AA 0E 00 02 E1 00 E3  翻译键单击结束
+//EF AA 07 00 02 E1 00 E3  翻译键长按
+//EF AA 08 00 02 E1 00 E3  翻译键长按松开
+/// 其他未定义
+- (void)m8MouseSendCmdData:(NSData *)data;
+
+/// 录音回调
+/// - Parameter data: pcm格式语音数据
+- (void)m8MouseSendRecordData:(NSData *)data;
+
+/// hid数据异常,需要重新开启监听usb设备
+- (void)m8HidDataError;
+
+/// 输出sdk日志
+/// - Parameter log: 日志
+- (void)m8MouseAddLog:(NSString *)log;
+
+@end
+
+@interface M8MouseSdk : NSObject
+@property (nonatomic, weak) id<M8MouseSdkDelegate> delegate;/// 代理
+@property (nonatomic, readonly) AiMouseConnectType connectType;//连接类型
+@property (nonatomic, readonly) BOOL connected;//是否已连接
+
+/// 断开连接
+- (void)didDisconnect;
+
+/// 切换连接类型
+/// - Parameter type: 连接类型
+- (void)switchConnect:(AiMouseConnectType)type isConnected:(BOOL)isConneted;
+
+/// 传输业务数据给sdk
+/// - Parameter data:ai特征传过来的数据
+- (void)sendAiDataToSdk:(NSData *)data;
+
+///  传输设备信息数据给sdk
+/// - Parameter data:设备信息特征传过来的数据
+- (void)sendDeviceDataToSdk:(NSData *)data;
+
+/// 获取设备信息
+/// - Parameter completation: 如果获取成功,则deviceInfo有值,否则为nil
+- (void)getFullDeviceInfo:(void (^)(AiMouseDeviceInfo *deviceInfo,NSError *error))finished;
+
+@end
diff --git a/MouseSdk/AiMouseSdk/M8/M8MouseSdk.m b/MouseSdk/AiMouseSdk/M8/M8MouseSdk.m
new file mode 100644 (file)
index 0000000..8206b95
--- /dev/null
@@ -0,0 +1,336 @@
+//
+//  M8MouseSdk.m
+//  AiMouseSdk
+//
+//  Created by liangshi on 2025/4/15.
+//
+
+#import "M8MouseSdk.h"
+#import "TlwAudioManager.h"
+#import "TlwTools.h"
+#import "AiRecordManager.h"
+#import "M8MouseInfo.h"
+@interface M8MouseSdk()
+
+@property (nonatomic, strong) TlwAudioManager *audioManager;
+@property (nonatomic, strong) AiRecordManager *recordManager;
+
+@property (nonatomic,strong)void (^dongleStateCallBack)(BOOL success);
+@property (nonatomic,assign)NSInteger dongleTimes;
+
+@property (nonatomic,strong)AiMouseDeviceInfo *fullInfo;
+@property (nonatomic,assign)NSInteger questTimes;
+@end
+
+@implementation M8MouseSdk
+
+-(instancetype)init{
+    if (self = [super init]) {
+        _connectType = AiMouseConnectType_bluetooth;
+        //        NSLog(@"[TlwMouseSdk]%@",[NSString stringWithFormat:@"AiMouseSdk_v%@",self.version]);
+        [self.recordManager checkPermissions];
+    }
+    return self;
+}
+
+-(NSString *)version{
+    return @"1.0.2";
+}
+
+-(TlwAudioManager *)audioManager{
+    if (!_audioManager) {
+        _audioManager = [[TlwAudioManager alloc] init];
+        __weak typeof(self) ws = self;
+        _audioManager.decodeCallBack = ^(NSData * _Nonnull data) {
+            [ws sendRecordData:data];
+        };
+        _audioManager.outputLog = ^(NSString * _Nonnull log) {
+            [ws showLog:log];
+        };
+    }
+    return _audioManager;
+}
+
+- (AiRecordManager *)recordManager{
+    if (!_recordManager) {
+        _recordManager = [[AiRecordManager alloc] init];
+        __weak typeof(self) ws = self;
+        _recordManager.didRecordData = ^(NSData * _Nonnull data) {
+            [ws showLog:[NSString stringWithFormat:@"%@",data]];
+            [ws sendRecordData:data];
+        };
+    }
+    return _recordManager;
+}
+- (void)sendOpenCmd{
+    uint8_t cmd = 0x0D;
+    uint8_t len = 0x00;
+    uint8_t tail = 0xEF;
+    NSMutableData *mData = NSMutableData.data;
+    [mData appendData:[self getHidHeader]];
+    [mData appendBytes:&cmd length:1];
+    [mData appendBytes:&len length:1];
+    [mData appendBytes:&tail length:1];
+    [self sendToDevice:mData];
+}
+
+#pragma mark - pub Api
+- (void)didDisconnect{
+    _connected = false;
+    [self stopRecord];
+}
+
+- (void)switchConnect:(AiMouseConnectType)type isConnected:(BOOL)isConneted{
+    [NSObject cancelPreviousPerformRequestsWithTarget:self];
+    if(isConneted ){
+        _connected = true;
+        _connectType = type;
+        [self showLog:type == AiMouseConnectType_bluetooth?@"sdk切换到蓝牙模式":@"sdk切换到usb模式"];
+        
+//        if (type == AiMouseConnectType_hid ) {
+//            [self.recordManager checkPermissions];
+//            //            [self sendOpenCmd];
+//            [self checkDongleState];
+//        }
+//        else{
+            [self TlwConnectManager:nil connectStateDidChange:true];
+//        }
+    }
+    else{
+        [self stopRecord];
+        if (self.connected) {
+            _connected = false;
+            [self TlwConnectManager:nil connectStateDidChange:false];
+        }
+    }
+}
+
+- (void)sendAiDataToSdk:(NSData *)data{
+        [self showLog:[NSString stringWithFormat:@"[receive][Voice] %@",data]];
+    if(self.connectType == AiMouseConnectType_hid){
+    }
+    else if (self.connectType == AiMouseConnectType_bluetooth){
+        [self bleReceiveAiData:data];
+    }
+}
+
+-(void)sendDeviceDataToSdk:(NSData *)data{
+    if(self.connectType == AiMouseConnectType_hid){
+        [self showLog:[NSString stringWithFormat:@"[receive][usb][info] %@",[TlwTools dataToHexString:data]]];
+        [self hidReceiveDeviceData:data];
+    }
+    else if (self.connectType == AiMouseConnectType_bluetooth){
+        [self showLog:[NSString stringWithFormat:@"[receive][ble][info] %@",[TlwTools dataToHexString:data]]];
+        [self bleReceiveDeviceData:data];
+    }
+}
+
+- (void)getFullDeviceInfo:(void (^)(AiMouseDeviceInfo *deviceInfo,NSError *error))finished{
+    AiMouseDeviceInfo *info = [[AiMouseDeviceInfo alloc] init];
+    info.type = 0;
+    info.battery_power = M8MouseInfo.shared.battery_power;
+    info.version = M8MouseInfo.shared.version;
+    info.brand = M8MouseInfo.shared.brand;
+    info.sn = M8MouseInfo.shared.sn;
+    info.mac = info.sn;
+    info.CPI_list = @"2400";
+    info.CPI = @"2400";
+    self.fullInfo = info;
+    finished(info,nil);
+    
+}
+
+#pragma mark - check dongle
+- (void)checkDongleState{
+    self.dongleTimes = 0;
+    __weak typeof(self) ws = self;
+    [self checkDongleStateAction:^(BOOL success) {
+        ws.dongleStateCallBack = nil;
+        if (success) {
+            [ws TlwConnectManager:nil connectStateDidChange:true];
+        }
+        else{
+            [ws TlwConnectManager:nil connectStateDidChange:false];
+        }
+    }];
+}
+- (void)checkDongleStateAction:(void (^)(BOOL success))finished{
+    self.dongleStateCallBack = finished;
+    [self performSelector:@selector(sendDongleCmd) withObject:nil afterDelay:1];
+}
+- (void)sendDongleCmd{
+    self.dongleTimes++;
+    if ( self.dongleStateCallBack == nil) {
+        return;
+    }
+    if (self.dongleTimes > 2) {
+        [self TlwConnectManager:nil connectStateDidChange:false];
+        return;
+    }
+    uint8_t cmd = 0x0D;
+    uint8_t len = 0x00;
+    uint8_t tail = 0xEF;
+    NSMutableData *mData = NSMutableData.data;
+    [mData appendData:[self getHidHeader]];
+    [mData appendBytes:&cmd length:1];
+    [mData appendBytes:&len length:1];
+    [mData appendBytes:&tail length:1];
+    [self sendToDevice:mData];
+    [self performSelector:@selector(sendDongleCmd) withObject:nil afterDelay:1];
+}
+#pragma mark - ble
+- (void)bleReceiveAiData:(NSData *)data{
+    [self.audioManager receiveData:data];
+}
+
+-(void)bleReceiveDeviceData:(NSData *)data{
+    uint8 type;
+    [ [data subdataWithRange:NSMakeRange(0, 1)] getBytes:&type length:1];
+    
+    uint8 len;
+    [[data subdataWithRange:NSMakeRange(1, 1)] getBytes:&len length:1];
+    
+    switch (type) {
+        case 0xef:
+        {
+            //鼠标按键上报
+            NSData *subData = [data subdataWithRange:NSMakeRange(2, 1)];
+            [self sendCmdData:subData];
+            break;
+        }
+        default:
+            break;
+    }
+}
+
+#pragma mark - hid
+- (void)hidReceiveDeviceData:(NSData *)data{
+    //    0x05fff1fec09f0114ef
+    if(data.length < 7 ){
+        [self showLog:@"收到异常数据"];
+        return;
+    }
+    if(![[[TlwTools dataToHexString:[data subdataWithRange:NSMakeRange(1, 2)]] lowercaseString] isEqualToString:@"fff1"]){
+        [self showLog:@"收到异常数据"];
+        return;
+    }
+    
+    uint8 type;
+    [[data subdataWithRange:NSMakeRange(5, 1)] getBytes:&type length:1];
+    
+    NSData *lenData = [data subdataWithRange:NSMakeRange(6, 1)];
+    uint8 len;
+    [lenData getBytes:&len length:1];
+    
+    switch (type) {
+        
+        case 0x9d:
+        {
+            uint16_t version;
+            [[data subdataWithRange:NSMakeRange(7, 2)] getBytes:&version length:2];
+            
+            uint8_t state;
+            [[data subdataWithRange:NSMakeRange(9, 1)] getBytes:&state length:1];
+            
+            [self showLog:[NSString stringWithFormat:@"dongle version = %d,bind = %d",version,state]];
+            if(self.dongleStateCallBack)self.dongleStateCallBack(state == 1);
+            break;
+        }
+        case 0x9f:
+        {
+            NSData *subData = [data subdataWithRange:NSMakeRange(7, 1)];
+            [self sendCmdData:subData];
+            
+            uint8 cmd;
+            [subData getBytes:&cmd length:1];
+            
+            if(cmd == 0x04 || cmd == 0x07 || cmd == 0x13 || cmd == 0x11 || cmd == 0x01 ||cmd == 0x09){
+                self.recordManager.startCmd = subData;
+                [self startRecord];
+            }
+            else if(cmd == 0x05 || cmd == 0x08 || cmd == 0x14 || cmd == 0x12 || cmd == 0x02 ||cmd == 0x10){
+                [self stopRecord];
+            }
+            break;
+        }
+            
+        default:
+            break;
+    }
+}
+- (NSData *)getHidHeader{
+    uint8_t head1 = 0x05;
+    uint16_t head2 = 0xF1FF;
+    uint8_t head3 = 0xfe;
+    uint8_t head4 = 0x00;
+    
+    NSMutableData *mData = NSMutableData.data;
+    [mData appendBytes:&head1 length:1];
+    [mData appendBytes:&head2 length:2];
+    [mData appendBytes:&head3 length:1];
+    [mData appendBytes:&head4 length:1];
+    
+    return mData;
+}
+#pragma mark - other
+- (void)sendRecordData:(NSData *)data{
+    [self showLog:[NSString stringWithFormat:@"[send][audio] %@",data]];
+    if (self.delegate)  [self.delegate m8MouseSendRecordData:data];
+}
+
+- (void)sendCmdData:(NSData *)data{
+    [self showLog:[NSString stringWithFormat:@"[send] %@",data]];
+    if (self.delegate) [self.delegate m8MouseSendCmdData:data];
+}
+
+- (void)showLog:(NSString *)log{
+    if (self.delegate && [self.delegate respondsToSelector:@selector(m8MouseAddLog:)]) {
+        [self.delegate m8MouseAddLog:[NSString stringWithFormat:@"[m8]%@",log]];
+    }
+}
+
+
+- (void)sendToDevice:(NSMutableData *)data{
+    if (data.length < 64) {
+        NSInteger len = 64 - data.length;
+        for (NSInteger i = 0; i < len; i++) {
+            uint8_t d = 0x00;
+            [data  appendBytes:&d length:1];
+        }
+    }
+    [self showLog:[NSString stringWithFormat:@"[send][info] %@",[TlwTools dataToHexString:data]]];
+    [self.delegate m8MouseSendDeviceInfoData:data];
+}
+#pragma mark - deviceInfo
+- (void)startRecord{
+    [self.recordManager start];
+}
+
+- (void)stopRecord{
+    if (self.recordManager.recording ) {
+        [self.recordManager stop];
+    }
+}
+
+#pragma mark - other
+-(void)TlwConnectManager:(NSString *)manager connectStateDidChange:(BOOL)connected{
+    _connected = connected;
+    [self showLog:[NSString stringWithFormat:@"连接状态 %@",connected ? @"true":@"false"]];
+    if([self.delegate respondsToSelector:@selector(m8MouseConnectStateDidChange:)]) [self.delegate m8MouseConnectStateDidChange:connected];
+}
+
+- (NSString *)getBrand:(NSData *)data{
+    NSString *text = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
+    for (NSInteger i = 0; i < text.length;i++) {
+        if ([[text substringWithRange:NSMakeRange(i, 1)] isEqual:@"\0"]) {
+            return [text substringWithRange:NSMakeRange(0, i)];
+        }
+    }
+    return text;
+}
+- (NSString *)getFullBrand:(NSData *)data{
+    NSString *text = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
+    NSString *replacedString = [text stringByReplacingOccurrencesOfString:@"\0" withString:@"0"];
+    return replacedString;
+}
+@end
index 07f3c3b..a704bfa 100644 (file)
 @property (nonatomic, copy)void (^logCallBack)(NSString *log);//输出日志
 @property (nonatomic, assign)AiMouseProductType productType;//
 
-//- (void)startScan;
-
-//- (void)stopScan;
-
-//- (void)start;
 
 - (void)open;
 
index 6c7eb7f..7772f53 100644 (file)
@@ -6,7 +6,8 @@
 //
 
 #import "BleManager.h"
-
+#import "TlwTools.h"
+#import "M8MouseInfo.h"
 // 服务id
 #define kFrkServiceUUID @"FFF1"
 //ai特征
 //通知设备信息特征
 #define kTlwNotifyDeviceInfoUUID @"FFF2"
 
+// 服务id
+#define kM8ServiceUUID @"FF00"
+//voice特征
+#define kM8VoiceUUID @"AE42"
+#define kM8ClickUUID @"FF03"
+
+
 
 @interface BleManager ()<CBCentralManagerDelegate,CBPeripheralDelegate>
 @property(nonatomic, strong) CBCentralManager *centralManager;///蓝牙管理
 @property(nonatomic, strong) CBPeripheral *curentPeripheral;//连接的设备
 @property(nonatomic, strong) CBCharacteristic *deviceInfoCha;//设备信息特征
-@property (nonatomic,strong) NSMutableData *recordData;//录音的数据
 
 @property (nonatomic, strong) NSTimer *timer;
 @property (nonatomic, strong) dispatch_queue_t mainQueue;
 
 // 发现特征
 - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
-    
+    for (CBCharacteristic *characteristic in service.characteristics){
+        [self showLog:characteristic.UUID.UUIDString];
+        if ([characteristic.UUID.UUIDString isEqualToString:@"2A25"]) {
+            M8MouseInfo.shared.sn = [TlwTools dataToUtf8String:characteristic.value];
+        }
+        else if ([characteristic.UUID.UUIDString isEqualToString:@"2A19"]) {
+            NSData *data = characteristic.value;
+            int result;
+            [data getBytes:&result length:1];
+            M8MouseInfo.shared.battery_power = [NSString stringWithFormat:@"%d",result];
+        }
+        else if ([characteristic.UUID.UUIDString isEqualToString:@"2A24"]) {
+            M8MouseInfo.shared.brand = [TlwTools dataToUtf8String:characteristic.value];
+        }
+        else if ([characteristic.UUID.UUIDString isEqualToString:@"2A26"]) {
+            M8MouseInfo.shared.version = [TlwTools dataToUtf8String:characteristic.value];
+            [self showLog:[NSString stringWithFormat:@"Firmware Revision = %@",[TlwTools dataToUtf8String:characteristic.value]]];
+        }
+        else if ([characteristic.UUID.UUIDString isEqualToString:@"2A28"]) {
+            [self showLog:[NSString stringWithFormat:@"Software Revision = %@",[TlwTools dataToUtf8String:characteristic.value]]];
+        }
+//        else if ([characteristic.UUID.UUIDString isEqualToString:@"2A27"]) {
+//            [self showLog:[NSString stringWithFormat:@"Hardware Revision = %@",[TlwTools dataToUtf8String:characteristic.value]]];
+//        }
+//
+
+//        else if ([characteristic.UUID.UUIDString isEqualToString:@"2A23"]) {
+//            [self showLog:[NSString stringWithFormat:@"System ID = %@",[TlwTools dataToUtf8String:characteristic.value]]];
+//        }
+//        else if ([characteristic.UUID.UUIDString isEqualToString:@"2A2A"]) {
+//            [self showLog:[NSString stringWithFormat:@"PnP ID = %@",[TlwTools dataToUtf8String:characteristic.value]]];
+//        }
+//        else if ([characteristic.UUID.UUIDString isEqualToString:@"2A29"]) {
+//            [self showLog:[NSString stringWithFormat:@"Manufacturer Name = %@",[TlwTools dataToUtf8String:characteristic.value]]];
+//        }
+        else if ([characteristic.UUID.UUIDString isEqualToString:kM8ClickUUID]) {
+            [peripheral setNotifyValue:YES forCharacteristic:characteristic];
+        }
+        else if ([characteristic.UUID.UUIDString isEqualToString:kM8VoiceUUID]) {
+            //语音特征
+            [peripheral setNotifyValue:YES forCharacteristic:characteristic];
+            self.productType = AiMouseProductType_m8;
+//            dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC);
+//            dispatch_after(delayTime, dispatch_get_main_queue(), ^{
+                [self showLog:[NSString stringWithFormat:@"连接成功 = %@",peripheral.name]];
+                self.connectStateCallBack(self.curentPeripheral.name,true);
+//            });
+        }
+        [self showLog:[NSString stringWithFormat:@"%@",characteristic]];
+    }
+//    return;
     for (CBCharacteristic *characteristic in service.characteristics){
         if ([characteristic.UUID.UUIDString isEqualToString:kFrkVoiceUUID]) {
             //语音特征
             self.deviceInfoCha = characteristic;
         }
     }
+    
+    for (CBCharacteristic *characteristic in service.characteristics){
+        if ([characteristic.UUID.UUIDString isEqualToString:kM8VoiceUUID]) {
+            //语音特征
+            [peripheral setNotifyValue:YES forCharacteristic:characteristic];
+        }
+        else if ([characteristic.UUID.UUIDString isEqualToString:kTlwNotifyDeviceInfoUUID]) {
+            //通知设备信息特征
+            [peripheral setNotifyValue:YES forCharacteristic:characteristic];
+            self.productType = AiMouseProductType_tlw;
+            // 使用dispatch_after来延迟执行任务
+            dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC);
+            dispatch_after(delayTime, dispatch_get_main_queue(), ^{
+                [self showLog:[NSString stringWithFormat:@"连接成功 = %@",peripheral.name]];
+                self.connectStateCallBack(self.curentPeripheral.name,true);
+            });
+        }
+        else if ([characteristic.UUID.UUIDString isEqualToString:kTlwSetDeviceInfoUUID]) {
+            //设备信息特征
+            self.deviceInfoCha = characteristic;
+        }
+    }
 }
 //收到蓝牙数据
 - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
-    if (self.productType == AiMouseProductType_tlw) {
+    if (self.productType == AiMouseProductType_m8) {
         NSData *data = characteristic.value;
-        if([characteristic.UUID.UUIDString isEqualToString:kTlwVoiceUUID]){
+        if( [characteristic.UUID.UUIDString isEqualToString:kM8ClickUUID]){
+            self.receiveInfoDataCallBack(data);
+        }
+        else{
+            if([characteristic.UUID.UUIDString isEqualToString:kM8VoiceUUID] ){
+                self.receiveVoiceDataCallBack(data);
+            }
+        }
+    }
+    else if (self.productType == AiMouseProductType_tlw) {
+        NSData *data = characteristic.value;
+        if([characteristic.UUID.UUIDString isEqualToString:kTlwVoiceUUID] || [characteristic.UUID.UUIDString isEqualToString:kM8VoiceUUID] ){
             self.receiveVoiceDataCallBack(data);
         }
         else if([characteristic.UUID.UUIDString isEqualToString:kTlwNotifyDeviceInfoUUID]){
 - (void)checkRightDevice{
     for (CBService *s in self.curentPeripheral.services) {
         for (CBCharacteristic *c in s.characteristics) {
-            if([c.UUID.UUIDString isEqualToString:kFrkVoiceUUID] ||[c.UUID.UUIDString isEqualToString:kTlwVoiceUUID] ){
+            if([c.UUID.UUIDString isEqualToString:kFrkVoiceUUID] ||[c.UUID.UUIDString isEqualToString:kTlwVoiceUUID]  ||[c.UUID.UUIDString isEqualToString:kM8VoiceUUID] ){
                 return;
             }
         }
 }
 #pragma mark - public
 - (void)startScan{
-    NSArray<CBPeripheral *> *devices = [self.centralManager retrieveConnectedPeripheralsWithServices:@[[CBUUID UUIDWithString:kFrkServiceUUID],[CBUUID UUIDWithString:kTlwServiceUUID]]];
+    NSArray<CBPeripheral *> *devices = [self.centralManager retrieveConnectedPeripheralsWithServices:
+                                        @[[CBUUID UUIDWithString:kFrkServiceUUID],
+                                          [CBUUID UUIDWithString:kTlwServiceUUID],
+                                          [CBUUID UUIDWithString:kM8ServiceUUID],
+                                        ]];
 //    [self showLog:[NSString stringWithFormat:@"查询配对过的设备%@",devices]];
 
     if (devices.count > 0) {
         [self connectPeripheral:devices[0]];
     }
     else{
-//        [self showLog:[NSString stringWithFormat:@"开始扫描%@",@""]];
-//        [self.centralManager scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey : [NSNumber numberWithBool:NO]}];
+
     }
 }
 
     NSString *text =  [NSString stringWithFormat:@"[BleManager] %@",log];
     if(self.logCallBack) self.logCallBack(text);
 }
-#pragma mark - timer
-- (void)start{
-    if (self.timer && [self.timer isValid]) {
-        [self.timer invalidate];
-        self.timer = nil;
-    }
-//    dispatch_async(dispatch_queue_create("timeoutQueue", DISPATCH_QUEUE_SERIAL), ^{
-//        self.timer = [NSTimer timerWithTimeInterval:5 target:self selector:@selector(timerAction) userInfo:nil repeats:true];
-//        [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
-//        [[NSRunLoop currentRunLoop] run];
-//    });
-//    self.timer = [NSTimer timerWithTimeInterval:5 target:self selector:@selector(timerAction) userInfo:nil repeats:true];
-    self.timer = [NSTimer scheduledTimerWithTimeInterval:5 target:self selector:@selector(checkConnected) userInfo:nil repeats:true];
-}
+
 
 - (void)open{
     if([DeviceManger shared].isConneted){
index 6912b81..e35bfd4 100644 (file)
@@ -14,6 +14,7 @@ typedef NS_ENUM(NSInteger,AiMouseProductType) {
     AiMouseProductType_tlw = 2,///泰凌微
     AiMouseProductType_n = 3,///一键上网
     AiMouseProductType_keyboard = 4,///键盘
+    AiMouseProductType_m8 = 5,///泰凌微m8
 };
 
 NS_ASSUME_NONNULL_BEGIN
@@ -27,15 +28,13 @@ NS_ASSUME_NONNULL_BEGIN
 @property (nonatomic, readonly) AiMouseConnectType connectType;//连接类型
 #pragma mark ------- 鼠标的回调
 @property (nonatomic,strong)void (^authCallBack)(BOOL isSuccess);/// 鉴权回调
-@property (nonatomic, copy)void (^aiMouseSendDeviceInfoDataCallBack)(NSString *data);/// 设备信息数据回调
+//@property (nonatomic, copy)void (^aiMouseSendDeviceInfoDataCallBack)(NSString *data);/// 设备信息数据回调
 @property (nonatomic, copy)void (^aiMouseSendCmdDataCallBack)(NSString *data);/// 鼠标按键指令回调
 
 @property (nonatomic, copy)void (^begainRecoredCallBack)(void);/// 录音开始回调
 @property (nonatomic, copy)void (^recordingCallBack)(NSString *data);/// 录音进行中回调
 @property (nonatomic, copy)void (^finishRecoredCallBack)(NSString *data);/// 录音结束回调
 
-//@property (nonatomic, copy)void (^aiMouseAddLogCallBack)(NSString *log);///输出日志
-
 
 #pragma mark ------- 接口
 ///单例
index c74161b..2c097ab 100644 (file)
@@ -15,6 +15,7 @@
 #import "KeyboardHidManager.h"
 #import "KeyboardSdk.h"
 #import "ByteDanceSdk.h"
+#import "M8MouseSdk.h"
 #import "LogManager.h"
 
 @interface DeviceManger()<TlwMouseDelegate,AiMouseDelegate,NMouseSdkDelegate,KeyboardSdkDelegate>
@@ -27,6 +28,7 @@
 @property (nonatomic,strong) AiMouse *frkSdk;
 @property (nonatomic,strong) NMouseSdk *nSdk;
 @property (nonatomic,strong) KeyboardSdk *kbSdk;
+@property (nonatomic,strong) M8MouseSdk *m8Sdk;
 @property (nonatomic,assign) AiMouseProductType productType;
 
 //connectType 返回为0代表蓝牙,为1代表usb
 - (instancetype)init{
     self = [super init];
     if (self) {
-//        NSString *version = @"MouseSdk_v2024120303";
-//        NSLog(@"[AiMouseSdk] %@",version);
-//        [self showLog:version];;
-//        [self setupSDK];
-//        [self setupBle];
-//        [self setupHid];
-//        [self setupTimer];
-        self.version = @"MouseSdk_v2025010303";
+        self.version = @"MouseSdk_v2025041501";
     }
     return self;
 }
     
     self.frkSdk = [AiMouse shared];
     [self.frkSdk setDelegate:self];
+    
+    self.m8Sdk = [[M8MouseSdk alloc] init];
+    [self.m8Sdk setDelegate:self];
 }
 
 - (void)setupTimer{
     [TimerManager shared].timerCallBack = ^{
 //        [self showLog:@"timer action。。。"];
-        if(self.kbSdk.connected || self.nSdk.connected || self.tlwSdk.connected || self.frkSdk.connected){
+        if(self.kbSdk.connected || self.nSdk.connected || self.tlwSdk.connected || self.frkSdk.connected|| self.m8Sdk.connected){
 //            [self.hid close];
         }
         else{
 
 
 - (void)setupHid{
-   
     self.hid = [HidManager shared];
     __weak typeof(self) ws = self;
     
             else if (ws.hid.productType == AiMouseProductType_keyboard){
                 [ws.kbSdk switchConnect:AiMouseConnectType_hid isConnected:true];
             }
+            else if (ws.hid.productType == AiMouseProductType_m8){
+                [ws.m8Sdk switchConnect:AiMouseConnectType_hid isConnected:true];
+            }
         }
         else{
             if (ws.hid.productType == AiMouseProductType_n) {
                 [ws.kbSdk switchConnect:AiMouseConnectType_hid isConnected:false];
                 [ws.kbSdk didDisconnect];
             }
+            else if (ws.hid.productType == AiMouseProductType_keyboard) {
+                [ws.m8Sdk switchConnect:AiMouseConnectType_hid isConnected:false];
+                [ws.m8Sdk didDisconnect];
+            }
         }
     };
     self.hid.receiveInfoDataCallBack = ^(NSData *data) {
         else if (ws.hid.productType == AiMouseProductType_keyboard) {
             [ws.kbSdk sendDeviceDataToSdk:data];
         }
+        else if (ws.hid.productType == AiMouseProductType_keyboard) {
+            [ws.m8Sdk sendDeviceDataToSdk:data];
+        }
     };
     self.hid.logCallBack = ^(NSString * _Nonnull log) {
         [ws showLog:log];
             else if (ws.ble.productType == AiMouseProductType_tlw) {
                 [ws.tlwSdk switchConnect:AiMouseConnectType_bluetooth isConnected:true];
             }
+            else if (ws.ble.productType == AiMouseProductType_m8) {
+                [ws.m8Sdk switchConnect:AiMouseConnectType_bluetooth isConnected:true];
+            }
             else{
                 [ws.frkSdk switchConnect:AiMouseConnectType_bluetooth isConnected:true];
             }
             else if (ws.ble.productType == AiMouseProductType_tlw) {
                 [ws.tlwSdk switchConnect:AiMouseConnectType_bluetooth isConnected:false];
             }
+            else if (ws.ble.productType == AiMouseProductType_m8) {
+                [ws.m8Sdk switchConnect:AiMouseConnectType_bluetooth isConnected:false];
+            }
             else{
                 [ws.frkSdk switchConnect:AiMouseConnectType_bluetooth isConnected:false];
             }
         else if (ws.productType == AiMouseProductType_tlw) {
             [ws.tlwSdk sendDeviceDataToSdk:data];
         }
+        else if (ws.productType == AiMouseProductType_m8) {
+            [ws.m8Sdk sendDeviceDataToSdk:data];
+        }
         else{
             [ws.frkSdk sendDeviceDataToSdk:data];
         }
         if (ws.productType == AiMouseProductType_tlw) {
             [ws.tlwSdk sendAiDataToSdk:data];
         }
+        else if (ws.productType == AiMouseProductType_m8) {
+            [ws.m8Sdk sendAiDataToSdk:data];
+        }
         else{
             [ws.frkSdk sendAiDataToSdk:data];
         }
     if (self.frkSdk != nil && self.frkSdk.connected) {
         return true;
     }
+    if (self.m8Sdk != nil && self.m8Sdk.connected) {
+        return true;
+    }
     return false;
 }
 
             return @"1";
         }
     }
+    else if (self.productType == AiMouseProductType_m8) {
+        if (self.m8Sdk.connectType == AiMouseConnectType_bluetooth) {
+            return @"0";
+        }
+        else {
+            return @"1";
+        }
+    }
     else{
         if (self.frkSdk.connectType == AiMouseConnectType_bluetooth) {
             return @"0";
     else if (self.productType == AiMouseProductType_tlw) {
         return self.tlwSdk.connectType;
     }
+    else if (self.productType == AiMouseProductType_m8) {
+        return self.m8Sdk.connectType;
+    }
     else {
         return self.frkSdk.connectType;
     }
     }else if (self.productType == AiMouseProductType_tlw) {
         [self.tlwSdk getFullDeviceInfo:finished];
     }
+    else if (self.productType == AiMouseProductType_m8) {
+        [self.m8Sdk getFullDeviceInfo:finished];
+    }
     else{
         [self.frkSdk getDeviceInfo:finished];
     }
         finished(false,[NSError errorWithDomain:@"AiMouse SDK Error" code:AiMouseErrorCode_unknown userInfo:@{@"NSLocalizedDescriptionKey":@"当前鼠标不支持该接口"}]);
         return;
     }
+    if (self.productType == AiMouseProductType_m8) {
+        finished(false,[NSError errorWithDomain:@"AiMouse SDK Error" code:AiMouseErrorCode_unknown userInfo:@{@"NSLocalizedDescriptionKey":@"当前鼠标不支持该接口"}]);
+        return;
+    }
     if (self.productType == AiMouseProductType_frk ) {
         [self.frkSdk getRSSI:finished];
     }
 
 /// 设置CPI
 - (void)setCPI:(NSInteger)value completation:(void (^)(BOOL isSuccess,NSError *error))finished{
+    if (self.productType == AiMouseProductType_m8) {
+        finished(false,[NSError errorWithDomain:@"AiMouse SDK Error" code:AiMouseErrorCode_unknown userInfo:@{@"NSLocalizedDescriptionKey":@"当前鼠标不支持该接口"}]);
+        return;
+    }
     if (self.productType == AiMouseProductType_keyboard) {
+        finished(false,[NSError errorWithDomain:@"AiMouse SDK Error" code:AiMouseErrorCode_unknown userInfo:@{@"NSLocalizedDescriptionKey":@"当前键盘不支持该接口"}]);
+        return;
+    }
+    if (self.productType == AiMouseProductType_m8) {
         finished(false,[NSError errorWithDomain:@"AiMouse SDK Error" code:AiMouseErrorCode_unknown userInfo:@{@"NSLocalizedDescriptionKey":@"当前鼠标不支持该接口"}]);
         return;
     }
 ///   - value: 品牌名称
 ///   - finished: 设置结果回调
 - (void)setBrand:(NSString *)brand completation:(void (^)(BOOL isSuccess,NSError *error))finished {
+    if (self.productType == AiMouseProductType_m8) {
+        finished(false,[NSError errorWithDomain:@"AiMouse SDK Error" code:AiMouseErrorCode_unknown userInfo:@{@"NSLocalizedDescriptionKey":@"当前鼠标不支持该接口"}]);
+        return;
+    }
     if (self.productType == AiMouseProductType_keyboard) {
         finished(false,[NSError errorWithDomain:@"AiMouse SDK Error" code:AiMouseErrorCode_unknown userInfo:@{@"NSLocalizedDescriptionKey":@"当前鼠标不支持该接口"}]);
         return;
 
 /// 设置录音模式
 - (void)setRecordMode:(int)mode completation:(void (^)(BOOL isSuccess,NSError *error))finished{
+    if (self.productType == AiMouseProductType_m8) {
+        finished(false,[NSError errorWithDomain:@"AiMouse SDK Error" code:AiMouseErrorCode_unknown userInfo:@{@"NSLocalizedDescriptionKey":@"当前鼠标不支持该接口"}]);
+        return;
+    }
     if (self.productType == AiMouseProductType_keyboard) {
         finished(false,[NSError errorWithDomain:@"AiMouse SDK Error" code:AiMouseErrorCode_unknown userInfo:@{@"NSLocalizedDescriptionKey":@"当前鼠标不支持该接口"}]);
         return;
 
 /// 设置长按滚轮弹出的网页地址
 - (void)setUrl:(NSString *)url completation:(void (^)(BOOL isSuccess,NSError *error))finished{
+    if (self.productType == AiMouseProductType_m8) {
+        finished(false,[NSError errorWithDomain:@"AiMouse SDK Error" code:AiMouseErrorCode_unknown userInfo:@{@"NSLocalizedDescriptionKey":@"当前鼠标不支持该接口"}]);
+        return;
+    }
     if (self.productType == AiMouseProductType_keyboard) {
         finished(false,[NSError errorWithDomain:@"AiMouse SDK Error" code:AiMouseErrorCode_unknown userInfo:@{@"NSLocalizedDescriptionKey":@"当前鼠标不支持该接口"}]);
         return;
 
 /// 设置长按滚轮弹出网页开关
 - (void)setUrlState:(int)state completation:(void (^)(BOOL isSuccess,NSError *error))finished{
+    if (self.productType == AiMouseProductType_m8) {
+        finished(false,[NSError errorWithDomain:@"AiMouse SDK Error" code:AiMouseErrorCode_unknown userInfo:@{@"NSLocalizedDescriptionKey":@"当前鼠标不支持该接口"}]);
+        return;
+    }
     if (self.productType == AiMouseProductType_keyboard) {
         finished(false,[NSError errorWithDomain:@"AiMouse SDK Error" code:AiMouseErrorCode_unknown userInfo:@{@"NSLocalizedDescriptionKey":@"当前鼠标不支持该接口"}]);
         return;
 
 /// 设置鼠标连接模式
 - (void)setMouseMode:(int)mode completation:(void (^)(BOOL isSuccess,NSError *error))finished{
+    if (self.productType == AiMouseProductType_m8) {
+        finished(false,[NSError errorWithDomain:@"AiMouse SDK Error" code:AiMouseErrorCode_unknown userInfo:@{@"NSLocalizedDescriptionKey":@"当前鼠标不支持该接口"}]);
+        return;
+    }
     if (self.productType == AiMouseProductType_keyboard) {
         finished(false,[NSError errorWithDomain:@"AiMouse SDK Error" code:AiMouseErrorCode_unknown userInfo:@{@"NSLocalizedDescriptionKey":@"当前鼠标不支持该接口"}]);
         return;
 
 /// 获取录音模式
 - (void)getRecordMode:(void (^)(int mode,NSError *error))finished{
+    if (self.productType == AiMouseProductType_m8) {
+        finished(false,[NSError errorWithDomain:@"AiMouse SDK Error" code:AiMouseErrorCode_unknown userInfo:@{@"NSLocalizedDescriptionKey":@"当前鼠标不支持该接口"}]);
+        return;
+    }
     if (self.productType == AiMouseProductType_keyboard) {
         finished(false,[NSError errorWithDomain:@"AiMouse SDK Error" code:AiMouseErrorCode_unknown userInfo:@{@"NSLocalizedDescriptionKey":@"当前鼠标不支持该接口"}]);
         return;
 
 /// 获取长按滚轮弹出的网页地址
 - (void)getUrl:(void (^)(NSString *url,NSError *error))finished{
+    if (self.productType == AiMouseProductType_m8) {
+        finished(false,[NSError errorWithDomain:@"AiMouse SDK Error" code:AiMouseErrorCode_unknown userInfo:@{@"NSLocalizedDescriptionKey":@"当前鼠标不支持该接口"}]);
+        return;
+    }
     if (self.productType == AiMouseProductType_keyboard) {
         finished(false,[NSError errorWithDomain:@"AiMouse SDK Error" code:AiMouseErrorCode_unknown userInfo:@{@"NSLocalizedDescriptionKey":@"当前鼠标不支持该接口"}]);
         return;
 
 /// 获取长按滚轮弹出的网页地址开关状态
 - (void)getUrlState:(void (^)(int state,NSError *error))finished{
+    if (self.productType == AiMouseProductType_m8) {
+        finished(false,[NSError errorWithDomain:@"AiMouse SDK Error" code:AiMouseErrorCode_unknown userInfo:@{@"NSLocalizedDescriptionKey":@"当前鼠标不支持该接口"}]);
+        return;
+    }
     if (self.productType == AiMouseProductType_keyboard) {
         finished(false,[NSError errorWithDomain:@"AiMouse SDK Error" code:AiMouseErrorCode_unknown userInfo:@{@"NSLocalizedDescriptionKey":@"当前鼠标不支持该接口"}]);
         return;
 
 /// 获取鼠标连接模式
 - (void)getMouseModel:(void (^)(int mode,NSError *error))finished{
+    if (self.productType == AiMouseProductType_m8) {
+        finished(false,[NSError errorWithDomain:@"AiMouse SDK Error" code:AiMouseErrorCode_unknown userInfo:@{@"NSLocalizedDescriptionKey":@"当前鼠标不支持该接口"}]);
+        return;
+    }
     if (self.productType == AiMouseProductType_keyboard) {
         finished(false,[NSError errorWithDomain:@"AiMouse SDK Error" code:AiMouseErrorCode_unknown userInfo:@{@"NSLocalizedDescriptionKey":@"当前鼠标不支持该接口"}]);
         return;
 
 /// 打开录音
 - (void)openRecord:(void (^)(BOOL isSuccess,NSError *error))finished{
+    if (self.productType == AiMouseProductType_m8) {
+        finished(false,[NSError errorWithDomain:@"AiMouse SDK Error" code:AiMouseErrorCode_unknown userInfo:@{@"NSLocalizedDescriptionKey":@"当前鼠标不支持该接口"}]);
+        return;
+    }
     if (self.productType == AiMouseProductType_keyboard) {
         finished(false,[NSError errorWithDomain:@"AiMouse SDK Error" code:AiMouseErrorCode_unknown userInfo:@{@"NSLocalizedDescriptionKey":@"当前鼠标不支持该接口"}]);
         return;
 
 /// 关闭录音
 - (void)closeRecord:(void (^)(BOOL isSuccess,NSError *error))finished{
+    if (self.productType == AiMouseProductType_m8) {
+        finished(false,[NSError errorWithDomain:@"AiMouse SDK Error" code:AiMouseErrorCode_unknown userInfo:@{@"NSLocalizedDescriptionKey":@"当前鼠标不支持该接口"}]);
+        return;
+    }
     if (self.productType == AiMouseProductType_keyboard) {
         finished(false,[NSError errorWithDomain:@"AiMouse SDK Error" code:AiMouseErrorCode_unknown userInfo:@{@"NSLocalizedDescriptionKey":@"当前鼠标不支持该接口"}]);
         return;
     if (connected) {
         [self.frkSdk switchConnect:AiMouseConnectType_bluetooth isConnected:false];
         [self.nSdk switchConnect:AiMouseConnectType_bluetooth isConnected:false];
+        [self.m8Sdk switchConnect:AiMouseConnectType_bluetooth isConnected:false];
     }
     
     if (self.aiMouseConnectStateDidChangeCallBack) {
 /// M  单击0x06, 按下0x13(开始录音)抬起0x14(结束录音)
 /// AI键  单击0x03, 按下0x11(开始录音)抬起0x12(结束录音)
 /// 语音键  第一次单击0x01, 第二次单击0x02(结束录音) , 按下0x09(开始录音)抬起0x10(结束录音)
+/// 翻译键  第一次单击0x04(开始录音), 第二次单击0x05(结束录音), 按下0x07(开始录音) 抬起0x08(结束录音)
 /// 其他未定义
 ///
 /// /// 鼠标按键指令回调 富瑞坤
     if (connected) {
         [self.tlwSdk switchConnect:AiMouseConnectType_bluetooth isConnected:false];
         [self.frkSdk switchConnect:AiMouseConnectType_bluetooth isConnected:false];
+        [self.m8Sdk switchConnect:AiMouseConnectType_bluetooth isConnected:false];
     }
     
     if (self.aiMouseConnectStateDidChangeCallBack) {
     if (connected) {
         [self.tlwSdk switchConnect:AiMouseConnectType_bluetooth isConnected:false];
         [self.nSdk switchConnect:AiMouseConnectType_bluetooth isConnected:false];
+        [self.m8Sdk switchConnect:AiMouseConnectType_bluetooth isConnected:false];
     }
     
     if (self.aiMouseConnectStateDidChangeCallBack) {
 - (void)aiMouseHidDataError{
     [self.hid open];
 }
+#pragma mark - M8MouseSdkDelegate
+/// 设备连接状态
+/// - Parameter connected: 是否连接
+- (void)m8MouseConnectStateDidChange:(BOOL)connected{
+    [self showLog:[NSString stringWithFormat:@"%@设备连接状态返回: %@",self.m8Sdk.connectType == AiMouseConnectType_bluetooth ? @"蓝牙 ":@"USB",connected ? @"true":@"false"]];
+    
+    if (connected) {
+        [self.tlwSdk switchConnect:AiMouseConnectType_bluetooth isConnected:false];
+        [self.nSdk switchConnect:AiMouseConnectType_bluetooth isConnected:false];
+        [self.frkSdk switchConnect:AiMouseConnectType_bluetooth isConnected:false];
+    }
+    
+    if (self.aiMouseConnectStateDidChangeCallBack) {
+        self.aiMouseConnectStateDidChangeCallBack(self.m8Sdk.connectType == AiMouseConnectType_bluetooth ? 0:1,connected);
+    }
+    if(self.authCallBack && connected)self.authCallBack(connected);
+}
+
+
+/// 设备信息数据回调,需要将此数据通过设备信息特征转发给蓝牙设备
+/// - Parameter data: 数据
+- (void)m8MouseSendDeviceInfoData:(NSData *)data{
+    if (self.m8Sdk.connectType == AiMouseConnectType_bluetooth) {
+        [self.ble writeToDevice:data];
+    }
+    else if (self.frkSdk.connectType == AiMouseConnectType_hid){
+        [self.hid writeToDevice:data];
+    }
+}
+
+/// 鼠标按键指令回调
+//EF AA 0B 00 02 E1 00 E3  语音键单击开始
+//EF AA 0C 00 02 E1 00 E3  语音键单击结束
+//EF AA 05 00 02 E1 00 E3  语音键长按
+//EF AA 06 00 02 E1 00 E3  语音键长按松开
+//
+//
+//EF AA 09 00 02 E1 00 E3  M键单击
+//EF AA 01 00 02 E1 00 E3  M键长按松开
+//EF AA 02 00 02 E1 00 E3  M键长按松开
+//
+//EF AA 0A 00 02 E1 00 E3  AI键单击
+//EF AA 03 00 02 E1 00 E3  AI键长按松开
+//EF AA 04 00 02 E1 00 E3  AI键长按松开
+//
+//EF AA 0D 00 02 E1 00 E3  翻译键单击开始
+//EF AA 0E 00 02 E1 00 E3  翻译键单击结束
+//EF AA 07 00 02 E1 00 E3  翻译键长按
+//EF AA 08 00 02 E1 00 E3  翻译键长按松开
+//@"09":@"43",
+//@"01":@"27",
+//@"02":@"28",
+//
+//@"0A":@"42",
+//@"03":@"25",
+//@"04":@"26",
+//
+//@"0B":@"31",
+//@"0C":@"32",
+//@"05":@"21",
+//@"06":@"22",
+
+//@"0D":@"04",
+//@"0E":@"05",
+//@"07":@"07",
+//@"08":@"08",
+/// 其他未定义
+- (void)m8MouseSendCmdData:(NSData *)data{
+    NSLog(@"%@",data);
+    uint8 cmd;
+    [data getBytes:&cmd length:1];
+    if( cmd == 0x01){
+        cmd = 0x27;
+    }else if( cmd == 0x02){
+        cmd = 0x28;
+    }
+    else if( cmd == 0x09){
+        cmd = 0x43;
+    }
+    else if( cmd == 0xa){
+        cmd = 0x42;
+    }
+    else if( cmd == 0x03){
+        cmd = 0x25;
+    }
+    else if( cmd == 0x4){
+        cmd = 0x26;
+    }
+    else if( cmd == 0x0B){
+        cmd = 0x31;
+    }
+    else if( cmd == 0x0C){
+        cmd = 0x32;
+    }
+    else if( cmd == 0x05){
+        cmd = 0x21;
+    }
+    else if( cmd == 0x06){
+        cmd = 0x22;
+    }
+    else if( cmd == 0x0D){
+        cmd = 0x04;
+    }
+    else if( cmd == 0x0E){
+        cmd = 0x05;
+    }
+    else if( cmd == 0x07){
+        cmd = 0x07;
+    }
+    else if( cmd == 0x08){
+        cmd = 0x08;
+    }
+    if (self.aiMouseSendCmdDataCallBack) {
+        self.aiMouseSendCmdDataCallBack([NSString stringWithFormat:@"%X",cmd]);
+    }
+    
+    if(cmd == 0x04 || cmd == 0x07 || cmd == 0x31 || cmd == 0x21 || cmd == 0x25 ||cmd == 0x27){
+        [self showLog:@"开始录音"];
+        self.recordData = [[NSMutableData alloc] init];
+        if (self.begainRecoredCallBack) {
+            self.begainRecoredCallBack();
+        }
+    }
+    else if(cmd == 0x05 || cmd == 0x08 || cmd == 0x32 || cmd == 0x22 || cmd == 0x26 ||cmd == 0x28){
+        [self showLog:@"结束录音"];
+        [self finishRecored:self.recordData];
+        if (self.finishRecoredCallBack) {
+            NSString *base64String = [self.recordData base64EncodedStringWithOptions:0];
+            self.finishRecoredCallBack(base64String);
+        }
+    }
+}
+
+/// 录音回调
+/// - Parameter data: pcm格式语音数据
+- (void)m8MouseSendRecordData:(NSData *)data{
+    [self.recordData appendData:data];
+    if (self.recordingCallBack) {
+        self.recordingCallBack( [data base64EncodedStringWithOptions:0]);
+    }
+}
+
+/// hid数据异常,需要重新开启监听usb设备
+- (void)m8HidDataError{
+    [self.hid open];
+}
+
+/// 输出sdk日志
+/// - Parameter log: 日志
+- (void)m8MouseAddLog:(NSString *)log{
+    [self showLog:log];
+}
+
 #pragma mark - other
 - (void)showLog:(NSString *)log{
 //    if (self.aiMouseAddLogCallBack) {
index fde3c58..294da9e 100644 (file)
@@ -288,14 +288,6 @@ static void hidReceiveData(void* context, IOReturn result, void* sender, IOHIDRe
     if(self.logCallBack) self.logCallBack(text);
 }
 
-///// 实际到数据长度
-//static inline int get_data_len(uint8_t *buf, u_long len) {
-//    if (len <= 0 ) return 0;
-//    int url_len = 0;
-//    while (buf[url_len] != 0x00) url_len++;
-//    return url_len;
-//}
-
 /// 实际到数据长度
 static inline int get_data_len(uint8_t *buf, int len) {
     if (len <= 0 ) return 0;
index 556807b..a0267d1 100644 (file)
@@ -32,7 +32,7 @@
 //        [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
 //        [[NSRunLoop currentRunLoop] run];
 //    });
-    self.timer = [NSTimer scheduledTimerWithTimeInterval:5 target:self selector:@selector(timerAction) userInfo:nil repeats:true];
+    self.timer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(timerAction) userInfo:nil repeats:true];
 }
 
 - (void)timerAction{
index 7b99edf..bc0c02b 100644 (file)
Binary files a/MouseSdk/MouseSdk.xcworkspace/xcuserdata/yaozuopan.xcuserdatad/UserInterfaceState.xcuserstate and b/MouseSdk/MouseSdk.xcworkspace/xcuserdata/yaozuopan.xcuserdatad/UserInterfaceState.xcuserstate differ
index 81258ac..51ba4e0 100644 (file)
@@ -5,15 +5,35 @@
    version = "2.0">
    <Breakpoints>
       <BreakpointProxy
-         BreakpointExtensionID = "Xcode.Breakpoint.ExceptionBreakpoint">
+         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
          <BreakpointContent
-            uuid = "B13C82BB-F468-4E93-A44A-F14FFAD4D10D"
+            uuid = "3FEEA307-9A37-4E1D-83CF-48F35AD81EF6"
             shouldBeEnabled = "Yes"
             ignoreCount = "0"
             continueAfterRunningActions = "No"
-            breakpointStackSelectionBehavior = "1"
-            scope = "1"
-            stopOnStyle = "0">
+            filePath = "AiMouseSdk/M8/M8MouseSdk.m"
+            startingColumnNumber = "9223372036854775807"
+            endingColumnNumber = "9223372036854775807"
+            startingLineNumber = "59"
+            endingLineNumber = "59"
+            landmarkName = "-recordManager"
+            landmarkType = "7">
+         </BreakpointContent>
+      </BreakpointProxy>
+      <BreakpointProxy
+         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
+         <BreakpointContent
+            uuid = "7811129E-8425-43E8-9FDC-75B40C321EE5"
+            shouldBeEnabled = "Yes"
+            ignoreCount = "0"
+            continueAfterRunningActions = "No"
+            filePath = "AiMouseSdk/AiMouseSdk/AiAudioManager.m"
+            startingColumnNumber = "9223372036854775807"
+            endingColumnNumber = "9223372036854775807"
+            startingLineNumber = "52"
+            endingLineNumber = "52"
+            landmarkName = "-setupAudioDecoder"
+            landmarkType = "7">
          </BreakpointContent>
       </BreakpointProxy>
    </Breakpoints>
index 2dfccfa..decd0e0 100644 (file)
             }
         });
     }];
+    manager.aiMouseSendCmdDataCallBack = ^(NSString * _Nonnull data) {
+        NSLog(@"%@",[NSString stringWithFormat:@"按键指令 = %@",data]);
+    };
+    manager.recordingCallBack = ^(NSString * _Nonnull data) {
+        NSLog(@"%@",[NSString stringWithFormat:@"语音数据 = %@",data]);
+    };
 }
 
 
index c230d1a..30f1cdd 100644 (file)
@@ -7,12 +7,12 @@
                <key>Masonry.xcscheme_^#shared#^_</key>
                <dict>
                        <key>orderHint</key>
-                       <integer>2</integer>
+                       <integer>3</integer>
                </dict>
                <key>Pods-MouseSdk.xcscheme_^#shared#^_</key>
                <dict>
                        <key>orderHint</key>
-                       <integer>3</integer>
+                       <integer>4</integer>
                </dict>
        </dict>
 </dict>