Search code examples
swiftpointersstructbytensdata

SWIFT: Paste Bytes from NSData to Struct?


I am writing a bluetooth packets protocol for communication between iPhone and a peripheral device. The device will send me some bits, possibly 128 or 256, and the communication protocol I am using will let me access this incoming data as some NSData variable. My question is, Can I take the bytes from NSDATA or directly use the NSData somehow to paste the bytes into a struct with entries that have predefined size? For example, in C, you would have a struct like:

struct CD2_CONFIG_TYPE {
    uint8_t     header;         // '<' or '>' start of a new packet from device or base station
    uint8_t     type;           // 'c' indicates device configuration packet
    uint8_t     devSN[8];       // device serial number 
};

and lets say the data we received is an NSData object that has 8 + 8 + 84 bits, which are the header, type, and devSN, respectively. So if I take these bits (or bytes) and make them a pointer using something like:

// swift code    
fun dataBYtesToPointer(incomingDataPacket: NSData){
         var packetBytes = UnsafePointer<UInt8>(incomingDataPacket.bytes)
    }

Is there any way to copy the pointer to the struct and have the struct variables header, type, and devSN populated properly based on the size allocated to them? In C you would use memcopy and copy that pointer to a struct. So I don't get how to make the struct with predefined sizes like in the example, and I don't know how to fill it with a pointer. Any help would be appreciated.


Solution

  • You can think of a C method as shown below:

    struct CD2_CONFIG_TYPE* commandFromData(uint8_t * data){
    
      struct CD2_CONFIG_TYPE* command = (struct CD2_CONFIG_TYPE*)malloc(sizeof(struct CD2_CONFIG_TYPE));
    
      command->type = data[0];
      command->header = data[1];
      memcpy(command->devSN, &data[2], 8* sizeof(uint8_t));
    
      return command;
    
    }
    

    You can export this function signature in a .h file and import it into the bridging header so that Swift code can access this.

    In your swift code, you can call this as:

    let bytes = UnsafePointer<UInt8>(incomingDataPacket.bytes)
    commandFromData(bytes)