BeerBoxiOS/BeerBox/SerialGATT.m

542 lines
18 KiB
Objective-C
Executable File

//
// SerialGATT.m
// HMSoft
//
// Created by HMSofts on 7/13/12.
// Copyright (c) 2012 jnhuamao.cn. All rights reserved.
//
#import "SerialGATT.h"
@implementation SerialGATT
@synthesize delegate;
@synthesize peripherals;
@synthesize manager;
@synthesize activePeripheral;
/*!
* @method swap:
*
* @param s Uint16 value to byteswap
*
* @discussion swap byteswaps a UInt16
*
* @return Byteswapped UInt16
*/
-(UInt16) swap:(UInt16)s {
UInt16 temp = s << 8;
temp |= (s >> 8);
return temp;
}
/*
* (void) setup
* enable CoreBluetooth CentralManager and set the delegate for SerialGATT
*
*/
-(void) setup
{
manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}
/*
* -(int) findHMSoftPeripherals:(int)timeout
*
*/
-(int) findHMSoftPeripherals:(int)timeout
{
if ([manager state] != CBCentralManagerStatePoweredOn) {
NSLog(@"CoreBluetooth is not correctly initialized !");
return -1;
}
[NSTimer scheduledTimerWithTimeInterval:(float)timeout target:self selector:@selector(scanTimer:) userInfo:nil repeats:NO];
//[manager scanForPeripheralsWithServices:[NSArray arrayWithObject:serviceUUID] options:0]; // start Scanning
[manager scanForPeripheralsWithServices:nil options:0];
return 0;
}
/*
* scanTimer
* when findHMSoftPeripherals is timeout, this function will be called
*
*/
-(void) scanTimer:(NSTimer *)timer
{
[manager stopScan];
}
/*
* @method printPeripheralInfo:
*
* @param peripheral Peripheral to print info of
*
* @discussion printPeripheralInfo prints detailed info about peripheral
*
*/
- (void) printPeripheralInfo:(CBPeripheral*)peripheral {
CFStringRef s = CFUUIDCreateString(NULL, (__bridge CFUUIDRef )peripheral.identifier);
printf("------------------------------------\r\n");
printf("Peripheral Info :\r\n");
printf("UUID : %s\r\n",CFStringGetCStringPtr(s, 0));
printf("RSSI : %d\r\n",[peripheral.RSSI intValue]);
printf("Name : %s\r\n",[peripheral.name cStringUsingEncoding:NSStringEncodingConversionAllowLossy]);
printf("isConnected : %d\r\n",peripheral.state == CBPeripheralStateConnected);
printf("-------------------------------------\r\n");
}
/*
* connect
* connect to a given peripheral
*
*/
-(void) connect:(CBPeripheral *)peripheral
{
if (!(peripheral.state == CBPeripheralStateConnected)) {
[manager connectPeripheral:peripheral options:nil];
}
}
-(void) stopScan
{
[manager stopScan];
}
/*
* disconnect
* disconnect to a given peripheral
*
*/
-(void) disconnect:(CBPeripheral *)peripheral
{
[manager cancelPeripheralConnection:peripheral];
}
#pragma mark - basic operations for SerialGATT service
-(void) write:(CBPeripheral *)peripheral data:(NSData *)data
{
[self writeValue:SERVICE_UUID characteristicUUID:CHAR_UUID p:peripheral data:data];
}
-(void) read:(CBPeripheral *)peripheral
{
printf("begin reading\n");
//[peripheral readValueForCharacteristic:dataRecvrCharacteristic];
printf("now can reading......\n");
}
-(void) notify: (CBPeripheral *)peripheral on:(BOOL)on
{
[self notification:SERVICE_UUID characteristicUUID:CHAR_UUID p:peripheral on:YES];
}
#pragma mark - CBCentralManager Delegates
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
//TODO: to handle the state updates
}
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
printf("Now we found device\n");
if (!peripherals) {
peripherals = [[NSMutableArray alloc] initWithObjects:peripheral, nil];
for (int i = 0; i < [peripherals count]; i++) {
[delegate peripheralFound: peripheral];
}
}
{
if((__bridge CFUUIDRef )peripheral.identifier == NULL) return;
//if(peripheral.name == NULL) return;
//if(peripheral.name == nil) return;
if(peripheral.name.length < 1) return;
// Add the new peripheral to the peripherals array
for (int i = 0; i < [peripherals count]; i++) {
CBPeripheral *p = [peripherals objectAtIndex:i];
if((__bridge CFUUIDRef )p.identifier == NULL) continue;
CFUUIDBytes b1 = CFUUIDGetUUIDBytes((__bridge CFUUIDRef )p.identifier);
CFUUIDBytes b2 = CFUUIDGetUUIDBytes((__bridge CFUUIDRef )peripheral.identifier);
if (memcmp(&b1, &b2, 16) == 0) {
// these are the same, and replace the old peripheral information
[peripherals replaceObjectAtIndex:i withObject:peripheral];
printf("Duplicated peripheral is found...\n");
//[delegate peripheralFound: peripheral];
return;
}
}
printf("New peripheral is found...\n");
[peripherals addObject:peripheral];
[delegate peripheralFound:peripheral];
return;
}
printf("%s\n", __FUNCTION__);
}
-(void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
activePeripheral = peripheral;
activePeripheral.delegate = self;
[activePeripheral discoverServices:nil];
//[self notify:peripheral on:YES];
[self printPeripheralInfo:peripheral];
printf("connected to the active peripheral\n");
}
-(void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
printf("disconnected to the active peripheral\n");
if(activePeripheral != nil)
[delegate setDisconnect];
activePeripheral = nil;
}
-(void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(@"failed to connect to peripheral %@: %@\n", [peripheral name], [error localizedDescription]);
}
#pragma mark - CBPeripheral delegates
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
printf("in updateValueForCharacteristic function\n");
if (error) {
printf("updateValueForCharacteristic failed\n");
return;
}
[delegate serialGATTCharValueUpdated:@"FFE1" value:characteristic.value];
}
//////////////////////////////////////////////////////////////////////////////////////////////
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
}
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error
{
}
- (void)peripheralDidUpdateRSSI:(CBPeripheral *)peripheral error:(NSError *)error
{
}
/*
* @method getAllCharacteristicsFromKeyfob
*
* @param p Peripheral to scan
*
*
* @discussion getAllCharacteristicsFromKeyfob starts a characteristics discovery on a peripheral
* pointed to by p
*
*/
-(void) getAllCharacteristicsFromKeyfob:(CBPeripheral *)p{
for (int i=0; i < p.services.count; i++) {
CBService *s = [p.services objectAtIndex:i];
printf("Fetching characteristics for service with UUID : %s\r\n",[self CBUUIDToString:s.UUID]);
[p discoverCharacteristics:nil forService:s];
}
}
/*
* @method didDiscoverServices
*
* @param peripheral Pheripheral that got updated
* @error error Error message if something went wrong
*
* @discussion didDiscoverServices is called when CoreBluetooth has discovered services on a
* peripheral after the discoverServices routine has been called on the peripheral
*
*/
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
if (!error) {
printf("Services of peripheral with UUID : %s found\r\n",[self UUIDToString:(__bridge CFUUIDRef )peripheral.identifier]);
[self getAllCharacteristicsFromKeyfob:peripheral];
}
else {
printf("Service discovery was unsuccessfull !\r\n");
}
}
/*
* @method didDiscoverCharacteristicsForService
*
* @param peripheral Pheripheral that got updated
* @param service Service that characteristics where found on
* @error error Error message if something went wrong
*
* @discussion didDiscoverCharacteristicsForService is called when CoreBluetooth has discovered
* characteristics on a service, on a peripheral after the discoverCharacteristics routine has been called on the service
*
*/
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
if (!error) {
printf("Characteristics of service with UUID : %s found\r\n",[self CBUUIDToString:service.UUID]);
for(int i = 0; i < service.characteristics.count; i++) { //Show every one
CBCharacteristic *c = [service.characteristics objectAtIndex:i];
printf("Found characteristic %s\r\n",[ self CBUUIDToString:c.UUID]);
}
char t[16];
t[0] = (SERVICE_UUID >> 8) & 0xFF;
t[1] = SERVICE_UUID & 0xFF;
NSData *data = [[NSData alloc] initWithBytes:t length:16];
CBUUID *uuid = [CBUUID UUIDWithData:data];
//CBService *s = [peripheral.services objectAtIndex:(peripheral.services.count - 1)];
if([self compareCBUUID:service.UUID UUID2:uuid]) {
printf("Try to open notify\n");
[self notify:peripheral on:YES];
}
}
else {
printf("Characteristic discorvery unsuccessfull !\r\n");
}
}
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
if (!error) {
printf("Updated notification state for characteristic with UUID %s on service with UUID %s on peripheral with UUID %s\r\n",[self CBUUIDToString:characteristic.UUID],[self CBUUIDToString:characteristic.service.UUID],[self UUIDToString:(__bridge CFUUIDRef )peripheral.identifier]);
[delegate setConnect];
}
else {
printf("Error in setting notification state for characteristic with UUID %s on service with UUID %s on peripheral with UUID %s\r\n",[self CBUUIDToString:characteristic.UUID],[self CBUUIDToString:characteristic.service.UUID],[self UUIDToString:(__bridge CFUUIDRef )peripheral.identifier]);
printf("Error code was %s\r\n",[[error description] cStringUsingEncoding:NSStringEncodingConversionAllowLossy]);
}
}
/*
* @method CBUUIDToString
*
* @param UUID UUID to convert to string
*
* @returns Pointer to a character buffer containing UUID in string representation
*
* @discussion CBUUIDToString converts the data of a CBUUID class to a character pointer for easy printout using printf()
*
*/
-(const char *) CBUUIDToString:(CBUUID *) UUID {
return [[UUID.data description] cStringUsingEncoding:NSStringEncodingConversionAllowLossy];
}
/*
* @method UUIDToString
*
* @param UUID UUID to convert to string
*
* @returns Pointer to a character buffer containing UUID in string representation
*
* @discussion UUIDToString converts the data of a CFUUIDRef class to a character pointer for easy printout using printf()
*
*/
-(const char *) UUIDToString:(CFUUIDRef)UUID {
if (!UUID) return "NULL";
CFStringRef s = CFUUIDCreateString(NULL, UUID);
return CFStringGetCStringPtr(s, 0);
}
/*
* @method compareCBUUID
*
* @param UUID1 UUID 1 to compare
* @param UUID2 UUID 2 to compare
*
* @returns 1 (equal) 0 (not equal)
*
* @discussion compareCBUUID compares two CBUUID's to each other and returns 1 if they are equal and 0 if they are not
*
*/
-(int) compareCBUUID:(CBUUID *) UUID1 UUID2:(CBUUID *)UUID2 {
char b1[16];
char b2[16];
[UUID1.data getBytes:b1];
[UUID2.data getBytes:b2];
if (memcmp(b1, b2, UUID1.data.length) == 0)return 1;
else return 0;
}
/*
* @method findServiceFromUUID:
*
* @param UUID CBUUID to find in service list
* @param p Peripheral to find service on
*
* @return pointer to CBService if found, nil if not
*
* @discussion findServiceFromUUID searches through the services list of a peripheral to find a
* service with a specific UUID
*
*/
-(CBService *) findServiceFromUUIDEx:(CBUUID *)UUID p:(CBPeripheral *)p {
for(int i = 0; i < p.services.count; i++) {
CBService *s = [p.services objectAtIndex:i];
if ([self compareCBUUID:s.UUID UUID2:UUID]) return s;
}
return nil; //Service not found on this peripheral
}
/*
* @method findCharacteristicFromUUID:
*
* @param UUID CBUUID to find in Characteristic list of service
* @param service Pointer to CBService to search for charateristics on
*
* @return pointer to CBCharacteristic if found, nil if not
*
* @discussion findCharacteristicFromUUID searches through the characteristic list of a given service
* to find a characteristic with a specific UUID
*
*/
-(CBCharacteristic *) findCharacteristicFromUUIDEx:(CBUUID *)UUID service:(CBService*)service {
for(int i=0; i < service.characteristics.count; i++) {
CBCharacteristic *c = [service.characteristics objectAtIndex:i];
if ([self compareCBUUID:c.UUID UUID2:UUID]) return c;
}
return nil; //Characteristic not found on this service
}
/*!
* @method notification:
*
* @param serviceUUID Service UUID to read from (e.g. 0x2400)
* @param characteristicUUID Characteristic UUID to read from (e.g. 0x2401)
* @param p CBPeripheral to read from
*
* @discussion Main routine for enabling and disabling notification services. It converts integers
* into CBUUID's used by CoreBluetooth. It then searches through the peripherals services to find a
* suitable service, it then checks that there is a suitable characteristic on this service.
* If this is found, the notfication is set.
*
*/
-(void) notification:(int)serviceUUID characteristicUUID:(int)characteristicUUID p:(CBPeripheral *)p on:(BOOL)on {
UInt16 s = [self swap:serviceUUID];
UInt16 c = [self swap:characteristicUUID];
NSData *sd = [[NSData alloc] initWithBytes:(char *)&s length:2];
NSData *cd = [[NSData alloc] initWithBytes:(char *)&c length:2];
CBUUID *su = [CBUUID UUIDWithData:sd];
CBUUID *cu = [CBUUID UUIDWithData:cd];
CBService *service = [self findServiceFromUUIDEx:su p:p];
if (!service) {
printf("Could not find service with UUID %s on peripheral with UUID %s\r\n",[self CBUUIDToString:su],[self UUIDToString:(__bridge CFUUIDRef )p.identifier]);
return;
}
CBCharacteristic *characteristic = [self findCharacteristicFromUUIDEx:cu service:service];
if (!characteristic) {
printf("Could not find characteristic with UUID %s on service with UUID %s on peripheral with UUID %s\r\n",[self CBUUIDToString:cu],[self CBUUIDToString:su],[self UUIDToString:(__bridge CFUUIDRef )p.identifier]);
return;
}
[p setNotifyValue:on forCharacteristic:characteristic];
}
/*!
* @method writeValue:
*
* @param serviceUUID Service UUID to write to (e.g. 0x2400)
* @param characteristicUUID Characteristic UUID to write to (e.g. 0x2401)
* @param data Data to write to peripheral
* @param p CBPeripheral to write to
*
* @discussion Main routine for writeValue request, writes without feedback. It converts integer into
* CBUUID's used by CoreBluetooth. It then searches through the peripherals services to find a
* suitable service, it then checks that there is a suitable characteristic on this service.
* If this is found, value is written. If not nothing is done.
*
*/
-(void) writeValue:(int)serviceUUID characteristicUUID:(int)characteristicUUID p:(CBPeripheral *)p data:(NSData *)data {
UInt16 s = [self swap:serviceUUID];
UInt16 c = [self swap:characteristicUUID];
NSData *sd = [[NSData alloc] initWithBytes:(char *)&s length:2];
NSData *cd = [[NSData alloc] initWithBytes:(char *)&c length:2];
CBUUID *su = [CBUUID UUIDWithData:sd];
CBUUID *cu = [CBUUID UUIDWithData:cd];
CBService *service = [self findServiceFromUUIDEx:su p:p];
if (!service) {
printf("Could not find service with UUID %s on peripheral with UUID %s\r\n",[self CBUUIDToString:su],[self UUIDToString:(__bridge CFUUIDRef )p.identifier]);
return;
}
CBCharacteristic *characteristic = [self findCharacteristicFromUUIDEx:cu service:service];
if (!characteristic) {
printf("Could not find characteristic with UUID %s on service with UUID %s on peripheral with UUID %s\r\n",[self CBUUIDToString:cu],[self CBUUIDToString:su],[self UUIDToString:(__bridge CFUUIDRef )p.identifier]);
return;
}
if(characteristic.properties & CBCharacteristicPropertyWriteWithoutResponse)
{
[p writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithoutResponse];
}else
{
[p writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
}
}
/*!
* @method readValue:
*
* @param serviceUUID Service UUID to read from (e.g. 0x2400)
* @param characteristicUUID Characteristic UUID to read from (e.g. 0x2401)
* @param p CBPeripheral to read from
*
* @discussion Main routine for read value request. It converts integers into
* CBUUID's used by CoreBluetooth. It then searches through the peripherals services to find a
* suitable service, it then checks that there is a suitable characteristic on this service.
* If this is found, the read value is started. When value is read the didUpdateValueForCharacteristic
* routine is called.
*
* @see didUpdateValueForCharacteristic
*/
-(void) readValue: (int)serviceUUID characteristicUUID:(int)characteristicUUID p:(CBPeripheral *)p {
printf("In read Value");
UInt16 s = [self swap:serviceUUID];
UInt16 c = [self swap:characteristicUUID];
NSData *sd = [[NSData alloc] initWithBytes:(char *)&s length:2];
NSData *cd = [[NSData alloc] initWithBytes:(char *)&c length:2];
CBUUID *su = [CBUUID UUIDWithData:sd];
CBUUID *cu = [CBUUID UUIDWithData:cd];
CBService *service = [self findServiceFromUUIDEx:su p:p];
if (!service) {
printf("Could not find service with UUID %s on peripheral with UUID %s\r\n",[self CBUUIDToString:su],[self UUIDToString:(__bridge CFUUIDRef )p.identifier]);
return;
}
CBCharacteristic *characteristic = [self findCharacteristicFromUUIDEx:cu service:service];
if (!characteristic) {
printf("Could not find characteristic with UUID %s on service with UUID %s on peripheral with UUID %s\r\n",[self CBUUIDToString:cu],[self CBUUIDToString:su],[self UUIDToString:(__bridge CFUUIDRef )p.identifier]);
return;
}
[p readValueForCharacteristic:characteristic];
}
@end