You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1376 lines
52 KiB
1376 lines
52 KiB
![]()
2 years ago
|
|
||
|
//
|
||
|
// Bluetooth.m
|
||
|
// BluetoothDemo
|
||
|
//
|
||
|
// Created by mac on 17/3/9.
|
||
|
// Copyright © 2017年 . All rights reserved.
|
||
|
//
|
||
|
|
||
![]()
1 year ago
|
#import "BluetoothFireBoltt.h"
|
||
|
#import "L2DataParseFireBoltt.h"
|
||
![]()
2 years ago
|
#import <SVProgressHUD/SVProgressHUD.h>
|
||
|
#import "NSString+methods.h"
|
||
|
#import "BLETools.h"
|
||
![]()
1 year ago
|
#import "BLEConstFireBoltt.h"
|
||
|
#import "BLEBaseBlFireBoltt.h"
|
||
![]()
1 year ago
|
#import "FireBoltt-Swift.h"
|
||
![]()
2 years ago
|
#import <CoreLocation/CoreLocation.h>
|
||
|
#import "User_Http.h"
|
||
|
|
||
|
|
||
|
NSString *kFLT_BLE_FOUND = @"FLT_BLE_FOUND"; //发现设备
|
||
|
NSString *kFLT_BLE_PAIRED = @"FLT_BLE_PAIRED"; //BLE已配对
|
||
|
NSString *kFLT_BLE_CONNECTED = @"FLT_BLE_CONNECTED"; //BLE已连接
|
||
|
NSString *kFLT_BLE_DISCONNECTED = @"FLT_BLE_DISCONNECTED"; //BLE断开连接
|
||
|
|
||
|
NSString *FLT_BLE_SERVICE = @"AE00"; //服务号
|
||
|
NSString *FLT_BLE_RCSP_W = @"AE01"; //命令“写”通道
|
||
|
NSString *FLT_BLE_RCSP_R = @"AE02"; //命令“读”通道
|
||
|
|
||
|
// 超时间隔
|
||
|
#define TimeOutNumber 5
|
||
|
// 连接延时
|
||
|
#define ConnectPeripheralTimerName @"Bluetooth_ConnectPeripheralTimerName"
|
||
|
#define ConnectPeripheralTimerName2 @"Bluetooth_ConnectPeripheralTimerName2"
|
||
|
|
||
![]()
1 year ago
|
@interface BluetoothFireBoltt () <CBPeripheralDelegate,CBCentralManagerDelegate>//CLLocationManagerDelegate
|
||
![]()
2 years ago
|
|
||
|
@property (nonatomic, strong) CBPeripheralManager *peripheralManager;
|
||
|
|
||
|
/** 蓝牙请求计数 */
|
||
|
@property (nonatomic, assign) NSInteger timeNumber;
|
||
|
/** 是否正在执行 */
|
||
|
@property (nonatomic, assign) BOOL isExecuting;
|
||
|
/** 超时定时器 */
|
||
|
@property (nonatomic, strong) NSTimer *checkoutTimer;
|
||
|
/** 当前执行的命令 */
|
||
![]()
1 year ago
|
@property (nonatomic, strong) BlueToothItemFireBoltt *currenItem;
|
||
![]()
2 years ago
|
/** 当前接收的数据 */
|
||
|
@property (nonatomic, strong) NSMutableData *currenData;
|
||
|
/** 总数据包 */
|
||
|
@property (nonatomic, strong) NSMutableData *totalData;
|
||
|
/** crc校验是否成功 */
|
||
|
@property (nonatomic, assign) BOOL isCrc;
|
||
|
/** 防止手表多次调用特征值变化 */
|
||
|
@property (nonatomic, assign) BOOL isChangeCharacteristic;
|
||
|
/** 重连外设 */
|
||
|
@property (nonatomic, strong) CBPeripheral *reconnectPeripheral;
|
||
|
/** 是否DFU扫描 */
|
||
|
@property (nonatomic, assign) BOOL isDFUScan;
|
||
|
|
||
|
//@property (nonatomic ,strong) CLLocationManager *locationManager;
|
||
|
//
|
||
|
//@property (nonatomic ,strong) CLBeaconRegion *beaconRegion;
|
||
|
|
||
|
/** */
|
||
|
@property (nonatomic, assign) BOOL is_JL;
|
||
|
|
||
|
|
||
|
/// 手表表盘资源文件
|
||
|
@property (nonatomic ,strong) NSArray *mWatchList;
|
||
|
|
||
|
/// 是否正在升级
|
||
|
@property (nonatomic ,assign) BOOL isOtaUpdate;
|
||
|
|
||
|
/// <#arguments#>
|
||
|
@property (nonatomic ,strong) NSString *mOtaPath;
|
||
|
|
||
|
@property (nonatomic ,strong) NSString *otaString;
|
||
|
|
||
|
@end
|
||
|
|
||
![]()
1 year ago
|
@implementation BluetoothFireBoltt
|
||
![]()
2 years ago
|
|
||
|
|
||
|
|
||
|
+ (nullable instancetype)shareInstance {
|
||
![]()
1 year ago
|
static BluetoothFireBoltt *share = nil;
|
||
![]()
2 years ago
|
static dispatch_once_t oneToken;
|
||
|
dispatch_once(&oneToken, ^{
|
||
|
share = [[self alloc] init];
|
||
|
});
|
||
|
return share;
|
||
|
}
|
||
|
|
||
|
- (id)init {
|
||
|
self = [super init];
|
||
|
if (self) {
|
||
|
self.isIndependentOff = NO;
|
||
|
self.bleRequestSid = 0;
|
||
|
self.bluetoothItems = [NSMutableArray array];
|
||
|
self.currenData = [NSMutableData new];
|
||
|
self.totalData = [NSMutableData new];
|
||
|
self.cMgr = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:@{CBCentralManagerOptionRestoreIdentifierKey: @"myCentralManagerIdentifier"}];
|
||
|
self.isChangeCharacteristic = NO;
|
||
|
self.is_JL = NO;
|
||
|
|
||
|
|
||
|
self.mAssist = [[JL_Assist alloc] init];
|
||
|
self.mAssist.mNeedPaired = YES; //是否需要握手配对
|
||
|
self.mAssist.mPairKey = nil; //配对秘钥
|
||
|
self.mAssist.mService = FLT_BLE_SERVICE; //服务号
|
||
|
self.mAssist.mRcsp_W = FLT_BLE_RCSP_W; //特征「写」
|
||
|
self.mAssist.mRcsp_R = FLT_BLE_RCSP_R; //特征「读」
|
||
|
|
||
|
// 监听时间改变
|
||
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||
|
selector:@selector(timeDidChanged)
|
||
|
name:UIApplicationSignificantTimeChangeNotification
|
||
|
object:nil];
|
||
|
}
|
||
|
return self;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
实时同步时间到设备
|
||
|
*/
|
||
|
- (void)timeDidChanged{
|
||
![]()
1 year ago
|
if ([[BluetoothFireBoltt shareInstance] isConnected]) {
|
||
![]()
2 years ago
|
// 延迟请求,防止时制切换未反应
|
||
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||
![]()
1 year ago
|
[[[BLEBaseBlFireBoltt alloc] init] setIngTimeWithBleCmdTypeFB:BleCMD_setIngTime];
|
||
![]()
2 years ago
|
});
|
||
|
}
|
||
|
// 更改了时间通知主要界面刷新界面,1为时间标示
|
||
|
[[NSNotificationCenter defaultCenter] postNotificationName:SycnDatas object:@(1)];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
扫描外设Peripherals
|
||
|
|
||
|
@param serviceUUIDs 过滤的服务UUID
|
||
|
@param isDFU 是否DFU升级使用
|
||
|
*/
|
||
|
- (void)scanForPeripheralsWithdiscoverServices:(nullable NSArray<CBUUID *> *)serviceUUIDs
|
||
|
IsDFU:(BOOL)isDFU {
|
||
|
// 停止扫描
|
||
|
[self cancelScan];
|
||
|
self.isDFUScan = isDFU;
|
||
|
// 获取系统已配对的手环平台设备,存在则加入
|
||
|
NSMutableArray *connectedArray = [self getPairedConnectedArray];
|
||
![]()
1 year ago
|
for (BLEModelFireBoltt *bleModel in connectedArray) {
|
||
![]()
2 years ago
|
[self.delegate onDiscoverToPeripheralsBleModel:bleModel];
|
||
|
}
|
||
|
// DFU模式不使用uuid的筛选扫描
|
||
|
if (isDFU || [[NSUserDefaults standardUserDefaults] objectForKey:DFUMASString])
|
||
|
{
|
||
|
NSDictionary *options= [NSDictionary dictionaryWithObject:@NO forKey:CBCentralManagerScanOptionAllowDuplicatesKey];
|
||
|
[self.cMgr scanForPeripheralsWithServices:nil options:options];
|
||
|
return;
|
||
|
}
|
||
|
NSArray *uuids = @[[CBUUID UUIDWithString:BraceletServicesUUID]];
|
||
|
NSDictionary *scanForPeripheralsWithOptions = @{CBCentralManagerScanOptionAllowDuplicatesKey:@YES};
|
||
|
[self.cMgr scanForPeripheralsWithServices:uuids options:scanForPeripheralsWithOptions];
|
||
|
}
|
||
|
|
||
|
|
||
|
#pragma mark - coreBlueTooth --系统代理
|
||
|
|
||
|
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
|
||
|
{
|
||
|
self.state = central.state;
|
||
|
[self.mAssist assistUpdateState:central.state];
|
||
|
if (central.state == CBManagerStatePoweredOn)
|
||
|
{
|
||
|
// 蓝牙开始重连
|
||
|
[self startAndStopReconnect:YES];
|
||
|
}
|
||
|
else if (central.state == CBManagerStatePoweredOff)
|
||
|
{
|
||
|
[[NSNotificationCenter defaultCenter] postNotificationName:BluetoothNotificationAtPowerOff object:@"PowerOff"];
|
||
|
CGFloat systemVision = DEVICEVERSION;
|
||
|
if (systemVision <10 || systemVision >= 11) {
|
||
|
if (self.isConnected) {
|
||
|
// 连接断开发出通知
|
||
|
self.isConnected = NO;
|
||
|
[[NSNotificationCenter defaultCenter] postNotificationName:BluetoothNotificationAtDisconnect object:nil];
|
||
|
// 清空所有
|
||
|
self.writecharacteristic = nil;
|
||
|
// 断开连接后处理,当前队列若存在则清空并且停止定时器
|
||
|
if (self.bluetoothItems.count) {
|
||
|
[self.bluetoothItems removeAllObjects];
|
||
|
[self.checkoutTimer invalidate];
|
||
|
self.timeNumber = 0;
|
||
|
_executing = NO;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
[self startAndStopReconnect: NO];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//搜索蓝牙设备
|
||
|
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral
|
||
|
advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI
|
||
|
{
|
||
|
NSLog(@"[蓝牙通讯] 搜索到了设备:%@ \n设备UUID:%@ \n advertisementData:%@",peripheral.name,
|
||
|
peripheral.identifier.UUIDString,
|
||
|
advertisementData);
|
||
|
NSString *ble_name = advertisementData[@"kCBAdvDataLocalName"];
|
||
|
|
||
|
NSString *MACString = [[NSString alloc] init];
|
||
|
NSData *manufacturerData = advertisementData[@"kCBAdvDataManufacturerData"];
|
||
|
if (manufacturerData && manufacturerData.length >= 8)
|
||
|
{
|
||
|
NSData *MACData = [advertisementData[@"kCBAdvDataManufacturerData"] subdataWithRange:NSMakeRange(2, 6)];
|
||
![]()
1 year ago
|
MACString = [BluetoothToolFireBoltt getPositiveSequenceMacWithData:MACData];
|
||
![]()
2 years ago
|
}
|
||
![]()
1 year ago
|
BLEModelFireBoltt *bleModel = [[BLEModelFireBoltt alloc] initWithCentral:central
|
||
![]()
2 years ago
|
Peripheral:peripheral
|
||
|
AdvertisementData:advertisementData
|
||
|
RSSI:RSSI
|
||
|
UUIDString:peripheral.identifier.UUIDString
|
||
|
MACString:MACString];
|
||
|
|
||
|
// 未完成升级设备 || 需要重连的设备
|
||
![]()
1 year ago
|
if ((self.isDFUScan && [peripheral.name isEqual:@"DfuTarg"]) || [bleModel.MACString isEqualToString:[UserDefaultsManagerFrieBoltt getLocalDeviceMacID]]) {
|
||
![]()
2 years ago
|
__weak typeof(self) weakSelf = self;
|
||
|
[GCDTimer.ocShareInstance scheduledDispatchTimerWithTimerName:ConnectPeripheralTimerName2 timeInterval:self.reconnectTime queue:dispatch_get_main_queue() repeats:false immediately:false action:^{
|
||
|
[weakSelf connectedWithBleModel:bleModel];
|
||
|
weakSelf.reconnectTime = 0;
|
||
|
}];
|
||
|
}
|
||
|
if (self.delegate && [self.delegate respondsToSelector:@selector(onDiscoverToPeripheralsBleModel:)])
|
||
|
{
|
||
|
[self.delegate onDiscoverToPeripheralsBleModel:bleModel];
|
||
|
}
|
||
|
// ota升级过程,回连使用
|
||
|
if (manufacturerData != nil && self.is_JL)
|
||
|
//if ([JL_BLEAction otaBleMacAddress:self.lastBleMacAddress isEqualToCBAdvDataManufacturerData:manufacturerData])
|
||
|
{
|
||
|
// self.is_JL = NO;
|
||
|
[self connectedWithBleModel:bleModel];
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
// 蓝牙状态的保存和恢复,进入后台和重新启动有关
|
||
|
- (void)centralManager:(CBCentralManager *)central willRestoreState:(NSDictionary<NSString *, id> *)dict
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
// 已经连接外设
|
||
|
- (void) centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
|
||
|
{
|
||
|
NSLog(@"[蓝牙通讯] BLE Connected ---> Device %@", peripheral.name);
|
||
|
peripheral.delegate = self;
|
||
|
[peripheral discoverServices:nil];
|
||
|
[self cancelScan];
|
||
|
// [peripheral discoverServices:[NSArray arrayWithObject:[CBUUID UUIDWithString:ServicesUUID]]];//再去发现服务
|
||
|
// 若是Dfu模式外设则在此处发出连接成功的通知
|
||
|
if ([peripheral.name rangeOfString:@"DfuTarg"].location != NSNotFound)
|
||
|
{
|
||
|
NSLog(@"DFUl连接成功!!!!");
|
||
|
self.isConnected = YES;
|
||
|
[[NSNotificationCenter defaultCenter] postNotificationName:BluetoothNotificationAtDFUConnectSuccess object:nil];
|
||
|
}
|
||
|
|
||
|
}
|
||
|
// 连接外设失败
|
||
|
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
|
||
|
{
|
||
|
NSLog(@"[蓝牙通讯] 设备:%@--连接失败",peripheral.name);
|
||
|
|
||
|
//if (self.isIndependentOff)
|
||
|
[SVProgressHUD showInfoWithStatus:NSLocalizedString(@"连接失败", nil)];
|
||
|
// 连接失败发出通知
|
||
|
[[NSNotificationCenter defaultCenter] postNotificationName:BluetoothNotificationAtConnectFail object:peripheral.name];
|
||
|
self.isConnected = NO;
|
||
|
//self.isRay = NO;
|
||
|
}
|
||
|
// 已经断开连接
|
||
|
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
|
||
|
NSLog(@"[蓝牙通讯] 设备:%@--断开连接",peripheral.name);
|
||
|
|
||
|
/*--- JLSDK ADD ---*/
|
||
|
[self.mAssist assistDisconnectPeripheral:peripheral];
|
||
|
|
||
|
// 连接断开发出通知
|
||
|
self.isConnected = NO;
|
||
|
//self.isRay = NO;
|
||
|
|
||
|
[[NSNotificationCenter defaultCenter] postNotificationName:BluetoothNotificationAtDisconnect object:peripheral.name];
|
||
|
// 清空所有
|
||
|
self.writecharacteristic = nil;
|
||
|
// 断开连接后处理,当前队列若存在则清空并且停止定时器
|
||
|
if (self.bluetoothItems.count)
|
||
|
{
|
||
|
|
||
|
[self.bluetoothItems removeAllObjects];
|
||
|
[self.checkoutTimer invalidate];
|
||
|
self.timeNumber = 0;
|
||
|
_executing = NO;
|
||
|
}
|
||
|
//if (!self.isIndependentOff)
|
||
|
[self startAndStopReconnect:YES];
|
||
|
}
|
||
|
|
||
|
|
||
|
// characteristic订阅状态改变
|
||
|
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error
|
||
|
{
|
||
|
NSLog(@"[蓝牙通讯] //characteristic订阅状态改变的block---- %@",characteristic.value);
|
||
|
// 判断是否监听设备广播通知成功 -->成功才发送连接成功通知
|
||
|
if (characteristic.isNotifying && [characteristic.UUID isEqual:[CBUUID UUIDWithString:NotifycharacteristicUUIDString]])
|
||
|
{
|
||
|
NSLog(@"[蓝牙通讯] 连接成功!!!!!!");
|
||
|
// 连接成功保存UUID,做重连使用
|
||
|
[[NSUserDefaults standardUserDefaults] setObject:peripheral.identifier.UUIDString forKey:AutomaticReconnectionDevice];
|
||
|
// 订阅了读数据才发出连接成功通知
|
||
|
self.isConnected = YES;
|
||
|
self.reconnectPeripheral = peripheral;
|
||
|
[[NSNotificationCenter defaultCenter] postNotificationName:BluetoothNotificationAtConnectSuccess object:self.currenModel];
|
||
|
}
|
||
|
[self jlTimeClose];
|
||
|
self.is_JL = NO;
|
||
|
__weak typeof(self) weakSelf = self;
|
||
|
[self.mAssist assistUpdateCharacteristic:characteristic Peripheral:peripheral Result:^(BOOL isPaired) {
|
||
|
if (isPaired == YES)
|
||
|
{
|
||
|
[[NSUserDefaults standardUserDefaults] setObject:peripheral.identifier.UUIDString forKey:AutomaticReconnectionDevice];
|
||
|
NSLog(@"[蓝牙通讯] 配对成功");
|
||
|
self.reconnectPeripheral = peripheral;
|
||
|
[JL_Tools post:kFLT_BLE_PAIRED Object:peripheral];
|
||
|
JL_EntityM *entity = [[JL_EntityM alloc] init];
|
||
|
[entity setBlePeripheral:peripheral];
|
||
|
self.mAssist.mCmdManager.mEntity = entity;
|
||
|
weakSelf.lastBleMacAddress = nil;
|
||
|
|
||
|
[JL_Tools delay:0.5 Task:^{
|
||
|
[self getInfo];
|
||
|
}];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
[weakSelf.cMgr cancelPeripheralConnection:peripheral];
|
||
|
}
|
||
|
}];
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//外设传来数据
|
||
|
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
|
||
|
// NSLog(@" 设备发过来的 characteristic name:%@ value is:%@",characteristic.UUID,characteristic.value);
|
||
|
|
||
|
/*--- JLSDK ADD ---*/
|
||
|
[self.mAssist assistUpdateValueForCharacteristic:characteristic];
|
||
|
|
||
|
if (characteristic.value.length && [characteristic.UUID isEqual:[CBUUID UUIDWithString:NotifycharacteristicUUIDString]]) {
|
||
|
// 接收到的数据处理
|
||
|
[self handleReceiveData:[characteristic value]];
|
||
|
}
|
||
|
// FRQ OTA是否存在数据
|
||
|
if (characteristic.value.length && [characteristic.UUID isEqual:[CBUUID UUIDWithString:kFRQReadCharacteristicUUID]]) {
|
||
|
[[NSNotificationCenter defaultCenter] postNotificationName:FRQReadCharacteristicUUIDNotify object:characteristic.value];
|
||
|
}
|
||
|
if (self.delegate && [self.delegate respondsToSelector:@selector(OnReadValueForCharacteristic:characteristicsL:)]) {
|
||
|
[self.delegate OnReadValueForCharacteristic:peripheral characteristicsL:characteristic];
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
//发现服务
|
||
|
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
|
||
|
{
|
||
|
if (error) { NSLog(@"Err: Discovered services fail."); return; }
|
||
|
|
||
|
for (CBService *service in peripheral.services)
|
||
|
{
|
||
|
NSLog(@"[蓝牙通讯] BLE Service ---> %@", service.UUID.UUIDString);
|
||
|
[peripheral discoverCharacteristics:nil forService:service];
|
||
|
}
|
||
|
if (self.delegate && [self.delegate respondsToSelector:@selector(onDiscoverServices:)])
|
||
|
{
|
||
|
[self.delegate onDiscoverServices:peripheral];
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
//发现特征值
|
||
|
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
|
||
|
{
|
||
|
[self.mAssist assistDiscoverCharacteristicsForService:service Peripheral:peripheral];
|
||
|
|
||
|
if (IsDelegate(self, OnDiscoverCharacteristics:Service:)) {
|
||
|
[self.delegate OnDiscoverCharacteristics:peripheral Service:service];
|
||
|
}
|
||
|
if ([service.UUID isEqual:[CBUUID UUIDWithString:ServicesUUID]]) {
|
||
|
for (CBCharacteristic *characteristic in service.characteristics ) {
|
||
|
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:NotifycharacteristicUUIDString]]) {
|
||
|
[peripheral setNotifyValue:true forCharacteristic:characteristic];
|
||
|
}
|
||
|
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:WirtecharacteristicUUIDString]]) {
|
||
|
self.writecharacteristic = characteristic;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// FRQ OTA
|
||
|
if ([service.UUID isEqual:[CBUUID UUIDWithString:kFRQServiceUUID]]) {
|
||
|
for (CBCharacteristic *characteristic in service.characteristics ) {
|
||
|
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:kFRQReadCharacteristicUUID]]) {
|
||
|
[peripheral setNotifyValue:true forCharacteristic:characteristic];
|
||
|
}
|
||
|
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:kFRQWriteCharacteristicUUID]]) {
|
||
|
self.frqOTAwritecharacteristic = characteristic;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
//写入值的监听
|
||
|
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error {
|
||
|
NSLog(@"写入成功");
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
停止扫描
|
||
|
*/
|
||
|
- (void)cancelScan {
|
||
|
[self.cMgr stopScan];
|
||
|
}
|
||
|
|
||
|
//-(void)centralManager:(CBCentralManager *)central connectionEventDidOccur:(CBConnectionEvent)event
|
||
|
// forPeripheral:(CBPeripheral *)peripheral
|
||
|
//{
|
||
|
// if (event == CBConnectionEventPeerConnected)
|
||
|
// {
|
||
|
// NSLog(@"---> 系统界面,已连接设备:%@",peripheral.name);
|
||
|
// if (peripheral.name.length > 0) {
|
||
|
// [self connectBLE:peripheral];
|
||
|
// }
|
||
|
// }
|
||
|
//
|
||
|
// if (event == CBConnectionEventPeerDisconnected) {
|
||
|
// NSLog(@"---> 系统界面,断开设备:%@",peripheral.name);
|
||
|
// }
|
||
|
//}
|
||
|
|
||
|
//-(void)connectBLE:(CBPeripheral*)peripheral
|
||
|
//{
|
||
|
// self.reconnectPeripheral = peripheral;
|
||
|
// [self.reconnectPeripheral setDelegate:self];
|
||
|
//
|
||
|
// [self.cMgr connectPeripheral:self.reconnectPeripheral
|
||
|
// options:@{CBConnectPeripheralOptionNotifyOnDisconnectionKey:@(YES),
|
||
|
// CBConnectPeripheralOptionNotifyOnConnectionKey:@(YES)
|
||
|
// }];
|
||
|
// [self.cMgr stopScan];
|
||
|
//
|
||
|
// NSLog(@"BLE Connecting... Name ---> %@ UUID:%@",peripheral.name,peripheral.identifier.UUIDString);
|
||
|
//}
|
||
|
|
||
|
/**
|
||
|
连接设备
|
||
|
@param bleModel ble模型
|
||
|
*/
|
||
![]()
1 year ago
|
- (void)connectedWithBleModel:(BLEModelFireBoltt *)bleModel
|
||
![]()
2 years ago
|
{
|
||
|
self.currenModel = bleModel;
|
||
|
self.reconnectPeripheral = bleModel.peripheral;
|
||
|
// 连接设备
|
||
|
NSLog(@"BLE Connecting... Name ---> %@", bleModel.peripheral.name);
|
||
|
[bleModel.peripheral setDelegate:self];
|
||
|
//[self.cMgr connectPeripheral:bleModel.peripheral options:@{CBConnectPeripheralOptionNotifyOnDisconnectionKey:@(YES)}];
|
||
|
if (@available(iOS 13.0, *)) {
|
||
|
[self.cMgr connectPeripheral:bleModel.peripheral options:@{CBConnectPeripheralOptionNotifyOnDisconnectionKey:@(YES),CBConnectPeripheralOptionEnableTransportBridgingKey:@(YES)}];
|
||
|
} else {
|
||
|
[self.cMgr connectPeripheral:bleModel.peripheral options:@{CBConnectPeripheralOptionNotifyOnDisconnectionKey:@(YES)}];
|
||
|
}
|
||
|
// 停止扫描
|
||
|
[self cancelScan];
|
||
|
}
|
||
|
|
||
|
/// 断开当前连接的设备
|
||
|
/// @param isUnbind 是否解绑
|
||
|
- (void)disConnectedCurrenDevice:(BOOL)isUnbind
|
||
|
{
|
||
|
if (isUnbind) {
|
||
|
[[NSUserDefaults standardUserDefaults] removeObjectForKey:AutomaticReconnectionDevice];
|
||
|
}
|
||
|
// 调用则立刻设置为断开
|
||
|
self.isConnected = NO;
|
||
|
// 存在设备则断开
|
||
|
if (self.reconnectPeripheral)
|
||
|
{
|
||
|
[self.cMgr cancelPeripheralConnection:self.reconnectPeripheral];
|
||
|
if (isUnbind)
|
||
|
{
|
||
|
self.reconnectPeripheral = nil;
|
||
|
self.currenModel = nil;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
蓝牙设备重连
|
||
|
|
||
|
@param isStart 开启停止
|
||
|
*/
|
||
|
- (void)startAndStopReconnect:(BOOL)isStart
|
||
|
{
|
||
|
if (!isStart || self.state != CBManagerStatePoweredOn) {
|
||
|
// 取消重连
|
||
|
if (self.reconnectPeripheral) {
|
||
|
[self.cMgr cancelPeripheralConnection:self.reconnectPeripheral];
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
// 获取本地设备
|
||
|
NSString *reconnectionUUIDSrting = [[NSUserDefaults standardUserDefaults] objectForKey:AutomaticReconnectionDevice];
|
||
|
if (!reconnectionUUIDSrting) {
|
||
|
return;
|
||
|
}
|
||
|
// 重连系统已配对设备
|
||
|
NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:reconnectionUUIDSrting];
|
||
|
NSArray *systemPeripherals = [self.cMgr retrievePeripheralsWithIdentifiers:@[uuid]];
|
||
|
if (systemPeripherals.count)
|
||
|
{
|
||
|
CBPeripheral *peripheral = systemPeripherals.firstObject;
|
||
![]()
1 year ago
|
BLEModelFireBoltt *bleModel = [[BLEModelFireBoltt alloc] initWithCentral:self.cMgr
|
||
![]()
2 years ago
|
Peripheral:peripheral
|
||
|
AdvertisementData:0
|
||
|
RSSI:[NSNumber numberWithInteger:0]
|
||
|
UUIDString:peripheral.identifier.UUIDString
|
||
|
MACString:nil];
|
||
|
self.currenModel = bleModel;
|
||
|
self.reconnectPeripheral = peripheral;
|
||
|
__weak typeof(self) weakSelf = self;
|
||
|
[GCDTimer.ocShareInstance scheduledDispatchTimerWithTimerName:ConnectPeripheralTimerName timeInterval:self.reconnectTime queue:dispatch_get_main_queue() repeats:false immediately:false action:^{
|
||
|
weakSelf.reconnectPeripheral.delegate = self;
|
||
|
[weakSelf.cMgr connectPeripheral:weakSelf.reconnectPeripheral options:@{CBConnectPeripheralOptionNotifyOnDisconnectionKey:@(YES),
|
||
|
CBConnectPeripheralOptionNotifyOnConnectionKey:@(YES),
|
||
|
CBConnectPeripheralOptionNotifyOnNotificationKey:@(YES)}];
|
||
|
weakSelf.reconnectTime = 0;
|
||
|
[self cancelScan];
|
||
|
}];
|
||
|
}
|
||
|
// 扫描设备
|
||
|
[self scanForPeripheralsWithdiscoverServices:nil IsDFU:true];
|
||
|
}
|
||
|
|
||
|
|
||
|
//========== 处理蓝牙指令 ========== //
|
||
|
|
||
|
/**
|
||
|
写入数据
|
||
|
|
||
|
@param bleItem 蓝牙命令模型
|
||
|
*/
|
||
![]()
1 year ago
|
- (void)writeWithBleItem:(BlueToothItemFireBoltt *)bleItem {
|
||
![]()
2 years ago
|
if (self.isConnected) {
|
||
|
[self.bluetoothItems addObject:bleItem];
|
||
|
[self loopRequest];
|
||
|
return;
|
||
|
}
|
||
|
// 代理超时返回
|
||
|
if (IsDelegate(bleItem.dataSource, bluetoothManager:sequenceID:didTimeOutWithData:cmdId:)) {
|
||
|
[bleItem.dataSource bluetoothManager:self sequenceID:bleItem.sid didTimeOutWithData:nil cmdId:bleItem.cmd];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// 清空指令队列
|
||
|
- (void)removeCmdItem {
|
||
|
// 当前队列若存在则清空并且停止定时器
|
||
|
if (self.bluetoothItems.count) {
|
||
|
[self.bluetoothItems removeAllObjects];
|
||
|
[self.checkoutTimer invalidate];
|
||
|
self.timeNumber = 0;
|
||
|
_executing = NO;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- (void)firmwareCompleteResetDelegate {
|
||
|
self.cMgr.delegate = self;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
循环串行 执行蓝牙请求(先进先出)
|
||
|
*/
|
||
|
- (void)loopRequest
|
||
|
{
|
||
|
if (_bluetoothItems.count > 0 && _executing == NO) {
|
||
![]()
1 year ago
|
BlueToothItemFireBoltt *bleItem = _bluetoothItems.firstObject;
|
||
![]()
2 years ago
|
if (!bleItem.isExecuting) {
|
||
|
|
||
|
self.currenItem = bleItem;
|
||
|
|
||
|
// 分包发送数据
|
||
|
[self handleWithByteBuffer:self.currenItem.byteBuffer];
|
||
|
|
||
|
bleItem.isExecuting = YES;
|
||
|
_executing = YES;
|
||
|
|
||
|
// 定时器开启 3秒超时
|
||
|
self.timeNumber = 0;
|
||
|
CGFloat timeOut = 1.0;
|
||
|
NSTimer *checkoutTimer = [NSTimer scheduledTimerWithTimeInterval:timeOut target:self selector:@selector(clickTimeout:) userInfo:nil repeats:YES];
|
||
|
self.checkoutTimer = checkoutTimer;
|
||
|
NSLog(@"[蓝牙通讯] 发送了蓝牙指令 %@ 序号是 %ld 指令是 %ld",bleItem.byteBuffer,bleItem.sid,bleItem.cmd);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
超时处理,进入此方法则重发
|
||
|
*/
|
||
|
- (void)clickTimeout:(NSTimer *)timer {
|
||
|
|
||
|
self.timeNumber++;
|
||
|
|
||
|
NSLog(@"[蓝牙通讯] 超时了,第 %ld 秒",self.timeNumber);
|
||
|
|
||
|
// 超时五秒后重发
|
||
|
if (self.timeNumber > TimeOutNumber) {
|
||
|
|
||
|
// 重发三次
|
||
|
if (self.currenItem.requestCount < 2) {
|
||
|
|
||
|
self.timeNumber = 0;
|
||
|
|
||
|
NSLog(@"[蓝牙通讯] 重新发送了 %ld",self.currenItem.requestCount);
|
||
|
|
||
|
self.currenItem.requestCount++;
|
||
|
|
||
|
// 重新发送时置空数据包
|
||
|
self.currenData = [NSMutableData new];
|
||
|
self.totalData = [NSMutableData new];
|
||
|
|
||
|
// 分包发送数据
|
||
|
[self handleWithByteBuffer:self.currenItem.byteBuffer];
|
||
|
|
||
|
}else {
|
||
|
// 超时隐藏提示框
|
||
|
[SVProgressHUD dismiss];
|
||
|
// [SVProgressHUD showInfoWithStatus:NSLocalizedString(@"请求超时", nil)];
|
||
|
// // 超时断开设备
|
||
|
// [self disConnectedCurrenDevice:false];
|
||
|
// 代理超时返回
|
||
|
if (IsDelegate(self.currenItem.dataSource, bluetoothManager:sequenceID:didTimeOutWithData:cmdId:)) {
|
||
|
|
||
|
[self.currenItem.dataSource bluetoothManager:self sequenceID:self.currenItem.sid didTimeOutWithData:nil cmdId:self.currenItem.cmd];
|
||
|
}
|
||
|
// 超时处理
|
||
|
[self completeAndTimeouthandleWithItem:self.currenItem];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
分包数据发送处理
|
||
|
*/
|
||
|
- (void)handleWithByteBuffer:(NSMutableData *)byteBuffer
|
||
|
{
|
||
|
// 发送时默认回调数据校验成功
|
||
|
self.isCrc = YES;
|
||
|
// 大于20字节则分包发送
|
||
|
if (byteBuffer.length > 20)
|
||
|
{
|
||
|
NSInteger count = byteBuffer.length / 20;
|
||
|
for (int i = 0; i <= count; i++)
|
||
|
{
|
||
|
NSData *data = [[NSData alloc] init];
|
||
|
if (i < count)
|
||
|
{
|
||
|
data = [byteBuffer subdataWithRange:NSMakeRange(i * 20, 20)];
|
||
|
}
|
||
|
else if (byteBuffer.length % 20)
|
||
|
{
|
||
|
// 最后不足20字节的数据
|
||
|
data = [byteBuffer subdataWithRange:NSMakeRange(i * 20, byteBuffer.length % 20)];
|
||
|
}
|
||
|
if (data)
|
||
|
{
|
||
|
if (self.writecharacteristic)
|
||
|
{
|
||
|
// 写入数据
|
||
|
[self.reconnectPeripheral writeValue:data forCharacteristic:self.writecharacteristic type:CBCharacteristicWriteWithoutResponse];
|
||
|
// NSLog(@"写入数据 %@",data);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (self.writecharacteristic)
|
||
|
{
|
||
|
// 写入数据
|
||
|
[self.reconnectPeripheral writeValue:byteBuffer forCharacteristic:self.writecharacteristic type:CBCharacteristicWriteWithoutResponse];
|
||
|
//NSLog(@"写入数据 %@",byteBuffer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// for (int i = 0; i < byteBuffer.length; i += 20)
|
||
|
// {
|
||
|
// // 预加 最大包长度,如果依然小于总数据长度,可以取最大包数据大小
|
||
|
// if ((i + 20) < byteBuffer.length)
|
||
|
// {
|
||
|
// NSString *rangeStr = [NSString stringWithFormat:@"%i,%i", i, 20];
|
||
|
// NSData *subData = [byteBuffer subdataWithRange:NSRangeFromString(rangeStr)];
|
||
|
// NSLog(@"%@",subData);
|
||
|
// if (self.writecharacteristic)
|
||
|
// {
|
||
|
// // 写入数据
|
||
|
// [self.reconnectPeripheral writeValue:subData forCharacteristic:self.writecharacteristic type:CBCharacteristicWriteWithoutResponse];
|
||
|
// NSLog(@"写入数据 %@",subData);
|
||
|
// }
|
||
|
// //根据接收模块的处理能力做相应延时
|
||
|
// usleep(20 * 1000);
|
||
|
// }
|
||
|
// else {
|
||
|
// if (self.writecharacteristic)
|
||
|
// {
|
||
|
// // 写入数据
|
||
|
// [self.reconnectPeripheral writeValue:byteBuffer forCharacteristic:self.writecharacteristic type:CBCharacteristicWriteWithoutResponse];
|
||
|
// NSLog(@"写入数据 %@",byteBuffer);
|
||
|
// }
|
||
|
// usleep(20 * 1000);
|
||
|
// }
|
||
|
// }
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
任务完成 || 超时 处理
|
||
|
|
||
|
@param item 当前蓝牙命令
|
||
|
*/
|
||
![]()
1 year ago
|
- (void)completeAndTimeouthandleWithItem:(BlueToothItemFireBoltt *)item {
|
||
![]()
2 years ago
|
|
||
|
[self.checkoutTimer invalidate];
|
||
|
_executing = NO;
|
||
|
self.currenData = [NSMutableData new];
|
||
|
self.totalData = [NSMutableData new];
|
||
|
[self.bluetoothItems removeObject:item];
|
||
|
[self loopRequest];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
根据序号查找当前队列是否存在
|
||
|
*/
|
||
![]()
1 year ago
|
- (BlueToothItemFireBoltt *)requestItemFromIndex:(int)index {
|
||
|
for (BlueToothItemFireBoltt *item in _bluetoothItems)
|
||
![]()
2 years ago
|
{
|
||
|
if (item.sid == index) {
|
||
|
return item;
|
||
|
}
|
||
|
}
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
处理收到的数据
|
||
|
|
||
|
@param data 返回的数据
|
||
|
*/
|
||
|
#pragma mark ---- 处理收到的数据
|
||
|
- (void)handleReceiveData:(NSData *)data {
|
||
|
NSLog(@"[蓝牙通讯] 接收到的数据------%@",data);
|
||
|
// 如果存在队列 收到数据则重新计算超时
|
||
|
if (_bluetoothItems.count) {
|
||
|
self.timeNumber = 0;
|
||
|
}
|
||
|
// 处理命令后的返回数据
|
||
|
[self.currenData appendData:data];
|
||
|
// 判断数据是否完整
|
||
|
Byte *currentDataBytes = (Byte *)[self.currenData bytes];
|
||
|
int contenLenght = (currentDataBytes[2] & 0xff) << 8 | (currentDataBytes[3] & 0xff);
|
||
|
int actualLenght = (int)self.currenData.length - 8;
|
||
|
// NSLog(@"现在的数据------ %@",self.currenData);
|
||
|
// NSLog(@"应该有的长度------ %d 现在的长度-------- %d",contenLenght,actualLenght);
|
||
|
//Byte *buffer = (Byte *)[self.currenData bytes];
|
||
|
// 接收到的数据包完整
|
||
|
if (contenLenght == actualLenght) {
|
||
|
// 判断序号是否存在当前队列
|
||
|
int sid = (currentDataBytes[6] & 0xff) << 8 | (currentDataBytes[7] & 0xff);
|
||
![]()
1 year ago
|
BlueToothItemFireBoltt *item = [self requestItemFromIndex:sid];
|
||
![]()
2 years ago
|
if (item) {
|
||
|
// 判断err,1:成功 0:失败
|
||
|
BOOL err = [self checkDataWithData:self.currenData ByteIndex:1 bitIndex:2];
|
||
|
if (err) {
|
||
|
// 大于200bytes字节的数据不做CRC处理
|
||
|
if (contenLenght <= 200) {
|
||
|
// CRC校验(失败则返回重发)
|
||
![]()
1 year ago
|
if (![BluetoothToolFireBoltt checkCRCWithData:self.currenData]) {
|
||
![]()
2 years ago
|
self.isCrc = NO;
|
||
|
}
|
||
|
}
|
||
|
// 判断是否有后续数据包返回 1:有 0:无
|
||
|
BOOL isData = [self checkDataWithData:self.currenData ByteIndex:1 bitIndex:1];
|
||
|
if (!isData && !self.isCrc) {
|
||
|
// 不存在后续数据并且数据检验失败直接重发
|
||
|
return;
|
||
|
}
|
||
|
if (isData) {
|
||
|
// 还有后续数据则将当前完整数据包以分隔符拼接
|
||
|
[self.totalData appendData:self.currenData];
|
||
|
self.currenData = [NSMutableData new];
|
||
|
[self.totalData appendData:[DataSeparator dataUsingEncoding:NSUTF8StringEncoding]];
|
||
|
return;
|
||
|
}else{
|
||
|
// 拼接最后完整数据包
|
||
|
[self.totalData appendData:self.currenData];
|
||
|
// 代理返回成功数据
|
||
|
if (IsDelegate(item.dataSource, bluetoothManager:sequenceID:didCompleteWithData:cmdId:)) {
|
||
|
[self.currenItem.dataSource bluetoothManager:self sequenceID:item.sid didCompleteWithData:self.totalData cmdId:item.cmd];
|
||
|
}
|
||
|
// 当前数据处理完成
|
||
|
[self completeAndTimeouthandleWithItem:item];
|
||
|
}
|
||
|
}
|
||
|
}else {
|
||
|
// 不存在此队列(设备主动发送过来的数据)
|
||
|
[self handleDeviceControlWithData:self.currenData];
|
||
|
self.currenData = [NSMutableData new];
|
||
|
}
|
||
|
}else {
|
||
|
// 数据不完整返回拼接
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
处理设备发送过来的指令(找手机,拍照功能,实时数据)
|
||
|
*/
|
||
|
- (void)handleDeviceControlWithData:(NSMutableData *)data {
|
||
|
|
||
|
NSLog(@"处理设备发送过的指令 ------- %@",data);
|
||
|
// 检查是否为指令
|
||
|
if (((Byte*)([data bytes]))[0] == 0xCB) {
|
||
|
|
||
|
// 判断err是否正确
|
||
|
BOOL err = [self checkDataWithData:data ByteIndex:1 bitIndex:2];
|
||
|
|
||
|
if (err) {
|
||
|
|
||
|
Byte key = ((Byte*)([data bytes]))[10];
|
||
|
|
||
![]()
1 year ago
|
BleCMD_FireBoltt blecmd = 0;
|
||
![]()
2 years ago
|
|
||
|
switch (key) {
|
||
|
case 0x46: //!< 拍照开关 0X46
|
||
|
{
|
||
|
blecmd = BleCMD_cameraSwitch;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 0x47: //!< 拍照 0X47
|
||
|
{
|
||
|
blecmd = BleCMD_cameraON;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 0x48: //!< 退出拍照 0X48
|
||
|
{
|
||
|
blecmd = BleCMD_cameraOFF;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 0x51: //!< 查找手机 0X51
|
||
|
{
|
||
|
blecmd = BleCMD_findPhone;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 0xB4: //!< 实时计步,心率,血压,血氧-> 同步实时数据
|
||
|
case 0xB3:
|
||
|
case 0xB6:
|
||
|
case 0xB7:
|
||
|
case 0xB8:
|
||
|
{
|
||
|
blecmd = BleCMD_realTimesync;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 0x01: //!< 抬手亮屏设置
|
||
|
{
|
||
|
blecmd = BleCMD_gesturesControl;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 0xA5: //!< 辅助运动,的运动数据
|
||
|
{
|
||
|
//blecmd = BleCMD_sportModelData;
|
||
|
blecmd = BleCMD_syncHealth;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 0x41: //!< 电量
|
||
|
{
|
||
|
blecmd = BleCMD_batteryBack;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
// 将设备控制的指令类型通知出去
|
||
|
if (blecmd) {
|
||
|
if (blecmd == BleCMD_realTimesync)
|
||
![]()
1 year ago
|
[BLEBaseBlFireBoltt.shareInstance readProfileWithBleCmdTypeFB:BleCMD_readProfile];
|
||
![]()
2 years ago
|
|
||
|
// 处理设备端发来的实时步数,心率,血压血氧
|
||
|
if (blecmd == BleCMD_realTimesync||blecmd == BleCMD_syncHealth) {
|
||
![]()
1 year ago
|
NSDictionary *dict = [L2DataParseFireBoltt L2_ParseData:data type:blecmd];
|
||
|
BleCMD_FireBoltt reportCMD = [dict[@"DataType"] integerValue];
|
||
![]()
2 years ago
|
[[NSNotificationCenter defaultCenter] postNotificationName:DeviceReportRealTimeHealthData object:@(reportCMD) userInfo:dict];
|
||
|
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
// 回复设备发出通知
|
||
|
[self checkCRCHandleWithData:data confirm:YES];
|
||
|
[[NSNotificationCenter defaultCenter] postNotificationName:DeviceControlNotification object:@(blecmd) userInfo:@{@"data": data}];
|
||
|
return;
|
||
|
}
|
||
|
} else {
|
||
|
[self checkCRCHandleWithData:data confirm:NO];// 回复设备发出通知
|
||
|
}
|
||
|
} else {
|
||
|
return; // 非请求返回的数据也不是设备发送过来的数据不处理
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
处理设备的运动状态
|
||
|
*/
|
||
|
- (void)handleSportStateWithData:(NSMutableData *)data {
|
||
|
// Byte *buffer = (Byte *)[data bytes];
|
||
|
// int sportState = buffer[13];
|
||
|
//
|
||
|
// UserGlobal *userGlobal = [UserGlobal ocShareInstance];
|
||
|
// if (!userGlobal.locationAide) {
|
||
|
// userGlobal.locationAide = [[LocationAide alloc]init];
|
||
|
// }
|
||
|
// if (sportState == 1) {//运动结束
|
||
|
// [userGlobal.locationAide stopLocation];
|
||
|
// } else {//运动开始
|
||
|
// [userGlobal.locationAide stratLocation];
|
||
|
// userGlobal.locationAide.gpsSignalBlock = ^(NSInteger signal) {
|
||
|
// [[[BLEBaseBl alloc] init] GPSSignalStrengthWithBleCmdType:BleCMD_GPSSignalStrength dialType:signal];
|
||
|
// NSLog(@"signal = %ld",(long)signal);
|
||
|
// };
|
||
|
// }
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
处理设备发送过来的数据
|
||
|
*/
|
||
![]()
1 year ago
|
- (void)handleDeviceDataCMD:(BleCMD_FireBoltt)blecmd Data:(NSMutableData *)data {
|
||
|
NSDictionary *dict = [L2DataParseFireBoltt L2_ParseData:data type:blecmd];
|
||
|
BleCMD_FireBoltt reportCMD = [dict[@"DataType"] integerValue];
|
||
![]()
2 years ago
|
[[NSNotificationCenter defaultCenter] postNotificationName:DeviceReportRealTimeHealthData object:@(reportCMD) userInfo:dict];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
检查data中某个字节中的某位的值 1:YES 0:NO
|
||
|
|
||
|
@param data 数据包
|
||
|
@param byteIndex 字节的下标
|
||
|
@param bitIndex 位的下标(从左到又)
|
||
|
*/
|
||
|
- (BOOL)checkDataWithData:(NSMutableData *)data ByteIndex:(NSInteger)byteIndex bitIndex:(NSInteger)bitIndex {
|
||
|
int num = ((Byte*)([data bytes]))[byteIndex];
|
||
|
UInt8 confirm = (UInt8)num;
|
||
|
confirm = confirm << bitIndex;
|
||
|
confirm = confirm >> 7;
|
||
|
return confirm;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
CRC校验成功或失败后回复设备端
|
||
|
*/
|
||
|
- (void)checkCRCHandleWithData:(NSMutableData *)data confirm:(BOOL)confirm {
|
||
|
if(data.length <=12) { //l1层就有13个字节了。不够长的数据是垃圾数据
|
||
|
return;
|
||
|
}
|
||
![]()
1 year ago
|
Byte byte = confirm == YES ? [BluetoothToolFireBoltt stitchWithErr:1 Ack:1 Vision:0] : [BluetoothToolFireBoltt stitchWithErr:0 Ack:1 Vision:0];
|
||
![]()
2 years ago
|
// 替换L1层第二个字节
|
||
|
[data replaceBytesInRange:NSMakeRange(1, 1) withBytes:&byte length:1];
|
||
|
// 替换长度为不带参数的5
|
||
|
Byte buffer[2];
|
||
|
buffer[0] = 5 >> 8;
|
||
|
buffer[1] = 5 & 0xff;
|
||
|
[data replaceBytesInRange:NSMakeRange(2, 2) withBytes:buffer length:2];
|
||
|
Byte dataLength[2];
|
||
|
dataLength[0] = 0;
|
||
|
dataLength[1] = 0;
|
||
|
[data replaceBytesInRange:NSMakeRange(11, 2) withBytes:dataLength length:2];
|
||
|
// NSLog(@"发送给设备端的确认码--------%@ 是否正确:%d",[data subdataWithRange:NSMakeRange(0, 13)],confirm);
|
||
|
// 发送L1层确认码给设备端
|
||
|
[self.reconnectPeripheral writeValue:[data subdataWithRange:NSMakeRange(0, 13)] forCharacteristic:self.writecharacteristic type:CBCharacteristicWriteWithoutResponse];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
获取系统已配对的设备
|
||
|
*/
|
||
|
- (NSMutableArray *)getPairedConnectedArray {
|
||
|
NSMutableArray *connectedArray = [[NSMutableArray alloc] init];
|
||
|
NSArray *braceletDeviceArr = [self.cMgr retrieveConnectedPeripheralsWithServices:@[[CBUUID UUIDWithString:ServicesUUID]]];
|
||
|
for (NSInteger i = 0; i < braceletDeviceArr.count; i ++) {
|
||
|
CBPeripheral *peripheral = braceletDeviceArr[i];
|
||
![]()
1 year ago
|
BLEModelFireBoltt *bleModel = [[BLEModelFireBoltt alloc] initWithCentral:self.cMgr
|
||
![]()
2 years ago
|
Peripheral:peripheral
|
||
|
AdvertisementData:0
|
||
|
RSSI:[NSNumber numberWithInteger:0]
|
||
|
UUIDString:peripheral.identifier.UUIDString
|
||
|
MACString:nil];
|
||
|
bleModel.isPaired = YES;
|
||
|
[connectedArray addObject:bleModel];
|
||
|
}
|
||
|
return connectedArray;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
#pragma mark 杰里升级
|
||
|
/// 打开表盘文件
|
||
|
- (void)openDialFile
|
||
|
{
|
||
|
[DialManager openDialFileSystemWithCmdManager:self.mAssist.mCmdManager withResult:^(DialOperateType type, float progress) {
|
||
|
if (type == DialOperateTypeUnnecessary) {
|
||
|
NSLog(@"已开启!");
|
||
|
}
|
||
|
if (type == DialOperateTypeFail || type == DialOperateTypeCmdFail) {
|
||
|
NSLog(@"获取失败!");
|
||
|
}
|
||
|
if (type == DialOperateTypeSuccess) {
|
||
|
NSLog(@"获取成功!");
|
||
|
}
|
||
|
}];
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
-(void)getInfo
|
||
|
{
|
||
|
[self.mAssist.mCmdManager cmdTargetFeatureResult:^(JL_CMDStatus status, uint8_t sn, NSData * _Nullable data) {
|
||
|
|
||
|
JLModel_Device *model = [self.mAssist.mCmdManager outputDeviceModel];
|
||
|
|
||
|
if (status == JL_CMDStatusSuccess) {
|
||
|
JL_OtaStatus upSt = model.otaStatus;
|
||
|
self.mOtaPath = [[NSUserDefaults standardUserDefaults] objectForKey:@"OTAPATH"];
|
||
|
if (upSt == JL_OtaStatusForce) {
|
||
|
NSLog(@"---> 进入强制升级.");
|
||
|
//[JL_Tools delay:5 Task:^{
|
||
|
[self onUpdateOTA];
|
||
|
//}];
|
||
|
return;
|
||
|
}else{
|
||
|
if (model.otaHeadset == JL_OtaHeadsetYES) {
|
||
|
NSLog(@"---> 进入强制升级: OTA另一只耳机.");
|
||
|
// [DFUITools showText:@"需要强制升级!" onView:self.view delay:1.0];
|
||
|
// [JL_Tools post:@"kJL_OTA_CONNECT" Object:nil];
|
||
|
// [JL_Tools delay:5 Task:^{
|
||
|
[self onUpdateOTA];
|
||
|
//}];
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
NSLog(@"---> 设备正常使用...");
|
||
|
[self openDialFile];
|
||
|
[JL_Tools mainTask:^{
|
||
|
//[DFUITools showText:@"设备正常使用" onView:self.view delay:1.0];
|
||
|
|
||
|
/*--- 获取公共信息 ---*/
|
||
|
[self.mAssist.mCmdManager cmdGetSystemInfo:JL_FunctionCodeCOMMON Result:nil];
|
||
|
}];
|
||
|
}else{
|
||
|
NSLog(@"---> ERROR:设备信息获取错误!");
|
||
|
}
|
||
|
}];
|
||
|
}
|
||
|
|
||
|
#pragma mark - OTA升级监听超时定时器(也可不监听超时)
|
||
|
static NSTimer *otaTimer = nil;
|
||
|
static int otaTimeout= 0;
|
||
|
static NSTimer *jlTimer = nil;
|
||
|
- (void)otaTimeCheck {
|
||
|
otaTimeout = 0;
|
||
|
if (otaTimer == nil) {
|
||
|
otaTimer = [JL_Tools timingStart:@selector(otaTimeAdd) target:self Time:1.0];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#pragma mark 关闭超时检测
|
||
|
- (void)otaTimeClose {
|
||
|
[JL_Tools timingStop:otaTimer];
|
||
|
otaTimeout = 0;
|
||
|
otaTimer = nil;
|
||
|
}
|
||
|
|
||
|
- (void)otaTimeAdd {
|
||
|
otaTimeout++;
|
||
|
if (otaTimeout == 10) {
|
||
|
[self otaTimeClose];
|
||
|
NSLog(@"OTA ---> 超时了!!!");
|
||
|
[SVProgressHUD showErrorWithStatus:@"升级超时"];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////
|
||
|
- (void)ljTimeCheck {
|
||
|
if (jlTimer == nil) {
|
||
|
jlTimer = [JL_Tools timingStart:@selector(scanForPeripherals) target:self Time:1.0];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- (void)scanForPeripherals
|
||
|
{
|
||
|
[self scanForPeripheralsWithdiscoverServices:nil IsDFU:YES];
|
||
|
}
|
||
|
|
||
|
- (void)jlTimeClose
|
||
|
{
|
||
|
[JL_Tools timingStop:jlTimer];
|
||
|
jlTimer = nil;
|
||
|
}
|
||
|
|
||
|
|
||
|
- (void)otaFuncWithFilePaths:(NSString *)otaFilePath
|
||
|
{
|
||
|
[[NSUserDefaults standardUserDefaults] setObject:otaFilePath forKey:@"OTAPATH"];
|
||
|
self.mOtaPath = otaFilePath;
|
||
|
NSString *lastZip = [[self.mOtaPath lastPathComponent] stringByReplacingOccurrencesOfString:@".zip" withString:@""];
|
||
|
NSString *lastPath = [JL_Tools listPath:NSDocumentDirectory MiddlePath:lastZip File:@""];
|
||
|
[JL_Tools removePath:lastPath];
|
||
|
// [self.mTimer threadContinue];
|
||
|
|
||
|
NSArray *zipArr = [FatfsObject unzipFileAtPath:self.mOtaPath toDestination:lastPath];
|
||
|
if (zipArr.count == 0) {
|
||
|
[SVProgressHUD showErrorWithStatus:@"文件解压出错"];
|
||
|
return;
|
||
|
}
|
||
|
if (zipArr.count > 1)
|
||
|
{
|
||
|
[DialManager listFile:^(DialOperateType type, NSArray * _Nullable array) {
|
||
|
if (type == DialOperateTypeSuccess && array.count > 0)
|
||
|
{
|
||
|
self.mWatchList = array;
|
||
|
[JL_Tools subTask:^{
|
||
|
[self onUpdateResource:^{
|
||
|
[self onUpdateOTA];
|
||
|
}];
|
||
|
}];
|
||
|
|
||
|
}
|
||
|
}];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/*--- 只需要【OTA升级】 ---*/
|
||
|
[JL_Tools mainTask:^{
|
||
|
[self onUpdateOTA];
|
||
|
}];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- (void)onUpdateOTA
|
||
|
{
|
||
|
NSData *otaData = [self outputDataOfOtaPath:self.mOtaPath];
|
||
|
__weak typeof(self) weakSelf = self;
|
||
|
[self.mAssist.mCmdManager.mOTAManager cmdOTAData:otaData Result:^(JL_OTAResult result, float progress) {
|
||
|
|
||
|
if (result == JL_OTAResultUpgrading || result == JL_OTAResultPreparing)
|
||
|
{
|
||
|
NSString *txt = [NSString stringWithFormat:@"%.1f%%",progress*100.0f];
|
||
|
if (result == JL_OTAResultPreparing)
|
||
|
{
|
||
|
NSLog(@"JL-校验文件中 %@",txt);
|
||
|
[SVProgressHUD showWithStatus:[NSString stringWithFormat:@"%@ %@",NSLocalizedString(@"校验文件", nil),txt]];
|
||
|
}
|
||
|
if (result == JL_OTAResultUpgrading)
|
||
|
{
|
||
|
NSLog(@"JL-正在升级 %@",txt);
|
||
|
[SVProgressHUD showWithStatus:[NSString stringWithFormat:@"%@ %@",NSLocalizedString(@"正在升级", nil),txt]];
|
||
|
}
|
||
|
|
||
|
[self otaTimeCheck];//增加超时检测
|
||
|
}
|
||
|
else if (result == JL_OTAResultPrepared)
|
||
|
{
|
||
|
NSLog(@"JL----> 检验文件【完成】");
|
||
|
[self otaTimeCheck];//增加超时检测
|
||
|
}
|
||
|
else if (result == JL_OTAResultReconnect)
|
||
|
{
|
||
|
NSLog(@"JL----> OTA正在回连设备... ");
|
||
|
[self startAndStopReconnect:YES];
|
||
|
[self otaTimeCheck];//关闭超时检测
|
||
|
}
|
||
|
else if (result == JL_OTAResultReconnectWithMacAddr)
|
||
|
{
|
||
|
[SVProgressHUD dismiss];
|
||
|
[SVProgressHUD showWithStatus:NSLocalizedString(@"正在重新连接", nil)];
|
||
|
JLModel_Device *model = [self.mAssist.mCmdManager outputDeviceModel];
|
||
|
NSLog(@"JL----> OTA正在通过Mac Addr方式回连设备... \n%@",model);
|
||
|
//[self startAndStopReconnect:YES];
|
||
|
self.lastBleMacAddress = model.bleAddr;
|
||
|
self.is_JL = YES;
|
||
|
[self ljTimeCheck];
|
||
|
|
||
|
[self otaTimeCheck];//关闭超时检测
|
||
|
}
|
||
|
else if (result == JL_OTAResultReboot)
|
||
|
{
|
||
|
[SVProgressHUD dismiss];
|
||
|
//[SVProgressHUD showWithStatus:NSLocalizedString(@"设备重启,正在回连", nil)];
|
||
|
NSLog(@"JL---->设备重启.");
|
||
|
[self otaTimeClose];//关闭超时检测
|
||
|
}
|
||
|
else if (result == JL_OTAResultSuccess || result == JL_OTAResultFail)
|
||
|
{
|
||
|
if ([weakSelf.jl_delegate respondsToSelector:@selector(otaProgressWithOtaResult:withProgress:)]) {
|
||
|
[weakSelf.jl_delegate otaProgressWithOtaResult:result withProgress:progress];
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
[SVProgressHUD showErrorWithStatus:NSLocalizedString(@"发生错误,升级失败", nil)];
|
||
|
// 其余错误码详细 Command+点击JL_OTAResult 查看说明
|
||
|
NSLog(@"JL-ota update result: %d", result);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
}];
|
||
|
}
|
||
|
|
||
|
- (void)startScanBLE
|
||
|
{
|
||
|
NSLog(@"BLE ---> startScanBLE.");
|
||
|
if (self.cMgr) {
|
||
|
if (self.cMgr.state == CBManagerStatePoweredOn) {
|
||
|
[self.cMgr scanForPeripheralsWithServices:nil options:nil];
|
||
|
} else {
|
||
|
__weak typeof(self) weakSelf = self;
|
||
|
dispatch_after(0.5, dispatch_get_main_queue(), ^{
|
||
|
if (weakSelf.cMgr.state == CBManagerStatePoweredOn) {
|
||
|
[weakSelf.cMgr scanForPeripheralsWithServices:nil options:nil];
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
- (NSData*)outputDataOfOtaPath:(NSString*)path
|
||
|
{
|
||
|
NSString *folderName = [[path lastPathComponent] stringByReplacingOccurrencesOfString:@".zip" withString:@""];
|
||
|
NSString *zipPath = [JL_Tools listPath:NSDocumentDirectory MiddlePath:folderName File:@""];
|
||
|
[FatfsObject unzipFileAtPath:path toDestination:zipPath];
|
||
|
|
||
|
NSArray *zipArray = [JL_Tools subPaths:zipPath];
|
||
|
|
||
|
for (NSString *name in zipArray)
|
||
|
{
|
||
|
if ([name hasSuffix:@".ufw"])
|
||
|
{
|
||
|
NSString *otaPath = [JL_Tools listPath:NSDocumentDirectory MiddlePath:folderName File:name];
|
||
|
NSLog(@"---->Start OTA:%@ ",otaPath);
|
||
|
NSData *otaData = [[NSData alloc] initWithContentsOfFile:otaPath];
|
||
|
return otaData;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
}
|
||
|
}
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
typedef void(^OTA_VIEW_BK)(void);
|
||
|
-(void)onUpdateResource:(OTA_VIEW_BK __nullable)result
|
||
|
{
|
||
|
self.isOtaUpdate = YES;
|
||
|
JL_ManagerM *mCmdManager = self.mAssist.mCmdManager;
|
||
|
/*--- 更新资源标志 ---*/
|
||
|
[mCmdManager.mFlashManager cmdWatchUpdateResource];
|
||
|
/*--- 展示手表更新资源UI ---*/
|
||
|
NSLog(@"--->Fats Update UI.(OTA)");
|
||
|
__block uint8_t m_flag = 0;
|
||
|
[mCmdManager.mFlashManager cmdUpdateResourceFlashFlag:JL_FlashOperateFlagStart
|
||
|
Result:^(uint8_t flag) {
|
||
|
m_flag = flag;
|
||
|
}];
|
||
|
if (m_flag != 0) {
|
||
|
[JL_Tools mainTask:^{
|
||
|
//[DFUITools showText:@"升级请求失败!" onView:self.view delay:1.0];
|
||
|
[SVProgressHUD showErrorWithStatus:NSLocalizedString(@"升级请求失败!", nil)];
|
||
|
}];
|
||
|
self.isOtaUpdate = NO;
|
||
|
return;
|
||
|
}
|
||
|
[DialManager updateResourcePath:self.mOtaPath List:self.mWatchList
|
||
|
Result:^(DialUpdateResult updateResult,
|
||
|
NSArray * _Nullable array,
|
||
|
NSInteger index, float progress){
|
||
|
[JL_Tools mainTask:^{
|
||
|
if (updateResult == DialUpdateResultReplace) {
|
||
|
[self otaTimeCheck];//增加超时检测
|
||
|
NSString *fileName = array[index];
|
||
|
|
||
|
[SVProgressHUD showWithStatus:[NSString stringWithFormat:@"正在更新表盘:%@(%d/%lu)\n%.1f%%",
|
||
|
fileName,(int)index+1,(unsigned long)array.count,progress*100.0]];
|
||
|
return;
|
||
|
}
|
||
|
if (updateResult == DialUpdateResultAdd)
|
||
|
{
|
||
|
[self otaTimeCheck];//增加超时检测
|
||
|
NSString *fileName = array[index];
|
||
|
[SVProgressHUD showWithStatus:[NSString stringWithFormat:@"正在传输新表盘%@(%d/%lu)\n%.1f%%",
|
||
|
fileName,(int)index+1,(unsigned long)array.count,progress*100.0]];
|
||
|
return;
|
||
|
}
|
||
|
if (updateResult == DialUpdateResultFinished) self.otaString = @"资源更新完成";
|
||
|
if (updateResult == DialUpdateResultNewest) self.otaString = @"资源已是最新";
|
||
|
if (updateResult == DialUpdateResultInvalid) self.otaString = @"无效资源文件";
|
||
|
if (updateResult == DialUpdateResultEmpty) self.otaString = @"资源文件为空";
|
||
|
if (updateResult == DialUpdateResultNoSpace) self.otaString = @"资源升级空间不足";
|
||
|
if (updateResult == DialUpdateResultZipError) self.otaString = @"ZIP资源文件错误";
|
||
|
[SVProgressHUD showErrorWithStatus:self.otaString];
|
||
|
// [JL_Tools delay:1.0 Task:^{
|
||
|
// [SVProgressHUD showErrorWithStatus:NSLocalizedString(self.otaString, nil)];
|
||
|
// if (result) result();
|
||
|
// }];
|
||
|
}];
|
||
|
}];
|
||
|
}
|
||
|
|
||
|
|
||
|
- (void)downloadZipUrl:(NSString *)url updatePath:(NSString *)path
|
||
|
{
|
||
|
[[User_Http shareInstance] downloadUrl:url Path:path Result:^(float progress, JLHTTP_Result result) {
|
||
|
[JL_Tools mainTask:^{
|
||
|
//self.updateTxt.text = kJL_TXT("下载固件");
|
||
|
if (result == JLHTTP_ResultDownload) {
|
||
|
// self.progressTxt.text = [NSString stringWithFormat:@"%.1f%%",progress*100.0];
|
||
|
// self.progressView.progress = progress;
|
||
|
//[DFUITools showTransparentHUDOnWindowWithLabel:[NSString stringWithFormat:@"%.1f%%",progress*100.0]];
|
||
|
[SVProgressHUD showWithStatus:[NSString stringWithFormat:@"%@ %.1f%%",NSLocalizedString(@"下载中", nil),progress*100.0]];
|
||
|
}
|
||
|
if (result == JLHTTP_ResultSuccess) {
|
||
|
/*--- 现在完直接升级 ---*/
|
||
|
[self otaFuncWithFilePaths:path];
|
||
|
}
|
||
|
if (result == JLHTTP_ResultFail) {
|
||
|
[SVProgressHUD showErrorWithStatus:@"下载失败"];
|
||
|
}
|
||
|
}];
|
||
|
}];
|
||
|
}
|
||
|
|
||
|
@end
|