IOS Bluetooth development how to better send and receive data

In mid March a job in the new company, has been “fill the pit”, busy like a pig (pig very busy is good, eat and sleep), March article has not write.

Look at the “ancestors” to write the code, I think there is room for improvement, so this time I want to talk about this part of the content – iOS Bluetooth development in how to better send and receive data better.

Adaptive object:

  • To a preliminary understanding of the development of Bluetooth iOS friends (even the best computer basis are not, I like this no computer Cobain based pseudo program ape (true arts Wang));
  • Bluetooth development, but there is no very elegant to send and receive data friends (directly with the C language char array installed back, with the index to get indexed).

Be careful:

  • This article refers to Bluetooth, refers to BLE (Bluetooth Low Energy/ low-power Bluetooth). Apple’s official application framework CoreBluetooth development. Of course, there will be a different third party framework, I recently used the project is to use the framework of the third party BabyBluetooth.
  • This part of the code, there are two versions, the application of the apple framework CoreBluetooth, using the Swift. When using BabyBluetooth, the use of Objective-C.

Where do we get the data?

We first briefly review the whole process of Bluetooth data reception:

  • 1, Bluetooth constantly broadcast signal;
  • 2, APP scan;
  • 3, find the device (according to the name or “service” UUID to identify whether we want to connect the device);
  • 4, connection (success);
  • 5, call the method found “service”;
  • 6, call the method discovery service in the “features”;
  • 7, found that the hardware used for data transmission of the “features” to save (APP send data to the hardware to use this “feature”);
  • 8, found that the hardware for data output of the “features”, “monitoring” (hardware is from the “feature” to send data to the mobile terminal);
  • 9, the use of data input “feature” to send data, or waiting for data output “feature” issued by the data.

Which seventh to 8 steps of the code (Swift version) is as follows:

The 8 step: Seventh / /, / / discovery feature callback (Commission) method (assuming before it has "successfully connected" and "discovery service") func peripheral (peripheral: CBPeripheral, didDiscoverCharacteristicsForService service: CBService, error: NSError print (?) {"found equipment / (service.characteristics?.count) features are: / (service.characteristics)") / / for cycle, they have to find the feature (such as UUID for characteristic in service.characteristics to identify)! Switch characteristic.UUID {{/ / 7, discovery feature data writing (our hardware is: FF01 kCharacteristicDataInUUID: print (case) "which is used to write data to the feature, it is UUID (characteristic.UUID)"): / 8 /, found that the hardware output data (APP data read hardware features (our) hardware is: FF02) case kCharacteristicDataOutUUID: DataOut print ("/ / monitoring feature which is used to read the data, it is UUID (characteristic.UUID): / / / 8"), peripheral.setNotifyValue (true forCharacteristic:, characteristic monitor) default: print ("default")}}} / / / / ninth: finally, the Bluetooth data sent over, we will get the func peripheral in the callback method (peripheral: CBPeripheral, didUpdateNotificationStateForCharacteristic characteristic: CBCharacteristic, error: NSError print ("{?) A "FFF2" feature from the Bluetooth data: / / / value) (characteristic.value) "is a" NSData "type of object}?

So, we will end up in peripheral (_: didUpdateNotificationStateForCharacteristic:error:) to get the data method. Objective-C corresponds to the method is peripheral:didUpdateNotificationStateForCharacteristic: error:

Note that the first with setNotifyValue (_: forCharacteristic characteristic:) features of monitoring correspondence, in order to get the data in the above method.

If in Objective-C, the president like this (not the official framework, using the BabyBluetooth framework):

This framework will monitor / / BabyBluetooth and callback written together (with Block), can make the code less dispersed: / / which is above eighth, 9 and two step in a method of [_baby notify:peripheral characteristic:_dataOutCharacteristic block:^ (CBPeripheral *peripheral, CBCharacteristic *characteristics, NSError *error) {NSLog (@ "received from" FFF2 "issued by the Bluetooth feature data: characteristics.value);}% @".

What data do we get?

Well, after a series of slightly more complicated steps, we got the “NSData” type (Objective-C corresponds to the “NSData” type) data from bluetooth.

We print a “NSData” object to see:

In the console, will output something like this: ` it received Bluetooth data: < da13ffff ff640099>

What the hell are these?

This is about NSData, NSData is how the data? How to deal with, in order to become the data we need?

Apple’s official document, “Binary Data Programming Guide” in the chapter: Accessing and BytesAccessing and Comparing Bytes said more detailed, good English friends can look at.

For the time being, we understand that NSData (NSMutableData) is a binary data object – Apple will be packaged into binary data objects, so that we can use object-oriented thinking to manipulate these data.

We can generate the NSData object through the original binary data (Raw Bytes), but also through NSData access / access (Accessing) of these binary data.

Are you kidding me? Good binary data? Shouldn’t all be 0, 1? Why can there be d ah, a ah, f ah, cup?

Don’t get angry, < da13ffff ff640099> just give us sixteen hexadecimal only, namely 0xda, 0x13, 0xff, 0xff, 0xff, 0x64, 0x00, 0x99, Bluetooth transmission of the 8 sixteen hexadecimal number (8 byte) to us.

Why not use binary? Well, I know you don’t want to give up, binary is like this: < 1101101000010011 1111111111111111 00000000 10011001> halo? Do you want to continue to use binary? “Alfa dog” should be happy.

It is because the binary and the conversion between the sixteen is relatively simple, so in the computer field, the general comparison of 16 hexadecimal. This explains why we print out the NSData object in the final sixteen () is only 8 byte and above. 1KB=1024Bytes, give you 0 of 0.5KB and 1, ten pair of reading glasses don’t come).

What are the implications of these data?

This is a good question, the question is good: for example, “chicken” why is called “chicken”, “duck” why is called “duck”? (a good analogy)

Actually, a long time ago, first discovered the “chicken” of this species Chinese, he did not know why the brain hole emerge the word “chicken”, and was randomly used for “chicken” of the “symbol” to “definition” for “chicken”. If you could go back, can let him use the “duck” the “symbol”, if so, now the “chicken” is not “chicken”, “duck” is not “duck”, and should be the “chicken” is a “duck”, “duck” is a “chicken.”…… Is it a little dizzy? Rest assured, at the current level of science and technology, you can not go through the back, so, “chicken” or “chicken”, “duck” or “duck”.

Okay, so the 8 sixteen hexadecimal data said what, depends entirely on our own “definition”, programmers will take this “definition” is called “the agreement”, also called “instruction”. Look at the picture below, which is one of the instructions for a clever ape:

IOS Bluetooth development how to better send and receive data
we will define the content of these 8 byte clearly defined
  • First byte representation start bit;
  • The second byte is the instruction number, which is used to identify which instruction;
  • The three or four bytes, represents the color value (representing the RGB color color);
  • Sixth bytes representing brightness values;
  • The seventh byte is reserved bit, the role is to suddenly increase the content, there is a place to add;
  • The eighth byte is the parity bit, is used to ensure the integrity of the entire instruction (can be a fixed value, can be calculated through a certain algorithm, here is the use of fixed value), it is to see the 0x99, said: This is a complete instruction.

Note: “MCU to Phone”, which means that this data is sent from the hardware (SCM) to the phone.

So, you receive data from Bluetooth, do not ask me what is the meaning of what is said. Should be asked to write the firmware, as defined by colleagues, or write APP and colleagues write firmware definition — often firmware colleagues defined separately for writing APP colleagues, there will be a lot of pits, because they are difficult to be considered APP case (suffer form).

How to better send and receive data

Well, a lot of talk about it, and finally to the title of a relationship.

Have received the instruction from the example above, you may have found that there is significance to our data, byte3~byte6 is actually the 4 bytes, the first 3 is the color value, the last 1 are brightness value (in fact, this is a use of Bluetooth products, mobile phone with APP control the color and brightness of the lamp. This instruction is from the hardware (Device to Mobile) to obtain the color, brightness value).

Of course we can simply directly declare a can accommodate several elements of the C language array (buffer), to receive the 8bytes data (my company’s former colleagues do), similar to the following process:

Can / will declare a C array containing a plurality of elements (type is unsigned / char type) in OC, UInt8, uint8_t are unsigned char UInt8 tmpBuffer[128] = {0}; / / NSData and then use getBytes: method to get the [characteristic.value data from getBytes: tmpBuffer]; / / startBit = char unsigned data access tmpBuffer[0]; light.brightness = tmpBuffer[5]; light.colorR = tmpBuffer[2]; light.colorG = tmpBuffer[3]; light.colorB = tmpBuffer[4];...... Sometimes the / / tmpBuffer operation, with a bunch of (such as memset), memcpy (C) and other functions, to direct blood shoes C language is not particularly mature

There appeared a lot of “magic number”, let the back look at the code, code maintenance people see foggy, if the complexity is a little higher, directly.

Is there a better way? That’s how we do it:

There is a kind of special / / structure defined these instructions #pragma - Device 2 Mobile mark #pragma mark Response: 0x13 Bluetooth module returns the data / / in fact there is a hole, when a single data size is 2 bytes or more, we use UInt16 or UInt32 to define a "alignment" problem is the received data, no order alignment according to the instruction definition, cause data is not correct, this time behind struct with the keyword "__attribute__" ((packed)). (I fall in the pit for a long time, finally on the StackOverflow typedef struct to solve the questions) {UInt8 startBit; UInt8 CMD; UInt8 colourR; / / UInt8 value range: 0-255 colourG; UInt8 colourB; UInt8 brightnessValue; / / range: 0-255, 0, 255 for the UInt8 reserved UInt8 checksum light; D2MDeviceParamResponse;}; / / then in the received data, and use the definition of this structure to receive data const void *raw = characteristics.value.bytes; D2MDeviceParamResponse = *responseData (D2MDeviceParamResponse * raw); / / use the data that light.brightness = responseData-> light.colorR = brightnessValue; responseData-> colourR; light.colorG = responseData-> colourG = resp; light.colorB OnseData-> colourB; / / does not appear to have a "magic number", a direct look at the code, you know what.

Here is the Swift version:

Device / / MARK:- / / definition instruction 2 Mobile / / MARK:Response: 0x13 struct D2MDeviceParamResponse Bluetooth module return data startBit: UInt8 var cmd: {var UInt8 var colourR: UInt8 var colourG: UInt8 var colourB: UInt8 var brightnessValue: UInt8 var reserved: UInt8 var checksum: UInt8} / / / / data access is not very familiar with the Swift, do not know there is no other better initialization method (crying) var CMD = D2MDeviceParamResponse (startBit: 0, cmd: 0, colourR: 0, colourG: 0, colourB: 0, brightnes SValue: 0, reserved: 0, checksum: 0) characteristic.value!.getBytes (& CMD, length:sizeof (D2MDeviceParamResponse) light.brightness) = cmd.brightnessValue light.colorR = cmd.colourR light.colorG = cmd.colourG light.colorB = cmd.colourB

Of course, the sending instructions are similar, the first definition of a good container (struct), and then assign the package to send, no more.

Is this a lot more intuitive than writing a bunch of parentheses and indexed?

People say the best documentation is the code, code to be written for people to realize your goals and intentions, is also a major merit of the code to the later maintenance to

Sleepy, sleepy.