Contributed by Dachuizi, organized by Ai-Thinker
[WB2 BLE Learning-2] Callback Functions
Introduction
This article still focuses on the BLE slave mode code. Let's study how the communication between the phone and the BLE device is implemented in the code. As before, this article does not explain the BLE protocol, because I only have a partial understanding of it myself. I don't dare to mislead everyone;
Startup Flow

As shown in the figure above, the main initialization flow of a BLE device:
Protocol stack initialization;
Slave device initialization;
Register the maximum transmission unit change callback;
Register a series of connection-related callbacks;
The figure also marks the callbacks registered at different stages. It is precisely these callbacks that implement the communication between the BLE device and the phone; next, let's study them one by one;
Callback Functions
bt_enable_cb
This function is called when BLE is enabled at the end of protocol stack initialization.
This function is described in Ai-Thinker's SDK documentation:

The concrete implementation of the callback:
Click to expand full code
static void bt_enable_cb(int err)
{
if (!err)
{
bt_addr_le_t bt_addr;
bt_get_local_public_address(&bt_addr);
bt_addr.a.val[5] = 0x88;
bt_addr.a.val[4] = 0x88;
bt_addr.a.val[3] = 0x88;
bt_addr.a.val[2] = 0x88;
bt_addr.a.val[1] = 0x88;
bt_addr.a.val[0] = 0x88;
printf("BD_ADDR:(MSB)%02x:%02x:%02x:%02x:%02x:%02x(LSB) \r\n",
bt_addr.a.val[5], bt_addr.a.val[4], bt_addr.a.val[3], bt_addr.a.val[2], bt_addr.a.val[1], bt_addr.a.val[0]);
}
}I don't quite understand this part; is it writing default values?
Let's try it without modifying the code:

Try modifying the code to remove the default value settings:

Now we can see the real address;
This callback is invoked after the BLE device is enabled.
ble_salve_conn_cb & ble_salve_conn_cb
These two functions are registered during slave initialization, but the implementation of the registered callbacks merely sets two global variables. They are actually used in the callbacks mentioned later.
This can be understood as these two functions enhancing the callbacks, because in the implementations of the two callbacks mentioned later, you can see that these two callbacks are called first if they exist. So we'll skip them for now;
_connected & _disconnected
These two callbacks are registered last in the BLE startup code. Ai-Thinker's SDK documentation also has a brief description:

However, I didn't fully understand the parameter descriptions; it doesn't affect understanding though — they just register connection-related callbacks.
First, the concrete implementation of _connected is as follows:
Click to expand full code
static void _connected(struct bt_conn *conn, u8_t err)
{
if (conn_cb)
{
if (conn_cb(conn, err) != 0)
{
return;
}
}
if (conn->type != BT_CONN_TYPE_LE)
{
return;
}
conn_cur = conn;
printf("[BLE] connected \r\n");
BleSetMtu();
return;
}As you can see, one of the callbacks mentioned above is used here. Connect with the phone's BLE debugging assistant, then check the serial log:

Three messages are printed here:
The first line is printed by the _connected callback;
The second line is caused by the BleSetMtu function called in the _connected callback.
The third line is output by the _le_param_updated function, the parameter update callback;
The _disconnected callback:
Click to expand full code
static void _disconnected(struct bt_conn *conn, u8_t reason)
{
if (disconn_cb)
{
if (disconn_cb(conn, reason) != 0)
{
return;
}
}
if (conn->type != BT_CONN_TYPE_LE)
{
return;
}
conn_cur = NULL;
printf("[BLE] disconnected, reason:%d \r\n", reason);
}When the BLE debugging assistant disconnects, the serial prints:

The first line says re-advertising failed; it comes from the previously mentioned ble_salve_disconn_cb 中尝试重新广播;
The second line is called within the _disconnected callback.
_ble_mtu_changed_cb
The concrete implementation of this function is as follows:
Click to expand full code
static void _ble_mtu_changed_cb(struct bt_conn *conn, int mtu)
{
printf("[BLE] mtu updated:%d \r\n", mtu);
}From the printed log, we can see that the mtu (maximum transmission unit) changed;
Summary
It is precisely through these registered callbacks that communication between the BLE host and slave is implemented. At the same time, we can see that these callbacks only take effect during startup, so if the application wants to do something during the connection process, it can implement its own logic in these callbacks. For example, in the device-enabled success callback, the module's LED can be made to blink; stop blinking after a successful connection; and blink again after disconnection. Next time, I'll study the device communication after a successful connection;

