IOS Core Bluetooth : Writing NSData for Characteristic - ios

I am using the following code to write the 0xDE value for a Bluetooth Caracteristic (Reset Device) using the IOS Core Bluetooth :
...
NSData *bytes = [#"0xDE" dataUsingEncoding:NSUTF8StringEncoding];
[peripheral writeValue:bytes
forCharacteristic:characteristic
type:CBCharacteristicWriteWithResponse];
...
is there any mistake in my code because the value is not written properly?

Swift 3.0: In case anyone is wondering the format for Swift is slightly different as writeValue can get the count from the array.
let value: UInt8 = 0xDE
let data = Data(bytes: [value])
peripheral.writeValue(data, for: characteristic, type: .withResponse)

Try creating your data with an array of single byte values.
const uint8_t bytes[] = {0xDE};
NSData *data = [NSData dataWithBytes:bytes length:sizeof(bytes)];
This is a useful approach for creating arbitrary constant data. For more bytes,
const uint8_t bytes[] = {0x01,0x02,0x03,0x04,0x05};
NSData *data = [NSData dataWithBytes:bytes length:sizeof(bytes)];
If you want to create data to send using variables, I would recommend using NSMutableData and appending the bytes that you need. It isn't very pretty, but it is easy to read / understand, especially when you are matching a packed struct on the embedded side. Example below is from a BLE project where we were making a simple communication protocol.
NSMutableData *data = [[NSMutableData alloc] init];
//pull out each of the fields in order to correctly
//serialize into a correctly ordered byte stream
const uint8_t start = PKT_START_BYTE;
const uint8_t bitfield = (uint8_t)self.bitfield;
const uint8_t frame = (uint8_t)self.frameNumber;
const uint8_t size = (uint8_t)self.size;
//append the individual bytes to the data chunk
[data appendBytes:&start length:1];
[data appendBytes:&bitfield length:1];
[data appendBytes:&frame length:1];
[data appendBytes:&size length:1];

The answer by bensarz is almost correct. Except one thing: you shouldn't use sizeof(int) as the length for NSData. The size of int is 4 or 8 bytes (depending on the architecture). As you want to send 1 byte, use uint8_t or Byte instead:
uint8_t byteToWrite = 0xDE;
NSData *data = [[NSData alloc] initWithBytes:&byteToWrite length:sizeof(&byteToWrite)];
[peripheral writeValue:data
forCharacteristic:characteristic
type:CBCharacteristicWriteWithResponse];
Of courser you could also use int as the variable's type, but you have to initialize NSData with the length of 1.

This code will fix the problem :
NSData * data = [self dataWithHexString: #"DE"];
[peripheral writeValue:data forCharacteristic:characteristic
type:CBCharacteristicWriteWithResponse];
dataWithHexString implementation :
- (NSData *)dataWithHexString:(NSString *)hexstring
{
NSMutableData* data = [NSMutableData data];
int idx;
for (idx = 0; idx+2 <= hexstring.length; idx+=2) {
NSRange range = NSMakeRange(idx, 2);
NSString* hexStr = [hexstring substringWithRange:range];
NSScanner* scanner = [NSScanner scannerWithString:hexStr];
unsigned int intValue;
[scanner scanHexInt:&intValue];
[data appendBytes:&intValue length:1];
}
return data;
}

What you are, in fact, doing here is writing the string "0xDE" to the characteristic. If you want to use binary/octal notation, you need to stay away from strings.
int integer = 0xDE;
NSData *data = [[NSData alloc] initWithBytes:&integer length:sizeof(integer)];
[peripheral writeValue:data
forCharacteristic:characteristic
type:CBCharacteristicWriteWithResponse];

Related

I am converting NSString a=#"0x401A" into int16_t?

Why when I am trying to convert it converts hexadecimal value into integer?
unsigned int outVal;
NSScanner* scanner = [NSScanner scannerWithString:final1];
[scanner scanHexInt:&outVal];
NSLog(#"%u",outVal);
Another way I am trying to do is converting it to normal integer it gives me 0 value.
I just want the same characters:
int16_t a=0x401A;
I am getting this number from user so dont have the control to define it myself. I want removed quotations and datatype int16_t so I can execute command.
I got the solution myself
first the function which converts the data into bytes
- (NSData *)dataWithString:(NSString *)hexstring
{
NSMutableData* data = [NSMutableData data];
int idx;
for (idx = 0; idx+2 <= hexstring.length; idx+=2) {
NSRange range = NSMakeRange(idx, 2);
NSString* hexStr = [hexstring substringWithRange:range];
NSScanner* scanner = [NSScanner scannerWithString:hexStr];
unsigned int intValue;
[scanner scanHexInt:&intValue];
[data appendBytes:&intValue length:1];
}
return data;
}
and call the function by giving parameters in the command which will be sent to BLE
NSData * data = [self dataWithString: #"401A"];
[peripheral writeValue:data forCharacteristic:characteristic
type:CBCharacteristicWriteWithResponse];
Through this code anybody can sent string to BLE device. Thanks and Cheers

Generating 64 bytes long NSData from key string

I think this generates random 64 bytes NSData.
uint8_t buffer[64];
SecRandomCopyBytes(kSecRandomDefault, 64, buffer);
NSData *keyData = [[NSData alloc] initWithBytes:buffer length:sizeof(buffer)];
I want to generate 64 bytes NSData like this but not a random data.
How can I generate 64 bytes NSData with a given key like "com.this.is.akey".
Tried this one but it gave me wrong bytes size(not 64 bytes).
NSString *base64EncodedString = [[#"somekey.here" dataUsingEncoding:NSUTF8StringEncoding] base64EncodedStringWithOptions:0];
NSData *encodedData = [[NSData alloc] initWithBase64EncodedString:base64EncodedString
options:0];
You can use -[NSString dataUsingEncoding:] to convert NSString to NSData.
NSString *key = #"com.this.is.akey";
NSData *keyData = [key dataUsingEncoding:NSASCIIStringEncoding];
If length of the data is less or greater than 64 bytes, you should pad or truncate data to exact 64 bytes.
if (keyData.length != 64) {
NSMutableData *mutableData = keyData.mutableCopy;
mutableData.length = 64;
keyData = mutableData.copy;
}
Then, you can pass the NSData object to RLMRealmConfiguration.encryptionKey.
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
config.encryptionKey = keyData;
NSError *error = nil;
RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:&error];
Given a string for a key one should use a key derivation function such as PBKDF2.
Example:
#import <CommonCrypto/CommonCrypto.h>
NSString *keyString = #"com.this.is.key"; // Should use a random value
NSData *keyData = [keyString dataUsingEncoding:NSUTF8StringEncoding];
NSData *salt = [#"saltstring" dataUsingEncoding:NSUTF8StringEncoding];
NSMutableData *derivedKey = [NSMutableData dataWithLength:CC_SHA512_DIGEST_LENGTH];
CCKeyDerivationPBKDF(kCCPBKDF2,
keyData.bytes, keyData.length,
salt.bytes, salt.length,
kCCPRFHmacAlgSHA512,
10000, // Choose for desired timing
derivedKey.mutableBytes, derivedKey.length);
NSLog(#"derivedKey: %#", derivedKey);
Output: derivedKey:
065d2106 1da7ebcf d155a50a b1ee5540 dee8efce f4678c47 02164488 e92e05e5 30c1f12d a3813013 652aca1b 0016b258 610d7929 f240de72 3eab85d9 7e028b35
Notes:
It is best to set the salt to a random value and provide it along with the derived key.
The iteration count should set to provide a suitable derivation tine, perhaps 100ms. There is a corresponding CCCalibratePBKDF function the help with this. The iteration count can also be provided along with the derived key.
Sorry if this seems to be more work that necessary but security is not easy to get right.

iOS how to convert a .aac audio file to binary data?

thanks for your help,my problem is : i need to convert a aac audio file to byte data then i can transmit this data to the server by using tcp.but i can not convert aac to byte. i use:
NSString *docDir = NSTemporaryDirectory();
NSString* _tempRecorderPath;
_tempRecorderPath = [docDir stringByAppendingPathComponent:#"ringtones_tmp.aac"];
NSData *testringdata=[NSData dataWithContentsOfFile:_tempRecorderPath];
Byte *nbyteData=(Byte*)[ringData bytes];
but the result is there is only '\xff' in nbyteData!
i do not know why ? And how to fix it!!
try this:-
NSData *data = [NSData dataWithContentsOfFile:filePath];
NSUInteger len = [data length];
Byte *byteData = (Byte*)malloc(len);
memcpy(byteData, [data bytes], len);
This code will dynamically allocate the array to the correct size (you must free(byteData) when you're done) and copy the bytes into it.
Have a look at this link . This link explains exactly what you want
NSData *data = [NSData dataWithContentsOfFile:filePath];
NSUInteger len = [data length];
Byte *byteData = (Byte*)malloc(len);
memcpy(byteData, [data bytes], len);

Trouble converting NSData to int

I have an NSData object that contains just <64> which is supposed to represent the int 100
How can I convert this NSData to an int?
I can convert it to it's Chr equivalent d using
NSString *string = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
but I need the Dec equivalent of 100
Thanks
<64> means that the NSData object contains a single byte with the value 0x64 = 100,
so the following should work;
const uint8_t *bytes = [data bytes]; // pointer to the bytes in data
int value = bytes[0]; // first byte
int *b = (int *)data.bytes;
printf("%d",*b); //prints 100
Below logic converts NSData to integer perefctly. Length of bytes does not matter. It just works.
NSData *data;
NSString *stringData = [data description];
stringData = [stringData substringWithRange:NSMakeRange(1, [stringData length]-2)];
unsigned dataAsInt = 0;
NSScanner *scanner = [NSScanner scannerWithString: stringData];
[scanner scanHexInt:& dataAsInt];

Converting NSInteger and NSString into array of bytes

I need to represent a NSInteger and NSString into array of bytes. below are the sample of what I am looking for.
For how, this harcodings are working fine. I want to do this through code. Any clue.
First, NSInteger into bytes of Hex:
NSInteger test = 1;
unsigned char byte[] = { 0x00, 0x01 };
NSInteger test = 16;
unsigned char byte[] = { 0x00, 0x10 };
NSData *data = [NSData dataWithBytes:byte length:sizeof(byte)];
Second, NSString into bytes of Hex:
NSString *test = #"31C5B562-BD07-4616-BCBD-130BA6822790";
unsigned char byte[] = {0x31, 0xC5, 0xB5, 0x62, 0xBD, 0x07, 0x46, 0x16, 0xBC, 0xBD, 0x13, 0x0B, 0xA6, 0x82, 0x27, 0x90};
NSData *data = [NSData dataWithBytes:byte length:sizeof(byte)];
I tried with below code and it works well for my UUID but for NSInteger to to be working I need to send "0010" instead of 16 and "0001" instead of 1. So any clue on how to do this conversion.
- (NSData *)hexData {
NSMutableData *hexData = [NSMutableData data];
int idx = 0;
for (idx = 0; idx+2 <= self.length; idx+=2) {
NSRange range = NSMakeRange(idx, 2);
NSString* hexStr = [self substringWithRange:range];
NSScanner* scanner = [NSScanner scannerWithString:hexStr];
unsigned int intValue;
[scanner scanHexInt:&intValue];
[hexData appendBytes:&intValue length:1];
}
return hexData;
}
EDIT:
int8_t test = -59;
int8_t bytes = CFSwapInt16HostToBig(test);
NSData *data1 = [NSData dataWithBytes:&bytes length:sizeof(bytes)];
Reaching as 0xFF instead of 0xC4
Since your string is a UUID string you can do something like this:
NSString *test = #"";
uuid_t uuid;
uuid_parse([test UTF8String], uuid)
NSData *data = [NSData dataWithBytes:uuid length:16];
For the number you can do:
NSInteger test = 1;
NSData *data = [NSData dataWithBytes:&test length:sizeof(test)];
Keep in mind that NSInteger is probably more than two bytes and you may also need to worry about byte order.
Update: Since it seems you need the integer value to be two bytes, you should do:
uint16_t test = 1;
NSData *data = [NSData dataWithBytes:&test length:sizeof(test)];
This will ensure 2 bytes. You also need to worry about byte ordering so you really need:
uint16_t test = 1;
uint16_t bytes = CFSwapInt16HostToBig(test);
NSData *data = [NSData dataWithBytes:&bytes length:sizeof(bytes)];
Change CFSwapInt16HostToBig to CFSwapInt16HostToLitte if appropriate.

Resources