// // BTDataProcessVC.m // Unity-iPhone // // Created by duowan123 on 2021/2/3. // #import "AFNetworking.h" #import "ZipArchive.h" #import "BTDataProcess.h" // #import "IOSPlatformSDK.h" //算法类 #import "AlgorithmTool.h" //systemte #define IOS_NSUSERDEFAULT [NSUserDefaults standardUserDefaults] #define CUS_NOTIFICATIONCENTER [NSNotificationCenter defaultCenter] //蓝牙提供的sdk算法 #import "GameObjc.h" #define LEFT_FOOT_OC 1 #define RIGHT_FOOT_OC 2 //动作数据 typedef NS_ENUM(NSInteger, GAME_MOTION) { MOTION_STOP =0, MOTION_RUN,// 跑 MOTION_JUMP, // 跳 MOTION_DOWN, // 蹲 MOTION_LEFT, // 滑左 MOTION_RIGHT, // 滑右 MOTION_FRONT, // 滑前 MOTION_BACK, // 滑后 MOTION_LEFT_UP, // 点击-左上 MOTION_LEFT_DOWN, // 点击-左下 MOTION_RIGHT_UP, // 点击-右上 MOTION_RIGHT_DOWN, // 点击-右下 MOTION_STEP, // 点击-原地踩 NUMBERS_OF_MOTION }; //蓝牙状态 typedef NS_ENUM(NSInteger, BLETOOTH_STUTAS){ CONNECT_DIS =0, // 未链接 CONNECT_ING , //链接中 CONNECT_ED,// 已链接 CONNECT_LOST, // 丢失链接 /链接失败 }; @interface BTDataProcess () @property (strong, nonatomic)NSMutableArray * deviceArray; /**< 蓝牙设备个数 */ @property (nonatomic,strong)IOSPlatformSDK * sdk;// ios_sdk @property (nonatomic,strong)GameObjc * game ;//主设备蓝牙算法sdk @property (nonatomic,strong)GameObjc * viceDeviceGame ;//副设备设备蓝牙算法sdk @property(nonatomic,weak)NSTimer * timer;//定时器 定时请求主、副设备电量 //是否在游戏模式 @property(nonatomic,assign)BOOL gameModel; //调试框 @property (nonatomic,strong)UILabel * testLabel; //当前的时间戳+丢包 @property (nonatomic,assign)int tempTs; @property (nonatomic,assign)int loss; @property (nonatomic,assign)int totalPackages; //缓存plist @property (nonatomic,strong)NSMutableArray * dataArr; @property (nonatomic,strong)NSString * dataString; @end @implementation BTDataProcess #pragma mark ===============================================>> 静态的初始化方法 init的时候(建立蓝牙中心管理类,设置代理) //单例静态 static BTDataProcess* instance = nil; +(instancetype)sharedInstance{ // NSLog(@"创建单例一次 1"); return [[self alloc] init]; } + (instancetype)allocWithZone:(struct _NSZone *)zone{ // NSLog(@"创建单例一次 2"); static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ instance = [super allocWithZone:zone]; }); return instance; } - (instancetype)init{ // NSLog(@"创建单例一次 3"); static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ instance = [super init]; [self initNotification]; }); return instance; } //监听所有通知 -(void)initNotification{ //默认游戏模式关 self.gameModel = NO; //监听unity --> 开始游戏/结束游戏/震动 [CUS_NOTIFICATIONCENTER addObserver:self selector:@selector(gameStartInitData) name:@"gameStartInitData" object:nil]; [CUS_NOTIFICATIONCENTER addObserver:self selector:@selector(gameEndInitData:) name:@"gameEndInitData" object:nil]; [CUS_NOTIFICATIONCENTER addObserver:self selector:@selector(vibrationAction:) name:@"vibrationAction" object:nil]; //监听程序从后台返回 系统方法 [CUS_NOTIFICATIONCENTER addObserver:self selector:@selector(appBackForeground) name:UIApplicationWillEnterForegroundNotification object:nil]; //监听 app group 消息 CFStringRef strRef = (__bridge CFStringRef)@"DISCONNECT_BLE"; CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, disConnectBle, strRef, NULL, CFNotificationSuspensionBehaviorDeliverImmediately); [self inittestLabel]; } //趣动APP吊起 发送通知->断开游戏的所有的蓝牙连接 (C语言函数) //C语言函数内 只能用指针instance调用实例不能用self void disConnectBle (CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo){ [instance disConnedctBle]; } //断开蓝牙 -(void)disConnedctBle{ NSLog(@"BTDataProcess 通知断开蓝牙操作"); [LEManager cancelPeripheralConnection]; } //监听程序从后台返回 -(void)appBackForeground{ // NSLog(@"BTDataProcess 收到程序从后台返回 peripheral.state = %ld",LEManager.peripheral.state); if (LEManager.peripheral!=nil&&LEManager.peripheral.state != CBPeripheralStateConnected){//蓝牙不为空 且蓝牙断开链接(有三种情况) [self connectPeripheral:LEManager.peripheral];//蓝牙重链接 } if (LEManager.vicePeripheral!=nil&&LEManager.vicePeripheral.state != CBPeripheralStateConnected){//蓝牙不为空 且蓝牙断开链接 [self connectPeripheral:LEManager.vicePeripheral];//蓝牙重链接 } } //监听通知开始游戏 -(void)gameStartInitData{ NSLog(@"通知开始游戏 --> BTDataProcess"); self.gameModel = YES; //反馈->蓝牙sdk // [self.game start]; } //监听通知结束游戏 -(void)gameEndInitData:(NSNotification*)notification{ NSLog(@"通知结束游戏 --> BTDataProcess"); self.gameModel = NO; //反馈->蓝牙sdk // [self.game end]; } //监听通知震动 -(void)vibrationAction:(NSNotification*)notification{ //unity回调数据 NSDictionary * notificationDict = notification.userInfo; // NSLog(@"弹出视图事件notificationDict == %@",notificationDict); NSNumber * typeNumber = [notificationDict objectForKey:@"type"]; NSNumber * durationNumber = [notificationDict objectForKey:@"duration"]; int deviceType = [typeNumber intValue]; int duration = [durationNumber intValue]; // NSLog(@"通知游戏震动 --> BTDataProcess %d",deviceType); [self vibration:(DEVICE_TYPE)deviceType duration:duration]; //每次踩对就反馈->蓝牙sdk // [self.game isBingo]; } #pragma mark ============================================================== leon new manager //测试自己封装的蓝牙类 -(void)initCBCentralManager{ [LEManager initCBCentralManager]; LEManager.stateUpdateBlock = ^(CBCentralManager * central){ switch(central.state){ case 0: NSLog(@"当前的蓝牙状态 ==================================>> CBCentralManagerStateUnknown"); break; case 1: NSLog(@"当前的蓝牙状态 ==================================>> CBCentralManagerStateResetting"); break; case 2: NSLog(@"当前的蓝牙状态 ==================================>> CBCentralManagerStateUnsupported"); break; case 3: NSLog(@"当前的蓝牙状态 ==================================>> CBCentralManagerStateUnauthorized"); break; case 4:{ NSLog(@"当前的蓝牙状态 ==================================>> 蓝牙已关闭"); if (LEManager.peripheral!=nil){ [self.sdk bridgingDeviceAction:DEVICETYPE_MAIN name:LEManager.peripheral.name address:LEManager.peripheral.identifier.UUIDString status:CONNECT_LOST electricity:0]; } if (LEManager.vicePeripheral!=nil){ [self.sdk bridgingDeviceAction:DEVICETYPE_VICE name:LEManager.vicePeripheral.name address:LEManager.vicePeripheral.identifier.UUIDString status:CONNECT_LOST electricity:0]; } } break; case 5:{ NSLog(@"当前的蓝牙状态 ==================================>> 蓝牙已开启");//蓝牙已开启 //扫描蓝牙外设 [LEManager scanForPeripheralsWithServices:nil options:nil]; } break; default: break; } }; //扫描蓝牙外设 // [LEManager scanForPeripheralsWithServices:nil options:nil]; [self.deviceArray removeAllObjects]; //发现蓝牙 LEManager.discoverPeripheralBlock = ^(CBCentralManager * _Nonnull central, CBPeripheral * _Nonnull peripheral, NSDictionary * _Nonnull advertisementData, NSNumber * _Nonnull RSSI){ // NSLog(@"扫描发现蓝牙设备advertisementData = %@",advertisementData); if (peripheral.name.length>0&& [peripheral.name hasPrefix:@"SH_"]){//SH_DANCE BLE_LOOP Shoes_4530 Shoes_2A74 // NSLog(@"主设备扫描发现有效的蓝牙设备 =============== %@ identifier == %@",peripheral.name,peripheral.identifier.UUIDString); if (self.deviceArray.count == 0){//数据源为0 // NSLog(@"add 扫描发现蓝牙设备 %@",peripheral.name); [self.deviceArray addObject:peripheral]; //判断扫描到外设之后是否要链接蓝牙 [self ifAppJumpWithIdentifier:peripheral]; }else{ BOOL isExist = NO; for (int i = 0; i < self.deviceArray.count; i++){ CBPeripheral *per = [self.deviceArray objectAtIndex:i]; if ([per.identifier.UUIDString isEqualToString:peripheral.identifier.UUIDString]){ isExist = YES; [self.deviceArray replaceObjectAtIndex:i withObject:peripheral]; } } if (!isExist){ [self.self.deviceArray addObject:peripheral]; //判断扫描到外设之后是否要链接蓝牙 [self ifAppJumpWithIdentifier:peripheral]; } } //数据回调给 搜索蓝牙弹窗 if (self.deviceArrBLock != nil){ self.deviceArrBLock(self.deviceArray); } } }; } #pragma mark ===============================================>> 主设备蓝牙数据 //是否是app跳转传参 区分app跳转和弹窗搜索 type=0的时候才会执行该方法 type=0的时候才会执行该方法 当时弹框的时候type==1 不执行该方法 -(void)ifAppJumpWithIdentifier:(CBPeripheral*)peripheral{ if (self.macAddress!=nil && [peripheral.identifier.UUIDString isEqualToString:self.macAddress]){//app跳转过来 主动链接蓝牙 [self connectPeripheral:peripheral]; } } #pragma mark ===============================================>> 链接蓝牙设备公用方法 可外部操作 //app跳转或选中tableview 链接蓝牙 -(void)connectPeripheral:(CBPeripheral*)peripheral{ if(instance!=NULL && peripheral!=NULL){ self.sdk = [IOSPlatformSDK sharedInstance];//蓝牙数据经过sdk数据转换后 ios call unity //app游戏列表id转为bobo sdk需要的游戏id switch (self.game_id){ case 1://跳舞 self.game_id = 2; break; case 2://赛达尔传说 self.game_id = 3; break; case 3://跑酷 self.game_id = 1; break; case 4://测试demo self.game_id = 2; break; default: break; } // self.deviceType = DEVICETYPE_VICE; self.game_id = 2; NSLog(@" connectPeripheral self.deviceType ==>> %ld self.game_id ==>> %d",(long)self.deviceType,self.game_id); //初始化运轨sdk if (self.deviceType==DEVICETYPE_MAIN){ LEManager.peripheral = peripheral; self.game = [[GameObjc alloc] initWithGametype:self.game_id]; }else if (self.deviceType == DEVICETYPE_VICE){ LEManager.vicePeripheral = peripheral; self.viceDeviceGame = [[GameObjc alloc] initWithGametype:self.game_id]; } //根据ios_sdk传入deviceType 链接 主/副 设备 [self connectBLEManagerData:peripheral deviceType:self.deviceType]; } } //链接主副设备 + 绑定特征 -(void)connectBLEManagerData:(CBPeripheral*)peripheral deviceType:(DEVICE_TYPE)deviceType{ //链接蓝牙 此时 LEManager.peripheral || LEManager.vicePeripheral 还未init [LEManager connectPeripheral:peripheral options:nil]; //发现服务和特征 LEManager.discoverCharacteristicsBlock = ^(CBPeripheral * _Nonnull peripheral, CBService * _Nonnull service, NSArray * _Nonnull characteristics, NSError * _Nonnull error){ if (peripheral==LEManager.peripheral&&deviceType==DEVICETYPE_MAIN){//主设备 for (CBCharacteristic * cha in service.characteristics){ if (cha.properties == 12){//写 LEManager.write = cha; [self initGameAction:DEVICETYPE_MAIN]; }else if (cha.properties == 16){//读 LEManager.read = cha; [LEManager.peripheral readValueForCharacteristic:cha]; [LEManager.peripheral setNotifyValue:YES forCharacteristic:cha]; } } }else if (peripheral==LEManager.vicePeripheral&&deviceType==DEVICETYPE_VICE){//副设备 for (CBCharacteristic * cha in service.characteristics){ if (cha.properties == 12){//写 LEManager.viceWrite = cha; [self initGameAction:DEVICETYPE_VICE]; }else if (cha.properties == 16){//读 LEManager.viceRead = cha; [LEManager.vicePeripheral readValueForCharacteristic:cha]; [LEManager.vicePeripheral setNotifyValue:YES forCharacteristic:cha]; } } } }; //读取特征的报文数据 LEManager.readValueForCharacteristicBlock = ^(CBPeripheral * _Nonnull peripheral, CBCharacteristic * _Nonnull characteristic, NSData * _Nonnull value, NSError * _Nonnull error, DEVICE_TYPE type){ if ([characteristic.UUID.UUIDString isEqualToString:@"6E400003-B5A3-F393-E0A9-E50E24DCCA9E"]){//判断是不是我们设备的特征值 // NSLog(@"characteristic.UUID.UUIDString = %@",characteristic.UUID.UUIDString); [self verifyData:characteristic deviceType:type]; } }; // //写入数据的回调 暂时用不到 // LEManager.writeToCharacteristicBlock = ^(CBPeripheral * _Nonnull peripheral,CBCharacteristic * _Nonnull characteristic, NSError * _Nonnull error, DEVICE_TYPE type) // }; } //启动定时器 -(void)initGameAction:(DEVICE_TYPE)deviceType{ //每次链接成功后 开启游戏模式 初始化步数数据 立马查询一次设备信息 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(),^{ if (deviceType==DEVICETYPE_MAIN){ [self startGameModel:DEVICETYPE_MAIN]; [self queryDevideInfo]; self.jump_count = 0; self.crouch_count = 0; self.step_count = 0; }else if (deviceType ==DEVICETYPE_VICE){ [self startGameModel:DEVICETYPE_VICE]; [self queryDevideInfo]; } }); //之后开启启定时器查询电量 一分钟查询一次 self.timer = [NSTimer scheduledTimerWithTimeInterval:60 target:self selector:@selector(queryDevideInfo) userInfo:nil repeats:YES]; } //报文数据 长度+校验位 校验 -(void)verifyData:(CBCharacteristic*)characteristic deviceType:(DEVICE_TYPE)deviceType{ if (characteristic.value.length>3){ //带cmd位的有效数据 计算校验位 if ([AlgorithmTool verificationRusult:characteristic.value]==YES){ [self analysisCharacteristic:characteristic.value deviceType:deviceType]; } }else{ NSLog(@"无效报文"); } } //报文数据解析 -(void)analysisCharacteristic:(NSData*)characteristic deviceType:(DEVICE_TYPE)deviceType{ // NSLog(@"接收到的数据data = %@",characteristic); int frameHead = [AlgorithmTool dataToChar:[characteristic subdataWithRange:NSMakeRange(0, 1)]];//帧头数据aa int messageLength = [AlgorithmTool dataToChar:[characteristic subdataWithRange:NSMakeRange(1, 1)]];//报文长度 int messageLengthNegation = ~messageLength;//报文长度取反 int dataType = [AlgorithmTool dataToChar:[characteristic subdataWithRange:NSMakeRange(3, 1)]];//cmd类型 if (dataType == 4 && characteristic.length == 60){//获取主动推过来的数据 //右脚坐标数据 int right_X = [AlgorithmTool dataToSwapBigIntToHost:characteristic andRange:NSMakeRange(4, 4)]; int right_Y = [AlgorithmTool dataToSwapBigIntToHost:characteristic andRange:NSMakeRange(8, 4)]; int right_Z = [AlgorithmTool dataToSwapBigIntToHost:characteristic andRange:NSMakeRange(12, 4)]; int right_pos[3] = {right_X,right_Y,right_Z}; //左脚坐标数据 int left_X = [AlgorithmTool dataToSwapBigIntToHost:characteristic andRange:NSMakeRange(16, 4)]; int left_Y = [AlgorithmTool dataToSwapBigIntToHost:characteristic andRange:NSMakeRange(20, 4)]; int left_Z = [AlgorithmTool dataToSwapBigIntToHost:characteristic andRange:NSMakeRange(24, 4)]; int left_pos[3] = {left_X,left_Y,left_Z}; //右脚姿势数据 short righrPosture_X = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(28, 2)]; short righrPosture_Y = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(30, 2)]; short righrPosture_Z = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(32, 2)]; int right_att[3] = {righrPosture_X,righrPosture_Y,righrPosture_Z}; //左脚姿势数据 short leftPosture_X = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(34, 2)]; short leftPosture_Y = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(36, 2)]; short leftPosture_Z = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(38, 2)]; int left_att[3] = {leftPosture_X,leftPosture_Y,leftPosture_Z}; //右脚三维数据 short righrAcc_x = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(40, 2)]; short righrAcc_Y = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(42, 2)]; short righrAcc_z = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(44, 2)]; int righrAcc[3] = {righrAcc_x,righrAcc_Y,righrAcc_z}; //左脚三维数据 short leftAcc_x = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(46, 2)]; short leftAcc_y = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(48, 2)]; short leftAcc_z = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(50, 2)]; int left_acc[3] = {leftAcc_x,leftAcc_y,leftAcc_z}; //左脚、右脚、蹲 、跳四个动作信息数据 int actionInformation = [AlgorithmTool dataToChar:[characteristic subdataWithRange:NSMakeRange(52, 1)]];;//0c 16进制字符串 int girlShoes = actionInformation & 16; if (girlShoes!=0){ girlShoes=1; }else{ girlShoes=0; } int rightZupt = actionInformation & 8; if (rightZupt!=0){ rightZupt=1; }else{ rightZupt=0; } int leftZupt = actionInformation & 4; if (leftZupt!=0){ leftZupt=1; }else{ leftZupt=0; } int down = actionInformation & 2; if (down!=0){ down=1; }else{ down=0; } int jump = actionInformation & 1; if (jump!=0){ jump=1; }else{ jump=0; } int rssi = [AlgorithmTool dataToChar:[characteristic subdataWithRange:NSMakeRange(53, 1)]];//rssi 信号强度 int ts = [AlgorithmTool dataToChar:[characteristic subdataWithRange:NSMakeRange(54, 1)]];;//ts 时间戳 int right_press = [AlgorithmTool dataToInt:[characteristic subdataWithRange:NSMakeRange(55, 2)]];//3 29新增 右鞋压力 int left_press = [AlgorithmTool dataToInt:[characteristic subdataWithRange:NSMakeRange(57, 2)]];//3 29新增 左鞋压力 int frameCheck = [AlgorithmTool dataToChar:[characteristic subdataWithRange:NSMakeRange(59, 1)]];//校验位 if (deviceType==DEVICETYPE_MAIN){//主设备 //调取鞋子SDK [self shoseSDKRight_pos:right_pos Right_att:right_att LeftPos:left_pos Left_att:left_att ts:ts rightZupt:rightZupt leftZupt:leftZupt jump:jump down:down rssi:rssi girlShoes:girlShoes right_press:right_press left_press:left_press]; }else if (deviceType==DEVICETYPE_VICE){//副设备动作数据 //调取鞋子SDK [self viceShoseSDKRight_pos:right_pos Right_att:right_att LeftPos:left_pos Left_att:left_att ts:ts rightZupt:rightZupt leftZupt:leftZupt jump:jump down:down rssi:rssi girlShoes:girlShoes right_press:right_press left_press:left_press]; } }else if (dataType == -95){//获取的是查询的数据 char-->int a1 = -95 if (characteristic.length == 74){//A1+0 >> 0: 设备基本信息 ==>> 预留参数 趣动app用 sdk暂未调用 // NSString *deviceModel = [[NSString alloc] initWithData:[characteristic subdataWithRange:NSMakeRange(5, 18)] encoding:NSUTF8StringEncoding]; // NSString *softwareVer = [AlgorithmTool hexadecimalString:[characteristic subdataWithRange:NSMakeRange(69, 2)]];//0102 // NSString *hardwareVer = [AlgorithmTool hexadecimalString:[characteristic subdataWithRange:NSMakeRange(71, 2)]];//0104 }else if (characteristic.length == 26){//A1+1 >> 1: 设备数据(左鞋,右鞋) aa 14 eb a1 01 64 00 1a 0000981d 64 00 17 00000000 f9 int leftElectricity = [AlgorithmTool dataToInt:[characteristic subdataWithRange:NSMakeRange(5, 1)]]; // int leftTempreature = [AlgorithmTool dataToInt:[characteristic subdataWithRange:NSMakeRange(6, 1)]]; // int leftPressure = [AlgorithmTool dataToInt:[characteristic subdataWithRange:NSMakeRange(7, 4)]]; // int leftStepCount = [AlgorithmTool dataToInt:[characteristic subdataWithRange:NSMakeRange(11, 4)]]; // int rightElectricity = [self dataToInt:[characteristic subdataWithRange:NSMakeRange(12, 1)]]; int rightElectricity = [AlgorithmTool dataToInt:[characteristic subdataWithRange:NSMakeRange(15, 1)]];//龙哥新协议 // int rightTempreature = [AlgorithmTool dataToInt:[characteristic subdataWithRange:NSMakeRange(16, 1)]]; // int rightPressure = [AlgorithmTool dataToInt:[characteristic subdataWithRange:NSMakeRange(17, 4)]]; // int rightStepCount = [AlgorithmTool dataToInt:[characteristic subdataWithRange:NSMakeRange(21, 4)]]; NSLog(@"接收到的数据data 26 = %@ 电量 %d %d",characteristic,leftElectricity,rightElectricity); if (deviceType==DEVICETYPE_MAIN){//主设备 //主 设备定时器 60秒调一次 /******************ios call unity*****************/ [self.sdk bridgingDeviceAction:DEVICETYPE_MAIN name:LEManager.peripheral.name address:LEManager.peripheral.identifier.UUIDString status:CONNECT_ED electricity:leftElectricity<=rightElectricity?leftElectricity:rightElectricity]; }else if (deviceType==DEVICETYPE_VICE){//副设备 //副 设备定时器 60秒调一次 /******************ios call unity*****************/ [self.sdk bridgingDeviceAction:DEVICETYPE_VICE name:LEManager.vicePeripheral.name address:LEManager.vicePeripheral.identifier.UUIDString status:CONNECT_ED electricity:leftElectricity<=rightElectricity?leftElectricity:rightElectricity]; } } } } //报文数据解析后 -- 调用蓝牙鞋子SDK装换数据 -- ios call unity 更新游戏动作 -(void)shoseSDKRight_pos:(int[3])right_pos Right_att:(int[3])right_att LeftPos:(int[3])left_pos Left_att:(int[3])left_att ts:(int)ts rightZupt:(int)rightZupt leftZupt:(int)leftZupt jump:(int)jump down:(int)down rssi:(int)rssi girlShoes:(int)girlShoes right_press:(int)right_press left_press:(int)left_press{ /********************初始化 运动轨迹算法 SDK *****************/ [self.game gameProcess:ts rightPos:right_pos rightAtt:right_att rightZupt:rightZupt right_press:right_press leftPos:left_pos leftAtt:left_att leftZupt:leftZupt left_press:left_press jump:jump down:down rssi:rssi girl_shoes:girlShoes]; int length = 4; int result[length]; [self.game getGameResult:result]; // NSLog(@"result == %d %d %d %d \n",result[0],result[1],result[2],result[3]); /******************步频数据处理 + 回调*****************/ int leftStepStatus = [self.game getStepStatus:LEFT_FOOT_OC]; int leftStepFreq = [self.game getStepFreq:LEFT_FOOT_OC]; int leftStepCount = [self.game getStepCount:LEFT_FOOT_OC]; int rightStepStatus = [self.game getStepStatus:RIGHT_FOOT_OC]; int rightStepFreq = [self.game getStepFreq:RIGHT_FOOT_OC]; int rightStepCount = [self.game getStepCount:RIGHT_FOOT_OC]; //ios call unity // [self.sdk bridgingStepAction:DEVICETYPE_MAIN leftStatus:leftStepStatus rightStatus:rightStepStatus leftFrag:leftStepFreq rightFrag:rightStepFreq];//左右脚速度 步频 //数据回调缓存 if (self.allMotionCountBLock){ self.step_count = leftStepCount+rightStepCount; self.allMotionCountBLock(self.jump_count, self.crouch_count, leftStepCount+rightStepCount); } /******************左右脚动作数据处理 + 回调*****************/ int motionLeft = result[0];//左脚的动作 int motionRight = result[1];//右脚的动作 int motionJump = result[2];//jump int motionDown = result[3];//down // if (motionLeft==-1 && motionRight == -1&& motionJump == -1&& motionDown == -1){//无效动作 // return; // }else{ //跳跃和蹲下的动作 双脚是同步的 if (motionJump == MOTION_JUMP){ motionLeft = motionJump; motionRight = motionJump; self.jump_count++; NSLog(@" 主设备 ================================== 跳起来 "); } if (motionDown == MOTION_DOWN){ motionLeft = motionDown; motionRight = motionDown; self.crouch_count++; NSLog(@" 主设备 =================================== 蹲下去 "); } //ios call unity // if (self.gameModel==YES){//当前是游戏模式 [self.sdk bridgingMotionAction:DEVICETYPE_MAIN left:motionLeft right:motionRight];//左右脚动作 // }else{//当前是交互模式 // int interaction = [self.game getInteractionCMD]; // [self.sdk bridgingInteraction:DEVICETYPE_MAIN code:interaction]; // } // } // int difference = abs(ts) - abs(self.tempTs); //当前丢包数>2算作丢包 if (abs(difference)>=2){ self.loss = self.loss + abs(difference)-1; self.totalPackages = self.totalPackages+abs(difference); // NSLog(@"总数据包 1== >> self.totalPackages %d",self.totalPackages); }else{ self.totalPackages++; // NSLog(@"总数据包 2== >> self.totalPackages %d",self.totalPackages); } self.tempTs = abs(ts); // NSLog(@"收到数据包 ===================>> ts: %d 当前包LOSS: %d 总包数: %d 总LOSS: %d",ts,abs(difference),self.totalPackages,self.loss); // self.testLabel.text = [NSString stringWithFormat:@"数据:[%d,%d,%d,%d] RSSI: %d 总包数: %d 总丢包: %d",result[0],result[1],result[2],result[3],rssi,self.totalPackages,self.loss]; self.testLabel.text = [NSString stringWithFormat:@"数据:[%d,%d,%d,%d] RSSI: %d 总包数: %d 总丢包: %d",motionLeft,motionRight,motionJump,motionDown,rssi,self.totalPackages,self.loss]; //写入沙盒数据 // [self.dataArr addObject:[NSString stringWithFormat:@"数据:[%d,%d,%d,%d] RSSI: %d 总包数: %d 总丢包: %d",motionLeft,motionRight,motionJump,motionDown,rssi,self.totalPackages,self.loss]]; self.dataString = [NSString stringWithFormat:@"%@\n数据:[%d,%d,%d,%d] RSSI: %d 总包数: %d 总丢包: %d",self.dataString,motionLeft,motionRight,motionJump,motionDown,rssi,self.totalPackages,self.loss]; [self writeFileToplist]; } //报文数据解析后 -- 调用蓝牙鞋子SDK装换数据 -- ios call unity 更新游戏动作 -(void)viceShoseSDKRight_pos:(int[3])right_pos Right_att:(int[3])right_att LeftPos:(int[3])left_pos Left_att:(int[3])left_att ts:(int)ts rightZupt:(int)rightZupt leftZupt:(int)leftZupt jump:(int)jump down:(int)down rssi:(int)rssi girlShoes:(int)girlShoes right_press:(int)right_press left_press:(int)left_press{ /********************运轨数据初始化*****************/ [self.viceDeviceGame gameProcess:ts rightPos:right_pos rightAtt:right_att rightZupt:rightZupt right_press:right_press leftPos:left_pos leftAtt:left_att leftZupt:leftZupt left_press:left_press jump:jump down:down rssi:rssi girl_shoes:girlShoes]; int length = 4; int result[length]; [self.viceDeviceGame getGameResult:result]; // NSLog(@"result == %d %d %d %d \n",result[0],result[1],result[2],result[3]); /********************蓝牙sdk返回的鞋子 状态 步频 步数*****************/ int leftStepStatus = [self.viceDeviceGame getStepStatus:LEFT_FOOT_OC]; int leftStepFreq = [self.viceDeviceGame getStepFreq:LEFT_FOOT_OC]; // int leftStepCount = [self.viceDeviceGame getStepCount:LEFT_FOOT_OC]; int rightStepStatus = [self.viceDeviceGame getStepStatus:RIGHT_FOOT_OC]; int rightStepFreq = [self.viceDeviceGame getStepFreq:RIGHT_FOOT_OC]; // int rightStepCount = [self.viceDeviceGame getStepCount:RIGHT_FOOT_OC]; //ios call unity [self.sdk bridgingStepAction:DEVICETYPE_VICE leftStatus:leftStepStatus rightStatus:rightStepStatus leftFrag:leftStepFreq rightFrag:rightStepFreq];//副设备左右脚速度 步频 /********************蓝牙sdk返回的鞋子 动作*****************/ int motionLeft = result[0];//左脚的动作 int motionRight = result[1];//右脚的动作 int ivce_motionJump = result[2];//jump int ivce_motionDown = result[3];//down if (motionLeft==-1 && motionRight == -1&& ivce_motionJump == -1&& ivce_motionDown == -1){//无效动作 return; }else{ //跳跃和蹲下的动作 双脚是同步的 if (ivce_motionJump == MOTION_JUMP){ motionLeft = ivce_motionJump; motionRight = ivce_motionJump; NSLog(@"副设备 ======================================== 跳起来 jump_count = %d ",self.jump_count); } if (ivce_motionDown == MOTION_DOWN){ motionLeft = ivce_motionDown; motionRight = ivce_motionDown; NSLog(@"副设备 ========================================= 蹲下去 crouch_count = %d ",self.crouch_count); } //ios call unity as相互NX你· [self.sdk bridgingMotionAction:DEVICETYPE_VICE left:motionLeft right:motionRight];//副设备左右脚动作 } } #pragma mark ===============================================>> 蓝牙发送各类数据 //查询设备信息 - (void)queryDevideInfo{ //头帧AA + 数据长度 + 长度取反 + cmd + 数据 + 校验 NSMutableData * writeData = [NSMutableData new]; Byte header = 0xaa; Byte length = 0x06;//长度A1->6 A2->5 A3->7 Byte lengthNegation = ~length; Byte cmd = 0xA1; Byte data = 0x1; Byte byte[] = {header,length,lengthNegation,cmd,data}; writeData = [[NSMutableData alloc] initWithBytes:byte length:sizeof(byte)]; // [writeData appendData:msData]; Byte bcc = [AlgorithmTool byteSumBBC:writeData]; [writeData appendBytes:&bcc length:sizeof(bcc)]; if (LEManager.peripheral!=nil){ NSLog(@"发送的报文 主设备查询设备信息 %@", writeData); [LEManager writeValue:writeData forCharacteristic:LEManager.write writeType:CBCharacteristicWriteWithResponse deviceType:DEVICETYPE_MAIN]; } if (LEManager.vicePeripheral!=nil){ NSLog(@"发送的报文 副设备查询设备信息 %@", writeData); [LEManager writeValue:writeData forCharacteristic:LEManager.viceWrite writeType:CBCharacteristicWriteWithResponse deviceType:DEVICETYPE_VICE]; } } //打开游戏模式 - (void)startGameModel:(DEVICE_TYPE)type{ //头帧AA + 数据长度 + 长度取反 + cmd + 数据 + 校验 NSMutableData * writeData = [NSMutableData new]; Byte header = 0xaa; Byte length = 0x06;//长度A1->6 A2->5 A3->7 Byte lengthNegation = ~length; Byte cmd = 0xA2; Byte data = 0x1; //计算校验位 Byte byte[] = {header,length,lengthNegation,cmd,data}; writeData = [[NSMutableData alloc] initWithBytes:byte length:sizeof(byte)]; Byte bcc = [AlgorithmTool byteSumBBC:writeData]; //传输数据 -->> NSData [writeData appendBytes:&bcc length:sizeof(bcc)]; if (type==DEVICETYPE_MAIN&&LEManager.peripheral!=nil){ NSLog(@"发送的报文 主设备开启游戏模式: %@", writeData); [LEManager writeValue:writeData forCharacteristic:LEManager.write writeType:CBCharacteristicWriteWithResponse deviceType:DEVICETYPE_MAIN]; } if (type == DEVICETYPE_VICE&&LEManager.vicePeripheral!=nil){ NSLog(@"发送的报文 副设备开启游戏模式: %@", writeData); [LEManager writeValue:writeData forCharacteristic:LEManager.viceWrite writeType:CBCharacteristicWriteWithResponse deviceType:DEVICETYPE_VICE]; } } //设置震动 - (void)vibration:(DEVICE_TYPE)deviceType duration:(int)duration{ //头帧AA + 数据长度 + 长度取反 + cmd + 数据 + 校验 NSMutableData * writeData = [NSMutableData new]; Byte header = 0xaa; Byte length = 0x07;//长度A1->6 A2->5 A3->7 Byte lengthNegation = ~length; Byte cmd = 0xA4; //振动时间 2字节 short ms = 400;//400毫秒 Byte mslow = (Byte) (0x00FF & ms);//定义第一个byte Byte mshigh = (Byte) (0x00FF & (ms>>8));//定义第二个byte //计算校验位 Byte bytes[] = {header,length,lengthNegation,cmd,mshigh,mslow}; Byte bcc = [AlgorithmTool bbcByte:bytes]; //传输数据 Byte -->> NSData Byte newByte[] = {header,length,lengthNegation,cmd,mshigh,mslow,bcc}; writeData = [[NSMutableData alloc] initWithBytes:newByte length:sizeof(newByte)]; if (deviceType==DEVICETYPE_MAIN){ NSLog(@"发送的报文 主 设备震动 %@", writeData); [LEManager writeValue:writeData forCharacteristic:LEManager.write writeType:CBCharacteristicWriteWithResponse deviceType:DEVICETYPE_MAIN]; }else if (deviceType == DEVICETYPE_VICE){ NSLog(@"发送的报文 副 设备震动 %@", writeData); [LEManager writeValue:writeData forCharacteristic:LEManager.viceWrite writeType:CBCharacteristicWriteWithResponse deviceType:DEVICETYPE_VICE]; } } #pragma mark ===============================================>> 懒加载 -- 蓝牙设备数据源 -(NSMutableArray*)deviceArray{ if (!_deviceArray){ _deviceArray = [NSMutableArray new]; } return _deviceArray;; } #pragma mark ===============================================>> DEBUG -(void)inittestLabel{ self.testLabel = [[UILabel alloc] initWithFrame:CGRectMake(50, 0, [UIScreen mainScreen].bounds.size.width-100, 40)]; self.testLabel.textColor = [UIColor redColor]; self.testLabel.font = [UIFont boldSystemFontOfSize:20]; self.testLabel.backgroundColor = [UIColor clearColor]; self.testLabel.textAlignment = NSTextAlignmentCenter; self.testLabel.numberOfLines = 2; UIButton * uploadButton = [UIButton buttonWithType:UIButtonTypeCustom]; uploadButton.frame = CGRectMake([UIScreen mainScreen].bounds.size.width-100, 0, 50, 40); // uploadButton.backgroundColor = [UIColor redColor]; [uploadButton.titleLabel setTextColor:[UIColor redColor]]; [uploadButton setFont: [UIFont systemFontOfSize:20]]; [uploadButton setTitle:@"上传" forState:UIControlStateNormal]; [uploadButton addTarget:self action:@selector(uploadpPlistFile) forControlEvents:UIControlEventTouchUpInside]; UIViewController *rootVC = [[UIApplication sharedApplication].delegate window].rootViewController; UIViewController *parent = rootVC; while ((parent = rootVC.presentedViewController) != nil ){ rootVC = parent; } while ([rootVC isKindOfClass:[UINavigationController class]]){ rootVC = [(UINavigationController *)rootVC topViewController]; } // [rootVC addChildViewController:searchVC]; [rootVC.view addSubview:self.testLabel]; [rootVC.view addSubview:uploadButton]; self.dataArr = [NSMutableArray new]; } #pragma mark ===============================================>> 存储和上传数据 -(void)writeFileToplist{ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //获取完整路径 NSString *documentsDirectory = [paths objectAtIndex:0]; NSString *plistPath = [documentsDirectory stringByAppendingPathComponent:@"lossLog.txt"];//这里就是你将要存储的沙盒路径(.plist文件,名字自定义) if(![[NSFileManager defaultManager] fileExistsAtPath:plistPath]) {//plistPath这个文件\文件夹是否存在 NSLog(@"------1----- 写入 不 成功"); [self.dataString writeToFile:plistPath atomically:YES encoding:NSUTF8StringEncoding error:nil]; }else{ [self.dataString writeToFile:plistPath atomically:YES encoding:NSUTF8StringEncoding error:nil]; // NSLog(@"------2---- 写入 成功"); // NSLog(@"%@",plistPath); } } -(void)uploadpPlistFile{ //这个方法获取出的结果是一个数组.因为有可以搜索到多个路径. NSArray *array = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //在这里,我们指定搜索的是Cache目录,所以结果只有一个,取出Cache目录 NSString *documentsDirectory = array[0]; // NSLog(@"%@",documentsDirectory); //拼接文件路径 NSString *filePathName = [documentsDirectory stringByAppendingPathComponent:@"lossLog.txt"]; //如果保存的是一个数组.那就通过数组从文件当中加载. NSString *string = [NSString stringWithContentsOfFile:filePathName encoding:NSUTF8StringEncoding error:nil]; // NSLog(@"%@",string); //4.设置请求体 NSData *upData = [string dataUsingEncoding:NSUTF8StringEncoding]; // AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; manager.requestSerializer.timeoutInterval=15; [manager.requestSerializer setValue:@"multipart/form-data" forHTTPHeaderField:@"Content-Type"]; manager.requestSerializer = [AFJSONRequestSerializer serializer]; manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/plain",@"text/html",@"application/json",@"text/javascript",@"image/jpeg",@"image/png",@"application/octet-stream",@"application/x-www-form-urlencoded", nil]; // NSLog(@"请求URL ===================>> %@",urlString); NSLog(@"******************* 请求头参数 = %@ ***************************",manager.requestSerializer.HTTPRequestHeaders); AFHTTPSessionManager *sessionManager = [[AFHTTPSessionManager alloc] initWithBaseURL:nil]; [sessionManager POST:@"http://172.16.14.127:8080/upload" parameters:nil headers:nil constructingBodyWithBlock:^(id _Nonnull formData){ [formData appendPartWithFileData:upData name:@"file" fileName:[NSString stringWithFormat:@"loss%@.txt",[self getNowTimeTimestamp]] mimeType:@"text/plain"]; // [formData appendPartWithFileData:upData name:@"file" fileName:[NSString stringWithFormat:@"lossLog%@.txt",@"1"] mimeType:@"text/plain"]; }progress:^(NSProgress * _Nonnull uploadProgress){ NSLog(@"上传进度 = %@",uploadProgress); }success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject){ NSLog(@"上传成功"); }failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error){ for (NSString * key in error.userInfo){ if ([key isEqualToString:@"com.alamofire.serialization.response.error.data"]){ id errorObject = [NSJSONSerialization JSONObjectWithData:error.userInfo[key] options:1 error:nil]; NSLog(@"上传失败 ===>> %@",errorObject); } } }]; } //获取当前时间戳有两种方法(以秒为单位) -(NSString *)getNowTimeTimestamp{ NSDateFormatter *formatter = [[NSDateFormatter alloc] init] ; [formatter setDateStyle:NSDateFormatterMediumStyle]; [formatter setTimeStyle:NSDateFormatterShortStyle]; [formatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"]; // ----------设置你想要的格式,hh与HH的区别:分别表示12小时制,24小时制 //设置时区,这个对于时间的处理有时很重要 NSTimeZone* timeZone = [NSTimeZone timeZoneWithName:@"Asia/Shanghai"]; [formatter setTimeZone:timeZone]; NSDate *datenow = [NSDate date];//现在时间,你可以输出来看下是什么格式 NSString *timeSp = [NSString stringWithFormat:@"%ld", (long)[datenow timeIntervalSince1970]]; return timeSp; } @end