본문 바로가기
아이폰 개발/ios 개념&튜토리얼

코어 블루투스 - IOS Core Bluetooth

by 인생여희 2020. 10. 25.

프로세스 순서도

 

#.CENTRAL (아이폰)

 

1.뷰컨트롤러.h

#import <CoreBluetooth/CoreBluetooth.h>
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController <CBCentralManagerDelegate, CBPeripheralDelegate>
@property (strong, nonatomic) CBCentralManager *centralManager;
@property (strong, nonatomic) CBPeripheral *discoveredPeripheral;
@property (strong, nonatomic) CBCharacteristic *characteristic; //특성정보
@property (strong, nonatomic) NSMutableData *data;
@property (weak, nonatomic) IBOutlet UITextView *textView;
@property (strong , nonatomic) NSMutableString *str;
@end

2.뷰컨트롤러.m

//
#define NAME @"" //블루투스 이름
#define SERVICE @"" //서비스
#define CHARACTERISTIC @"" //특성
#import "ViewController.h"
#import "PeripheralManager.h"
@interface ViewController ()
@end
@implementation ViewController
//스캔
- (IBAction)scanStart:(id)sender {
NSLog(@"scanStart - !");
_centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
_data = [[NSMutableData alloc] init];
}
//메시지 보내기
- (IBAction)sendMsg:(id)sender {
NSLog(@"메시지 보내기..");
//######## 휴대폰에서 특정 값을 던지면 연결 하기!####
NSString *signNum = @"0";
NSData *data = [signNum dataUsingEncoding:NSUTF8StringEncoding];
[_discoveredPeripheral writeValue:data forCharacteristic:_characteristic type:CBCharacteristicWriteWithResponse];
}
//연결끊기
- (IBAction)cancelAction:(id)sender {
NSLog(@"cancelAction - !");
[self cleanup];
}
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"viewDidLoad - !");
_str = [[NSMutableString alloc]initWithString:@""];
}
- (void)centralManagerDidUpdateState:(nonnull CBCentralManager *)central {
// You should test all scenarios
if (central.state != CBManagerStatePoweredOn) {
return;
}
if (central.state == CBManagerStatePoweredOn) {
//[_centralManager scanForPeripheralsWithServices:nil options:nil];
// Scan for devices
[_centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:SERVICE]] options:@{ CBCentralManagerScanOptionAllowDuplicatesKey : @YES }];
NSLog(@"Scanning started");
//[_str appendString:@"Scanning started\n"];
[_textView setText:_str];
}
}
//연결 - 시도
-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI{
if(peripheral.name.length > 0){
NSLog(@"Discovered %@ at %@", peripheral.name, RSSI);
if (_discoveredPeripheral != peripheral) {
// Save a local copy of the peripheral, so CoreBluetooth doesn't get rid of it
_discoveredPeripheral = peripheral;
// And connect
NSLog(@"Connecting to peripheral %@", peripheral);
[_str appendFormat:@"Connecting to peripheral %@\n", peripheral];
[_textView setText:_str];
[_centralManager connectPeripheral:peripheral options:nil];
}
}
}
//연결 완료
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
NSLog(@"Connected");
[_centralManager stopScan];
NSLog(@"Scanning stopped");
[_data setLength:0];
peripheral.delegate = self;
[peripheral discoverServices:@[[CBUUID UUIDWithString:SERVICE]]];
}
//서비스 찾기
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
if (error) {
[self cleanup];
return;
}
for (CBService *service in peripheral.services) {
[peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:CHARACTERISTIC]] forService:service];
}
// Discover other characteristics
}
//특성 구독
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
if (error) {
[self cleanup];
return;
}
for (CBCharacteristic *characteristic in service.characteristics) {
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:CHARACTERISTIC]]) {
[peripheral setNotifyValue:YES forCharacteristic:characteristic];
_characteristic = characteristic;
}
}
}
//기기가 보내는 데이터 수신
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
if (error) {
NSLog(@"Error");
return;
}
NSString *stringFromData = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
NSLog(@"stringFromData : %@",stringFromData);
if (characteristic.value != nil) {
//NSLog(@"characteristic.value : %@" ,characteristic.value); // - byte 단위
NSLog(@"characteristic.value.description : %@" ,characteristic.value.description); //
NSString *peripheralSendSign = characteristic.value.description;
NSLog(@"peripheralSendSign : %@",peripheralSendSign);
if([peripheralSendSign containsString:@"2"]){
//주변기기가 던저 주는 데이터 종료 시키기 -
[_discoveredPeripheral setNotifyValue:NO forCharacteristic:characteristic];
[_centralManager cancelPeripheralConnection:peripheral];
[_data appendData:characteristic.value];
}else if([peripheralSendSign containsString:@"0"]){
NSLog(@"연결");
}
}
}
//CBCentral이 특성 변경에 대한 통지상태 체크
-(void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
if (![characteristic.UUID isEqual:[CBUUID UUIDWithString:CHARACTERISTIC]]) {
return;
}
if (characteristic.isNotifying) {
NSLog(@"Notification began on %@", characteristic);
} else {
// Notification has stopped
[_centralManager cancelPeripheralConnection:peripheral];
}
}
-(void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
NSLog(@"didWriteValueForCharacteristic ? 언제 호출되지?");
}
//didWriteValueForCharacteristic
//
-(void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
[_centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:SERVICE]] options:@{ CBCentralManagerScanOptionAllowDuplicatesKey : @YES }];
}
//연결 실패
-(void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
NSLog(@"Failed to connect");
[self cleanup];
}
//제거
- (void)cleanup {
// See if we are subscribed to a characteristic on the peripheral
if (_discoveredPeripheral.services != nil) {
for (CBService *service in _discoveredPeripheral.services) {
if (service.characteristics != nil) {
for (CBCharacteristic *characteristic in service.characteristics) {
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:CHARACTERISTIC]]) {
if (characteristic.isNotifying) {
[_discoveredPeripheral setNotifyValue:NO forCharacteristic:characteristic];
return;
}
}
}
}
}
}
[_centralManager cancelPeripheralConnection:_discoveredPeripheral];
[_centralManager stopScan];
}
@end

 

#.PERIPHERAL (블루투스 기기)

 

1.기기정보

#ifndef LE_Transfer_TransferService_h
#define LE_Transfer_TransferService_h
//블루투스 기기의 서비스 아이디와 특성아디를 적어준다!
//#define TRANSFER_SERVICE_UUID @"181C"
#define TRANSFER_SERVICE_UUID @"xxxxxx-xxxx-xxxx-xxx-xxxxx"
#define TRANSFER_CHARACTERISTIC_UUID @"xxxxxx-xxxx-xxxx-xx-xxxxxx"
#define NOTIFY_MTU 20
#endif

2.뷰컨트롤러.h

#import <CoreBluetooth/CoreBluetooth.h>
#import "TransferService.h"
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController<CBPeripheralManagerDelegate>
@property (strong, nonatomic) CBPeripheralManager *peripheralManager;
@property (strong, nonatomic) CBMutableCharacteristic *transferCharacteristic;
@property (strong, nonatomic) CBMutableService *transferService;
@property (strong, nonatomic) NSData *dataToSend;
@property (nonatomic, readwrite) NSInteger sendDataIndex;
@end

3.뷰컨트롤러.m

#import "ViewController.h"
@interface ViewController () <UITextViewDelegate>
@property (strong, nonatomic) IBOutlet UITextView *textView;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//_peripheralManager = [[CBPeripheralManager alloc] initWithDelegate: self queue:nil options:@{ CBCentralManagerOptionRestoreIdentifierKey:@"peripheralManagerIdentifier" }];
_peripheralManager = [[CBPeripheralManager alloc]initWithDelegate:self queue:nil];
}
#pragma mark - Peripheral Methods
//
// Delegate for CBPeripheralDelegate
//
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral
{
// CBPeripheralManagerState... state other than CBPeripheralManagerStatePoweredOn
if (peripheral.state != CBPeripheralManagerStatePoweredOn) {
NSLog(@"%s: peripheralManager state is now: %li",__PRETTY_FUNCTION__,(long)peripheral.state);
}
// CBPeripheralManagerStatePoweredOn state...
else {
NSLog(@"%s: peripheralManager powered on.",__PRETTY_FUNCTION__);
// Start with the CBMutableCharacteristic
_transferCharacteristic = [[CBMutableCharacteristic alloc] initWithType:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]
properties:CBCharacteristicPropertyNotify | CBCharacteristicPropertyRead
value:nil
permissions:CBAttributePermissionsReadable | CBAttributePermissionsWriteable];
// Then the service
_transferService = [[CBMutableService alloc] initWithType:[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID] primary:YES];
// Add the characteristic to the service
_transferService.characteristics = @[_transferCharacteristic];
// And add it to the peripheral manager
[_peripheralManager addService:_transferService];
// Start advertising using a timed thread... this won't work without a timer because you must have time to for
// the peripheral manager to add the service.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[_peripheralManager stopAdvertising];
[_peripheralManager startAdvertising:@{CBAdvertisementDataServiceUUIDsKey : @[_transferService.UUID] }];
NSLog(@"%s: started advertising with ServiceUUID: %@ and CharacteristicUUID: %@",__PRETTY_FUNCTION__,_transferService.UUID,_transferCharacteristic.UUID);
});
}
}
//메시지 보내기 버튼
- (IBAction)sendMsgButton:(id)sender {
NSLog(@"메시지 보내기 버튼!");
[self.peripheralManager updateValue:[@"1" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil];
}
//
// Delegate for CBPeripheralDelegate
//
// Start sending data once we've got a subscriber to the characteristic
//
- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic
{
NSLog(@"%s: central subscribed to characteristic: localkey: %@ dataserviceUUIDs: %@ datasolicitedserviceuuidskey: %@",__PRETTY_FUNCTION__,CBAdvertisementDataLocalNameKey,CBAdvertisementDataServiceUUIDsKey,CBAdvertisementDataSolicitedServiceUUIDsKey);
[BackgroundTimeRemainingUtility NSLog];
// Get the data
//self.dataToSend = [@"Hello from a bluetooth peripheral. Hope you get this just fine!" dataUsingEncoding:NSUTF8StringEncoding];
// self.dataToSend = [@"1" dataUsingEncoding:NSUTF8StringEncoding];
// Reset the index
//self.sendDataIndex = 0;
// Start sending
//[self sendData];
// for (int i = 0; i < 10; i++) {
//
// }
[self.peripheralManager updateValue:[@"1" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil];
// [self.peripheralManager updateValue:[@"1" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil];
}
-(void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveReadRequest:(CBATTRequest *)request{
NSLog(@"didReceiveReadRequest");
}
-(void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray<CBATTRequest *> *)requests{
NSLog(@"didReceiveWriteRequests");
for (CBATTRequest *request in requests) {
if (@available(iOS 11.0, *)) {
if ([request.characteristic.UUID isEqual:[CBUUID UUIDWithString:CBUUIDL2CAPPSMCharacteristicString]]) {
//#ifdef DEBUG
NSString *dataString = [[NSString alloc] initWithData:request.value encoding:NSUTF8StringEncoding];
NSLog(@"Received from manager - %@", dataString);
//#endif
// if (self.delegate && [self.delegate respondsToSelector:@selector(BLEServiceDidReceiveData:peripheral:service:)]) {
// [self.delegate BLEServiceDidReceiveData:request.value peripheral:nil service:self];
// }
}
} else {
// Fallback on earlier versions
}
}
}
//
// Sends the next amount of data to the connected central
//
- (void)sendData
{
// First up, check if we're meant to be sending an EOM
static BOOL sendingEOM = NO;
NSLog(@"%s:",__PRETTY_FUNCTION__);
[BackgroundTimeRemainingUtility NSLog];
// Special case if we're done sending the message
if (sendingEOM) {
// send it
BOOL didSend = [self.peripheralManager updateValue:[@"EOM" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil];
// Did it send?
if (didSend) {
// It did, so mark it as sent
sendingEOM = NO;
NSLog(@"%s: send EOM succeeded.",__PRETTY_FUNCTION__);
}
else {
NSLog(@"%s: send EOM failed.. will try again.",__PRETTY_FUNCTION__);
}
}
// We're not sending an EOM, so we're sending data
else {
// Is there any left to send?
if (self.sendDataIndex >= self.dataToSend.length) {
// No data left. Do nothing
return;
}
// There's data left, so send until the callback fails, or we're done.
BOOL didSend = YES;
while (didSend) {
// Make the next chunk
// Work out how big it should be
NSInteger amountToSend = self.dataToSend.length - self.sendDataIndex;
// Can't be longer than 20 bytes
if (amountToSend > NOTIFY_MTU) amountToSend = NOTIFY_MTU;
// Copy out the data we want
NSData *chunk = [NSData dataWithBytes:self.dataToSend.bytes+self.sendDataIndex length:amountToSend];
// Send it
didSend = [self.peripheralManager updateValue:chunk forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil];
// If it didn't work, drop out and wait for the callback
if (!didSend) {
return;
}
NSString *stringFromData = [[NSString alloc] initWithData:chunk encoding:NSUTF8StringEncoding];
NSLog(@"Sent: %@", stringFromData);
// It did send, so update our index
self.sendDataIndex += amountToSend;
// Was it the last one?
if (self.sendDataIndex >= self.dataToSend.length) {
// It was - send an EOM
// Set this so if the send fails, we'll send it next time
sendingEOM = YES;
// Send it
BOOL eomSent = [self.peripheralManager updateValue:[@"EOM" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil];
if (eomSent) {
// It sent, we're all done
sendingEOM = NO;
NSLog(@"Sent: EOM");
}
return;
}
}
}
}
@end

 

파일

Center.zip
0.12MB
peri.zip
0.20MB