0

I am reading data off of a hardware device through Core Bluetooth (BLE). One of the charecteristics I am reading is a struct compressed down to a single value. The struct as programmed to the board looks like this:

typedef struct
{
  uint8          id;
  uint32        dur;
  uint16        dis;
} record;

Most of the other characteristics I am parsing are of a single type, uint8, uint32, so on.

How can I loop through the bytes and parse each individual characteristic either to native type or an NSString? Is there a way to iterate over the bytes or substring the NSData object?

NSData *data = [characteristic value]; // characteristic is of type CBCharacteristic
    NSUInteger len = data.length;
    Byte *bytes = (Byte *)[data bytes];
    for (Byte in bytes) { // no fast enumeration here, but the general intention is to iterate byte by byte
        // TODO: parse out uint8
        // TODO: parse out uint32
        // TODO: parse out uint16
    }
ilrugel
  • 3
  • 3
  • If the struct is always that fixed layout then simply access the bytes directly - [data bytes][0] will be your id. [data bytes[1]]-[data bytes[4] will be dur and bytes 5 & 6 will be dis – Paulw11 Feb 27 '15 at 20:44

2 Answers2

1

You can do something like this to create an instance of your struct from the data.

typedef struct
{
  uint8          id;
  uint32        dur;
  uint16        dis;
} record;

@implementation YourClass (DataRetrieval)
- (void)process:(CBCharacteristic *)characteristic {
  record r;
  [[characteristic value] getBytes:&r length:sizeof(r)];
  // r.id
  // r.dur
  // r.dis
}
@end
Ian MacDonald
  • 13,472
  • 2
  • 30
  • 51
dan
  • 9,695
  • 1
  • 42
  • 40
  • The struct exists on the board, or device, I am connecting to. It is pushed over bluetooth as a single data object. There isn't automatic parsing of that data to an NSObject or struct, the mapping has to be done manually, which is why I am trying to iterate over the data object. – ilrugel Feb 27 '15 at 20:54
  • You must know the format of the data you are getting back if you are planning to parse it though, right? Just define a struct in your code that matches that format. – dan Feb 27 '15 at 21:03
  • Maybe the knowledge he's missing is that the struct he has used in his example will work as-is in Objective-C. – Ian MacDonald Feb 27 '15 at 21:09
  • 1
    @ilrugel the answer is a bit unclear on that, but in Objective-C you can use C structs as well. Just define the same struct `record` in the code of your iOS app and use it like in dan's answer: after calling `getBytes:length` on an instance of `NSData`, all the fields in `record` struct will be assigned the correct values. – Michał Ciuba Feb 27 '15 at 21:41
0

Instead of iterating across your data, and if you want to pull out individual values you use subDataWithRange of the Characteristic NSData.

Something like...

    //create test data as an example.
    unsigned char bytes[STRUCT_SIZE] = {0x01, 0x00, 0x0, 0x00, 0x02, 0x00, 0x03};
    NSData *data = [NSData dataWithBytes:bytes length:sizeof(bytes)];

    //assume that you have a packed structure and endianess is correct
    //[0] = id
    //[1] = dur
    //[2] = dur
    //[3] = dur
    //[4] = dur
    //[5] = dis
    //[6] = dis

    assert(STRUCT_SIZE == [data length]);

    uint8_t     idu = *( uint8_t*)[[data subdataWithRange:NSMakeRange(0, 1)] bytes];
    uint32_t    dur = *(uint32_t*)[[data subdataWithRange:NSMakeRange(1, 4)] bytes];
    uint16_t    dis = *(uint16_t*)[[data subdataWithRange:NSMakeRange(5, 2)] bytes];

    assert(1 == idu);
    assert(2 == dur);
    assert(3 == dis);

A good description of the approach is here

And an approach for endianness is here

I am also not sure if you are doing any Structure Packing

Community
  • 1
  • 1
Jeffrey Stewart
  • 567
  • 3
  • 10