-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
dispatch_async(dispatch_get_main_queue(), ^{
NSData *data = characteristic.value;
uint8_t *array = (uint8_t*) data.bytes;
cadenceValue = [CharacteristicReader readUInt8Value:&array];
self.cadence.text = [NSString stringWithFormat:#"%d", cadenceValue];
});
}
How to get cadence from bLE (Bluetooth low energy) device in swift 2. I am unable to find exact code for this. For this didUpdateValueForCharacteristic delegate method is called.
I have a code of nRF Toolbox but it is in objective c or swift 3 but my project is in swift 2. I tried to call objective c method using bridging header but it was always returned 0 cadence.
I'm not sure the definition of CharacteristicReader, but you might try:
[CharacteristicReader readUInt8Value:&array];
cadenceValue = Int(array[0])
self.cadence.text = [NSString stringWithFormat:#"%d", cadenceValue];
The above assumes that the result of the call to readUInt8Value gets put into the array of UInt8 objects, and the cadence value is in the first byte of the array. You could also check if the proper value is in other bytes by trying cadenceValue = Int(array[1]) or cadenceValue = Int(array[2]), etc.
Related
I am working on BLE app(Heath related), In that i have one option to get ECG values from BLE device.In that i need to enable 8 waveforms to get ECG data in my app.
My question how i can enable all waveforms using CBDescriptor.I need to pass data like below to CBDescriptor.
Format of Waveform ID
0: 8bit, 1: 16bit, 2: 32bit, 3: 64bit, 4:128bit, 5: 8bit*3, 6: 16bit*3, 7: 32bit*3
uint8_t waveArray[8] = {0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00};
NSData *waveData = [NSData dataWithBytes:waveArray length:sizeof(waveArray)/sizeof(uint8_t)];
[peripheral writeValue:waveData forDescriptor:descript];
But i didn't get any response from device. Please help me.
Finally i got solution for my question. First we need to call discover methods for CBDescriptor.
[peripheral discoverDescriptorsForCharacteristic:characteristic];
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
NSArray *Descroptors = [characteristic descriptors];
CBDescriptor *descript;
[peripheral setNotifyValue:YES forCharacteristic:characteristic];
for (descript in Descroptors)
{
if ([descript.UUID isEqual:[CBUUID UUIDWithString:KT_WP_WC_CHARACTERISTIC]])
{
uint8_t waveArray[9] = {0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00};//Your data which you need to send to BLE device
NSData *waveData = [NSData dataWithBytes:waveArray length:sizeof(waveArray)/sizeof(uint8_t)];
[peripheral writeValue:waveData forDescriptor:descript];
NSLog(#"waveData ==%#",waveData);
CBUUID * sCBUUID = [CBUUID UUIDWithString:KT_WP_SERVICE];
CBUUID * cCBUUID = [CBUUID UUIDWithString:KT_WP_WF_CHARACTERISTIC];
[self CBUUIDwriteValue:sCBUUID characteristicUUID:cCBUUID p:peripheral data:waveData];
}else
{
const unsigned char bytes[] = { 0x28, 0x00 };//Your data which you need to send BLE device
NSData *descriptorData = [NSData dataWithBytes:bytes length:2];
CBUUID * sCBUUID = [CBUUID UUIDWithString:KT_WP_SERVICE];
CBUUID * cCBUUID = [CBUUID UUIDWithString:KT_WP_WF_CHARACTERISTIC];
[self CBUUIDwriteValue:sCBUUID characteristicUUID:cCBUUID p:peripheral data:descriptorData];
}
}
}
Sending data through the iOS (writeValue: forCharacteristic: type :) method works fine without error, but the value does not change. Do you know why?
> 2017-06-27 14:53:54.846963+0900 BluetoothSample[12662:5477661] Did
> write characteristic <CBCharacteristic: 0x1700ad500, UUID =
> 2A588021-4FB2-40F5- 8204-85315DEF11C5, properties = 0xA, value =
> <1357>, notifying = NO>
uint8_t val = 123;
NSData * valData = [NSData dataWithBytes:(void*)&val length:sizeof(val)];
[self.discoveredPeripheral writeValue:valData forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
- (void) peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
if (error) {
NSLog(#"didWriteValueForCharacteristic With error: %#", [error localizedDescription]);
self.receivePaketDataTextView.text = [[NSString alloc] initWithFormat:#"%#",[error localizedDescription]];
return ;
}
self.receivePaketDataTextView.text = [[NSString alloc] initWithFormat:#"%#",characteristic.value];
}
When I try to write, only the same logs are printed.
Try:
[self.discoveredPeripheral writeValue: valData
forCharacteristic:self.usedCharacteristic
type:CBCharacteristicWriteWithoutResponse];
Use type: CBCharacteristicWriteWithoutResponse
Also check if you have set the notifier
[self.discoveredPeripheral setNotifyValue:YES forCharacteristic:self.usedCharacteristic];
Before hand in your delegates.
On your iOS central the value of the characteristic in didWriteValueForCharacteristic does not reflect the change you just wrote.
You need to issue an explicit read to get the new value.
This is by design, since there is no guarantee that the value you have just written is the current value of the characteristic; only the peripheral can give you the current value.
I'm currently working with CBPeripheralDelegate to exchange messages between an iOS device and a Bluetooth Low Energy USB dongle. I have to implement the sendMessage: method that writes data bytes using a serial emulation service. This method has to send a frame of 15 bytes (or less) at the time, waiting for an ack from dongle before sending the next one.
Below is my code:
- (void)sendMessage:(NSData *)message {
NSArray *chuncks = [self splitMessage:message];
for (NSUInteger i = 0; i < chunks.count; i++) {
NSData *chunk = [chunks objectAtIndex:i];
[self sendChunk:chunk withId:i ofChunks:chances.count];
// Wait for the ack to be received
}
}
- (void)sendChunk:(NSData *)chunk withId:(NSInteger)id ofChunks:(NSInteger)count {
NSMutableData *frame = [NSMutableData new];
// Here I build my frame, adding header, current chunk ID and total number of chunks, then I call...
[serialEmulationService writeValue:frame forCharacteristic:serialEmulationServiceCharacteristic type:CBCharacteristicWriteWithResponse];
}
Now the issue: the for loop within the sendMessage: method has to be blocked until the peripheral won't receive the ack, possibly with a timeout. This ack is received inside the delegate method - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error, so here I have to restart the for loop previously blocked.
What's the best practice for this particular situation? I'd like to use GCD's semaphores, but I cannot figure out how to implement synchronous calls and cannot manage to understand any of the many online examples that explain this technique.
Could someone please give me a hand?
How about skipping the for loop entirely…
#property (nonatomic) NSMutableArray *chunks;
#property (nonatomic) NSInteger chunkId;
- (void)sendMessage:(NSData *)message {
self.chunks = [[self splitMessage:message] mutableCopy];
self.chunkId = 0;
[self sendNextChunk];
}
- (void sendNextChunk {
NSData * chunk = self.chunks.firstObject;
if chunk == nil {
return
}
[self.chunks removeObjectAtIndex: 0];
[self sendChunk:chunk withId:chunkId++ ofChunks:chances.count];
}
- (void)sendChunk:(NSData *)chunk withId:(NSInteger)id ofChunks:(NSInteger)count {
NSMutableData *frame = [NSMutableData new];
// Here I build my frame, adding header, current chunk ID and total number of chunks, then I call...
[serialEmulationService writeValue:frame forCharacteristic:serialEmulationServiceCharacteristic type:CBCharacteristicWriteWithResponse];
}
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error {
[self sendNextChunk];
}
The approach would be to use the Notification. Create separate method to run your for loop. This method will observer for the Notification, inside the delegate method post the Notification. In the sendMessage: keep adding the message to a property.
I am a ios developer.
I can take a value from arduino sensor. But i cannot send a message by using the following the method.
[peripheral writeValue:dataToWrite forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
"dataToWrite" value is alloc by using NSString*
NSString* data = #"1";
NSData* dataToWrite = [data dataUsingEncoding:NSUTF8StringEncoding];
and the following code is full code of "DiscoverCharacteristics in service"
//DISCOVER CHAR
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
if (error) {NSLog(#"DISCOVER_CHAR - Error");return;}
NSString* data = #"1";
NSData* dataToWrite = [data dataUsingEncoding:NSUTF8StringEncoding];
for (CBCharacteristic * characteristic in service.characteristics) {
NSLog(#"DISCOVER_CHAR - Characteristic : %#",characteristic);
[peripheral writeValue:dataToWrite forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
}
}
In this point, I want to summarize my question.
My Question is
"Even i used the [Peripheral writeValue:forCharacteristic:type] Method. why an error message is shown in log monitor? " Like "Writing is not permitted."
Do i need to get some permission to writing the message for an Arduino?
OR I have to change my following code?
OR I have a problem in Arduino(Acutally, Arduino can get a message from other device... so, Arduino source code is fine. maybe...)
NSString* data = #"1";
NSData* dataToWrite = [data dataUsingEncoding:NSUTF8StringEncoding];
I'm a bit of a bluetooth noob. So it's probably something obvious I've overlooked but any help would be much appreciated.
Thank you!:)
Thank you a lot!!!!!!! Paulw11. Finally, i sent a data from iphone to Arduino. what i checked properties of my characteristic is
<CBCharacteristic: 0x13564a680, UUID = FFE1, properties = 0x16, value = (null), notifying = NO>.
My characteristic's properties = 0x16. but i can not find a 0x16 in enum of properties. Still, I don't know the 0x16 meaning. Someone said that "Values representing the possible properties of a characteristic. Since characteristic properties can be combined, a characteristic may have multiple property values set."
URL: Interpret Characteristic Properties (iOS and BLE) .
Anyway I could find a solution by PaulW11 help! How i can do it? Here is my way of solution.
At first, My method is [peripheral writeValue:dataToWrite forCharacteristic:characteristic *type:CBCharacteristicWriteWithResponse]*;.
The problem code is type field. I had to understand the type. The type has a meaning of write, read and so on. So, I changed the type from CBCharacteristicWriteWithResponse to CBCharacteristicPropertyWrite. That is what i did.
[peripheral writeValue:dataToWrite forCharacteristic:characteristic *type:CBCharacteristicPropertyWrite*];
Thank you again! Paulw11
try to print error inside following method:
-(void)peripheral:(CBPeripheral *)peripheral
didWriteValueForCharacteristic:(CBCharacteristic *)characteristic
error:(NSError *)error
{
NSLog(#"%#",error.localizedDescription);
}
If the error is "Writing is not permitted", then you might not writing the data correctly.Convert the string value in this format
NSData* data = [#"string_to_write" dataUsingEncoding:NSASCIIStringEncoding];
And try this:
[self.peripheral writeValue:data forCharacteristic:self.characteristic type:CBCharacteristicWriteWithoutResponse];
Hope it works!!
I use the CC2541 as the peripheral and iPad mini as the Central. I transfer the data every single second through serial port(the baud rate is 19200) from CC2541 as notify. (Also I tried to transfer data in every 100 ms.It seemed to be same in accuracy)
Here's my code:
- (void) peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
if (error)
{
NSLog(#"Error receiving notification for characteristic %#: %#", characteristic, error);
return;
}
//NSLog(#"Received data on a characteristic.");
if (characteristic == self.rxCharacteristic)
{
NSData *data = [characteristic value];
//NSString* string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSString* string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
[self.delegate didReceiveData:string];
}
else if ([characteristic.UUID isEqual:self.class.hardwareRevisionStringUUID])
{
NSString *hwRevision = #"";
const uint8_t *bytes = characteristic.value.bytes;
for (int i = 0; i < characteristic.value.length; i++)
{
NSLog(#"%x", bytes[i]);
hwRevision = [hwRevision stringByAppendingFormat:#"0x%02x, ", bytes[i]];
}
//[self.delegate didReadHardwareRevisionString:[hwRevision substringToIndex:hwRevision.length-2]];
}
}
I tried single-step debug, but it seemed that this code was right. And it's wrong in the transmission from peripheral(because the "string" was wrong when I debugged this). I got about 85% the right data. And 15% data was wrong.
the right data(string) is "12399921" and it will notify as 0x3132333939393231. Often the wrong data will occurs continuously such as 0x31323339393932 and 0x3132E739393231 , 0x31323339393231 and 0x249ACACACA928AFE ...
Maybe it has a way to correct them because it seems that it has some regular there... Or is there any way to avoid the wrong data transmission from the peripheral. Either way will be OK.
Thanks in advance.
Sorry...
I think I found what's wrong by myself.
The accuracy will be much better when baud rate is set to 57600 not 19200.
But it seemed the same for the Android app(it still runs well even no matter the baud rate is 19200 or 57600).