iOS Bluetooth Protocol NSData+CRC Verifies NSData Transliteration. c File Import Xcode

Keywords: Mobile iOS xcode Android

In the past two days, iOS Bluetooth data interaction was done. Initially, the company's plan was to use the mobile phone as a Bluetooth slave device to allow the company platform to scan the Bluetooth address obtained by the code on the mobile phone as the only sign to connect in a directional way. However, the scheme was rejected because the security of Apple's mobile phone about users'personal privacy had failed after iOS 7.

Later, the company proposed that the mobile phone as the main device do not directly connect to the given Bluetooth by scanning, because I just learned Bluetooth. I know that the Bluetooth on iOS side must scan even the name of the given scanning device to establish a Bluetooth connection. The final solution is still under discussion, but the interaction between Bluetooth and peripherals has to be done. During this period, I encountered many problems. Fortunately, the company has the patience of Android to explain them to me. For example, Bluetooth communication protocol:

To be honest, when I first saw this protocol, my heart was broken because I didn't know how to do it, like converting a string to NSData, which I used directly from the beginning.
[text dataUsingEncoding:NSUTF8StringEncoding]
But no matter how I translate and use any coding format, it's wrong. It's different from what I expected. On this point, I have been wrestling with all kinds of experiments for a day.

Later, I invited Android to tell me about this agreement. She took about ten minutes to tell me more about it. It was really like listening to her ten minutes beating me in the afternoon. First, the first string is a hexadecimal string. Converting a hexadecimal string to NSData is not the way I used to do, but rather the way I did.
#pragma mark - Converts the hexadecimal number represented by characters into binary data
+ (NSMutableData *)dataWithHexString:(NSString *)hexString
{
    if (!hexString || [hexString length] == 0) {
        return nil;
    }

    NSMutableData *hexData = [[NSMutableData alloc] initWithCapacity:8];
    NSRange range;
    if ([hexString length] % 2 == 0) {
        range = NSMakeRange(0, 2);
    } else {
        range = NSMakeRange(0, 1);
    }
    for (NSInteger i = range.location; i < [hexString length]; i += 2) {
        unsigned int anInt;
        NSString *hexCharStr = [hexString substringWithRange:range];
        NSScanner *scanner = [[NSScanner alloc] initWithString:hexCharStr];

        [scanner scanHexInt:&anInt];
        NSData *entity = [[NSData alloc] initWithBytes:&anInt length:1];
        [hexData appendData:entity];

        range.location += range.length;
        range.length = 2;
    }

    //    NSLog(@"hexdata: %@", hexData);
    return hexData;
}
Of course, there are more than one conversion method, such as the following, which is also possible. Of course, I use the first one:
#pragma mark - Converts the hexadecimal number represented by characters into binary data
+ (NSMutableData *)dataWithHexString:(NSString *)hexString
{
    // The length of hexString should be even
    if ([hexString length] % 2 != 0)
        return nil;

    NSUInteger len = [hexString length];
    NSMutableData *retData = [NSMutableData data];
    const char *ch = [[hexString dataUsingEncoding:NSASCIIStringEncoding] bytes];
    for (int i=0 ; i<len ; i+=2) {

        int height=0;
        if (ch[i]>='0' && ch[i]<='9')
            height = ch[i] - '0';
        else if (ch[i]>='A' && ch[i]<='F')
            height = ch[i] - 'A' + 10;
        else if (ch[i]>='a' && ch[i]<='f')
            height = ch[i] - 'a' + 10;
        else
            // Erroneous data
            return nil;

        int low=0;
        if (ch[i+1]>='0' && ch[i+1]<='9')
            low = ch[i+1] - '0';
        else if (ch[i+1]>='A' && ch[i+1]<='F')
            low = ch[i+1] - 'A' + 10;
        else if (ch[i+1]>='a' && ch[i+1]<='f')
            low = ch[i+1] - 'a' + 10;
        else
            // Erroneous data
            return nil;

        int byteValue = height*16 + low;
        [retData appendBytes:&byteValue length:1];
    }
    return retData;
}
Secondly, it's also my biggest headache - > NSData's CRC validation. First, I look at my CRC validation source file:
unsigned short get_crc16(unsigned char *buf, int len)
First I need to pass it an unsigned char * type of data, and then I find all kinds of ways to find NSData to unsigned char * and I find that nothing is right. However, I started looking for CRC validation of NSData and found that unsigned char* could be a Byte array, that is:
#pragma mark - Converting hexadecimal strings to NSData+CRC data
+ (NSData *)calCRCWithData:(NSData *)visibleData
{
    //Converting hexadecimal strings to NSData data
    NSMutableData *visibleDataM = [visibleData mutableCopy];
    //    Byte byte[5] = {0x00,0xc0,0x00,0x00,0x32};

    //NSData does crc validation to get short return value
    Byte *byte = (Byte *)[visibleDataM bytes];
    unsigned short crcShort = get_crc16(byte, (int)visibleDataM.length);
    //Add short return value to byte type to the end of variable array
    Byte bytes[2];
    bytes[0] = (Byte) (crcShort >> 8);
    bytes[1] = (Byte) (crcShort);

    [visibleDataM appendBytes:bytes length:sizeof(bytes)];

    return visibleDataM;
}
The unsigned short returned is converted to NSData and found to be normal. It's really a relief.
Next is the NSData escape, which is a byte-to-byte comparison, such as the NSData data < 00238900a0 > You found that there is 0A but no escape is wrong, but the NSData above can be converted into such data as 0x00,0x23,0x89,0x00,0xa0. There is no 0A in it, so the escape is also a byte comparison, such as my escape method:?
#pragma mark - Transliterate Data+CRC Data
+ (NSData *)EscapedData:(NSData *)converData
{
    /**
     Conversion of Data+CRC Data
     Transfer rules: 0xc0 - > 0xc0 0x00; 0x45 - > 0xc0 0x01; 0x32 - > 0xc0 0x02; 0x0b - > 0xc0 0x03; 0x0a - > 0xc0 0x04
     */
    Byte *myBytes = (Byte *)[converData bytes];
    NSMutableData *finalDataM = [NSMutableData data];
    for (int i = 0; i < converData.length; i++) {

        if (myBytes[i] == 0xc0) {
            Byte temByte[2];
            temByte[0] = 0xc0;
            temByte[1] = 0x00;
            [finalDataM appendBytes:temByte length:sizeof(temByte)];

        }
        else if (myBytes[i] == 0x45) {
            Byte temByte[2];
            temByte[0] = 0xc0;
            temByte[1] = 0x01;
            [finalDataM appendBytes:temByte length:sizeof(temByte)];

        }
        else if (myBytes[i] == 0x32) {
            Byte temByte[2];
            temByte[0] = 0xc0;
            temByte[1] = 0x02;
            [finalDataM appendBytes:temByte length:sizeof(temByte)];

        }
        else if (myBytes[i] == 0x0b) {
            Byte temByte[2];
            temByte[0] = 0xc0;
            temByte[1] = 0x03;
            [finalDataM appendBytes:temByte length:sizeof(temByte)];

        }
        else if (myBytes[i] == 0x0a) {
            Byte temByte[2];
            temByte[0] = 0xc0;
            temByte[1] = 0x04;
            [finalDataM appendBytes:temByte length:sizeof(temByte)];

        }else{
            Byte temByte[1];
            temByte[0] = myBytes[i];
            [finalDataM appendBytes:temByte length:sizeof(temByte)];

        }
    }
    return finalDataM;
}
Similarly inversion:
#pragma mark - Conversion of Data+CRC Data
+ (NSData *)UnescapesData:(NSData *)converData
{
    /**
     Conversion of Data+CRC Data
     Transfer rules: 0xc0 - > 0xc0 0x00; 0x45 - > 0xc0 0x01; 0x32 - > 0xc0 0x02; 0x0b - > 0xc0 0x03; 0x0a - > 0xc0 0x04
     */
    Byte *myBytes = (Byte *)[converData bytes];
    NSMutableData *finalDataM = [NSMutableData data];
    for (int i = 0; i < converData.length; i++) {

        if (myBytes[i] == 0xc0 && myBytes[i+1] == 00) {
            Byte temByte[1];
            temByte[0] = 0xc0;
            [finalDataM appendBytes:temByte length:sizeof(temByte)];
            i++;
        }
        else if (myBytes[i] == 0xc0 && myBytes[i+1] == 01) {
            Byte temByte[1];
            temByte[0] = 0x45;
            [finalDataM appendBytes:temByte length:sizeof(temByte)];
            i++;
        }
        else if (myBytes[i] == 0xc0 && myBytes[i+1] == 02) {
            Byte temByte[1];
            temByte[0] = 0x32;
            [finalDataM appendBytes:temByte length:sizeof(temByte)];
            i++;
        }
        else if (myBytes[i] == 0xc0 && myBytes[i+1] == 03) {
            Byte temByte[1];
            temByte[0] = 0x0b;
            [finalDataM appendBytes:temByte length:sizeof(temByte)];
            i++;
        }
        else if (myBytes[i] == 0xc0 && myBytes[i+1] == 04) {
            Byte temByte[2];
            temByte[1] = 0x0a;
            [finalDataM appendBytes:temByte length:sizeof(temByte)];
            i++;
        }else{
            Byte temByte[1];
            temByte[0] = myBytes[i];
            [finalDataM appendBytes:temByte length:sizeof(temByte)];

        }
    }

    return finalDataM;
}
My general directory structure is as follows:

Only two methods of encryption and decryption are exposed.

Import Xcode into. c file

In addition, suddenly see the use of import project of this. C file, by the way. Because Xcode supports C, there's no need to do anything extra. Just import your. C file into Xcode and Ctrl+N creates a new. h file:

Write the method name of the. c file you want to expose to. h file

Call the. h file where you need it, as shown in my directory outline. If there are any shortcomings, please point out.

Posted by rtown on Thu, 20 Dec 2018 16:57:04 -0800