reading battery level ble Xcode - iphone

I have written an app which I am trying to get and update the battery level on my cB-OLP425 module.
I have used the following code but sometimes it gives me a value of 70 and at other times it gives me a value of -104. I have looked at numerous posts and tried a lot of things but nothing seems to work.
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
if([service.UUID isEqual:[CBUUID UUIDWithString:#"180F"]]) {
for (CBCharacteristic *characteristic in service.characteristics) {
NSLog(#"discovered service %#", service.UUID);
if([characteristic.UUID isEqual:[CBUUID UUIDWithString:#"2A19"]]) {
NSLog(#"Found Notify Characteristic %#", characteristic.UUID);
self.mycharacteristic = characteristic;
[self.testPeripheral readValueForCharacteristic:mycharacteristic];
[self.testPeripheral setNotifyValue:YES forCharacteristic:mycharacteristic];
char batlevel;
[mycharacteristic.value getBytes:& batlevel length:0];
int n = (float)batlevel;
int value = n ;
self.batteryLevel = value;
NSLog(#"batterylevel1;%f",batteryLevel);
/* [[NSUserDefaults standardUserDefaults]setFloat: batteryLevel forKey:#"battery_level"];*/
}
} }
}
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
if([characteristic.UUID isEqual:[CBUUID UUIDWithString:#"2A19"]]) {
NSLog(#"Found Battery Characteristic %#", characteristic.UUID);
[mycharacteristic.value getBytes:& batteryLevel length:0];
return;
}
[self.delegate peripheralDidReadChracteristic:mycharacteristic withPeripheral:testPeripheral withError:error];
}
Could someone please help me!!

Your getBytes seems to be the issue. We read the battery level in our app using:
UInt8 batteryLevel = ((UInt8*)value.bytes)[0];
You could also do it with:
UInt8 batteryLevel;
[value getBytes:&battery length:1];
You need to make sure the type is UInt8 otherwise you would read it into the wrong location.
Also, don't read the value right away in the didDiscoverCharacteristicsForService. Wait until you get notified that the value has been updated. The docs state:
When you attempt to read the value of a characteristic, the peripheral calls the peripheral:didUpdateValueForCharacteristic:error: method of its delegate object to retrieve the value. If the value is successfully retrieved, you can access it through the characteristic’s value property, like this:

Related

Id UUID static over sessions?

I want to use an alternative to the UDID and found this:
+ (NSString *)GetUUID
{
CFUUIDRef theUUID = CFUUIDCreate(NULL);
CFStringRef string = CFUUIDCreateString(NULL, theUUID);
CFRelease(theUUID);
return [(NSString *)string autorelease];
}
but in the simulator the method gives me different results every session?
Is this only in simulator?
I need to be sure that on actual devices the method returns me always the same string
to identify a user.
Is it true or not?
Mirza
CFUUIDRef will create different values at each session.
Solution 1:
Save the value in NSUserDefaults and next time onwards use it from the NSUserDefaults.
Solution 2:
You can use identifierForVendor for doing this.
NSString *udidVendor = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
According to UIDevice Class Reference:
The value of this property is the same for apps that come from the
same vendor running on the same device. A different value is returned
for apps on the same device that come from different vendors, and for
apps on different devices regardless of vendor.
Please check Unique Identifier In iOS 6
CFUUIDCreate gives you a Universally Unique Identifier every time you call that function, so each time you will get a different result (by definition).
What you can do is persist this in between sessions using, for example, NSUserDefaults, to uniquely identify a particular user (or bunch of user's settings).
CFUUID is not persisted at all.
Every time you call CFUUIDCreate the system will return to you a brand new unique identifier.
If you want to persist this identifier you will need to do that yourself using NSUserDefaults, Keychain, Pasteboard or some other means.
Read the code one line at a time and try to understand what it does. The CFUUIDCreate function creates a new UUID every time you call it. That would explain your finding. You need to save the value in NSUserDefaults* the first time and use that value the next time you launch the app:
+ (NSString *)GetUUID
{
NSString *string = [[NSUserDefaults standardUserDefaults] objectForKey: #"UUID"];
if (!string)
{
CFUUIDRef theUUID = CFUUIDCreate(NULL);
string = (NSString*)[CFUUIDCreateString(NULL, theUUID) autorelease];
CFRelease(theUUID);
[[NSUserDefaults standardUserDefaults] setObject: string forKey: #"UUID"];
}
return string;
}
*There are one small caveat of using NSUserDefaults - UUID will be created again if user uninstalls and reinstalls the app again. If you can't live with this, look into saving it in Keychain. Alternatively, you might want to look at OpenUDID.
The method will always return a unique string. If the app will only ever have a single user, run this method once when the user first launches the app and persist that string in a plist, or NSUserDefaults, or core data if you've already using it.
The link below may help with this UUID persistence logic:
UUID for app on iOS5
However, if the user then uninstalls and reinstalls the app, this persisted UUID will still be lost and need will be generated again.
Device IDs are also no longer allowed by Apple.
Assuming the UUID is required because the app connects to a server, as far as I know, you need the user log in to the server with a user name and password.
It is always different. UUID includes timestamps, so every time you call this function, you will get a different (random) one.
I have followed this approach in IDManager class,
This is a collection from different solutions. KeyChainUtil is a wrapper to read from keychain. A similar keychain util is found in github.
// IDManager.m
/*
A replacement for deprecated uniqueIdentifier API. Apple restrict using this from 1st May, 2013.
We have to consider,
* iOS <6 have not the ASIIdentifer API
* When the user upgrade from iOS < 6 to >6
- Check if there is a UUID already stored in keychain. Then use that.
- In that case, this UUID is constant for whole device lifetime. Keychain item is not deleted with application deletion.
*/
#import "IDManager.h"
#import "KeychainUtils.h"
#import "CommonUtil.h"
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 60000
#import <AdSupport/AdSupport.h>
#endif
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>
/* Apple confirmed this bug in their system in response to a Technical Support Incident request. They said that identifierForVendor and advertisingIdentifier sometimes returning all zeros can be seen both in development builds and apps downloaded over the air from the App Store. They have no work around and can't say when the problem will be fixed. */
#define kBuggyASIID #"00000000-0000-0000-0000-000000000000"
#pragma mark
#pragma mark
#implementation IDManager
+ (NSString *) getUniqueID {
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 60000
if (NSClassFromString(#"ASIdentifierManager")) {
NSString * asiID = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
if ([asiID compare:kBuggyASIID] == NSOrderedSame) {
NSLog(#"Error: This device return buggy advertisingIdentifier.");
return [IDManager getUniqueUUID];
} else {
return asiID;
}
} else {
#endif
return [IDManager getUniqueUUID];
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 60000
}
#endif
}
+ (NSString *) getUniqueUUID
{
NSError * error;
NSString * uuid = [KeychainUtils getPasswordForUsername:#"UserName" andServiceName:#"YourServiceName" error:&error];
if (error) {
NSLog(#"Error geting unique UUID for this device! %#", [error localizedDescription]);
return nil;
}
if (!uuid) {
DLog(#"No UUID found. Creating a new one.");
uuid = [IDManager getUUID];
uuid = [CommonUtil md5String:uuid]; // create md5 hash for security reason
[KeychainUtils storeUsername:#"UserName" andPassword:uuid forServiceName:#"YourServiceName" updateExisting:YES error:&error];
if (error) {
NSLog(#"Error geting unique UUID for this device! %#", [error localizedDescription]);
return nil;
}
}
return uuid;
}
+ (NSString *) readUUIDFromKeyChain {
NSError * error;
NSString * uuid = [KeychainUtils getPasswordForUsername:#"UserName" andServiceName:#"YourServiceName" error:&error];
if (error) {
NSLog(#"Error geting unique UUID for this device! %#", [error localizedDescription]);
return nil;
}
return uuid;
}
/* NSUUID is after iOS 6. So we are using CFUUID for compatibility with iOS 4.3 */
+ (NSString *)getUUID
{
CFUUIDRef theUUID = CFUUIDCreate(NULL);
CFStringRef string = CFUUIDCreateString(NULL, theUUID);
CFRelease(theUUID);
return [(NSString *)string autorelease];
}
#pragma mark - MAC address
/* THIS WILL NOT WORK IN iOS 7. IT WILL RETURN A CONSTANT MAC ADDRESS ALL THE TIME.
SEE - https://developer.apple.com/news/?id=8222013a
*/
// Return the local MAC address
// Courtesy of FreeBSD hackers email list
// Last fallback for unique identifier
+ (NSString *) getMACAddress
{
int mib[6];
size_t len;
char *buf;
unsigned char *ptr;
struct if_msghdr *ifm;
struct sockaddr_dl *sdl;
mib[0] = CTL_NET;
mib[1] = AF_ROUTE;
mib[2] = 0;
mib[3] = AF_LINK;
mib[4] = NET_RT_IFLIST;
if ((mib[5] = if_nametoindex("en0")) == 0) {
printf("Error: if_nametoindex error\n");
return NULL;
}
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
printf("Error: sysctl, take 1\n");
return NULL;
}
if ((buf = malloc(len)) == NULL) {
printf("Error: Memory allocation error\n");
return NULL;
}
if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
printf("Error: sysctl, take 2\n");
free(buf); // Thanks, Remy "Psy" Demerest
return NULL;
}
ifm = (struct if_msghdr *)buf;
sdl = (struct sockaddr_dl *)(ifm + 1);
ptr = (unsigned char *)LLADDR(sdl);
NSString *outstring = [NSString stringWithFormat:#"%02X:%02X:%02X:%02X:%02X:%02X",
*ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)];
free(buf);
return outstring;
}
+ (NSString *) getHashedMACAddress
{
NSString * mac = [IDManager getMACAddress];
return [CommonUtil md5String:mac];
}
#end

Sending data to Core Bluetooth Framework Xcode

. I am working on an app that uses a core bluetooth framework .App is related to start, lock, unlock doors. I am almost done with the app with the help of examples provided by the Apple. That is Heart Rate Monitor and Temperature Sensor.
I have 2 Questions.
1: Heart Rate Monitor app reads the data from a peripheral while in my case I just have to signal the peripheral that startButton is pressed. So my Question is that whether I have to use writeValueForCharacteristic in discoverCharacteristics method.
2: If so kindly help me with the button code here
- (IBAction) startButtonPressed: (id) sender {
}
- (IBAction) lockDoors: (id) sender {
}
- (IBAction) unLockDoors: (id) sender {
}
Code is given by.
- (void) peripheral:(CBPeripheral *) peripheral didDiscoverServices:(NSError *)error
{
if (error)
{
NSLog(#"Discovered services for %# with error: %#", peripheral.name, [error localizedDescription]);
return;
}
for (CBService * service in peripheral.services)
{
NSLog(#"Service found with UUID: %#", service.UUID);
if([service.UUID isEqual:[CBUUID UUIDWithString:#"1809"]])
{
/* Car Start Service - discover
CAR_START_CHARACTERISTIC_UUID,
LOCK_DOOR_CHARACTERISTIC_UUID,
UNLOCK_DOOR_CHARACTERISTIC_UUID,
TRUNK_CHARACTERISTIC_UUID
ALARM_CHARACTERISTIC_UUID
*/
[peripheralManager discoverCharacteristics:[NSArray arrayWithObjects:[CBUUID UUIDWithString:#"2A1E"], [CBUUID UUIDWithString:#"2A1C"], [CBUUID UUIDWithString:#"2A21"], [CBUUID UUIDWithString:#"2A1F"],[CBUUID UUIDWithString:#"2A1G"],nil] forService:service];
}
else if([service.UUID isEqual:[CBUUID UUIDWithString:#"180A"]])
{
/* Device Information Service - discover manufacture name characteristic */
[peripheralManager discoverCharacteristics:[NSArray arrayWithObject:[CBUUID UUIDWithString:#"2A29"]] forService:service];
}
else if ( [service.UUID isEqual:[CBUUID UUIDWithString:CBUUIDGenericAccessProfileString]] )
{
/* GAP (Generic Access Profile) - discover device name characteristic */
[peripheralManager discoverCharacteristics:[NSArray arrayWithObject:[CBUUID UUIDWithString:CBUUIDDeviceNameString]] forService:service];
}
}
}
- (void) peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
if (error)
{
NSLog(#"Discovered characteristics for %# with error: %#", service.UUID, [error localizedDescription]);
return;
}
if([service.UUID isEqual:[CBUUID UUIDWithString:#"1809"]]) {
for (CBCharacteristic * characteristic in service.characteristics)
{
/* Set Car Start */
if([characteristic.UUID isEqual:[CBUUID UUIDWithString:#"2A1C"]])
{
self.carStartCharacteristic = characteristic;
NSLog(#"Found Car Start Characteristic");
}
/* Set Lock Doors */
if([characteristic.UUID isEqual:[CBUUID UUIDWithString:#"2A1E"]])
{
self.lockDoorsCharacteristic = characteristic;
NSLog(#"Found Lock Doors Characteristic");
}
/* Set Un Lock Doors */
if([characteristic.UUID isEqual:[CBUUID UUIDWithString:#"2A11"]])
{
self.unLockDoorsCharacteristic = characteristic;
NSLog(#"Found UnLock Doors Characteristic");
}
/* Set Trunk Open */
if([characteristic.UUID isEqual:[CBUUID UUIDWithString:#"2A13"]])
{
self.trunkCharacteristic = characteristic;
NSLog(#"Found Trunk Characteristic");
}
/* Set Alarm */
if([characteristic.UUID isEqual:[CBUUID UUIDWithString:#"2A14"]])
{
self.alarmCharacteristic = characteristic;
NSLog(#"Found Alarm Characteristic");
}
}
}if([service.UUID isEqual:[CBUUID UUIDWithString:#"180A"]])
{
for (CBCharacteristic * characteristic in service.characteristics)
{
/* Read manufacturer name */
if([characteristic.UUID isEqual:[CBUUID UUIDWithString:#"2A29"]])
{
[peripheralManager readValueForCharacteristic:characteristic];
NSLog(#"Found a Device Manufacturer Name Characteristic - Read manufacturer name");
}
}
}
if ( [service.UUID isEqual:[CBUUID UUIDWithString:CBUUIDGenericAccessProfileString]] )
{
for (CBCharacteristic *characteristic in service.characteristics)
{
/* Read device name */
if([characteristic.UUID isEqual:[CBUUID UUIDWithString:CBUUIDDeviceNameString]])
{
[peripheralManager readValueForCharacteristic:characteristic];
NSLog(#"Found a Device Name Characteristic - Read device name");
}
}
}
}
You will use both. You will scan (if not previously connected), then discover services, then discover characteristics. Once that is done, you will call writeValueForCharacteristic from your button with whatever value you wish to write.
(IBAction) startButtonPressed: (id) sender {
[peripheral writeValue:yourNSData forCharacteristic:yourCBCharacteristic type:yourWriteType];
}

GCDAsyncSocket - Read stream never completes

I am playing with GCDAsyncSocket (MRC / iOS5.1) for a while, especially with "large" files (5 - 10 mb). Unfortunately sometimes the read stream is never completed (e.g. it gets stuck) just a few bytes at the end of the stream; the didReadPartialDataOfLength: stops giving me information and the didReadData is not fired at all.
Here's some of my code (for both writing / reading examples the connection between the host and client have been established)
WRITING
#define kHeadTag 0
#define kDataTag 1
typedef struct {
NSUInteger size;
} head_t;
-(void)sendData:(NSData *)__data {
_sendData = [__data retain];
head_t header;
header.size = __data.length;
[_socket writeData:[NSData dataWithBytes:&header
length:sizeof(header)]
withTimeout:-1
tag:kHeadTag];
}
-(void)socket:(GCDAsyncSocket *)sock
didWriteDataWithTag:(long)tag {
if (tag == kHeadTag) {
[sock writeData:_sendData withTimeout:-1 tag:kDataTag];
[_sendData release];
_sendData = nil;
}
}
READING
-(void)socket:(GCDAsyncSocket *)sock
didReadData:(NSData *)data
withTag:(long)tag {
switch (tag) {
// ------------------------------------- HEAD
case kHeadTag:{
head_t head;
[data getBytes:&head length:sizeof(head)];
_readHead = head;
NSLog(#"Received header (total size = %i bytes)", head.size);
[sock readDataToLength:head.size
withTimeout:-1
tag:kDataTag];
}
break;
// ------------------------------------- BODY
case kDataTag: {
NSLog(#"Data received with %i bytes", data.length);
[sock readDataToLength:sizeof(head_t) withTimeout:-1 tag:kHeadTag];
}
break;
}
};
-(void)socket:(GCDAsyncSocket *)sock
didReadPartialDataOfLength:(NSUInteger)partialLength
tag:(long)tag {
if (tag == kDataTag) {
NSLog(#"Data read with %i bytes", partialLength);
}
};
I hope this is enough code to see what I'm doing wrong or maybe this is a bad practice for writing/reading large chunks of data.
I added
[self.partnerSocket writeData:[GCDAsyncSocket CRLFData] withTimeout:-1 tag:0];
at the end of sendData: method, and it works fine for me. You just have to append separator chars at the end of the data.
I can transfer around 48MB of file from one iDevice to other iDevice

Show Opponent's Score (Multiplayer/GameKit) - Cocos2d

I have it set up so it sends the player's score to the opponents's screen so they can see what their score is, but it never updates the value. Any ideas?
typedef enum
{
kMessageTypeRandomNumber = 0,
kMessageTypeScore,
} MessageType;
typedef struct
{
Message message;
int score;
} MessageScore;
#interface GSMultiplayer : CCLayer <GCHelperDelegate>
{
CCLabelTTF *oppScoreLabel;
uint32_t ourRandom;
BOOL receivedRandom;
}
--------------------------------------------
- (void)sendScore
{
CCLOG(#"Sent Score");
int oppScore = score;
MessageScore message;
message.message.messageType = kMessageTypeScore;
message.score = oppScore;
NSData *data = [NSData dataWithBytes:&message length:sizeof(MessageScore)];
[self sendData:data];
}
- (void)tryStartGame
{
if (isPlayer1 && gameState == kGameStateWaitingForStart)
{
[self setGameState:kGameStateActive];
[self sendGameBegin];
}
[self sendScore];
}
- (void)matchStarted
{
CCLOG(#"Match started");
if (receivedRandom)
{
[self setGameState:kGameStateWaitingForStart];
} else {
[self setGameState:kGameStateWaitingForRandomNumber];
}
[self sendRandomNumber];
[self tryStartGame];
}
- (void)match:(GKMatch *)match didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID
{
Message *message = (Message *) [data bytes];
if (message->messageType == kMessageTypeScore)
{
CCLOG(#"Score Received");
[scoreLabel setString:[NSString stringWithFormat:#"Score: %d", score]];
}
}
}
Also, score is globally delcared from the main "GameScene". I am very new to multiplayer so help is greatly appreciated
Thanks
Keep track of the score yourself and add a layer to display the score.. after player changes scene, send the score to gamecenter?
Is your game using gamekit? If yes, you might wan to look at an example in a game called Infinight.. there is a lite version in the App store.. It has gamecenter multiplayer in it.. Just play it with friends and see how it works.. It also sends score to gamecenter after playing..
in your send data function:
msg.oppScore = score;
NSData *packet = [NSData dataWithBytes:&msg length:sizeof(charInfo)];
[sharedData.myMatch sendDataToAllPlayers: packet withDataMode: GKMatchSendDataUnreliable error:&error];
sharedData.myMatch is suppose to be the GKMatch that you are suppose to reference to when the game starts..

Game Center multiplayer code

As per the docs, I'm using:
- (void) match:(GKMatch*) match
player:(NSString*) playerID
didChangeState:(GKPlayerConnectionState) state;
to carry out the initial game negotiation. I do this in the scope of:
if (matchStarted_ == NO && [match expectedPlayerCount] == 0) { ... }
I need to decide which device is responsible for setting up the game. I do this by sorting the match.playerIDs NSArray instance and comparing the [GKLocalPlayer localPlayer].playerID NSString to the playerID NSString at index 0 of the sorted array. This player creates the game, sending out the data to all players.
However, and even with an expectedPlayerCount of 0, the playerIDs array has zero entries at this point, giving me an array overrun. Why is that? And what should I do instead to make a well-defined choice of player to generate the game?
For the decision code, take a look at the GKTank example provided by Apple - they take a hash of the device id, send it to the other client, and whichever has the lower number is the "host". That seems like a pretty solid way to decide.
here is sample code to do that thing
NSString *uid = [[UIDevice currentDevice] uniqueIdentifier];
CoinTossID = [uid hash];
now in delegate Function
- (void)match:(GKMatch *)match didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID
{
NSMutableArray *ReceivedArray = [[NSMutableArray alloc] init];
ReceivedArray = [NSKeyedUnarchiver unarchiveObjectWithData:data];
int flag = [[ReceivedArray objectAtIndex:0] intValue];
[ReceivedArray removeObjectAtIndex:0];
int CoinValue = [ReceivedCoinTossID intValue];
if(CoinValue > CoinTossID)
{
isPlayer1 = YES;
}
else
{
isPlayer1 = NO;
}
}