IOS Bluetooth data receiving and sending

  1. Noun: Central, Peripheral, advertising, Services, Characteristic
  2. Create a Central Manager instance for Bluetooth management
  3. Search peripherals
  4. Connecting peripherals
  5. Get services from peripherals
  6. Characteristics of access to services
  7. Send data to peripheral devices
  8. Read data from peripherals

Bluetooth is introduced

CoreBluetooth, which this article introduces, is specifically designed to communicate with BLE devices. And now many Bluetooth devices support 4.0,4.0 is known for its low power consumption, so it is also commonly called BLE(Bluetoothlow Energy), so it is also a recommended development method in iOS.

CoreBluetooth introduction

There are two main parts in CoreBluetooth,Central and Peripheral, CBPeripheralManager as peripherals. CBCentralManager serves as the central device. All available iOS devices can be used as peripherals or Central, but not both.

  1. The Peripheral device is the data of the broadcast device, and the Central device is the device that manages and uses the data.
  2. That is, the Peripheral sends a broadcast around, telling the surrounding Central that there’s data here, and it says what services and eigenvalues it can provide,
  3. In fact, the bluetooth transmission value is equivalent to the network interface, the hardware service UUID plus characteristic UUID, a comparison: The UUID of the service is equivalent to the main address, and the UUID of the characteristic is equivalent to the short link. The short link must be the branch of the main address, which is put together as the interface. The Bluetooth transmission format set by you and the hardware is similar to JSON, and the data can be identified by both parties, because Bluetooth can only support hexadecimal. And only 20 bytes can be transferred at a time, so the flow has to be converted into hexadecimal, which is mutually identifiable

Implementation method introduction

  • H Imports the header file
#import <CoreBluetooth/CoreBluetooth.h>
Copy the code
  • Custom set enumeration state

typedef NS_ENUM(NSInteger, BluetoothState){
    BluetoothStateDisconnect = 0,
    BluetoothStateScanSuccess,
    BluetoothStateScaning,
    BluetoothStateConnected,
    BluetoothStateConnecting
};

typedef NS_ENUM(NSInteger, BluetoothFailState){
    BluetoothFailStateUnExit = 0,
    BluetoothFailStateUnKnow,
    BluetoothFailStateByHW,
    BluetoothFailStateByOff,
    BluetoothFailStateUnauthorized,
    BluetoothFailStateByTimeout
};

Copy the code
  • Set the agent
<CBCentralManagerDelegate,CBPeripheralDelegate>
Copy the code
  • Add attributes
@property (strong , nonatomic) UITableView *tableView; @property (strong , nonatomic) CBCentralManager *manager; @property (Assign, nonatomic) BluetoothFailState BluetoothFailState; @property (assign , nonatomic) BluetoothState bluetoothState; @property (strong , nonatomic) CBPeripheral * discoveredPeripheral; @property (strong, nonatomic) CBCharacteristic * Characteristic1; @property (strong, nonatomic) NSMutableArray *BleViewPerArr;Copy the code
  • Create a UITableView
-(void)setTableView{
    _tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 20, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height) style:UITableViewStyleGrouped];
    _tableView.delegate = self;
    _tableView.dataSource = self;
    _tableView.backgroundColor = [UIColor whiteColor];
    [self.view addSubview:_tableView];
}
Copy the code
  • So let’s write the dalegate of the tableView
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:@"IsConnect"];
    if (cell == nil) {
        cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"IsConnect"]; } // Connect the Bluetooth peripheral object to the BleViewPerArr array. CBPeripheral *per=(CBPeripheral *)_BleViewPerArr[indepath.row]; NSString *bleName=[per.name substringWithRange:NSMakeRange(0, 9)]; cell.textLabel.text = per.name;return cell;
}

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    return 44;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return _BleViewPerArr.count;
}

Copy the code
  • Create instances, set up proxies, create array management peripherals,
self.manager = [[CBCentralManager alloc]initWithDelegate:self queue:dispatch_get_main_queue()];
self.manager.delegate = self;
self.BleViewPerArr = [[NSMutableArray alloc]initWithCapacity:1];

Copy the code
  • Start scanning
-(void)scan{// Determine status start scan for surrounding devices if the first parameter is null then scan for all connected devices. You can // specify a CBUUID object to scan only the devices registered with the specified service / / scanForPeripheralsWithServices after the method call will call agent CBCentralManagerDelegate / / - (void) centralManager: (CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI (NSNumber *) the RSSI method [self. Manager scanForPeripheralsWithServices: nil options: @ { CBCentralManagerScanOptionAllowDuplicatesKey : @NO }]; Bluetoothstate = BluetoothStateScaning; // Empty all peripheral arrays [self.BleViewPerArr removeAllObjects]; // If bluetooth is not enabled, it prompts you to enable Bluetoothif(_bluetoothFailState==BluetoothFailStateByOff)
    {
        NSLog(@"% @"The @"Check that your Bluetooth is enabled and try again."); }}Copy the code
  • The bluetooth status is then detected
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
    if(central.state ! = CBCentralManagerStatePoweredOn) { NSLog(@"fail, state is off.");
        switch (central.state) {
            case CBCentralManagerStatePoweredOff:
                NSLog(@"Connection failed \n Please check your mobile phone bluetooth is enabled, \n then try again");
                _bluetoothFailState = BluetoothFailStateByOff;
                break;
            case CBCentralManagerStateResetting:
                _bluetoothFailState=BluetoothFailStateByTimeout;
                break;
            case CBCentralManagerStateUnsupported:
                NSLog(@"Detected that your phone does not support Bluetooth 4.0\ N and therefore cannot establish a connection. I suggest you change your phone and try again.");
                _bluetoothFailState = BluetoothFailStateByHW;
                break;
            case CBCentralManagerStateUnauthorized:
                NSLog(@"Connection failed \n Please check your mobile phone bluetooth is enabled, \n then try again");
                _bluetoothFailState = BluetoothFailStateUnauthorized;
                break;
            case CBCentralManagerStateUnknown:
                _bluetoothFailState = BluetoothFailStateUnKnow;
                break;
            default:
                break;
        }
        return;
    }
    _bluetoothFailState = BluetoothFailStateUnExit;
    // ... so start scanning
}

Copy the code
  • After the central machine starts scanning, we need to implementcentralManager:didDiscoverPeripheral:advertisementData:RSSI:This callback is used to obtain the discovery device. This callback indicates that a peripheral of the RSSI-Received Signal Strength Indicator has been detected. The signal quality can be used to judge the distance between peripheral devices and central devices.
- (void)centralManager:(CBCentralManager *)central
 didDiscoverPeripheral:(CBPeripheral *)peripheral
     advertisementData:(NSDictionary *)advertisementData
                  RSSI:(NSNumber *)RSSI
{
    if (peripheral == nil||peripheral.identifier == nil/*||peripheral.name == nil*/)
    {
        return;
    }
    NSString *pername=[NSString stringWithFormat:@"% @",peripheral.name]; // Check whether @ exists"Name of your device"
    NSRange range=[pername rangeOfString:@"Name of your device"]; // If the specified device name is found in the device searched, and the BleViewPerArr array does not have its address // add to the BleViewPerArr arrayif(range.location! =NSNotFound&&[_BleViewPerArr containsObject:peripheral]==NO){ [_BleViewPerArr addObject:peripheral]; } _bluetoothFailState = BluetoothFailStateUnExit; _bluetoothState = BluetoothStateScanSuccess; [_tableView reloadData]; }Copy the code

Scan device output station log:

<CBPeripheral: 0x14e625f80, identifier = 954DBF72-104A-E041-19F8-D9538DBA7C23, name = brand, state = disconnected>
Copy the code

Bluetooth broadcast can carry some information, preferably the MAC address is also broadcast here!! AdvertisementData output station log:

Printing description of advertisementData:
{
    kCBAdvDataIsConnectable = 1;
    kCBAdvDataLocalName = "brand";
    kCBAdvDataTxPowerLevel = 2;
}
Copy the code
  • And then after you scan to the device, of course, the link device, you’re going to have a UITableView, and you’re going to write the connection method inside the tableview click method
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ CBPeripheral *peripheral=(CBPeripheral *)_BleViewPerArr[indexPath.row]; // Set peripheral, specify agent _discoveredPeripheral = Peripheral; _discoveredPeripheral.delegate = self; / / connected devices [_manager connectPeripheral: peripheral options: @ {CBConnectPeripheralOptionNotifyOnConnectionKey: @ YES}]. }Copy the code

Description: Click the cell to connect the corresponding device, Connect the device and after calling this method it calls the proxy – (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral means connected to the device

Connection failure can call – (void) centralManager: (CBCentralManager *) central didFailToConnectPeripheral: (peripheral CBPeripheral *) error:(NSError *)error

  • After the device is connected, you can obtain the information about the current device
// get the current device - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {NSLog(@"% @",peripheral); // Set the peripheral proxysetDelegate:self]; [peripheral discoverServices:nil]; // Maybe just get the UUID array of your device's Bluetooth service, one or more //[Peripheral discoverServices:@[[CBUUID UUIDWithString:@""],[CBUUID UUIDWithString:@""]]];
    
    
    NSLog(@"Peripheral Connected");
    
    [_manager stopScan];
    
    NSLog(@"Scanning stopped");
    
    _bluetoothState=BluetoothStateConnected;
    
}

Copy the code
  • A variety of services

Description: So in this method we’re going to find the service that we want and then we’re going to call discoverCharacteristics which is going to call the – of the proxy CBPeripheralDelegate (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error

// get the current device service services - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {if (error) {
        NSLog(@"Error discovering services: %@", [error localizedDescription]);
        return;
    }
    
    NSLog(@"All servicesUUID%@",peripheral.services); // Iterate over all servicesfor (CBService *service in peripheral.services)
    {
        
        NSLog(@"Service % @",service.UUID); // Find the servicesuuid you needif ([service.UUID isEqual:[CBUUID UUIDWithString:@"Uuid of your device service"]]) {/ / to monitor it [peripheral discoverCharacteristics: nilforService:service];
        }
        
        
        
    }
    NSLog(@So this peripheral link: %@,peripheral);
    
}

Copy the code
  • Characteristics of the access

Description: In this method we are going to find the property of the service we want and then call setNotifyValue to tell us to monitor the state change of the property of the service and when setNotifyValue is called call the CBPeripheralDelegate – (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
    
    if (error)
    {
        NSLog(@"Discovered characteristics for %@ with error: %@", service.UUID, [error localizedDescription]);
        return;
    }
    NSLog(@"Service: %@",service.UUID); / / featuresfor (CBCharacteristic *characteristic in service.characteristics)
    {
        NSLog(@"% @",characteristic.UUID); Note: uUID can be read, writable, and treated differently!!if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"Your characteristic UUID"]])
        {
            NSLog(@"Monitor: %@",characteristic); // The value of a characteristic characteristic value object is characteristic_characteristic1 = characteristic; [_discoveredPeripheralsetNotifyValue:YES forCharacteristic:characteristic]; } // Of course, you can also listen on multiple characteristic valuesif ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"Your characteristic UUID"// _characteristic2 = characteristic; // _characteristic2 = characteristic; // [peripheralsetNotifyValue:YES forCharacteristic:_characteristic2];
//            NSLog(@"Monitor: %@",characteristic); }}}Copy the code
  • read
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
    if (error)
    {
        NSLog(@"Error updating value for characteristic %@ error: %@", characteristic.UUID, [error localizedDescription]);
        return;
    }
    
    NSLog(@"Received data: %@",characteristic.value);
}
Copy the code

Bluetooth transmission value

Since my project is bracelet, I will introduce how to interact with hardware based on the Bluetooth interface document of our hardware engineer. In fact, Bluetooth value transmission is equivalent to network interface. The UUID of the hardware service is characteristic UUID. The UUID of the service is equivalent to the main address, and the UUID of the characteristic is equivalent to the short link. The short link must be the branch of the main address, which is put together as the interface. The Bluetooth transmission format set by you and the hardware is similar to JSON, and the data can be identified by both parties, because Bluetooth can only support hexadecimal. And only 20 bytes can be transferred at a time, so the flow has to be converted into hexadecimal, which is mutually identifiable

  1. The following is the interface documentation for the wristband

Total number of packets split when APP requests basic data transfer in motion mode

Byte sequence number The parameter value
0 0xa5
1 0x06
2 0x03
3 ~ 4 2-byte time, for example, January 2, represented by 0x0102.
5 Xor checksum

This shows that 0, 1, and 2 bytes are fixed, 3 bytes are month (hexadecimal), 4 bytes are day (hexadecimal), and 5 bytes are xOR checksum

So:

// sportBao {Byte reg[6]; // sportBao {Byte reg[6]; reg[0]=0xa5; reg[1]=0x06; reg[2]=0x03; reg[3]=0x01; reg[4]=0x02; reg[5]=(Byte)(reg[0]^reg[1]^reg[2]^reg[3]^reg[4]); NSData *data=[NSData dataWithBytes:reg length:6];return data;
}

Copy the code

The request is then sent to the bracelet to the Signature value of the discoveredPeripheral Bluetooth device just recorded

- (void)getAltogether {// Generate getAltogether data NSData *d1 = [self sportBao]; NSLog(@"Write % @",d1);
  	NSLog(@"% @",discoveredPeripheral);
  [discoveredPeripheral writeValue:d1 forCharacteristic:characteristic1 type:CBCharacteristicWriteWithResponse];
  
}
  
Copy the code

The bracelet returns data in the following format:

The wristband returns the total number of packets split during the transfer of basic data in motion mode

Byte sequence number The parameter value
0 0xa5
1 0x06
2 0x83
3 ~ 4 The total number of packets split during data transmission in this motion mode
5 Xor checksum

It can be seen that 0, 1, and 2 bytes are fixed, 3-4 bytes are the total number of packets (hexadecimal), and 5 bytes are the xOR checksum

So: we need to convert 3-4 bytes of hexadecimal to get the total number of packets

- (void)SetAltogether:(NSData *)DayData
{
    Byte *testByte = (Byte *)[DayData bytes];
    if(daydata.length == 6) {// After receiving the data, xOR is checked to see if the data is complete and correctif (testByte[5]==(testByte[0]^testByte[1]^testByte[2]^testByte[3]^testByte[4])) {int totalBao = 0; totalBao =testByte[4]*256+testByte[3]; }}}Copy the code

The format for parsing the data already exists, so when receiving the data

- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    if (error)
    {
        NSLog(@"Read failed");
        
        return;
    }
    NSLog(@"Received data :%@",characteristic.value);

    NSString *str = [NSString stringWithFormat:@"% @",characteristic.value]; // Total number of sports packagesif (str.length>7&&[[str substringWithRange:NSMakeRange(1, 2)]isEqualToString:@"a5"]&&[[str substringWithRange:NSMakeRange(5, 2)]isEqualToString:@"83"]) {/ / call resolution to the total number of package method [self SetAltogether: characteristic, value]; }}Copy the code

Data transmission introduction is complete, the basic usage has been explained