iOS BLE no Glucose Measurement notifications - ios

Context:
- iOS 7.1.2 on iPhone 5c
- A glucose measuring "peripheral" (BT LE)
- Device and peripheral have been paired (introducing a code)
- Peripheral has >= 1 records on/in it.
- The behavior described below was reproduced several times. With the peripheral only having one record, and as well having made two new ones. The results (characteristic.value's) read are always the same.
I'm trying to read (receive) records from the peripheral using an iOS device the following way:
Make the glucose peripheral try to send its records to my iOS device.
Discover and connect to relevant peripheral (Glucose Service 0x1808) on iOS device.
In peripheral:didDiscoverServices:error: discover characteristics, which are Glucose Measurement (0x2A18), Glucose Measurement Context (0x2A34), Glucose Feature (0x2A51) and Record Access Control Point (0x2A52)
In peripheral:didDiscoverCharacteristicsForService:error: iterate over all characteristics and read values for those characteristics (via [_peripheral readValueForCharacteristic:characteristic])
Call [_peripheral setNotifyValue:YES forCharacteristic:characteristic] (for all but the "Glucose Feature" characteristic). This is triggered via a button click, when "everything has been loaded".
Request number of records available (triggered by user) via "Record Access Control Point" like:
char buffer[3];
// Op Code: 0x04 report number of stored records
buffer[0] = 0x04;
// Operator: 0x01 All records
buffer[1] = 0x01;
// Operand: 0x00 n/a
buffer[2] = 0x00;
NSData *data = [NSData dataWithBytes:buffer length:3];
[_peripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
Callback calls peripheral:didUpdateValueForCharacteristic:error: delegate method and the updated value is 06000405. I don't fully understand the related specification (see link below), so I'm not able to interpret the response my self but either 5 or 6 in the LSO (Least Significant Octet) would mean a "success" (or at least not an error).
Trigger the request of all stored records (triggered by user) like:
char buffer[3];
// Op Code: 0x01 report stored records
buffer[0] = 0x01;
// Operator: 0x01 All records, 0x06 last one
buffer[1] = 0x01; // Tried 0x06 as well with the same result
// Operand: 0x00 n/a
buffer[2] = 0x00;
NSData *data = [NSData dataWithBytes:buffer length:3];
[_peripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
Call back calls peripheral:didUpdateValueForCharacteristic:error: with an updated value of 06000105. Changing the second octet from 0x01 to 0x06 gave the same response (value). Which as well I'm not able to understand/interpret.
Nothing more happens. Neither on Glucose Measurement nor on Glucose Measurement Context.
Note: On Android it seems that one must also set the Client Characteristic Configuration descriptor to notify and/or indicate, but trying either of that results in an exception and a message that notifications should be set on the characteristic itself using setNotifyValue:forCharacteristic: on the peripheral.
My main problem is, that there are no callbacks to peripheral:didUpdateValueForCharacteristic:error: on Glucose Measurement characteristic including the records. I event tried calling [_peripheral setNotifyValue:YES forCharacteristic:characteristic] again on that characteristic, after requesting the records.
Does anyone see where my error(s) lie? Does anyone achieved (on iOS) what I'm trying to achieve?
Another thing is the BT glucose service specification. I would greatly appreciate, if someone could enlighten me as on how to interpret the responses (means the updated values of the Record Access Control Point characteristic) I get. As I'm not even sure in which order the bytes in the characteristic.value come (e.g. when they are read via getBytes:length: method of NSData).
I think I'm following the process described in the Glucose Profile specification so I'm really at a loss here.
Thank you very much in advance!
Best regards,
Gabriel

Having encountered the same issue, I was unable to work out how to interpret the 06000105 value, however I think that is an error response code of sorts.
What fixed the issue for me was to exclude the Operand if it was null, and only use the Op Code and Operator:
char buffer[2];
// Op Code: 0x01 report stored records
buffer[0] = 0x01;
// Operator: 0x01 All records, 0x06 last one
buffer[1] = 0x01;
NSData *data = [NSData dataWithBytes:buffer length:2];
...
Then all the records came flowing in as expected in didUpdateValueForCharacteristic

Related

How to send int between 32bit and 64bit processors iOS

Pretty much the title, I send an int in a struct using Gamekit and on the receiving end the other device gets it.
Between 64bit cpus (iPhone 5S and over) the number is received fine. But when a iPhone 5 gets it (32bit cpu) the int is received as 0. Whats the correct way?
I've tried sending as NSInteger and the results are the same.
I have to add I have this issue with u_int_32t:
When devices connect, each device trades random numbers. These numbers determine which player starts, and I'm using u_int_32t for this, however, 32bit cpus still receive 0. For example:
I declare
uint32_t _ourRandomNumber;
Then, _ourRandomNumber = arc4random();
And then the numbers are sent, in a struct like this.
typedef struct {
Message message;
uint32_t randomNumber;
} MessageRandomNumber;
Using a method like this:
- (void)sendRandomNumber{
MessageRandomNumber message;
message.message.messageType = kMessageTypeRandomNumber;
message.randomNumber = _ourRandomNumber;
NSData *data = [NSData dataWithBytes:&message length:sizeof(MessageRandomNumber)];
[self sendData:data];
}
When the 32 bit cpu receives it then in the receiving method:
Message *message = (Message*)[data bytes];
if (message->messageType == kMessageTypeRandomNumber) {
MessageRandomNumber *messageRandomNumber = (MessageRandomNumber*)[data bytes];
NSLog(#"Received random number:%d", messageRandomNumber->randomNumber);
The NSLog shows: Received random number:0
NSInteger is going to be 64-bit on a 64-bit platform and 32-bit on a 32-bit platform. If you don't care about 64-bit precision, you could always use an int32_t (or a u_int32_t if you want unsigned) type to explicitly just use a 32-bit value. It is generally wise to be explicit about data lengths when sending values between devices, which is what these types exist for (there's int8_t, int16_t, int32_t, and int64_t and their unsigned counterparts).
It's also worth mentioning that you need to be concerned about the byte order of the values (assuming larger values than int8_t and u_int8_t) when sending values to arbitrary hardware. If you're only working with iOS devices this isn't going to be an issue, however.

CoreBluetooth: number of bytes sent != number of bytes received

I have an app that is acting as a peripheral and another app that is acting as a central.
The central app is reading a characteristic on the peripheral:
[self.service.peripheral readValueForCharacteristic:self.packetCharacteristic]
The peripheral handles the request as such:
- (void)peripheralManager:(CBPeripheralManager *)manager didReceiveWriteRequests:(NSArray *)requests
{
for (CBATTRequest *request in requests)
{
if ([request.characteristic.UUID isEqual:self.service.packetCharacteristic.UUID])
{
NSData *value = self.packets[0]; // This value's length logs at 512 bytes, tested 500 bytes too
request.value = value;
[self.peripheralManager respondToRequest:request withResult:CBATTErrorSuccess];
}
}
}
The size of NSData *value is equal to 512 bytes. Note that I have also tested this with 500 bytes.
The central then receives the the delegate call as such:
- (void)didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
if (characteristic == self.packetCharacteristic)
{
NSLog(#"PACKET RECEIVED: %lu bytes", (unsigned long)characteristic.value.length);
}
}
The NSLog statement states that the value received is 536 bytes regardless of if I send 500 or 512 bytes. The bytes sent and the bytes received are identical until about a quarter of the way through (by looking at the HEX value provided by Xcode), the rest of the bytes are completely different.
The questions are as follows:
1. Why am I receiving more bytes than I have sent?
2. What are these bytes? What do they represent?
3. Where can I find documentation on this? I have reviewed the CoreBluetooth docs/guides over and over and can't find anything indicating that this could happen.
4. Could this be related to endianness?
EDIT #1
Ok, so I have done a little bit more testing and found out the following...
The MTU seems to be 134 bytes (from iOS to iOS). As soon as the data being sent is equal or bigger than 134 bytes, CoreBluetooth is calling peripheralManager:didReceiveReadRequest: 4 times.
My assumption is that because the data being sent is at least equal to the MTU, CoreBluetooth doesn't know whether or not it is done sending all the data. Therefore it calls peripheralManager:didReceiveReadRequest: N number of times until N x MTU covers the maximum possible size of a characteristic's value (512 bytes). In my particular case, 4 x 134 bytes equals the magical 536 bytes.
Note that the request's offset is being updated every time, in my particular case, 0, 134, 268, 402.
Edit #2
Ok, figured it out.
I was semi-right in my assumption. CoreBluetooth calls peripheralManager:didReceiveReadRequest: N time until the data being sent is smaller than the MTU. If the data being sent is equal or larger than the MTU, CoreBluetooth will keep calling peripheralManager:didReceiveReadRequest: until it N x MTU covers the max size (512 bytes). If the data % MTU == 0 then peripheralManager:didReceiveReadRequest: will be called one last time where you have to return 0 bytes.
Answering my own question.
Look at edit #2.

iOS iBeacon: How to get all of proximityUUID programmatically?

I want to see all of proximityUUID of advertising packets programmatically. Some articles say that it is impossible on iOS but Android is possible. But I cannot believe it because I found the fantastic app "BLExplr" has the feature. I need to implement the function into my app. Does anyone knows how to do it or good examples? Any help will be appreciated.
(UPDATE 2014/1/17)
I believe #davidgyoung answer is right. Estimote beacon's proximityUUID is "B9407F30-F5F8-466E-AFF9-25556B57FE6D" but displayed my Estimote beacon's UUID on BLExplr app is another ID.
Unfortunately, you cannot to this on iOS. When you say that BLExplr and LightBlue can do this, you are confusing the Bluetooth service UUID with the iBeacon Proximity UUID. These are two very different things.
The Bluetooth service UUID is visible to iOS, but has nothing to do with an iBeacon's identifiers, and is useless for working with iBeacons. The service UUID is generated by iOS each time a bluetooth device is seen, and stays the same only for the duration of time the bluetooth device is in range. If you take a bluetooth device away and bring it back later, it will have a different service UUID.
An iBeacon's identifiers (ProximityUUID, Major, Minor) are embedded inside the body of the Bluetooth advertisement. The problem on iOS devices is that Apple's CoreBluetooth APIs disallow access to the raw advertisement body, so no third-party app is able to read these identifiers. Apple only allows access to these identifiers using the special iBeacon CoreLocation APIs, but these APIs require you to know the Proximity UUID up front.
Sorry, I know this is not the answer you want to hear! (I'm sorry about it, too!) For what it's worth, you can do this on Android, on OSX Mavericks and Linux.
See details here.
davidgyoung is partially wrong about not being able to get iBeacon info. You actually can get the proximity UUID on OS X, but not iOS.
In a CBPeripheral's advertisingData, there should be a key called kCBAdvDataManufacturerData; It is an NSData representing the iBeacon advertising information. This key is only available on OS X.
Check that the 2nd byte is equal to 0x02, the 1st two bytes are equal to 0x004c (76 in decimal), and the 4th byte (in decimal) + 4 equals the data's length (should be 25).
NSRanges (sorry for Mac syntax)
Proximity UUID: NSMakeRange(4, 16)
Major: NSMakeRange(20,2)
Minor: NSMakeRange(22,2)
To make sure you're doing it right, you can log the values as hex (use the format string %x) and make sure they match the description of the NSData from whence they came.
NSRange uuidRange = NSMakeRange(4, 16);
NSRange majorRange = NSMakeRange(20, 2);
NSRange minorRange = NSMakeRange(22, 2);
NSRange powerRange = NSMakeRange(24, 1);
Byte uuidBytes[16];
[data getBytes:&uuidBytes range:uuidRange];
NSUUID *uuid = [[NSUUID alloc] initWithUUIDBytes:uuidBytes];
int16_t majorBytes;
[data getBytes:&majorBytes range:majorRange];
int16_t majorBytesBig = (majorBytes >> 8) | (majorBytes << 8);
int16_t minorBytes;
[data getBytes:&minorBytes range:minorRange];
int16_t minorBytesBig = (minorBytes >> 8) | (minorBytes << 8);
int8_t powerByte;
[data getBytes:&powerByte range:powerRange];
return #{ #"uuid" : uuid,
#"major" : #(majorBytesBig),
#"minor" : #(minorBytesBig),
#"power" : #(powerByte)
};
but the uuid is the DeviceUUID, not the ProximityUUID

How to manual set minimal value for dynamic buffer in Netty 3.2.6? For example 2048 bytes

I need to receive full packet from other IP (navigation device) by TCP/IP.
The device has to send 966 bytes periodically (over one minute), for example.
In my case first received buffer has length 256 bytes (first piece of packet), the second is 710 bytes (last piece of packet), the third is full packet (966 bytes).
How to manual set minimal value for first received buffer length?
This is piece of my code:
Executor bossExecutors = Executors.newCachedThreadPool();
Executor workerExecutors = Executors.newCachedThreadPool();
NioServerSocketChannelFactory channelsFactory =
new NioServerSocketChannelFactory(bossExecutors, workerExecutors);
ServerBootstrap bootstrap = new ServerBootstrap(channelsFactory);
ChannelPipelineFactory pipelineFactory = new NettyServerPipelineFactory(this.HWController);
bootstrap.setPipelineFactory(pipelineFactory);
bootstrap.setOption("child.tcpNoDelay", true);
bootstrap.setOption("child.keepAlive", true);
bootstrap.setOption("child.receiveBufferSizePredictorFactory",
new FixedReceiveBufferSizePredictorFactory(2048)
);
bootstrap.bind(new InetSocketAddress(this.port));
No matter what receiveBufferSizePredictorFactory you specify, you will see a message is split into multiple MessageEvents. It's because TCP/IP is not a message-oriented protocol but a stream-oriented one. Please read the user guide that explains how to write a proper decoder that deals with this common issue.

AudioQueue: Can't read raw data in AudioFileReadPackets

I'm working on a DSP related iOS app. Part of the work is to copy audio data from outBuffer ->mAudioData to an user-specified array for data processing. The read method is like this:
OSStatus result = AudioFileReadPackets(myInfo->mAudioFile, // The audio file from which packets of audio data are to be read.
false, // Set to true to cache the data. Otherwise, set to false.
&numBytes, // On output, a pointer to the number of bytes actually returned.
myInfo->mPacketDescs, // A pointer to an array of packet descriptions that have been allocated.
myInfo->mCurrentPacket, // The packet index of the first packet you want to be returned.
&nPackets, // On input, a pointer to the number of packets to read. On output, the number of packets actually read.
outBuffer->mAudioData); // A pointer to user-allocated memory.
This process is successful. But when I'm trying to read data from outBuffer->mAudioData, there is always an error saying invalid conversion from 'void* const' to 'SInt16*':
outBuffer->mAudioDataByteSize = numBytes;
SInt16 *testBuffer = outBuffer->mAudioData; //Read data from buffer... Error!
for (int i=0; i<numBytes; i++)
{
UInt16 currentData = testBuffer[i];
printf("Current data in testbuffer is %d", currentData);
}
I have gone through several related questions like THIS and THIS, seems theirs are working...
I also tried to replace outBuffer->mAudioData to testBuffer in AudioFileReadPackets(), but the testBuffer turns out to be an empty array.
So is it the right approach? Is there any other way to read the raw data to an int/float array?
Or more generally, how to access an void constant pointer and perform read/write operation to it? (Yeah my C++ is not that strong...)
Any help will be appreciated :-)
Cheers,
Manca
I just put a cast in front and it seemed to work:
SInt16* frames = (SInt16*)inBuffer->mAudioData;

Resources