iOS使用BabyBluetooth进行蓝牙链接读写数据,分包拼包

这篇博客是把BabyBluetooth封装成了framework只供参考直接复制肯定不能使用的

#import <Foundation/Foundation.h>
#import <CoreBluetooth/CoreBluetooth.h>
#import <AudioToolbox/AudioToolbox.h>


#define channelOnPeropheral @"BleContectModelChannel"


NS_ASSUME_NONNULL_BEGIN

@interface BleContectModel : NSObject

@property(strong, nonatomic)FBluetooth *Fblue;//蓝牙类
@property __block NSMutableArray *services;//蓝牙服务数组
@property(strong,nonatomic)dispatch_source_t gcdTimer;
@property(strong,nonatomic)CBPeripheral *currPeripheral;//蓝牙硬件
@property(strong, nonatomic)NSMutableData *bluedata;
@property(strong, nonatomic)NSString *datelength;//返回数据长度计算
@property(strong, nonatomic)CBCharacteristic *writeCharacteristic;//写入特征
@property(assign, nonatomic)BOOL isKey;//是否是加密数据
@property(assign, nonatomic)BOOL blockIsSendData;//判断连接蓝牙后是否直接发送数据
@property(assign, nonatomic)BOOL timerIsRun;//判断定时器是否运行
@property(assign, nonatomic)NSInteger gcdIdx;
@property (nonatomic, copy) void(^block25)(void);//新设备绑定,发送手机号返回结果
@property (nonatomic, copy) void(^block23)(void);//新设备绑定,时间同步返回结果
@property (nonatomic, copy) void(^block36)(void);//新设备绑定,验证信道密码
@property (nonatomic, copy) void(^block34)(void);//新设备绑定,注册设备
@property (nonatomic, copy) void(^sendbindblock)(void);//新设备绑定,加密后block返回
@property (nonatomic, copy) void(^blueErrorBlock)(NSString *error);  //新设备绑定,蓝牙返回错误
@property (nonatomic, copy) void(^blueSendData)(void); //block 蓝牙返回的数据


//初始化
+ (instancetype)shared;
//发送cmd命令到蓝牙,并等待返回数据
+ (void)sendDatacmd:(NSString *)packetType
       packetLength:(NSString *)packetLength
                cmd:(NSString *)cmd
            payload:(NSString *)payload
           nativeId:(NSString *)nativeId
            success:(void (^)(NSString *msg))success
               fail:(void (^)(NSString *msg))fail;
//绑定设备
+ (void)bindBlowerDevice:(NSString *)phone success:(void (^)(NSString *msg))success fail:(void (^)(NSString *msg))fail;
+ (void)bisciddsex:(NSData *)data;
-(void)FblueDelegate:(NSString *)bind;
-(void)CBPeripheralManagerStatePoweredOn;

//  校验CRC
- (BOOL)checkCRC:(NSData *)didGetData;
// 断开后重连
-(void)beginscan;

@end

----------------------  .m文件 -----------------------

#import "BleContectModel.h"


#import "NSTimer+Addition.h"
#import "NoumenonModel.h"
#import "YUTimer.h"
#import "Common.h"
#import "DataMgr.h"
 


#define blueName @"蓝牙名字"
#define uuidStrHont0        @"自己的UUID"
#define uuidWrite           @"自己的UUID"
#define uuidNotify2         @"自己的UUID"
#define uuidHistoryNotify3  @"自己的UUID"

//#define blueName @"蓝牙名字"
//#define uuidStrHont @"自己的UUID"
//#define uuidOther   @"自己的UUID"
//#define uuidMOM     @"自己的UUID"

// 秘钥
uint8_t KeyaSph[16] =
{
};
uint8_t KeyTSph[16] =
{
};
//公钥 二进制文件
//uint8_t Key_ContcaSph[16] =
//{
//    0x07, 0xba, 0x06, 0xa7, 0x66, 0xcf, 0xfd, 0xa6, 0x3b, 0x58, 0xb9, 0x63, 0x97, 0x83, 0x75, 0x5F
//};

uint8_t Key_ContcaSph[16] =
{
    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16
};

@interface SphygmomanometerBleContectModel ()<CBPeripheralDelegate>
@property (nonatomic,strong) NSTimer* updateTimer;

@property (nonatomic,assign) BOOL isRepeat;
@property (nonatomic,assign) BOOL isCmd; //是否允许发送Cmd
@property (nonatomic , assign) int threeIndex; // 参数three标识 未了看log 定义标识
@property (nonatomic, strong) YUTimer *timerIndex;

@property (nonatomic , copy) NSString *TypeFour;//  参数配置分发:
@property (nonatomic , copy) NSString *modelFive; //模式
@property (nonatomic , copy) NSString *autoHandSix; // 0:自動/1:手動/FF:skip
@property (nonatomic , copy) NSString *flowSeven;
@property (nonatomic , copy) NSString *longShotEight;
@property (nonatomic , copy) NSString *otherNine;//

@property (nonatomic , copy) NSString *productKey; //16位随机数秘钥
@property (nonatomic, assign) int seqNumber;
@property (nonatomic, strong) NoumenonModel *model;


@property (nonatomic , strong) NSMutableData *subcontractData; // 分包接收 A6 数据
@property (nonatomic , assign) BOOL isTimeOut;
@property (nonatomic , copy) NSString *nativeId;
@property (nonatomic , assign) BOOL dataEnd; // 数据是否接收完成
@property (nonatomic , assign) BOOL oneFor; // 只遍历一次
@property (nonatomic , copy) NSString *packetType;
@property (nonatomic , copy) NSString *packetLength;
@property (nonatomic , assign) BOOL isSecret; // 是否是秘钥
@property (nonatomic , assign) int packLengthTmp;
@property (nonatomic , strong) NSMutableArray *pinArray;
@property (nonatomic , strong) CBCharacteristic *notify2Characteristic;
@property (nonatomic , strong) CBCharacteristic *notify3Characteristic;
@property (nonatomic , assign) BOOL onceRunning;
@end

@implementation SphygmomanometerBleContectModel

//重写init
- (instancetype)init {
    self = [super init];
    if (self) {
        self.seqNumber = 1;
        self.model = [[NoumenonModel alloc]init];
        //初始化对象
        _Fblue = [FBluetooth shareFBluetooth];
        [_Fblue cancelAllPeripheralsConnection];
        [_Fblue cancelScan];
        _Fblue.scanForPeripherals().begin();
        _gcdTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
        
        _oneFor = NO;
        _pinArray = [[NSMutableArray alloc]init];
        //        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(CBPeripheralManagerStatePoweredOn) name:@"CBPeripheralManagerStatePoweredOn" object:nil];
    }
    return self;
}
//监听蓝牙是否打开
-(void)CBPeripheralManagerStatePoweredOn{
    [_Fblue cancelAllPeripheralsConnection];
    _Fblue.scanForPeripherals().begin();
}
- (UIViewController *)findCurrentViewController
{
    UIWindow *window = [[UIApplication sharedApplication].delegate window];
    UIViewController *topViewController = [window rootViewController];
    
    while (true) {
        
        if (topViewController.presentedViewController) {
            
            topViewController = topViewController.presentedViewController;
            
        } else if ([topViewController isKindOfClass:[UINavigationController class]] && [(UINavigationController*)topViewController topViewController]) {
            
            topViewController = [(UINavigationController *)topViewController topViewController];
            
        } else if ([topViewController isKindOfClass:[UITabBarController class]]) {
            
            UITabBarController *tab = (UITabBarController *)topViewController;
            topViewController = tab.selectedViewController;
            
        } else {
            break;
        }
    }
    return topViewController;
}

- (NSMutableData *)subcontractData {
    if (_subcontractData == nil) {
        _subcontractData = [[NSMutableData alloc]init];
    }
    return _subcontractData;
}

//蓝牙的block
-(void)FblueDelegate:(NSString *)bind{
    
    self.isRepeat = YES;
    self.isCmd = NO;
    
    
    // ---- 500 毫秒 ----
    
    __weak typeof(self) weakSelf = self;
    [_Fblue setBlockOnCentralManagerDidUpdateState:^(CBCentralManager *central) {
        //手机蓝牙是否开启
        if (@available(iOS 10.0, *)) {
            if (central.state == CBManagerStatePoweredOff) {
                if (weakSelf.blueErrorBlock != nil) {
                    weakSelf.blueErrorBlock(@"请打开蓝牙开关");
                }
            }
        } else {
            
        }
    }];
    
    //设置扫描到设备的委托
    [_Fblue setBlockOnDiscoverToPeripherals:^(CBCentralManager *central, CBPeripheral *peripheral, NSDictionary *advertisementData, NSNumber *RSSI) {
        NSLog(@"搜索到了设备:%@",peripheral.name);
        
        [[NSNotificationCenter defaultCenter] postNotificationName:@"otherBleContentSuccess" object:nil userInfo:nil];
        
        if ([peripheral.name containsString:blueName]) {
            
            
            weakSelf.currPeripheral = peripheral;
            // 搜索到了设备就停止扫描
            [weakSelf.Fblue cancelScan];
            
            if ([bind isEqualToString:@"bind"]) {
                weakSelf.Fblue.having(weakSelf.currPeripheral).and.channel(channelOnPeropheral).then.connectToPeripherals().discoverServices().discoverCharacteristics().readValueForCharacteristic().discoverDescriptorsForCharacteristic().begin();
            } else {
                weakSelf.Fblue.having(weakSelf.currPeripheral).and.channel(channelOnPeropheral).then.connectToPeripherals().discoverServices().discoverCharacteristics().discoverDescriptorsForCharacteristic().begin();
            }
        }
    }];
    
    //设置查找设备的过滤器
    [_Fblue setFilterOnDiscoverPeripherals:^BOOL(NSString *peripheralName, NSDictionary *advertisementData, NSNumber *RSSI) {
        NSLog(@"搜索设备:%@",peripheralName);

        if ([peripheralName containsString:blueName]) {
            return YES;
        }
        return NO;
    }];
    
    NSDictionary *scanForPeripheralsWithOptions = @{CBCentralManagerScanOptionAllowDuplicatesKey:@YES};
    
    //设置设备连接成功的委托,同一个_Fblue对象,使用不同的channel切换委托回调
    [_Fblue setBlockOnConnectedAtChannel:channelOnPeropheral block:^(CBCentralManager *central, CBPeripheral *peripheral) {
        weakSelf.currPeripheral = peripheral;
        CBUUID *macServiceUUID = [CBUUID UUIDWithString:@"180A"];
        [peripheral discoverServices:@[macServiceUUID]];
        // PANAQBLE EH-XD30_B923 // 暂时 固定值 避免其他人连接 上传时把 B923删除 EH-XD30_B325是吹风机蓝牙名称
        NSLog(@"蓝牙名字:%@",peripheral.name);
        // liuwen bletest123
        if ([peripheral.name containsString:blueName]) {
            //            [[NSNotificationCenter defaultCenter] postNotification:[[NSNotification alloc]initWithName:@"deviceConnect" object:@"1" userInfo:nil]];
            //            [[NSUserDefaults standardUserDefaults] setObject:@"yes" forKey:@"deviceConnect"];
        }
    }];
    
    //设置设备连接失败的委托
    [_Fblue setBlockOnFailToConnectAtChannel:channelOnPeropheral block:^(CBCentralManager *central, CBPeripheral *peripheral, NSError *error) {
        NSLog(@"设备:%@--连接失败",peripheral.name);
        if ([peripheral.name containsString:blueName]) {
            
        }
    }];
    
    //设置设备断开连接的委托
    [_Fblue setBlockOnDisconnectAtChannel:channelOnPeropheral block:^(CBCentralManager *central, CBPeripheral *peripheral, NSError *error) {
        NSLog(@"设备:%@--断开连接",peripheral.name);
        // 想H5发送断开链接操作
        [[NSNotificationCenter defaultCenter] postNotificationName:@"SphygmomanometerBleDiscontect" object:nil userInfo:nil];
        weakSelf.updateTimer = nil;
        [weakSelf.updateTimer invalidate];
        weakSelf.currPeripheral = nil;
        weakSelf.writeCharacteristic = nil;
        weakSelf.timerIsRun = NO;
    }];
    
    //设置发现设service的Characteristics的委托 == old
    [_Fblue setBlockOnDiscoverCharacteristicsAtChannel:channelOnPeropheral block:^(CBPeripheral *peripheral, CBService *service, NSError *error) {
        NSLog(@"===service name:%@",service.UUID);
        NSLog(@"peripheral.name:%@",peripheral.name);
        //        weakSelf.writeCharacteristic = nil;
        if ([bind isEqualToString:@"bind"]) {


            if ([service.UUID.UUIDString isEqualToString:uuidStrHont0]) {
                // 00001C00-D102-11E2-9B23-000E5B00A5A5
                [weakSelf insertService:service];
            }
        } else {
            
        }
    }];
    
    NSDictionary *connectOptions = @{CBConnectPeripheralOptionNotifyOnConnectionKey:@YES,
                                     CBConnectPeripheralOptionNotifyOnDisconnectionKey:@YES,
                                     CBConnectPeripheralOptionNotifyOnNotificationKey:@YES};
    
    [_Fblue setFOptionsAtChannel:channelOnPeropheral scanForPeripheralsWithOptions:scanForPeripheralsWithOptions connectPeripheralWithOptions:connectOptions scanForPeripheralsWithServices:nil discoverWithServices:nil discoverWithCharacteristics:nil];
    
    [_Fblue setBlockOnDidWriteValueForCharacteristicAtChannel:channelOnPeropheral block:^(CBCharacteristic *characteristic, NSError *error) {
        NSLog(@"---\\????\\---%@", characteristic);
    }];
    
    [weakSelf.Fblue setBlockOnReadValueForCharacteristicAtChannel:channelOnPeropheral block:^(CBPeripheral *peripheral, CBCharacteristic *characteristic, NSError *error) {
        if ([[NSUserDefaults standardUserDefaults] objectForKey:@"bleMAC"] == nil) {
            if ([characteristic.UUID.UUIDString isEqualToString:@"2A23"]) {
                NSString *value = [NSString stringWithFormat:@"%@",characteristic.value];
                NSMutableString *macString = [[NSMutableString alloc] init];
                [macString appendString:[[value substringWithRange:NSMakeRange(12, 2)] uppercaseString]];
                [macString appendString:[[value substringWithRange:NSMakeRange(14, 2)] uppercaseString]];
                [macString appendString:[[value substringWithRange:NSMakeRange(16, 2)] uppercaseString]];
                [macString appendString:[[value substringWithRange:NSMakeRange(5, 2)] uppercaseString]];
                [macString appendString:[[value substringWithRange:NSMakeRange(7, 2)] uppercaseString]];
                [macString appendString:[[value substringWithRange:NSMakeRange(10, 2)] uppercaseString]];
                NSLog(@"macstring:%@", macString);
                [[NSUserDefaults standardUserDefaults] setObject:macString forKey:@"bleMAC"];
                if (self.sendbindblock != nil) {
                    weakSelf.sendbindblock();
                }
            } else {
                return;
            }
        }
    }];
}


- (void)timeer {
    __block NSInteger second = 0.8;
    //(1)
    dispatch_queue_t quene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //(2)
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, quene);
    //(3)
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
    //(4)
    dispatch_source_set_event_handler(timer, ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            if (second == 0) {
                //如果超时添加Bool值
                self.isCmd = YES;
                self.isRepeat = YES;
                dispatch_cancel(timer);
            } else {
                second--;
            }
        });
    });
    //(5)
    dispatch_resume(timer);
}
//#pragma mark - 轮循方法
//- (void)repeatData {
//    if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"deviceConnect"] isEqualToString:@"yes"]) {
//        if (self.updateTimer != nil) {
//            NSLog(@"轮循方法");
//            if (self.isRepeat == YES) {
//                // 发送数据
//                [SphygmomanometerBleContectModel sendDatacmd:@"A3" payload:@"" success:^(NSString * _Nonnull msg) {
//                    NSLog(@"%@",msg);
//                } fail:^(NSString * _Nonnull msg) {
//                    NSLog(@"%@",msg);
//                }];
//            }
//        }
//    }
//}
//遍历获取特征
-(void)insertService:(CBService *)service {
    
    for (int row=(int)service.characteristics.count-1;row>=0;row--) {
        NSLog(@"<<<<<<<<+++:%@", service.characteristics[row]);
        if ([service.characteristics[row].UUID.UUIDString isEqualToString:uuidWrite]) {
            _writeCharacteristic = service.characteristics[row];
        } else if ([service.characteristics[row].UUID.UUIDString isEqualToString:uuidNotify2]) {
            _notify2Characteristic = service.characteristics[row];
            // 去注册notify 一个notify服务,对应一个write服务,可以write的时候把notify的订阅开启,接收完把notify的订阅关掉
            // 关闭订阅的代码 [self->_Fblue cancelNotify:self.currPeripheral characteristic:characteristic];
            [self setnotif:service.characteristics[row]];
        } //最好把注册服务分开写
//        else if ([service.characteristics[row].UUID.UUIDString isEqualToString:uuidHistoryNotify3]) {
//            _notify3Characteristic = service.characteristics[row];
//            // 不去注册notify [注]
//            [self setnotif:service.characteristics[row]];
//        }
    }
    [self sendrandNums];
    _isSecret = YES;
}

//发送数据到蓝牙。需要处理分包发送,每次发送20字节
-(void)sendDatacmd:(NSString *)cmd payload:(NSString *)payload{
    if (self.currPeripheral == nil || _writeCharacteristic == nil) {
        return;
    }
    // 开订阅
    if (_notify2Characteristic != nil) {
        [self setnotif:_notify2Characteristic];
    }
    if (_notify3Characteristic != nil) {
        [self setnotif:_notify3Characteristic];
    }
    
    NSData *writeData = [self sendDatatoBlue:cmd payLoad:payload];
    for (int i = 0; i < writeData.length; i += 20) {
        if ((i + 20) <= [writeData length]) {
            NSString *rangeStr = [NSString stringWithFormat:@"%i,%i", i, 20];
            NSData *subData = [writeData subdataWithRange:NSRangeFromString(rangeStr)];
            NSLog(@"subDataUUUUU:%d:%@",i,subData);
            [self.currPeripheral writeValue:subData forCharacteristic:_writeCharacteristic type:CBCharacteristicWriteWithResponse];
        } else {
            NSString *rangeStr = [NSString stringWithFormat:@"%i,%i", i, (int)([writeData length] - i)];
            NSData *subData = [writeData subdataWithRange:NSRangeFromString(rangeStr)];
            NSLog(@"subDataXXXXX:%d:%@",i,subData);
            [self.currPeripheral writeValue:subData forCharacteristic:_writeCharacteristic type:CBCharacteristicWriteWithResponse];
        }
    }
}

//发送16位随机数,获取秘钥
-(void)sendrandNums {
    //没有发现服务就退出,不能注释掉
    if (self.currPeripheral == nil || _writeCharacteristic == nil) {
        return;
    }
    NSString *randStr = @"";
    for (int i = 0;i<16; i++) {
        //        NSUInteger r = arc4random_uniform(255); //随机数
        
        NSUInteger r = (18 + (arc4random() % (255 - 18 + 1)));
        
        randStr = [NSString stringWithFormat:@"%@%@",randStr,[FToy getHexByDecimal:r]];
    }
    _productKey = randStr;
    NSData *tempData = [FToy convertHexStrToData:randStr];
    // 发送16位随机数时 已经把 Kaya赋值了,等待回来解析数据把解析完的数据在存入到Kaya 中
    NSData *writeData = [SphygmomanometerBleContectModel sendrandNumspayload:@[randStr]];
    
    // 保存起来 蓝牙会返回给新秘钥 用 productKey 解密  用 解出来之后的 秘钥
    // 16位随机数 写入秘钥中,蓝牙回来的时候用秘钥解密
    NSLog(@"16位随机数是:%@",_productKey);
    for (int i = 0; i < 16; i++) {
        NSString *rangeStr = [NSString stringWithFormat:@"%i,%i", i, 1];
        NSData *as = [tempData subdataWithRange:NSRangeFromString(rangeStr)]; //ios 的二进制(16)
        /// 把解析回来的数据 把之前的私钥替换掉,之后发数据是都用私钥
        KeyTSph[i] = [FToy ConvertDataToInt:as];
    }
    NSLog(@"fuqiang发送随机数%@",writeData);
    for (int i = 0; i < writeData.length; i += 20) {
        if ((i + 20) <= [writeData length]) {
            NSString *rangeStr = [NSString stringWithFormat:@"%i,%i", i, 20];
            NSData *subData = [writeData subdataWithRange:NSRangeFromString(rangeStr)];
            
            NSLog(@"subData+++:%d:%@",i,subData);
            [self.currPeripheral writeValue:subData forCharacteristic:_writeCharacteristic type:CBCharacteristicWriteWithResponse];
        } else {
            NSString *rangeStr = [NSString stringWithFormat:@"%i,%i", i, (int)([writeData length] - i)];
            NSData *subData = [writeData subdataWithRange:NSRangeFromString(rangeStr)];
            NSLog(@"subData+++:%d:%@",i,subData);
            [self.currPeripheral writeValue:subData forCharacteristic:_writeCharacteristic type:CBCharacteristicWriteWithResponse];
        }
    }
}
//蓝牙断开后重开扫描
-(void)beginscan{
    _Fblue = [FBluetooth shareFBluetooth];
    [_Fblue cancelAllPeripheralsConnection];
    [_Fblue cancelScan];
    _Fblue.scanForPeripherals().begin();
    [[SphygmomanometerBleContectModel shared] FblueDelegate:@"bind"];
}
//蓝牙监听,接受返回值
-(void)setnotif:(CBCharacteristic *)characteristic{
    NSLog(@"????%@", characteristic.UUID);

    // 把需要订阅的特正 发送给蓝牙, notify 注册yes (封装的已经做好)
    __weak typeof(self)weakSelf = self;
    [_Fblue notify:self.currPeripheral
    characteristic:characteristic
             block:^(CBPeripheral *peripheral, CBCharacteristic *characteristics, NSError *error) {
        
        NSString *dataStr = [[[[characteristics.value description] stringByReplacingOccurrencesOfString:@"<"withString:@""]stringByReplacingOccurrencesOfString:@">" withString:@""]stringByReplacingOccurrencesOfString:@" " withString:@""];
        
        NSLog(@"收到数据:%@",dataStr);
        
        if (self.blueSendData != nil) {
            self.blueSendData();
        }
        NSMutableArray *byteArray = [NSMutableArray array];
        // 美隔两个截取字符串
        for (int i = 0 ; i < dataStr.length ; i += 2) {
            NSString *strTmp = [dataStr substringWithRange:NSMakeRange(i, 2)];
            [byteArray addObject:strTmp];
        }
        if ([characteristic.UUID.UUIDString isEqualToString:uuidNotify2]) {
            if (byteArray.count > 0) {
                if ([byteArray[0] isEqualToString:@"fd"] ) { // 秘钥反信
                    [SphygmomanometerBleContectModel keyAesDec:characteristics.value];
//                    if(weakSelf.updateTimer == nil) {
//                        weakSelf.updateTimer = [NSTimer scheduledTimerWithTimeInterval:0.8 block:^{
//                            if (self.isRepeat == YES) {
//                                [self timeer];
//                                // 轮询方法
//                                //                        [self repeatData];
//                                self.isRepeat = NO;
//                            }
//                        } repeats:YES];
//                        [weakSelf.updateTimer fire];
//                    }
                    return;
                } else {
                    [SphygmomanometerBleContectModel bisciddsex:characteristics.value];
                    NSLog(@"--------:%@",characteristic.value);
                    
                    // 关订阅
//                    [self->_Fblue cancelNotify:self.currPeripheral characteristic:characteristic];
                }
            }
        }
        else { // 03一对多 不能关订阅
            [[NSUserDefaults standardUserDefaults] setObject:characteristics.value forKey:@"charValue"];
            [SphygmomanometerBleContectModel bisciddsex:characteristics.value];

        }
    }];
}

#pragma mark - 锁蓝牙类方法
//单利模式,初始化
+ (instancetype)shared {
    static SphygmomanometerBleContectModel *share = nil;
    static dispatch_once_t oneToken;
    dispatch_once(&oneToken, ^{
        share = [[SphygmomanometerBleContectModel alloc]init];
    });
    return share;
}

//发送数据到蓝牙
- (NSData *)sendDatatoBlue:(NSString *)Cmd payLoad:(NSString *)payLoad {
    
    // 体脂秤
    _isTimeOut = YES;
    NSMutableData *newdata = [[NSMutableData alloc]init];
    
    NSData *header = [FToy convertHexStrToData:_packetType];
    NSData *length = [FToy convertHexStrToData:_packetLength];
    
    [newdata appendData:header];
    [newdata appendData:length];
    
    NSMutableData *aesData = [[NSMutableData alloc]init];
    NSData *playLoadZero = [FToy convertHexStrToData:payLoad];
    [aesData appendData:playLoadZero];
    NSData *payloadCome = [SphygmomanometerBleContectModel aesEncrypt:aesData typeFlag:2];
    
    [newdata appendData: payloadCome];
    // 原来有crc加密
    NSData *crcCome = [SphygmomanometerBleContectModel crcCome:newdata];
    [newdata appendData: crcCome];
    
    // 超时时间
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        if (self->_isTimeOut == YES) { // 超时
            NSLog(@"%@",@"超时");
            [self centerSendData:NO data:[NSData new] errorCode:@"1"];
        } else { // 没有超时
            NSLog(@"%@",@"不超时");
        }
    });
    
    return newdata;
}

//解析返回的私钥
+ (void)keyAesDec:(NSData *)data {
    NSString *dataStr_Aes = [[[[data description] stringByReplacingOccurrencesOfString:@"<"withString:@""]stringByReplacingOccurrencesOfString:@">" withString:@""]stringByReplacingOccurrencesOfString:@" " withString:@""];
    NSInteger datelength = [FToy getDecimalByBinary:[FToy getBinaryByHex:[dataStr_Aes substringWithRange:NSMakeRange(2,2)]]];
    NSString *rangeStr = [NSString stringWithFormat:@"%i,%li", 2, (long)datelength];
    NSData *Aes_ayData = [data subdataWithRange:NSRangeFromString(rangeStr)];
    
    // 用私钥解密,私钥匙 _productKey 用公钥加密时写入了 二进制私钥文件
    NSData *aesData = [SphygmomanometerBleContectModel aesDecryp:Aes_ayData typeFlag:3];
    
    NSLog(@"收到解密数据:%@",aesData);
    for (int i = 0; i < 16; i++) {
        NSString *rangeStr = [NSString stringWithFormat:@"%i,%i", i, 1];
        NSData *as = [aesData subdataWithRange:NSRangeFromString(rangeStr)]; //ios 的二进制(16)
        /// 把解析回来的数据 把之前的私钥替换掉,之后发数据是都用私钥
        KeyaSph[i] = [FToy ConvertDataToInt:as];
    }
    
}

//发送随机数给蓝牙,获取秘钥
+ (NSData *)sendrandNumspayload:(NSArray *)payload {
    NSString *payload1 = @"";
    //计算length
    NSString *str = payload[0];
    payload1 = str;
    NSData *payloadData1 = [FToy convertHexStrToData:payload1];
    NSMutableData *newdata = [[NSMutableData alloc]init];
    [newdata appendData:payloadData1];
    NSMutableData *aesData = [[NSMutableData alloc]init];
    NSData *typeCome = [FToy convertHexStrToData:@"FE"];
    [aesData appendData: typeCome];
    NSData *payloadCome = [SphygmomanometerBleContectModel aesEncrypt:newdata typeFlag:1];
    NSData *lenCome = [FToy convertHexStrToData:@"10"];
    [aesData appendData: lenCome];
    [aesData appendData: payloadCome];
    NSData *crcCome = [SphygmomanometerBleContectModel crcCome:aesData];
    [aesData appendData: crcCome];
    
    return aesData;
}

//计算crc
+ (NSData *)crcCome:(NSData *)data{
    int crc = 0;
    for (int i = 0; i < data.length; i++) {
        NSString *rangeStr = [NSString stringWithFormat:@"%i,%i", i, 1];
        NSData *as = [data subdataWithRange:NSRangeFromString(rangeStr)];
        crc = crc + [FToy ConvertDataToInt:as];
    }
    NSString *crcCome = [FToy getHexByDecimal:crc];
    for (int i = 0; i < 4 - crcCome.length; i++) {
        crcCome = [NSString stringWithFormat:@"0%@",crcCome];
    }
    return [FToy convertHexStrToData:crcCome];
}

//aes解密
+ (NSData *)aesDecryp:(NSData *)data typeFlag:(NSInteger)flag{
    
    //flag = 1 获取秘钥,key使用公钥; flag = 2 发送cmd指令,key使用秘钥
    cf_aes_context stu;
    if (flag == 1) {
        cf_aes_init(&stu, Key_ContcaSph, 16);
    } else if (flag == 2) {
        cf_aes_init(&stu, KeyaSph, 16);
    } else if (flag == 3) {
        cf_aes_init(&stu, KeyTSph, 16);
    }
    
    //解密数据数组
    uint8_t out_data[16] =
    {
    };
    uint8_t aesclo[16];
    NSMutableData *newdata = [[NSMutableData alloc]init];
    for (int i = 0; i < data.length; i++) {
        //16位一组解密
        int flag = (i)%16;
        NSString *rangeStr = [NSString stringWithFormat:@"%i,%i", i, 1];
        NSData *as = [data subdataWithRange:NSRangeFromString(rangeStr)];
        aesclo[flag] = [FToy ConvertDataToInt:as];
        if (flag == 15) {
            cf_aes_decrypt(&stu, aesclo, out_data);
            for (int i = 0; i < 16; i++) {
                NSInteger it = out_data[i];
                [newdata appendData:[NSData dataWithBytes: &it length: 1]];
            }
            for (int i = 0; i < 16; i++) {
                aesclo[i] = 0;
            }
        }
    }
    return newdata;
}

//aes加密
+ (NSData *)aesEncrypt:(NSMutableData *)data typeFlag:(NSInteger)flag{
    
    //flag = 1 获取秘钥,key使用公钥; flag = 2 发送cmd指令,key使用秘钥
    //16位一组加密,不足16位补0
    NSInteger addCount = 16 - (data.length%16);
    if (data.length%16 != 0) {
        for (int i = 0; i < addCount; i++) {
            [data appendData:[FToy convertHexStrToData:@"00"]];
        }
    }
    
    cf_aes_context stu;
    if (flag == 1) {
        cf_aes_init(&stu, Key_ContcaSph, 16);
    }else if (flag == 2) {
        cf_aes_init(&stu, KeyaSph, 16);
    }else if (flag == 3) {
        cf_aes_init(&stu, KeyTSph, 16);
    }
    
    //加密数据数组
    uint8_t out_data[16] =
    {
    };
    uint8_t aesclo[16];
    NSMutableData *newdata = [[NSMutableData alloc]init];
    for (int i = 0; i < data.length; i++) {
        //16位一组加密
        int flag = (i)%16;
        NSString *rangeStr = [NSString stringWithFormat:@"%i,%i", i, 1];
        NSData *as = [data subdataWithRange:NSRangeFromString(rangeStr)];
        aesclo[flag] = [FToy ConvertDataToInt:as];
        if (flag == 15) {
            cf_aes_encrypt(&stu, aesclo, out_data);
            for (int i = 0; i < 16; i++) {
                NSInteger it = out_data[i];
                [newdata appendData:[NSData dataWithBytes: &it length: 1]];
            }
            for (int i = 0; i < 16; i++) {
                aesclo[i] = 0x00;
            }
        }
    }
    return newdata;
}

+ (NSString *)DictionaryToString:(NSDictionary *)initDic {
    NSError * err;
    NSString * jsonString;
    
    if (!initDic || [initDic count] == 0) {
        return @"";
    }
    
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:initDic options:NSJSONWritingPrettyPrinted error:&err];
    
    if (!jsonData) {
        
        return @"";
    }else{
        jsonString = [[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding];
    }
    
    return jsonString;
}
// 发送数据
+ (void)sendDatacmd:(NSString *)packetType
       packetLength:(NSString *)packetLength
                cmd:(NSString *)cmd
            payload:(NSString *)payload
           nativeId:(NSString *)nativeId
            success:(void (^)(NSString *msg))success
               fail:(void (^)(NSString *msg))fail{
    
    SphygmomanometerBleContectModel *Lockblue = [SphygmomanometerBleContectModel shared];
    [Lockblue FblueDelegate:@"cmd"];
    __weak typeof(Lockblue) weakLockblue = Lockblue;
    __strong typeof(weakLockblue) strongSelf = weakLockblue;
    Lockblue.blockIsSendData = YES;
    
    Lockblue.nativeId = nativeId;
    Lockblue.packetType = packetType;
    Lockblue.packetLength = packetLength;
    Lockblue.onceRunning = NO;
    
    weakLockblue.blueSendData = ^{
        success(@"成功");
    };
    if (Lockblue.timerIsRun == NO) {
        Lockblue.gcdIdx = 0;
        Lockblue.timerIsRun = YES;
    }
    if (Lockblue.writeCharacteristic != nil) {
        if (payload == nil) {
            payload = @"";
        }
        // 发送数据
        [strongSelf sendDatacmd:cmd payload:payload];
        strongSelf.blockIsSendData = NO;
    } else {
        [Lockblue sendrandNums];
    }
}
+ (void)bindBlowerDevice:(NSString *)phone success:(void (^)(NSString *msg))success fail:(void (^)(NSString *msg))fail{
    
    SphygmomanometerBleContectModel *Lockblue = [SphygmomanometerBleContectModel shared];
    [Lockblue FblueDelegate:@"bind"];
    __weak typeof(Lockblue) weakLockblue = Lockblue;
    weakLockblue.blueErrorBlock = ^(NSString * _Nonnull error) {
        fail(error);
    };
    Lockblue.blockIsSendData = YES;
    if (Lockblue.timerIsRun == NO) {
        Lockblue.gcdIdx = 0;
        Lockblue.timerIsRun = YES;
    }
    
    weakLockblue.sendbindblock = ^{
        success(@"设备绑定成功");
    };
}

- (YUTimer *)timerIndex {
    if (_timerIndex == nil) {
        _timerIndex = [[YUTimer alloc] init];
    }
    return _timerIndex;
}
#pragma mark - 解析数据
+ (void)bisciddsex:(NSData *)data {
    
    SphygmomanometerBleContectModel *Lockblue = [SphygmomanometerBleContectModel shared];
    __weak typeof(Lockblue) weakLockblue = Lockblue;
    
    // ----- 是不是分包的处理 -----
    NSString *dataLength = [[[[data description] stringByReplacingOccurrencesOfString:@"<"withString:@""]stringByReplacingOccurrencesOfString:@">" withString:@""]stringByReplacingOccurrencesOfString:@" " withString:@""];
    NSString *packLength = [dataLength substringWithRange:NSMakeRange(2, 2)];
    // 16进制-->二进制
    NSString *secondNumber = [FToy getBinaryByHex:packLength];
    // 2进制-->十进制
    NSInteger tenNumber = [FToy getDecimalByBinary:secondNumber];
    // ----- 是不是分包的处理 -----
    
    NSString *rangeStr = NULL;
    NSData *Aes_ayData = NULL;
    if (tenNumber > 16) {
        rangeStr = [NSString stringWithFormat:@"%i,%lu", 2, ((dataLength.length)/2) - 4];
        Aes_ayData = [data subdataWithRange:NSRangeFromString(rangeStr)];
    } else {
        rangeStr = [NSString stringWithFormat:@"%i,%li", 2, (long)16];
        Aes_ayData = [data subdataWithRange:NSRangeFromString(rangeStr)];
    }
    
    // 用私钥解密,私钥匙 _productKey 用公钥加密时写入了 二进制私钥文件
    NSData *aesData = [SphygmomanometerBleContectModel aesDecryp:Aes_ayData typeFlag:2];
    
    // ---- 数据放在数组中截取 -----
    NSString *dataStr = [[[[aesData description] stringByReplacingOccurrencesOfString:@"<"withString:@""]stringByReplacingOccurrencesOfString:@">" withString:@""]stringByReplacingOccurrencesOfString:@" " withString:@""];
    
    NSMutableArray *byteArray = [NSMutableArray array];
    // 美隔两个截取字符串
    for (int i = 0 ; i < dataStr.length ; i += 2) {
        NSString *strTmp = [dataStr substringWithRange:NSMakeRange(i, 2)];
        [byteArray addObject:strTmp];
    }
    NSLog(@"byteArray----:%@",byteArray);
    
    //    SphygmomanometerBleContectModel *Lockblue = [SphygmomanometerBleContectModel shared];
    //    __weak typeof(Lockblue) weakLockblue = Lockblue;
    
    // 接收到数据没有超时
    Lockblue.isTimeOut = NO;
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(timeOutFun) object:nil];
    
    if (Lockblue.isSecret == YES) {
        if (tenNumber > 16) {
            if (Lockblue.onceRunning == NO) {
                if ([weakLockblue checkCRC:data]) { //CRC校验正确
                    // 大于16字节只执行一次
                    [Lockblue centerSendData:YES data:aesData errorCode:@"0"];
                    Lockblue.onceRunning = YES;
                } else {
                    NSLog(@"%@",@"CRC校验错误");
                    [Lockblue centerSendData:NO data:[NSData new] errorCode:@"2"];
                }
            }
        } else {
            if (Lockblue.onceRunning == NO) {
                if ([weakLockblue checkCRC:data]) {
                    [Lockblue centerSendData:YES data:aesData errorCode:@"0"];
                } else {
                    NSLog(@"%@",@"CRC校验错误");
                    [Lockblue centerSendData:NO data:[NSData new] errorCode:@"2"];
                }
            }
        }
    } else {
        NSLog(@"%@",@"秘钥执行不发送数据给H5");
        Lockblue.isSecret = NO;
    }
}

- (void)timeOutFun {
    NSLog(@"体脂计 A5超时");
    [self centerSendData:NO data:[NSData new] errorCode:@"1"];
}
- (void)centerSendData:(BOOL)success data:(NSData *)data errorCode:(NSString *)coerrorCodede {
    
    NSString *lastDataStr = [[[[data description] stringByReplacingOccurrencesOfString:@"<"withString:@""]stringByReplacingOccurrencesOfString:@">" withString:@""]stringByReplacingOccurrencesOfString:@" " withString:@""];

    
    NSLog(@"向H5发送的数据%@",lastDataStr);
    
    if (success) {
        
        NSDictionary *dic = @{
            @"errorCode":@(0),
            @"nativeId":@([_nativeId intValue]),
            @"results":lastDataStr
        };
        
        [[NSNotificationCenter defaultCenter] postNotificationName:@"SphygmomanometerBleContectModelNotification" object:nil userInfo:dic];
    } else {
        NSDictionary *dic = @{
            @"errorCode":@([coerrorCodede intValue]),
            @"nativeId":@([_nativeId intValue]),
            @"results":@""
        };
        
        [[NSNotificationCenter defaultCenter] postNotificationName:@"SphygmomanometerBleContectModelNotification" object:nil userInfo:dic];
    }
}

#pragma mark - 校验CRC
- (BOOL)checkCRC:(NSData *)didGetData {
    
    NSString *dataStr = [[[[didGetData description] stringByReplacingOccurrencesOfString:@"<"withString:@""]stringByReplacingOccurrencesOfString:@">" withString:@""]stringByReplacingOccurrencesOfString:@" " withString:@""];
    
//    dataStr = @"0710150a3b146b54bb6b3a5c86cb9f6f9e82067f";

    NSMutableArray *byteArray = [NSMutableArray array];
    // 美隔两个截取字符串
    for (int i = 0 ; i < dataStr.length - 4; i += 2) {
        NSString *strTmp = [dataStr substringWithRange:NSMakeRange(i, 2)];
        // 16进制-->二进制
        NSString *secondNumber = [FToy getBinaryByHex:strTmp];
        // 2进制-->十进制
        NSInteger tenNumber = [FToy getDecimalByBinary:secondNumber];

        [byteArray addObject:[NSNumber numberWithInteger:tenNumber]];
    }
    
//    NSLog(@"UUUUUUUU:%@",byteArray);
    
    int ind = 0;
    for (NSNumber *number in byteArray) {
        ind = ind + [number intValue];
    }
    
    NSLog(@"十进制数加和:%d",ind);
    
    NSString *strInt = [NSString stringWithFormat:@"%d",ind];
    // 10 --> 16
    NSString *strLast = [FToy getHexByDecimal:[strInt integerValue]].lowercaseString;
    if (strLast.length == 4) {
        strLast = [NSString stringWithFormat:@"%@",strLast];
    } else if (strLast.length == 3) {
        strLast = [NSString stringWithFormat:@"0%@",strLast];
    } else if (strLast.length == 2) {
        strLast = [NSString stringWithFormat:@"00%@",strLast];
    } else if (strLast.length == 1) {
        strLast = [NSString stringWithFormat:@"000%@",strLast];
    } else {
        
    }
    
    NSString *strMMP = [dataStr substringFromIndex:dataStr.length - 4];
    
    NSLog(@"strMMP:%@",strMMP);
    if ([strMMP isEqualToString:strLast]) {
        NSLog(@"%@",@"YES");
        return YES;
    } else {
        NSLog(@"%@",@"NO");
        return NO;
    }
}

发布了49 篇原创文章 · 获赞 7 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_29680975/article/details/103727626