ble编程-外设发送数据到中心
一、外设
1.在外设的.h文件中定义如下
- 1 //周边管理者
- 2
- 3 @property (nonatomic , strong) CBPeripheralManager *peripheralManager;
- 4
- 5 // 中心
- 6
- 7 @property (nonatomic,strong) CBCentral *central;
- 8
- 9 // 特征
- 10
- 11 @property (nonatomic , strong) CBMutableCharacteristic *customCharacteristic;
- 12
- 13 // 服务
- 14
- 15 @property (nonatomic , strong) CBMutableService *customService;
- 16
- 17 // 向中心发送的数据
- 18
- 19 @property (strong, nonatomic) NSData *dataToSend;
- 20
- 21 @property (nonatomic, readwrite) NSInteger sendDataIndex;
2.然后在.m文件中进行如下操作
2.1在viewDidLoad方法中初始化外设和要发送的数据
- 1 // 初始化外设
- 2 self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil];
- 3 // 初始化数据
- 4 self.dataToSend = [@"snadjfkhaw加大困难的是咖啡euijferlfmn ksxncjxznvjeajfrnjadnfjasfndsafnjsadkfnjsa" dataUsingEncoding:NSUTF8StringEncoding];
2.2 Peripheral Manager被创建,状态改变时调用
CBPeripheralManagerStatePoweredOff 设备关闭状态
CBPeripheralManagerStateUnauthorized 未授权
CBPeripheralManagerStateUnsupported 您的设备不支持蓝牙4.0
CBPeripheralManagerStateResetting 重置状态
CBPeripheralManagerStateUnknown 未知状态
- 1 - (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral
- 2
- 3 {
- 4
- 5 switch (peripheral.state) {
- 6
- 7 case CBPeripheralManagerStatePoweredOn:
- 8
- 9 NSLog(@"蓝牙设备已经打开,可以扫描外设");
- 10
- 11 [self setupService];
- 12
- 13 break;
- 14
- 15 default:
- 16
- 17 NSLog(@"外设改变状态");
- 18
- 19 break;
- 20
- 21 }
- 22
- 23 }
- 24
- 25 - (void)setupService
- 26
- 27 {
- 28
- 29 //creates the characteristic UUID
- 30
- 31 CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID];
- 32
- 33 //create the characteristic
- 34
- 35 self.customCharacteristic = [[CBMutableCharacteristic alloc] initWithType:characteristicUUID
- 36
- 37 properties:CBCharacteristicPropertyNotify
- 38
- 39 value:nil
- 40
- 41 permissions:CBAttributePermissionsReadable];
- 42
- 43 //create the service UUID
- 44
- 45 CBUUID *servieceUUID = [CBUUID UUIDWithString:kServiceUUID];
- 46
- 47 //creates the service and adds the charecteristic to it
- 48
- 49 self.customService = [[CBMutableService alloc] initWithType:servieceUUID primary:YES];
- 50
- 51 //sets the characteristics for this service
- 52
- 53 [self.customService setCharacteristics:@[self.customCharacteristic]];
- 54
- 55 // And add it to the peripheral manager
- 56
- 57 [self.peripheralManager addService:self.customService];
- 58
- 59 }
2.3 当你执行addService方法后执行如下回调
- 1 - (void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error {
- 2 if (error != nil) {
- 3 NSLog(@"%s,error = %@",__PRETTY_FUNCTION__, error.localizedDescription);
- 4 } else {
- 5 //starts advertising the service
- 6 [self.peripheralManager startAdvertising:@{CBAdvertisementDataLocalNameKey:@"服务门店",
- 7 CBAdvertisementDataServiceUUIDsKey:@[[CBUUID UUIDWithString:kServiceUUID]]}];
- 8
- 9 }
- 10 }
2.4 central订阅了characteristic的值,当更新值的时候peripheral会调用
- 1 - (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic
- 2 {
- 3 self.central = central;
- 4 if (_lastDeviceUUID == central.identifier) {
- 5 return;
- 6 }
- 7 _lastDeviceUUID = central.identifier;
- 8 self.sendDataIndex = 0;
- 9 [self sendData];
- 10 }
- 11
- 12
- 13 #pragma mark - 向客户端发消息
- 14 - (void)sendData {
- 15
- 16 // 标记是否为最后一次发送
- 17 static BOOL sendingEOM = NO;
- 18 // 1. 如果是最后一次发送
- 19 if (sendingEOM) {
- 20 // 只发送 "EOM" 表示结束
- 21 BOOL didSend = [self.peripheralManager updateValue:[@"EOM" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:self.customCharacteristic onSubscribedCentrals:@[self.central]];
- 22
- 23 // 1.1. 最后一次发送成功
- 24 if (didSend) {
- 25 sendingEOM = NO;
- 26 NSLog(@"Sent: EOM");
- 27 }
- 28 return;
- 29 }
- 30 // 2. 不是最后一次发送,且数据为空,则返回
- 31 if (self.sendDataIndex >= self.dataToSend.length) {
- 32 return;
- 33 }
- 34 // 3. 数据尚未发送完成,继续发送直到完成
- 35 BOOL didSend = YES;
- 36 while (didSend) {
- 37 // 3.1. 计算剩余多大数据量需要发送
- 38 NSInteger amountToSend = self.dataToSend.length - self.sendDataIndex;
- 39 // 不能大于20个字节
- 40 if (amountToSend > NOTIFY_MTU)
- 41 amountToSend = NOTIFY_MTU;
- 42 // 3.2. copy出我们想要发送的数据
- 43 NSData *chunk = [NSData dataWithBytes:self.dataToSend.bytes+self.sendDataIndex length:amountToSend];
- 44 // 3.3. 发送
- 45 didSend = [self.peripheralManager updateValue:chunk forCharacteristic:self.customCharacteristic onSubscribedCentrals:@[self.central]];
- 46 // 3.4. 如果没有发送成功,重新发送
- 47 // If it didn't work, drop out and wait for the callback
- 48 if (!didSend) {
- 49 NSLog(@"SEND ERROR");
- 50 return;
- 51 }
- 52 NSString *stringFromData = [[NSString alloc] initWithData:chunk encoding:NSUTF8StringEncoding];
- 53 NSLog(@"Sent: %@", stringFromData);
- 54 // 3.5. 发送成功,修改已经发送成功数据index值
- 55 self.sendDataIndex += amountToSend;
- 56 // 3.6. 如果是最后一次需要发送
- 57 if (self.sendDataIndex >= self.dataToSend.length) {
- 58 // 3.6.1. 把 标识是否为最后一次发送 改为YES
- 59 sendingEOM = YES;
- 60 // 3.6.2. 发送
- 61 BOOL eomSent = [self.peripheralManager updateValue:[@"EOM" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:self.customCharacteristic onSubscribedCentrals:@[self.central]];
- 62 if (eomSent) {
- 63 // 3.6.3. 发送成功,则我们已经完成这个功能
- 64 sendingEOM = NO;
- 65 NSLog(@"Sent: EOM");
- 66 }
- 67 return;
- 68 }
- 69 }
- 70 }
2.5 peripheral再次准备好发送Characteristic值的更新时候调用
- 1 - (void)peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager *)peripheral
- 2 {
- 3 [self sendData];
- 4 }
2.6 当central取消订阅characteristic这个特征的值后调用方法
- 1 - (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic
- 2 {
- 3 NSLog(@"central=%@设备拒绝请求,%s,",central,__PRETTY_FUNCTION__);
- 4 }
二、中心
1.在中心的.h文件中定义如下
- 1 /**
- 2 * 中心角色
- 3 */
- 4 @property (nonatomic , strong) CBCentralManager *centralManager;
- 5 @property (nonatomic , strong) CBPeripheral *peripheral;
- 6 @property (nonatomic, strong) CBCharacteristic *character;
- 7 @property (nonatomic , strong) NSMutableData *data;
2.然后在.m文件中进行如下操作
2.1在viewDidLoad方法中初始化中心和要发送的数据
- 1 // 1.建立中心角色,queue为执行队列,默认为主线程
- 2 self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
- 3 // 2.初始化显示控件
- 4 [self setupUI];
- 5 // 3.初始化data
- 6 _data = [[NSMutableData alloc] init];
2.2 CBCentralManagerDelegate代理方法
回调,返回当前设备蓝牙状态
- 1 #pragma mark - CBCentralManagerDelegate
- 2 #pragma mark 回调,返回当前设备蓝牙状态
- 3 - (void)centralManagerDidUpdateState:(CBCentralManager *)central {
- 4
- 5 switch (central.state) {
- 6 case CBCentralManagerStatePoweredOn:{
- 7 // 扫描外设(discover)
- 8 _messageLabel.text = @"蓝牙设备已经打开,可以扫描外设";
- 9 [self scan];
- 10 }
- 11 break;
- 12 default:
- 13 break;
- 14 }
- 15 }
- 16
- 17 #pragma mark - 扫描外设(discover) 超时停止扫描
- 18 - (void)scan{
- 19 /**
- 20 * 第一个参数指定了要搜寻的服务,如果传nil,表示搜寻搜所有的服务
- 21 * 第二个参数指定了CBCentralManagerScanOptionAllowDuplicatesKey为已发现的设备是否重复扫描,
- 22 * 如果是同一设备不会多次回调。
- 23 */
- 24 [self.centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:kServiceUUID]] options:@{CBCentralManagerScanOptionAllowDuplicatesKey:@YES}];
- 25
- 26 }
- 27
发现外设,回调
- 1 - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
- 2
- 3 NSLog(@"找到了服务:%@,信号质量:%@",advertisementData,RSSI);
- 4 self.serviceName = [advertisementData objectForKey:@"kCBAdvDataLocalName"];
- 5
- 6 if (self.peripheral != peripheral) {
- 7 self.peripheral = peripheral;
- 8 NSLog(@"开始连接blueServer:%@",peripheral);
- 9 [self.centralManager connectPeripheral:self.peripheral options:nil];
- 10 }
- 11 }
连接失败,回调
- 1 - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
- 2 NSLog(@"Failed to connect to %@. (%@)", peripheral, [error localizedDescription]);
- 3 [self cleanup];
- 4 }
连接成功,回调
- 1 - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
- 2 //因为一个peripheral可能不止提供一个service
- 3 NSLog(@"连接成功,进一步获取peripheral的service");
- 4 [self.centralManager stopScan];
- 5
- 6 // 每过 0.1 秒钟执行一次 readBLEServiceRSSI 方法
- 7 self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(readBLEServiceRSSI) userInfo:nil repeats:YES];
- 8
- 9 [self.data setLength:0];
- 10
- 11 // 设置代理
- 12 self.peripheral.delegate = self;
- 13
- 14 //查询符合条件的外设
- 15 [self.peripheral discoverServices:@[[CBUUID UUIDWithString:kServiceUUID]]];
- 16 }
- 17
- 18
失去连接,回调
- 1 - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
- 2 NSLog(@"Failed to connect to %@. (%@)", peripheral, [error localizedDescription]);
- 3 [self cleanup];
- 4 }
2.3 CBPeripheralDelegate代理方法
读取到RSSI值后的操作
- 1 - (void)peripheralDidUpdateRSSI:(CBPeripheral *)peripheral error:(NSError *)error {
- 2 NSLog(@"%s,%@",__PRETTY_FUNCTION__,peripheral);
- 3 int rssi = abs([peripheral.RSSI intValue]);
- 4 CGFloat ci = (rssi - 49) / (10 * 4.);
- 5
- 6 self.messageLabel.text = [NSString stringWithFormat:@"发现BLT4.0热点:%@,距离:%.1fm",self.serviceName,pow(10,ci)];
- 7 }
找到我们刚刚指定的服务
- 1 - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
- 2 if (error) {
- 3 NSLog(@"%s,error=%@", __PRETTY_FUNCTION__, error.localizedDescription);
- 4 [self cleanup];
- 5 return;
- 6 } else {
- 7 for (CBService *service in peripheral.services) {
- 8 NSLog(@"发现UUID=%@的服务",service.UUID);
- 9 NSLog(@"开始检测这个服务的特征码...");
- 10 if ([service.UUID isEqual:[CBUUID UUIDWithString:kServiceUUID]]) {
- 11 [self.peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:kCharacteristicUUID]] forService:service];
- 12 }
- 13 }
- 14 }
- 15 }
如果一个特征被检测到,回调
- 1 - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
- 2 if (error) {
- 3 NSLog(@"%s,%@",__PRETTY_FUNCTION__,error);
- 4 [self cleanup];
- 5 return;
- 6 } else {
- 7 if ([service.UUID isEqual:[CBUUID UUIDWithString:kServiceUUID]]) {
- 8 for (CBCharacteristic *characteristic in service.characteristics) {
- 9 if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:kCharacteristicUUID]]) {
- 10 [peripheral setNotifyValue:YES
- 11 forCharacteristic:characteristic];
- 12 self.character=characteristic;
- 13 }
- 14 }
- 15 }
- 16 }
- 17 }
处理蓝牙发过来的数据
- 1 - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
- 2 if (error) {
- 3 NSLog(@"didUpdateValueForCharacteristic - Error discovering characteristics: %@", [error localizedDescription]);
- 4 return;
- 5 }
- 6 NSString *stringFromData = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
- 7 // 如果我们获得了所有的数据
- 8 if ([stringFromData isEqualToString:@"EOM"]) {
- 9 // 显示数据
- 10 [self alarm:self.data];
- 11 // 取消订阅
- 12 [peripheral setNotifyValue:NO forCharacteristic:characteristic];
- 13 // 让中心失去和设备的连接
- 14 [self.centralManager cancelPeripheralConnection:peripheral];
- 15 }
- 16 // 否则,拼接数据
- 17 [self.data appendData:characteristic.value];
- 18 // Log it
- 19 NSLog(@"Received: %@", stringFromData);
- 20 }
外围设备是否被注销
- 1 - (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
- 2 if (error) {
- 3 NSLog(@"%s,%@",__PRETTY_FUNCTION__,error.localizedDescription);
- 4 }
- 5 if (![characteristic.UUID isEqual:[CBUUID UUIDWithString:kCharacteristicUUID]]) {
- 6 return;
- 7 }
- 8 //已经发送通知
- 9 if (characteristic.isNotifying) {
- 10 NSLog(@"Notification began on %@",characteristic);
- 11 } else {
- 12 //Notification has stopped
- 13 //so disconnect from the peripheral
- 14 NSLog(@"Notification stopped on %@ Disconnecting",characteristic);
- 15 [self.centralManager cancelPeripheralConnection:self.peripheral];
- 16 }
- 17 }
2.4 出现错误或者结束连接时调用(私有方法)
- 1 #pragma mark - Call this when things either go wrong, or you're done with the connection.
- 2 - (void)cleanup {
- 3 // Don't do anything if we're not connected
- 4 if (!self.peripheral.isConnected) {
- 5 return;
- 6 }
- 7 // See if we are subscribed to a characteristic on the peripheral
- 8 if (self.peripheral.services != nil) {
- 9 for (CBService *service in self.peripheral.services) {
- 10 if (service.characteristics != nil) {
- 11 for (CBCharacteristic *characteristic in service.characteristics) {
- 12 if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:kCharacteristicUUID]]) {
- 13 if (characteristic.isNotifying) {
- 14 // It is notifying, so unsubscribe
- 15 [self.peripheral setNotifyValue:NO forCharacteristic:characteristic];
- 16 // And we're done.
- 17 return;
- 18 }
- 19 }
- 20 }
- 21 }
- 22 }
- 23 }
- 24 // If we've got this far, we're connected, but we're not subscribed, so we just disconnect
- 25 [self.centralManager cancelPeripheralConnection:self.peripheral];
- 26 }
ble编程-外设发送数据到中心的更多相关文章
- Java基础知识强化之网络编程笔记06:TCP之TCP协议发送数据 和 接收数据
1. TCP协议发送数据 和 接收数据 TCP协议接收数据:• 创建接收端的Socket对象• 监听客户端连接.返回一个对应的Socket对象• 获取输入流,读取数据显示在控制台• 释放资源 TCP协 ...
- Java基础知识强化之网络编程笔记03:UDP之UDP协议发送数据 和 接收数据
1. UDP协议发送数据 和 接收数据 UDP协议发送数据: • 创建发送端的Socket对象 • 创建数据,并把数据打包 • 调用Socket对象的发送方法,发送数据包 • 释放资源 UDP协议接 ...
- {网络编程}和{多线程}应用:基于UDP协议【实现多发送方发送数据到同一个接收者】--练习
要求: 使用多线程实现多发送方发送数据到同一个接收者 代码: 发送端:可以在多台电脑上启动发送端,同时向接收端发送数据 注意:匹配地址和端口号 package com.qf.demo; import ...
- python网络编程-socket发送大数据包问题
一:什么是socket大数据包发送问题 socket服务器端或者客户端在向对方发送的数据大于对方接受的缓存时,会出现第二次接受还接到上次命令发送的结果.这就出现象第一次接受结果不全,第二次接果出现第一 ...
- STM32 使用 printf 发送数据配置方法 -- 串口 UART, JTAG SWO, JLINK RTT
STM32串口通信中使用printf发送数据配置方法(开发环境 Keil RVMDK) http://home.eeworld.com.cn/my/space-uid-338727-blogid-47 ...
- php以post方式向接口发送数据
工作需要,我负责收集服务器数据,然后定时向中心服务器发送.我看到了接口信息,需要设置heads头信息,需要发送数据,且是post方式. 这里就用到了curl //发送post请求 function r ...
- C#带cookie Post和Get方式发送数据,保持cookie
在实际编程中,可能需要读取特定网页的信息,但很多网站需要用户登录后,才能够获取相关的页面内容,这就需要编程者先临时存储当前的cookie,在C#中可以使用CookieContainer 对象来保存登录 ...
- HTTP 笔记与总结(3 )socket 编程:发送 GET 请求
使用 PHP + socket 模拟发送 HTTP GET 请求,过程是: ① 打开连接 ② 构造 GET 请求的数据:写入请求行.请求头信息.请求主体信息(GET 请求没有主体信息) ③ 发送 GE ...
- Android(java)学习笔记80:UDP协议发送数据
UDP协议发送数据:我们总是先运行接收端,再运行发送端发送端: 1 package cn.itcast_02; import java.io.IOException; import java.net. ...
随机推荐
- Linux记录-批量安装LNMP(转载)
#!/bin/bash # Describe: This is a one - button installation service script # 提示:使用此脚本时,尽量先选择第一项配置Yum ...
- 宣化上人:大佛顶首楞严经四种清净明诲浅释(2-3) -------------------------------------------------------------------------------- (转自学佛网:http://www.xuefo.net/nr/article23/230612.html)
大佛顶首楞严经四种清净明诲浅释(2-3) 唐天竺·沙门般剌密帝译 宣化上人主讲 一九八三年四月十七日晚讲于万佛圣城 欲摄其心入三摩地:这种邪师说法,在末法的时候像恒河沙这么多:可是我想在这时候,令一切 ...
- [转载] HashMap的工作原理-hashcode和equals的区别
目录 前言 为什么需要使用Hashcode,可以从Java集合的常用需求来描述: 更深入的介绍 先来些简单的问题 HashMap的0.75负载因子 总结 我在网上看到的这篇文章,介绍的很不错,但是我看 ...
- PhpStorm (强大的PHP开发环境)10.0.2 附注
最新版PhpStorm 10正式版改进了PHP 7支持,改进代码完成功能. PhpStorm 是最好的PHP开发工具,使用它进行PHP开发将会让你感觉到编程的乐趣. 快乐无极终于从oschina看到了 ...
- 神啊,看看Log4Net这个东西吧
这个东西实在是让人感动的想哭囊…………-_-..... Log4Net.config文件 <?xml version="1.0" encoding="utf-8&q ...
- CSS控制元素背景透明度总结
方法一:CSS3的background rgba filter:progid:DXImageTransform.Microsoft.gradient(enabled='true',startColor ...
- 解决RedisDesktopManager连接不上redis问题
linux 下安装redis很简单,在此不做赘述 发现linux上启动redis,测试redis使用正常, 但使用RedisDesktopManager却连接不上,报错如下,报错信息显示:当前使用的P ...
- MFC无法使用CDialogEx类
在stdafx.h中添加以下代码: #include <afxcontrolbars.h>
- 虚拟机中使用Samba实现文件共享
首先我们给虚拟机安装samba服务(如果搭的是别的仓库记得开仓库) 输入命令:yum install samba samba服务的配置文件在,我们来看一下/etc/samba/smb.conf 输入命 ...
- Linux查看库依赖方法
1.查看依赖的库:objdump -x xxx.so | grep NEEDED 2.查看可执行程序依赖的库:objdump -x 可执行程序名 | grep NEEDED 3.查看缺少的库: ldd ...