//首先,定义一个蓝牙操作类
//
//  LSBuzzBTmanager.h
//  gene
//
//  Created by lollipop on 2017/4/7.
//  Copyright © 2017年 lesports. All rights reserved.
//
 
#import <Foundation/Foundation.h>
#import <CoreBluetooth/CoreBluetooth.h>
 
// 错误类型,后续根据厂商加上其他错误
typedef NS_ENUM(NSInteger,BuzzResult) {
    BuzzBTSuccess = 0,  // 成功
    BuzzBTFail,         // 失败
    BuzzBTInvalid,      // 目前蓝牙不可用
    BuzzTimeout,        // 此标志位只说明超时,并不说明没有搜到结果
};
 
typedef void (^LSBikeFailedBlock)(NSError *error);
typedef void (^LSBikeResultBlock)(BOOL result, NSError *error);
 
@protocol LSBuzzBTmanagerDelegate <NSObject>
 
 
/*
 * @descripe 当前蓝牙是否可用
 * @param available 当前蓝牙是否可用
 */
- (void)centralManagerDidUpdateState:(BOOL)available;
 
/*
 * @descripe 搜到蓝牙设备的回调,每次搜到一个新设备都会回调
 * @param isFinish 搜索是否结束
 * @param list 搜索当前搜索结果
 * @param error 参考BuzzError
 */
- (void)fetchDevice:(BOOL)isFinish device:(NSArray *)list apack:(NSArray *)adpacklist withResult:(BuzzResult)error;
 
/*
 * @descripe 连接制定蓝牙设备结果的回调
 * @param error 参考BuzzError
 */
- (void)connectResult:(BuzzResult)result withError:(NSError *)error;
 
/*
 * @descripe 连接被断开,被动断开或者主动断开
 * @param error 参考BuzzError
 */
- (void)disConnectResult:(BuzzResult)result withError:(NSError *)error;
 
/*
 * @descripe 连接制定蓝牙设备结果的回调(成功)
 * @param error 参考BuzzError
 */
- (void)hasconnectResult:(BuzzResult)result withError:(NSError *)error;
 
@end
 
 
@interface LSBuzzBTmanager : NSObject
 
@property (nonatomic, weak)  id<LSBuzzBTmanagerDelegate> delegate; // 部分回调
 
@property (nonatomic,assign) NSInteger scanTimeInterval;// 扫描时间
 
@property (nonatomic,strong) NSMutableArray *rssiarray;// 信号强度
 
 
// 单例
+ (instancetype)sharedInstance;
 
/*
 *
 * 搜索并连接指定的蓝牙设备
 *
 */
- (BOOL)FinddevFiter:(BOOL)pp;//查找设备,pp为YES表示开uuid过滤,NO表示关闭
 
- (void)stopSearchDevice;//停止扫描设备
 
- (void)connectBuzzard:(CBPeripheral *)peripheral;//连接某项蓝牙设备
 
- (void)disconnectBuzzard:(CBPeripheral *)peripheral;//与某项设备断开连接
 
- (void)writeValue:(NSString *)command option:(NSString *)option;
@end
 
 
//.m文件如下
//
//  LSBuzzBTmanager.m
//  gene
//
//  Created by lollipop on 2017/4/7.
//  Copyright © 2017年 lesports. All rights reserved.
//
 
#import "LSBuzzBTmanager.h"
#import "kbConsoleLog.h"
 
 
#define UUID_CONTROL_SERVICE            @"FEE0"
#define UUID_LISTEN_CHARACTERISTICS     @"FEE1"//写
@interface LSBuzzBTmanager() <CBCentralManagerDelegate,CBPeripheralDelegate> {
    
    CBCentralManager *centerManager;
    CBPeripheral *activePeripheral;
    CBCharacteristic *readCharacteristic;
    CBCharacteristic *controlCharacteristic;
}
 
@property (nonatomic,strong) NSMutableArray *devLists;
@property (nonatomic,strong) NSMutableArray *adpackLists;
 
@end
 
@implementation LSBuzzBTmanager
 
+ (instancetype)sharedInstance {
    static LSBuzzBTmanager *_sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _sharedInstance = [[LSBuzzBTmanager alloc] init];
    });
    return _sharedInstance;
}
 
- (instancetype)init {
    if (self = [super init]) {
        centerManager = [[CBCentralManager alloc]initWithDelegate:self queue:nil];
    }
    return self;
}
 
#pragma mark 搜索蓝牙设备相关
- (BOOL)FinddevFiter:(BOOL)ppp {
    // 蓝牙不可用
    if (centerManager.state != CBManagerStatePoweredOn) {
        if (_delegate && [_delegate respondsToSelector:@selector(fetchDevice:device:apack:withResult:)]) {
            [_delegate fetchDevice:NO device:nil apack:nil withResult:BuzzBTSuccess];
        }
        return NO;
    }
    
    // 开始搜索
    NSArray *serviceUUIDs = nil;
    if (ppp) {  // 过滤
//        serviceUUIDs = @[[CBUUID UUIDWithString:@""]];
    }
    [centerManager scanForPeripheralsWithServices:serviceUUIDs options:nil];
    if (_scanTimeInterval == 0) {
        _scanTimeInterval = 20;
    }
    // 先取消之前的延时
    [LSBuzzBTmanager cancelPreviousPerformRequestsWithTarget:self selector:@selector(scanTimeOut) object:self];
    // 重新执行超时
    [self performSelector:@selector(scanTimeOut) withObject:self afterDelay:_scanTimeInterval];
    return YES;
}
 
- (void)stopSearchDevice {
    [centerManager stopScan];
}
 
 
- (void)connectBuzzard:(CBPeripheral *)peripheral {
    [centerManager connectPeripheral:peripheral options:nil];
}
 
- (void)disconnectBuzzard:(CBPeripheral *)peripheral {
    [centerManager cancelPeripheralConnection:peripheral];
    activePeripheral = nil;
//    [HintView hintViewWithMessage:@"断开连接"];
}
 
- (void)scanTimeOut {
    [centerManager stopScan];
    if (_delegate && [_delegate respondsToSelector:@selector(fetchDevice:device:apack:withResult:)]) {
        [_delegate fetchDevice:NO device:_devLists apack:self.adpackLists withResult:BuzzBTSuccess];
    }
}
 
- (void)writeValue:(NSString *)command option:(NSString *)option{
    
    if (activePeripheral.state == CBPeripheralStateConnected) {
  
    }else if (activePeripheral.state == CBPeripheralStateConnecting){
        [HintView hintViewWithMessage:@"正在连接"];
        return;
    }else if (activePeripheral.state == CBPeripheralStateDisconnected){
       [HintView hintViewWithMessage:@"peripheral disconnected"];
        return;
    }else if (activePeripheral.state == CBPeripheralStateDisconnecting){
        [HintView hintViewWithMessage:@"peripheral disconnecting"];
        return;
    }
 
    NSData *data;
    if (option.length > 0) {
        data = [self command:command withOption:option];
    } else {
        data = [self dataFromHexString:command];
    }
    NSString *msg = [NSString stringWithFormat:@"Write command %@ on peripheral %@(%@)", data, activePeripheral.name, activePeripheral.identifier];
    NSLogK(msg);
    TDLog(@"controlCharacteristic is %@",controlCharacteristic);
    if (controlCharacteristic==nil) {
        [HintView hintViewWithMessage:@"未找到该设备"];
        return;
    }
 
    [activePeripheral writeValue:data forCharacteristic:controlCharacteristic type:CBCharacteristicWriteWithoutResponse];
 
}
 
#pragma mark - getter
- (NSMutableArray *)devLists{
    if (!_devLists) {
        _devLists = [[NSMutableArray alloc] init];
    }
    return _devLists;
}
- (NSMutableArray *)adpackLists{
    if (!_adpackLists) {
        _adpackLists = [[NSMutableArray alloc] init];
    }
    return _adpackLists;
}
- (NSMutableArray *)rssiarray{
    if (!_rssiarray) {
        _rssiarray = [[NSMutableArray alloc] init];
    }
    return _rssiarray;
}
 
#pragma mark CBCentralManagerDelegate
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
    BOOL isAvaliable = NO;
    if (central.state == CBManagerStatePoweredOn) {
        isAvaliable = YES;
    }
    if (_delegate && [_delegate respondsToSelector:@selector(centralManagerDidUpdateState:)]) {
        [_delegate centralManagerDidUpdateState:isAvaliable];
    }
}
// 扫描到设备
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI {
 
    if (!peripheral.name ) {
        return;
    }
    if (peripheral.name == 0) {
        return;
    }
    // 如果已经被搜索,就不新加入
    if ([self.devLists containsObject:peripheral]) {
        return;
    }
    
    // 1.信号过滤,信号太弱连不上
    // 2.名称过滤
    // 根据startScanBuzzard方法中扫描结果 再看是否需要增加过滤逻辑
    [self.devLists addObject:peripheral];
    NSData *data=advertisementData[@"kCBAdvDataManufacturerData"];
    NSString *adpackstr= [self dataToHex:data];
    [self.adpackLists addObject:adpackstr];
 
    [self.rssiarray addObject:[NSString stringWithFormat:@"%@",RSSI]];
    if (_delegate && [_delegate respondsToSelector:@selector(fetchDevice:device:apack:withResult:)]) {
        [_delegate fetchDevice:NO device:_devLists apack:self.adpackLists withResult:BuzzBTSuccess];
    }
}
 
// 连接设备
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
 
    activePeripheral = peripheral;
 
    if (_delegate && [_delegate respondsToSelector:@selector(hasconnectResult:withError:)]) {
        [_delegate hasconnectResult:BuzzBTSuccess withError:nil];
    }
    NSArray *services = nil;// @[[CBUUID UUIDWithString:@""]];
    activePeripheral.delegate = self;
    [activePeripheral discoverServices:services];
}
 
// 连接设备失败
-(void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
    NSString *msg = [NSString stringWithFormat:@"-didFailToConnectPeripheral-%@",peripheral.name];
    NSLogK(msg);
    if (_delegate && [_delegate respondsToSelector:@selector(connectResult:withError:)]) {
        [_delegate connectResult:BuzzBTFail withError:error];
    }
}
 
// 丢失连接
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
    NSString *msg = [NSString stringWithFormat:@"-didDisconnectPeripheral-%@",peripheral.name];
    NSLogK(msg);
    activePeripheral = nil;
    if (_delegate && [_delegate respondsToSelector:@selector(disConnectResult:withError:)]) {
        [_delegate disConnectResult:BuzzBTFail withError:error];
    }
}
 
// 服务
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
    if (error) {
        NSString *msg = [NSString stringWithFormat:@"did discover peripheral:%@(%@) service error : %@", peripheral.name, peripheral.identifier, error.localizedDescription];
        NSLogK(msg);
        return;
    }
    NSString *msg = [NSString stringWithFormat:@"did discover peripheral:%@(%@) service %@", peripheral.name, peripheral.identifier, peripheral.services];
    NSLogK(msg);
    //,[CBUUID UUIDWithString:UUID_LISTEN_CHARACTERISTICS]
    for (CBService *service in peripheral.services) {
        if ([service.UUID.UUIDString isEqualToString:UUID_CONTROL_SERVICE]) {
           [peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:UUID_LISTEN_CHARACTERISTICS]] forService:service];
                break;
        }
 
    }
}
 
// periperal discoverCharacteristics:(nullable NSArray<CBUUID *> *)characteristicUUIDs forService:(CBService *)service;
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
    if (error) {
        NSString *msg = [NSString stringWithFormat:@"peripheral %@(%@) did discover characteristic error %@", peripheral.name, peripheral.identifier, error.localizedDescription];
        NSLogK(msg);
        return;
    }
    
    NSString *msg = [NSString stringWithFormat:@"peripheral %@(%@) did discover characteristics %@", peripheral.name, peripheral.identifier, service.characteristics];
    NSLogK(msg);
    for (CBCharacteristic *chara in service.characteristics) {
        if ([chara.UUID isEqual:[CBUUID UUIDWithString:UUID_LISTEN_CHARACTERISTICS]]) {
            [peripheral setNotifyValue:YES forCharacteristic:chara];
            controlCharacteristic = chara;
        }
 
    }
 
}
 
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
    NSData *data = characteristic.value;
    NSString *response = [self dataToHex:data];
    NSString *msg = [NSString stringWithFormat:@"command did get response:%@", response];
    NSLogK(msg);
  
}
 
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
//    NSString *msg = [NSString stringWithFormat:@"didWriteValueForCharacteristic:%@", error];
//    TDLogK(msg);
    
    TDLog(@"error is %@",error);
    TDLog(@"characteristic is %@",characteristic);
    
}
 
#pragma mark 发送和接收数据解析相关,以下是针对我目前项目中蓝牙功能的封装,不一定适用其他项目
- (NSData *)command:(NSString *)hexCommand withOption:(NSString *)option{
    
    NSData *optionData = [option dataUsingEncoding:NSUTF8StringEncoding];
    
    NSInteger totalLength = optionData.length + 5;
    
    NSString *hexOptionString = [self dataToHex:optionData];
    
    NSString *lengthString = [NSString stringWithFormat:@"%X",(int)totalLength];
    
    //最长只支持 255 长度的命令
    if (lengthString.length==1) {
        lengthString = [NSString stringWithFormat:@"0%@",lengthString];
    }
    
    NSString *hexCommandString = [NSString stringWithFormat:hexCommand,lengthString,hexOptionString];
    
    NSData *commandData = [self dataFromHexString:hexCommandString];
    
    return commandData;
}
 
- (NSData *)dataFromHexString:(NSString *)hexString {
    const char *chars = [hexString UTF8String];
    long i = 0, len = hexString.length;
    
    NSMutableData *data = [NSMutableData dataWithCapacity:len / 2];
    char byteChars[3] = {'\0','\0','\0'};
    unsigned long wholeByte;
    
    while (i < len) {
        byteChars[0] = chars[i++];
        byteChars[1] = chars[i++];
        wholeByte = strtoul(byteChars, NULL, 16);
        [data appendBytes:&wholeByte length:1];
    }
    
    return data;
}
 
- (NSString *)dataToHex:(NSData *)data {
    NSUInteger i, len;
    unsigned char *buf, *bytes;
    
    len = data.length;
    bytes = (unsigned char*)data.bytes;
    buf = malloc(len*2);
    
    for (i=0; i<len; i++) {
        buf[i*2] = itoh((bytes[i] >> 4) & 0xF);
        buf[i*2+1] = itoh(bytes[i] & 0xF);
    }
    
    return [[NSString alloc] initWithBytesNoCopy:buf
                                          length:len*2
                                        encoding:NSUTF8StringEncoding
                                    freeWhenDone:YES];
}
 
static inline char itoh(int i) {
    if (i > 9) 
        return 'A' + (i - 10);
    return '0' + i;
}
 
 
/*
 *   把返回命令里的传递值拿出来
 */
- (NSString *)valueStringWithResponse:(NSData *)data {
    //NSData *ad = [NSData dataWithBytes:0x00 length:2];
    if (data.length <= 5) {
        return nil;
    }
    NSData *tailData = [data subdataWithRange:NSMakeRange(data.length-1, 1)];
    if ([tailData isEqualToData:[NSData dataWithBytes:"\0" length:1]]) {
        if (data.length > 6) {
            NSData *valueData = [data subdataWithRange:NSMakeRange(4, data.length-5)];
            NSString *valueString = [[NSString alloc] initWithData:valueData encoding:NSUTF8StringEncoding];
            return valueString;
        }
    } else {
        if (data.length > 5) {
            NSData *valueData = [data subdataWithRange:NSMakeRange(4, data.length-4)];
            NSString *valueString = [[NSString alloc] initWithData:valueData encoding:NSUTF8StringEncoding];
            return valueString;
        }
    }
    return nil;
}
 
@end
 //定义日志类
//
//  kbConsoleLog.h
//  TestDemoForKB
//
//  Created by lollipop on 2017/4/1.
//  Copyright © 2017年 lollipop. All rights reserved.
//
 
#import <UIKit/UIKit.h>
 
@interface kbConsoleLog : NSObject
 
+ (instancetype)sharedInstance;
 
- (void)showLog:(NSString *)log;
 
@end
 //.m文件
//
//  kbConsoleLog.m
//  TestDemoForKB
//
//  Created by lollipop on 2017/4/1.
//  Copyright © 2017年 lollipop. All rights reserved.
//
 
#import "kbConsoleLog.h"
 
@interface kbConsoleLog()
 
@property (nonatomic,copy)      UIWindow    *mainWindow;
 
@property (nonatomic,strong)    UITextView  *logView;
 
@end
 
@implementation kbConsoleLog
 
static kbConsoleLog *_consoleManager;
 
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    static dispatch_once_t onceToken;
    
    dispatch_once(&onceToken, ^{
        _consoleManager = [super allocWithZone:zone];
    });
    
    return _consoleManager;
}
 
- (nonnull id)copyWithZone:(nullable NSZone *)zone {
    return _consoleManager;
}
 
+ (instancetype)sharedInstance {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _consoleManager = [[self alloc] init];
    });
    
    return _consoleManager;
}
 
- (void)showLog:(NSString *)log {
    if ([NSThread isMainThread]) {
//        [self show:log];
    } else {
        dispatch_async(dispatch_get_main_queue(), ^{
//            [self show:log];
        });
    }
}
 
- (void)show:(NSString *)log {
    [self initMainWindow];
    // 打印到控制台中
    TDLog(@"%@", log);
    
    NSMutableString *string = [_logView.text mutableCopy];
    [string appendFormat:@"\n %@",log];
    _logView.text = string;
    
    NSRange bottom = NSMakeRange(string.length - 1, 1);
    [_logView scrollRangeToVisible:bottom];
}
 
- (void)initMainWindow {
    if (_mainWindow) {
        return;
    }
    _mainWindow = [[UIWindow alloc] init];
    _mainWindow.rootViewController = [UIViewController new];
    _mainWindow.windowLevel = UIWindowLevelAlert;
    _mainWindow.userInteractionEnabled = NO;
    CGFloat rgbF = 30.0 / 255;
    _mainWindow.backgroundColor = [UIColor colorWithRed:rgbF green:rgbF blue:rgbF alpha:0.1];
    _mainWindow.frame = [UIScreen mainScreen].bounds;
    _logView = [[UITextView alloc] init];
    _logView.frame = _mainWindow.bounds;
    _logView.textColor = [UIColor blackColor];
    _logView.backgroundColor = [UIColor clearColor];
    _logView.text = @"0-----";
    [_mainWindow addSubview:_logView];
    _mainWindow.hidden = NO;
    [_mainWindow makeKeyWindow];
}
@end
 
//当前使用蓝牙
-(void)CONNECT{
    
    [LSBuzzBTmanager sharedInstance].delegate = self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        
        [[LSBuzzBTmanager sharedInstance] FinddevFiter:YES];
    });
}
/*
 * @descripe 当前蓝牙是否可用
 * @param available 当前蓝牙是否可用
 */
- (void)centralManagerDidUpdateState:(BOOL)available {
    TDLog(@"--centralManagerDidUpdateState--");
    
}
/*
 * @descripe 搜到蓝牙设备的回调,每次搜到一个新设备都会回调
 * @param isFinish 搜索是否结束
 * @param list 搜索当前搜索结果
 * @param error 参考BuzzError
 */
-(void)fetchDevice:(BOOL)isFinish device:(NSArray *)list apack:(NSArray *)adpacklist withResult:(BuzzResult)error{
    self.devList = list;
    self.adpackList=adpacklist;
    TDLog(@"self.adpackList is %@",self.adpackList);
    [self.tableView reloadData];
}
 
/*
 * @descripe 连接制定蓝牙设备结果的回调
 * @param error 参考BuzzError
 */
- (void)connectResult:(BuzzResult)result withError:(NSError *)error {
    if (result == BuzzBTSuccess) {
        [self performSegueWithIdentifier:@"pushToDetail" sender:nil];
    }
    TDLog(@"error is %@",error);
}
 
/*
 * @descripe 连接被断开,被动断开或者主动断开
 * @param error 参考BuzzError
 */
- (void)disConnectResult:(BuzzResult)result withError:(NSError *)error {
    TDLog(@"error is %@",error);
    
    [SVProgressHUD dismiss];
    [HintView hintViewWithMessage:error.localizedDescription];
 
//    [self initycdata:self.currentmodels];
    //远程开门
}
-(void)hasconnectResult:(BuzzResult)result withError:(NSError *)error{
 
    
    __block RemoteOpenDoorViewController *weakSelf = self;
    dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC));
    dispatch_after(delayTime, dispatch_get_main_queue(), ^{
        [weakSelf delayMethod];
    });
    
    
 
    NSTimer *timer = [NSTimer timerWithTimeInterval:30 target:self selector:@selector(timerAction) userInfo:nil repeats:NO];
    [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
    [timer invalidate];
}
-(void)delayMethod{
    [SVProgressHUD dismiss];
    [[LSBuzzBTmanager sharedInstance] writeValue:self.currentmacs option:nil];
}
-(void)timerAction{
    [[LSBuzzBTmanager sharedInstance] stopSearchDevice];
    for (int i=0; i<self.devList.count; i++) {
        CBPeripheral *per=self.devList[i];
      [[LSBuzzBTmanager sharedInstance] disconnectBuzzard:per];
    }
}
//开门
    [[LSBuzzBTmanager sharedInstance] connectBuzzard:per];//后台直接操作