CoreBluetooth Characteristic value
The specification limits the maximum length of a characteristic value in 512 octets (Bluetooth specification V4.0 Vol 3. Part F 3.2.9). On the central side you start a read request with the readValueForCharacteristic:
API. Then on the peripheral side you receive the corresponding callback:
CBMutableCharacteristic *characteristic = // the characteristic with long data
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveReadRequest:(CBATTRequest *)request {
// Ensure offset is in the valid range
if (request.offset > characteristic.value.length) {
// respond with error
[self.peripheralManager respondToRequest:request withResult:CBATTErrorInvalidOffset];
return;
}
NSRange range = NSMakeRange(request.offset, characteristic.value.length - request.offset);
request.value = [characteristic.value subdataWithRange:range];
[self.peripheralManager respondToRequest:request withResult:CBATTErrorSuccess];
}
The callback will be called with increasing offset
values as long as the response is not less than the Maximum Transferrable Unit (MTU). The MTU is negotiated by the system and you have no way to query it in advance. For this reason the range
is set up to stretch all the way to the data length so the system can decide how much of the data it is going to send to the central. By default it is 20 but iOS 7 has some tweaks that enable greater sizes. Check out the WWDC videos for more detail.
With this info you should be able to figure out a way to expose your data. Keep in mind that the more services and characteristics you have, the longer the discovery will take. Using long reads and long writes is just a convenience.
Reading a BLE Peripheral Characteristic and checking its value?
Updated For Swift3
After you execute that method, the delegate
of your peripheral is going to asynchronously receive the peripheral(_:didUpdateValueFor:error:)
method. In that method you can query the value
of the passed characteristic
parameter. value
will be an NSData
which you can pull the bytes out of. E.g.
// MARK: - CBPeripheralDelegate
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
if let e = error {
print("ERROR didUpdateValue \(e)")
return
}
guard let data = characteristic.value else { return }
...
}
The value
method actually returns an Optional
around the expected Data
, so a let guard is the way to go.
Usually a characteristic will have a simple value encoded in it's up-to-20-byte Data
payload. E.g. maybe it's a simple UInt16 counter. To
To convert between these Data
glumps and meaningful numbers, have a look at the answer to round trip Swift number types to/from Data (I've included my own implementation of that below).
So for example, if you know that the characteristic of interest is some counter that is a meant to be extracted as a UInt16
, I would fill out the above example with something like:
// MARK: - CBPeripheralDelegate
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
if let e = error {
print("ERROR didUpdateValue \(e)")
return
}
guard let data = characteristic.value else { return }
print("counter is \(UInt16(data:data))")
}
// Data Extensions:
protocol DataConvertible {
init(data:Data)
var data:Data { get }
}
extension DataConvertible {
init(data:Data) {
guard data.count == MemoryLayout<Self>.size else {
fatalError("data size (\(data.count)) != type size (\(MemoryLayout<Self>.size))")
}
self = data.withUnsafeBytes { $0.pointee }
}
var data:Data {
var value = self
return Data(buffer: UnsafeBufferPointer(start: &value, count: 1))
}
}
extension UInt8:DataConvertible {}
extension UInt16:DataConvertible {}
extension UInt32:DataConvertible {}
extension Int32:DataConvertible {}
extension Int64:DataConvertible {}
extension Double:DataConvertible {}
extension Float:DataConvertible {}
How to read information from core bluetooth device
Take a nice good read through the framework. if you have come this far you shouldn't have any problem finding 'discoverCharacteristics' and the peripheral delegate callback 'didDiscoverCharacteristic'. You need to know the UUID of the services and characteristics you want to discover and apply it to those methods.
Then you can read with 'readValueForCharacteristic' and the delegate callback 'didUpdateValueForCharacteristic'.
This is sent from my phone, so I will maybe edit a bit when I get to a computer. Hope it helps
New question:
[connectedPeripheral readValueForCharacteristic:wantedCharacteristic]
and at peripheral delegate
- (void) peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
NSLog(@"Characteristic value : %@ with ID %@", characteristic.value, characteristic.UUID);
[delegate characteristicValueRead:characteristic.value];
}
works for me
Related Topics
Uitextview Starts at Bottom or Middle of the Text
Does Firebase Cloud Messaging Support Voip Pushkit Services
How to Know Which Is the Default Measure System (Imperial or Metric) on iOS
Wanted: How to Reliably, Consistently Select an Mkmapview Annotation
Sudzc Arc Version - Objc_Msgsend Call Causes Exc_Bad_Access Using 64-Bit Architecture
iOS 11 Large Navigation Bar Title Unexpected Velocity
Change Size of Uibarbuttonitem (Image) in Swift 3
Resize Mkannotationview Image When Map Zooms in and Out
Why My App Is Not Shown in Icloud Drive Folder
How to Get 1 Hour Ago from a Date in iOS Swift
How to Populate Uitableview from the Bottom Upwards
How to Push Two View Controllers But Animate Transition Only for the Second One
Uicollectionview Registerclass: Forcellwithreuseidentifier Method Breaks Uicollectionview
Ios: Perform Upload Task While App Is in Background
Setting Maximum Number of Characters of 'Uitextview ' and 'Uitextfield '
iOS 4.3 Hide Status Bar Permanently
Swift 2.0 Minimum System Version Requirement (Deployment Target)