FireBLE/Proxr app for IOS

来自Firefly wiki
跳转至: 导航搜索

Project Summary

Roles Definition

There are two roles in Bluetooth protocol, one is Central, another is Peripheral. In this Project,the cellphone app is Central,and the anti-lost is peripheral. So we need to use the left side API of the picture below:

API.jpg

Project Principle

Bluetooth Anti-lost Alarm: The anti-lost alarm and the smartphone app are connected with each other via Bluetooth. Once the distance of these two devices is out of range.They will alarm the user.

Calculating Distance: If we want to know the distance between the Bluetooth communication node(such as cellphone and Bluetooth device),The easiest calculating method is reading the receive RSSI(Received Signal Strength Indication).The relationship of wireless communication power and distance is:RSSI.jpg A can be considered as the signal receiving power of signal transferred to 1 meter,n is the propagation factor( affected by barrier,temperature and humidity,etc) r is the distance between nodes. When knowing the value of A and n,we can calculating the distance r according PR(dBm).

Realization Process

Define Service and Characteristic

Define the corresponding UUID service and characteristic which needed in Bluetooth communications, such as:

#define BATTERY_SERVICE_UUID            @"180F"
#define IMALERT_SERVICE_UUID            @"1802"
#define INTERACTION_SERVICE_UUID        @"CC07"
 
#define BATTERY_CHARACTERISTIC_UUID     @"2A19"
#define ALERT_CHARACTERISTIC_UUID       @"2A06"
#define RECEIVE_CHARACTERISTIC_UUID     @"CD01"
#define SENDCMD_CHARACTERISTIC_UUID     @"CD20"
#define VERSION_CHARACTERISTIC_UUID     @"CD30"

Use Bluetooth to scan the peripheral with services

CBCentralManager *centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
 
[centralManager scanForPeripheralsWithServices:[CBUUID UUIDWithString:BATTERY_SERVICE_UUID],[CBUUID UUIDWithString:IMALERT_SERVICE_UUID],[CBUUID UUIDWithString:INTERACTION_SERVICE_UUID]] options:@{ CBCentralManagerScanOptionAllowDuplicatesKey : @YES };

Achieve two important delegates

CBCentralManagerDelegate

Inside.h file:

@interface TCBleCentralManager : NSObject <CBCentralManagerDelegate>
@property (strong,nonatomic)TCBlePeripheral *blePeripheral; //This class will achieve the second proxy CBPeripheralDelegate

Inside.m file,achieve several proxy approachs:

(void)centralManagerDidUpdateState:(CBCentralManager *)central
 
{
    //Get the central.status of central device in this method.
}
 
//This methods is to scan the callback function of the device.
 
(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
 
{
      //Required devices
      blePeripheral.discoveredPeripheral = peripheral;
      //Send out connecting request to the suitable device
      [self.centralManager connectPeripheral:peripheral options:nil];
}
 
//Callback this method when the devices are connected successfully.
(void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
     //Achieve the peripheral proxy
     peripheral.delegate = blePeripheral.self;
     //Get the corresponding services
     [peripheral discoverServices:@[[CBUUID UUIDWithString:BATTERY_SERVICE_UUID],[CBUUID UUIDWithString:IMALERT_SERVICE_UUID],[CBUUID           UUIDWithString:INTERACTION_SERVICE_UUID]]];
}
 
(void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
    /**Two reasons of using this method:
            One is using method(void)connectPeripheral:(CBPeripheral *)peripheral options:(NSDictionary *)options failed,
            Another is using method(void)cancelPeripheralConnection:(CBPeripheral *)peripheral.
            The difference is: if the first method is error,and no for nil. then the second method is for nil.
    */
    //delete device infomation
     [self cleanup: blePeripheral.discoveredPeripheral];
     blePeripheral.discoveredPeripheral = nil;
}
(void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
    //It is because of using this method(void)connectPeripheral:(CBPeripheral *)peripheral options:(NSDictionary *)optionsoptions out of time
    //delete device information
     [self cleanup: blePeripheral.discoveredPeripheral];
     blePeripheral.discoveredPeripheral = nil;
}
 
//Disconnect the devices and delete information
(void)cleanup:(CBPeripheral*)peripheral
{
    // Don't do anything if we're not connected
    if (!peripheral.isConnected)
    {
        return;
    }
 
    // See if we are subscribed to a characteristic on the peripheral
    if (peripheral.services != nil)
    {
        for (CBService *service in peripheral.services)
        {
            if (service.characteristics != nil)
            {
                for (CBCharacteristic *characteristic in service.characteristics)
                {
                    if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:BATTERY_CHARACTERISTIC_UUID]])
                    {
                        if (characteristic.isNotifying)
                        {
                            // It is notifying, so unsubscribe
                            [peripheral setNotifyValue:NO forCharacteristic:characteristic];
 
                            // And we're done.
                            return;
                        }
                    }
                }
            }
        }
    }
    // If we've got this far, we're connected, but we're not subscribed, so we just disconnect
    [self.centralManager cancelPeripheralConnection:peripheral];
}

CBPeripheralDelegate

Inside.h file:

@interface TCBlePeripheral : NSObject <CBPeripheralDelegate>
@property (strong,nonatomic) CBPeripheral * discoveredPeripheral;

Inside.m file,achieve several proxy approachs:

//Find device service
 
(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
   //Scan characteristic in service
   for (CBService *service in peripheral.services)
    {
        if ([service.UUID isEqual:[CBUUID UUIDWithString:BATTERY_SERVICE_UUID]])
        {
            [peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:BATTERY_CHARACTERISTIC_UUID]] forService:service];
        }
    }
}
 
//Find the characteristic of service(used in communication)
(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
    //Find these characteristics,manage them ,and using them in communication
    for (CBCharacteristic *characteristic in service.characteristics)
    {
        if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:BATTERY_CHARACTERISTIC_UUID]])
        {
            [peripheral setNotifyValue:YES forCharacteristic:characteristic];//set to reading mode
            batteryCh = characteristic;
        }
    }
}
//Update the characteristic status
(void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
}
//Update the information which gained by characteristic, such as power.
(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
    NSString *stringFromData = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
    if ([characteristic.UUID.UUIDString compare:batteryCh.UUID.UUIDString] == 0)
    {
        char * value = (char*)[characteristic.value bytes];
        NSLog(@"power: %@,,%@,%c", stringFromData,characteristic.value,value[0]);
        return;
    }
}
//Reading device information via characteristic.
[discoveredPeripheral readValueForCharacteristic:characteristic];
 
//Writing device information via characteristic
static int data = 0x04;
 
[discoveredPeripheral writeValue:[[NSData alloc] initWithBytes:&data length:1] forCharacteristic:characteristic type:1];

Get RSSI value

[discoveredPeripheral readRSSI];

using discoveredPeripheral.RSSI.intValue directly; readRSSI will callback method(void)peripheralDidUpdateRSSI:(CBPeripheral *)peripheral error:(NSError *)error(Start from IOS5.0,Abandon after IOS8.0)