欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

ios ble 蓝牙锁开发用例

程序员文章站 2022-06-21 19:23:04
开发流程:1. 建立中心管家2. 扫描外部设备3. 获取扫描的 外部设备,获取外部设备 , 连接外部设备4. 连接外设 成功,获取 发现服务5. 发现服务 uuid, 发现 服务下 特征值6. 读取 特征值 ,订阅 ble->app 通道 获取app->ble 特征值7. 接收 读取的特征值8. 锁入网,传递psw2 给app9. p1+p2 加密 systemId 鉴权 10. 锁回复 psw3 11.发送 开锁 确认帧代码......

开发流程:

1. 建立中心管家
2. 扫描外部设备
3. 获取扫描的 外部设备,获取外部设备 , 连接外部设备
 4.  连接外设 成功,获取  发现服务
 5.  发现服务 uuid, 发现 服务下 特征值
 6.  读取 特征值  ,订阅 ble->app 通道   获取app->ble 特征值
 7.  接收 读取的特征值
 8. 锁入网,传递psw2 给app
 9. p1+p2 加密 systemId 鉴权
  10. 锁回复 psw3
  11.发送  开锁 确认帧 

 代码实现: 

//
//  ViewController.m
//  mutipeerConnectivityTest
//
//  Created by 邓安置 on 2020/6/11.
//  Copyright © 2020 邓安置. All rights reserved.
//

#import "ViewController.h"
#import <CoreBluetooth/CoreBluetooth.h>
#import "CBPeripheral+Extension.h"
#import "KDSBleOptions.h"
#import "NSData+JKEncrypt.h"
#import "KDSBleAssistant.h"
#import "NSTimer+KDSBlock.h"
@interface ViewController ()<CBCentralManagerDelegate,CBPeripheralDelegate>

@property(nonatomic,strong) CBCentralManager* mgr;


@property(nonatomic,strong) CBPeripheral*  peripheral;


@property(nonatomic,copy,nullable) void(^myBlock)(CBPeripheral* cbP);


@property (nonatomic, strong) CBCharacteristic *batteryCharacteristic; //电量
@property (nonatomic, strong) CBCharacteristic *systemIDCharacteristic; //系统ID
@property (nonatomic, strong) CBCharacteristic *modelNumCharacteristic; //
@property (nonatomic, strong) CBCharacteristic *seriaNumCharacteristic; //
///要写入到哪个特征
@property (nonatomic, strong) CBCharacteristic *writeCharacteristic;
@property (nonatomic, strong) CBCharacteristic *functionSetCharacteristic;//功能集
@property (nonatomic, strong, nullable) CBPeripheral *connectedPeripheral;

@property (nonatomic, strong) NSData *systemID;

///连接外设绑定时,收到SN后,从服务器请求回来。绑定后从绑定设备列表获得。测试没有上市的蓝牙时,服务器没有值返回,这是使用mac提取。
@property (nonatomic, copy, nullable) NSString  *pwd1;
///用户入网(绑定)的时候生成,锁蓝牙返回的payload数据的1~4字节。
@property (nonatomic, strong, nullable) NSData *pwd2;
///鉴权成功时,锁蓝牙返回的payload数据的1~4字节。
@property (nonatomic, strong, nullable) NSData *pwd3;

/**传输序号,每次传输+1,到了255置为50 (为了区分心跳包 设置范围为50-255)*/
@property (nonatomic, assign) int tsn;


///心跳包tsn 1 - 49
@property (nonatomic, assign) NSInteger heartbeatTsn;
@property (nonatomic, weak) NSTimer *heartbeatTimer;
@end

@implementation ViewController



- (IBAction)searchShow:(id)sender {
    
    // 1. 建立中心管家
    // nil: 在主线程中扫描
        CBCentralManager *centralManager= [[CBCentralManager alloc] initWithDelegate:self queue:nil];
        _mgr = centralManager;
        NSLog(@"%@",@"开始扫描");
     //
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.myBlock= ^(CBPeripheral* cbP){
        NSLog(@"block回调--->%@",cbP.advDataLocalName);
    };
    
     self.pwd1=@"62375ea279e77356aa0a77f9";
    
}

-(void)centralManagerDidUpdateState:(CBCentralManager *)central{
     NSLog(@"%ld",central.state);
    // 开机状态   5
    if(central.state== CBManagerStatePoweredOn ){
       // 2. 扫描外部设备      CBPeripheral表示外部设备
        [self.mgr scanForPeripheralsWithServices:nil options:@{ CBCentralManagerScanOptionAllowDuplicatesKey : @YES }];
    }
    
     __weak typeof(self) weakSelf = self;
    dispatch_block_t block = dispatch_block_create(DISPATCH_BLOCK_ASSIGN_CURRENT, ^{
        if (weakSelf.mgr.isScanning) {
            [weakSelf stopScan];
        }
    });
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
           block();
       });
    
}

- (void)stopScan
{
    NSLog(@"%@",@"停止扫描");
    [self.mgr stopScan];
}

-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI{
    /**
       ===peripheral名:Kaadas DoorLock
       ===广播名:KDSF0F8F2BFB618
       ===设备uuid:22F116CE-D746-16A4-8408-BE1476E11B0C
       ===peripheral:<CBPeripheral: 0x2822b4fa0, identifier = 22F116CE-D746-16A4-8408-BE1476E11B0C, name = Kaadas DoorLock, state = disconnected>
       ===设备广播数据:{
         kCBAdvDataIsConnectable = 1;
         kCBAdvDataLocalName = KDSF0F8F2BFB618;
         kCBAdvDataRxPrimaryPHY = 0;
         kCBAdvDataRxSecondaryPHY = 0;
         kCBAdvDataServiceUUIDs =     (
             FFD0,
             FFF0
         );
         kCBAdvDataTimestamp = "614075187.3347189";
         kCBAdvDataTxPowerLevel = 0;
     }
     */
//    NSLog(@"\n\n===peripheral名:%@ \n===广播名:%@\n ===设备uuid:%@\n  ===peripheral:%@\n ===设备广播数据:%@\n\n",peripheral.name,advertisementData[@"kCBAdvDataLocalName"],peripheral.identifier.UUIDString,peripheral,advertisementData);
    //解析广播包中的kCBAdvDataLocalName 区分凯迪仕的设备
     NSString *key = CBAdvertisementDataLocalNameKey;
    // 3. 获取扫描的 外部设备,获取外部设备 , 连接外部设备
    if (peripheral==nil || peripheral.name==nil || ![advertisementData[key] containsString:@"KDSA434F1CC143A"]) return;
    [self stopScan];
    NSLog(@"peripheral==%@",advertisementData[key]);
    peripheral.advDataLocalName = advertisementData[key];
    self.myBlock(peripheral);
    self.peripheral = peripheral;
    // 连接外部设备
    [self.mgr connectPeripheral:peripheral options:nil];
}

// 4.  连接外设 成功,获取  发现服务
-(void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
    // 通过连接的外部设置保存扫描到的
    NSLog(@"连接成功:%@",peripheral.advDataLocalName);
     _connectedPeripheral = peripheral;
    NSInteger allLenth =peripheral.advDataLocalName.length;
     if (allLenth >= 12) {
          NSString *orgStr = [peripheral.advDataLocalName substringFromIndex:allLenth-12];
          NSData *password1 = [orgStr dataUsingEncoding:NSASCIIStringEncoding];
         
     }

    peripheral.delegate =self;
    //  扫描服务 根据服务 扫描特征值
    [self.peripheral discoverServices:nil];
}
// 5.  发现服务 uuid, 发现 服务下 特征值
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
    NSArray* services= peripheral.services;
    NSLog(@"设备服务值:%@",services);
    for (CBService *sevice in peripheral.services) {
        /**
         设备服务值:(
             "<CBService: 0x2803c6800, isPrimary = YES, UUID = Device Information>",
             "<CBService: 0x2803c5840, isPrimary = YES, UUID = FFF0>",
             "<CBService: 0x2803c66c0, isPrimary = YES, UUID = FFE0>",
             "<CBService: 0x2803c6740, isPrimary = YES, UUID = FFE5>",
             "<CBService: 0x2803c6640, isPrimary = YES, UUID = FFB0>",
             "<CBService: 0x2803c60c0, isPrimary = YES, UUID = F000FFD0-0451-4000-B000-000000000000>"
         )
         */
        
      //  NSLog(@"%@",sevice.UUID.UUIDString);
        
        if ([sevice.UUID.UUIDString isEqualToString:OADResetServiceUUID]
                     ||[sevice.UUID.UUIDString isEqualToString:DFUResetServiceUUID]) {

               //存在FFD0或1802服务,OAD复位服务
            //存在FFD0或1802服务,OAD复位服务
            peripheral.isNewDevice = YES;
            peripheral.bleVersion = 2;
            NSLog(@"--{Kaadas}--bleVersion:%d",peripheral.bleVersion);
        }
        [peripheral discoverCharacteristics:nil forService:sevice];//发现服务下面所有的特征
    }
}
// 6.  读取 特征值  ,订阅 ble->app 通道   获取app->ble 特征值,发送 心跳包
// 发现特征值就会调用
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(nullable NSError *)error {
    
    if (error){
         NSLog(@"获取服务:%@的特征失败: %@", service.UUID, error);
         return;
     }
   
    
    UInt64 uuid = strtoul(service.UUID.UUIDString.UTF8String, 0, 16);
    KDSBleService serviceType = (KDSBleService)uuid;
    NSLog(@"读的服务-service===%@",service.characteristics);
    switch (serviceType)
       {
           case KDSBleServiceModule:
               for (CBCharacteristic *characteristic in service.characteristics) {
                   NSLog(@"读的服务-模块信息 (电量 pwd3):severUUId:%@====charUUId:%@",service.UUID.UUIDString,characteristic.UUID.UUIDString);
                  // [peripheral setNotifyValue:YES forCharacteristic:characteristic];
                   if ([characteristic.UUID.UUIDString isEqualToString:batteryDUUID]) {
                       [peripheral readValueForCharacteristic:characteristic];
                       //电量特征值
                       _batteryCharacteristic = characteristic;
                   }
               }
               break;
           case KDSBleServiceDevice:
             for (CBCharacteristic *characteristic in service.characteristics) {
                   NSLog(@"读的服务-BLE设备信息参数:severUUId:%@====charUUId:%@",service.UUID.UUIDString,characteristic.UUID.UUIDString);
                   //监听characteristic值变化
                //   [peripheral setNotifyValue:YES forCharacteristic:characteristic];
                   if ([characteristic.UUID.UUIDString isEqualToString:systemIDUUID]) {
                       _systemIDCharacteristic = characteristic;
                       [peripheral readValueForCharacteristic:characteristic];
                   }
                   else if ([characteristic.UUID.UUIDString isEqualToString:modelNumUUID]) {
                       _modelNumCharacteristic = characteristic;
                       [peripheral readValueForCharacteristic:characteristic];
                   }
                   else if ([characteristic.UUID.UUIDString isEqualToString:seriaLNumUUID]) {
                       _seriaNumCharacteristic = characteristic;
                       [peripheral readValueForCharacteristic:characteristic];
                   }
               }
               break;
           case KDSBleServiceLock:
               
               break;
           case KDSBleServiceApp2BleTunnel:  // app->蓝牙  0xFFE5 ,下只有一个特征值,app->ble
                for (CBCharacteristic *characteristic in service.characteristics) {
                    NSLog(@"读的服务-APP-->BLE数据通道severUUId:%@====charUUId:%@",service.UUID.UUIDString,characteristic.UUID.UUIDString);
                                       //主动去读取一次外围设备的消息
                   [peripheral readValueForCharacteristic:characteristic];
                 //  [peripheral setNotifyValue:YES forCharacteristic:characteristic];
                   self.writeCharacteristic = characteristic;
                }
               if(self.connectedPeripheral.isNewDevice){
                    [self createHeartbeatTimer];
               }
                
               break;
           case KDSBleServiceBle2AppTunnel:    //0xFFE0
               for (CBCharacteristic *characteristic in service.characteristics) {
                              NSLog(@"读的服务-BLE-->APP数据通道:severUUId:%@====charUUId:%@",service.UUID.UUIDString,characteristic.UUID.UUIDString);
                              [peripheral setNotifyValue:YES forCharacteristic:characteristic];
                   // ffe0 下功能集 ffe1
                              if ([characteristic.UUID.UUIDString isEqualToString:kFFE1])
                              {
                                  peripheral.bleVersion = 3;
                                  NSLog(@"--{Kaadas}--bleVersion:%d",peripheral.bleVersion);
                                  _functionSetCharacteristic = characteristic;
                                  [peripheral readValueForCharacteristic:characteristic];
                              }
                          }
               break;
           case KDSApp2BleDisNetworkTunnel:
               
               break;
           case KDSBle2AppDisNetworkTunnel:
               
               break;
       }
}

// 7.  接收 读取的特征值 ,
#pragma mark 接收特征的数据
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    if (error) return;
    
      NSString *uuid = characteristic.UUID.UUIDString;
      NSLog(@"读取所有特征值的时候蓝牙UUID的值:%@",uuid);
    
    
    if ([uuid isEqualToString:batteryDUUID]) {//电量信息
        NSData *batteryData = characteristic.value;
        u_int8_t tt;
        [batteryData getBytes:&tt length:sizeof(tt)];
        int elct = tt;//0-100
        peripheral.power = elct;
        NSLog(@"电量值是=%d",elct);
    }
    
    else if ([uuid isEqualToString:seriaLNumUUID]) {//SN
         peripheral.serialNumber = characteristic.value.jk_UTF8String;
        NSLog(@"sn是=%@",peripheral.serialNumber);
     }

    else if ([uuid isEqualToString:systemIDUUID]){//System ID
            //获取systemId
                   _systemID = characteristic.value;
                   NSString *systemIDStr = [KDSBleAssistant convertDataToHexStr:_systemID];
                   if (!systemIDStr || strtol(systemIDStr.UTF8String, NULL, 16) == 0) {
                       _systemID = [KDSBleAssistant extractSystemIDFromAdvName:peripheral.advDataLocalName];
                   }
           NSLog(@"systemID是=%@",_systemID);
    }
    
    else if ([uuid isEqualToString:modelNumUUID])  //  modulenum
       {
           self.connectedPeripheral.lockModelNumber = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
           
           NSLog(@"modulenum是=%@",self.connectedPeripheral.lockModelNumber);
       }
    else if ([uuid isEqualToString:bleToAppDUUID]){//模块向App发送数据通道
          if (characteristic.value.length == 16) {  //没用,都是20个字节
              NSData *pwd1Data = [characteristic.value subdataWithRange:NSMakeRange(0, 12)];
              NSData *pwd = [KDSBleAssistant convertHexStrToData:self.pwd1];
              NSString* pwdS= [KDSBleAssistant convertDataToHexStr:pwd];
              NSLog(@"%@",pwdS);
              return;
          }
          if (characteristic.value.length < 20) {return;/**数据丢包了 */ }
            //新设备数据的处理
                      NSData *data = characteristic.value;
                      NSLog(@"--{Kaadas}--蓝牙--处理模块发来的数据==%@",data);
                      const unsigned char* bytes = (const unsigned char*)data.bytes;
                      u_int8_t control = bytes[0];
                      u_int8_t check1 = bytes[2];
                      NSData *decryptData = data;
                      if (control != 0) {//心跳包不加密
                         //解密数据
                          decryptData =  [self getAes256_decryptDataWithOriginData:data];
                          NSLog(@"解密以后的数据:%@",[KDSBleAssistant convertDataToHexStr:decryptData]);
                      }
                      u_int8_t check2 = [KDSBleAssistant sumOfDataThroughoutBytes:[decryptData subdataWithRange:NSMakeRange(4, 16)]];
                      if (check1 == check2) {
                     //      KDSLog(@"校验正确=%@",decryptData)
                           NSLog(@"处理校验正确之后的数据------%@",decryptData);
                           const unsigned char *bytes = (const unsigned char *)decryptData.bytes;
                           unsigned char transferSerialNumber = bytes[1];  //tsn
                           unsigned char cmd = bytes[3];
                           unsigned char status = bytes[4];
                           if (cmd==0 && transferSerialNumber<50) return;//心跳包确认帧。
                           NSString *receipt = @(transferSerialNumber).stringValue;
                           //如果是app主动发送命令,那么队列里会有记录,根据tsn和命令值执行相应的命令就行。
                           //执行app主动发送命令队列中不存在的上报命令
                           KDSBleTunnelOrder order = (KDSBleTunnelOrder)cmd;
                           switch (order) {
                                 case KDSBleTunnelOrderEncrypt:
                                   // 8. 锁入网,传递psw2 给app
                                     if (status == 1)//收到锁发送过来的入网(绑定)指令,可以在返回数据中提取pwd2
                                      {
                                         self.pwd2 = [decryptData subdataWithRange:NSMakeRange(5, 4)];
                                          // 9. p1+p2 加密 systemId 鉴权
                                         [self sendResponseInOrOutNet:(int)transferSerialNumber];
                                         NSLog(@"~~~~~收到入网命令self.pwd2=%@",self.pwd2);
                                         [self authenticationWithPwd1:self.pwd1 pwd2:self.pwd2];
                                     }
                                    else if (status == 2)//收到pwd3,绑定成功。
                                    {
                                        // 10. 锁回复 psw3
                                        self.pwd3 = [decryptData subdataWithRange:NSMakeRange(5, 4)];
                                        NSLog(@"~~~~~收到self.pwd3,绑定成功=%@",self.pwd3);
                                        [self sendResponseInOrOutNet:(int)transferSerialNumber];
                                    }
                                      break;
                               case KDSBleTunnelOrderLockOperate:
                                   NSLog(@"%@",@"锁操作上报");
                                   
                                   break;
                           };
                          
                      }else{
                          NSLog(@"--{Kaadas}--校验出错--check1=%d--check2=%d",check1,check2);
                     }
  
         
    }
    
    else if ([uuid isEqualToString:kFFE1])//功能集
     {
      
        NSString *FunctionSetKey = [NSString stringWithFormat:@"0x%@",[KDSBleAssistant convertDataToHexStr:characteristic.value]];
    
        NSLog(@"--{Kaadas}--功能集=锁上=%@",FunctionSetKey);
     
     }
}


#pragma mark - 获取解密数据
///解密数据,绑定/重置时只能使用密码1+4字节都为0的NSData解密(即密码2必须为nil);鉴权时只能使用密码1+密码2解密(即密码3必须为nil);鉴权成功获取密码3后只能使用密码1+密码3解密;否则解密的数据都不正确。
- (NSData *)getAes256_decryptDataWithOriginData:(NSData *)data{
    NSMutableData *keyData = [NSMutableData data];
    NSData *key1Data = [KDSBleAssistant convertHexStrToData:_pwd1]; //12个字节
    [keyData appendData:key1Data];
    if (self.pwd2 == nil) {//解密pwd2  4个字节
        Byte behindByte[] = {0x00,0x00,0x00,0x00};
        NSData *behindData= [NSData dataWithBytes:behindByte length:sizeof(behindByte)];
        [keyData appendData:behindData];
        NSLog(@"keyData:%@",keyData);
        
    }else if(self.pwd2 && self.pwd3 == nil){//解密pwd3
        [keyData appendData:self.pwd2];
        NSLog(@"keyData2:%@",keyData);
    }
    else if(self.pwd2 && self.pwd3){//建立通道以后 解密数据
        [keyData appendData:self.pwd3];
//        KDSLog(@"keyData3:%@",keyData);
    }
//    KDSLog(@"收到的原始数据:%@",data);
    NSData *resultData = [[data subdataWithRange:NSMakeRange(4, 16)] aes256_decryptData:keyData];
    NSMutableData *decryptData = [NSMutableData data];
    [decryptData appendData:[data subdataWithRange:NSMakeRange(0, 4)]];
    [decryptData appendData:resultData];
//    KDSLog(@"--{Kaadas}--蓝牙--收到的解密后数据%@",decryptData);
    return decryptData.copy;
}

#pragma mark - 发送收到 入网/退网 确认帧
- (void)sendResponseInOrOutNet:(int)tsn{
    if (_connectedPeripheral.isNewDevice) {
        [self sendConfirmDataToBleDevice:tsn];
        return;
    }
}
#pragma mark - 新模块发送确认帧
- (void)sendConfirmDataToBleDevice:(NSInteger)tsn{
    if (tsn != 0) {
//        [self pauseTimer];
        Byte conformByte[] = {0x00,tsn,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,};
        NSData *conformData = [[NSData alloc] initWithBytes:conformByte length:sizeof(conformByte)];
        if (self.writeCharacteristic && self.connectedPeripheral ) {///设备已经连接且要写入特征
//            KDSLog(@"发送了确认帧:%@ %@",conformData,getcurretenDate);
            [self.connectedPeripheral writeValue:conformData forCharacteristic:self.writeCharacteristic type:0];
        }
        return;
    }
}

- (NSString *)authenticationWithPwd1:(NSString *)pwd1 pwd2:(id)pwd2
{
      Byte payload[16] = {0};
      for (int i = 0; i < self.systemID.length; ++i)
      {
          // 把NSData 转化为 Byte
          payload[i] = ((Byte *)self.systemID.bytes)[i];
      }
      int sum = [KDSBleAssistant sumOfDataThroughoutBytes:[[NSData alloc] initWithBytes:payload length:16]];
      self.tsn++;
      unsigned char* bytes = (unsigned char*)malloc(20);
      bytes[0] = 1; bytes[1] = self.tsn; bytes[2] = sum; bytes[3] = KDSBleTunnelOrderAuth;
      memcpy(bytes + 4, payload, 16);
      NSData* sendData= [[NSData alloc] initWithBytesNoCopy:bytes length:20];
    
    
      NSMutableData *key = [NSMutableData dataWithData:[KDSBleAssistant convertHexStrToData:self.pwd1]]; //12个字节
      [key appendData:self.pwd2];  //4个字节
      NSData *encryptData = [[sendData subdataWithRange:NSMakeRange(4, 16)] aes256_encryptData:key];
      
      NSLog(@"--{Kaadas}--encryptData=key=%@",key);
      NSLog(@"--{Kaadas}--encryptData====%@",encryptData);
      [key setData:[sendData subdataWithRange:NSMakeRange(0, 4)]];
      [key appendData:encryptData];
    
      [self.connectedPeripheral writeValue:key forCharacteristic:self.writeCharacteristic type:CBCharacteristicWriteWithResponse];
    
    return nil;
    
}

#pragma mark - 发送心跳包
- (void)createHeartbeatTimer{
    if (self.heartbeatTimer==nil) {
        //重复每3秒发送一次心跳包
        __weak typeof(self) weakSelf = self;
        NSTimer *timer = [NSTimer kdsScheduledTimerWithTimeInterval:3 repeats:YES block:^(NSTimer * _Nonnull timer) {
             self.heartbeatTsn ++;
             Byte bytePayload[16] = {0xFF, 0};
             NSData *payloadData = [[NSData alloc] initWithBytes:bytePayload length:sizeof(bytePayload)];
             Byte byteHeader[] = {0x00,self.heartbeatTsn,0xff,0xAA};
             NSData *headerData = [[NSData alloc] initWithBytes:byteHeader length:sizeof(byteHeader)];
             NSMutableData *senderData = [NSMutableData data];
             [senderData appendData:headerData];
             [senderData appendData:payloadData];
             NSLog(@"发送心跳:%@",[KDSBleAssistant convertDataToHexStr:senderData]);
             [self.connectedPeripheral writeValue:senderData forCharacteristic:self.writeCharacteristic type:0];
            
        }];
        self.heartbeatTimer = timer;
        [timer fire];
    }
}
// 如果发送开锁命令,暂停3s发送心跳包
- (void)pauseTimer{
    self.heartbeatTimer.fireDate = [NSDate dateWithTimeIntervalSinceNow:3];
}

- (IBAction)openLock:(id)sender {
    
    [self operateLockWithPwd:@"147258" actionType:KDSBleLockControlActionUnlock keyType:KDSBleLockControlKeyPIN
                  completion:^(KDSBleError error, CBPeripheral * _Nullable peripheral) {
        
    }];
        
}
// 11.发送  开锁 确认帧
- (NSString *)operateLockWithPwd:(NSString *)pwd actionType:(KDSBleLockControl)action keyType:(KDSBleLockControl)key completion:(nullable void(^)(KDSBleError error, CBPeripheral * __nullable peripheral))completion{
   
    Byte payload[16] = {(char)action, (char)key, 0, 0};
    
    payload[3] = pwd.length;//密码长度
    //第4个字节开始是密码,每一个字节保存一位密码。
    for (int i = 0; i< pwd.length; i++)
    {
        payload[i + 4] = pwd.UTF8String[i];
    }
    int sum = [KDSBleAssistant sumOfDataThroughoutBytes:[[NSData alloc] initWithBytes:payload length:16]];
    self.tsn++;
    unsigned char* bytes = (unsigned char*)malloc(20);
    bytes[0] = 1; bytes[1] = self.tsn; bytes[2] = sum; bytes[3] = KDSBleTunnelOrderControl;
    memcpy(bytes + 4, payload, 16);
    
    NSData* sendData= [[NSData alloc] initWithBytesNoCopy:bytes length:20];
    
    
    NSMutableData *key13 = [NSMutableData dataWithData:[KDSBleAssistant convertHexStrToData:self.pwd1]];
    if (self.pwd3)//鉴权后+密码3加密
    {
        [key13 appendData:self.pwd3];
    }
    NSData *encryptData = [[sendData subdataWithRange:NSMakeRange(4, 16)] aes256_encryptData:key13];
    [key13 setData:[sendData subdataWithRange:NSMakeRange(0, 4)]];
    [key13 appendData:encryptData];
    
    [self.connectedPeripheral writeValue:key13 forCharacteristic:self.writeCharacteristic type:CBCharacteristicWriteWithResponse];
    
    return nil;
}


@end

源码下载 : https://download.csdn.net/download/dreams_deng/12576424

本文地址:https://blog.csdn.net/dreams_deng/article/details/107126490