Home > Article > Backend Development > BLE-NRF51822 tutorial 3-sdk program framework analysis_PHP tutorial
nordicBLE technical exchange group 498676838
This lecture is an introduction to the framework and will not involve too much Multiple code details.
51822’s official SDK is actually not framework dependent. What is a framework? For example, TI's BLE SDK has an operating system abstraction layer (OSAL), which is a polling schedule. You need to follow his way to create tasks and so on.
The 51822 SDK essentially only provides various calling interfaces, such as opening the initialization protocol stack, initializing some hardware function modules, starting broadcast, initiating links, etc. How you use these interfaces is entirely up to you. However, general firmware development involves the initialization of various resources through similar processes, and 51822 is no exception. Therefore, the main function of the slave example in the SDK is similar to the following steps:
Take the official serial port BLE as an example:
int main(void)
{
leds_init(); //Not necessary, but this example uses
timers_init(); //Not necessary, but this example uses
buttons_init( ; ; //Must
gap_params_init(); //Must
services_init(); //Related to the services you create, the details of different services are different but the general establishment
//process Basically the same, usually you can directly use the official example to modify some parameters advertising_init(); //Broadcast data initialization must be conn_params_init(); //It depends on the situation, if There is no need to negotiate connection parameters after connection, and this initialization is // optional
sec_params_init(); //Security parameter initialization, if pairing binding is not used, this does not need to be initialized
advertising_start(); // To enable broadcasting,
// Enter main loop
for (;;)
{
power_manage(); //Enter sleep
}
}
You can see that only the core is necessary Just these 5 functions. You can remove all other codes, and as long as these five functions are left, the device can still run, and the mobile phone can also search for the device and communicate with the device.
This method of initialization can be said to be no different from our general microcontroller development.
What about after initialization. In the past when developing bare-board microcontrollers, we entered a while loop to perform some repetitive tasks. Later, in order to reduce power consumption, we started to add a sleep code in the while(1) loop to put the chip into sleep state when not working, and rely on interrupts to wake up. Deal with what comes.
The main function of 51822 above is also a for{} loop at the end, and the internal code of power_manage(); is actually a sleep instruction. The Main function is gone here, and in the end it is actually a sleep cycle. There are no tasks visible here, only sleep. It is conceivable that the protocol stack implementation of 51822 should be based on "event wake-up", that is, it sleeps when nothing happens, wakes up when something happens, and then continues to sleep. So where are the codes for handling events?
How does the protocol stack work?
Where do I add a service I want to create?
Where is the data sent from the mobile phone?
How do I send data to my mobile phone?
These issues are explained one by one below:
How does the protocol stack work?
To understand how the protocol stack works, you must first understand that the 51822 protocol stack is 100% event-driven. That is to say, any data sent by the protocol stack to the app is event-based.
For example, the device receives a link request from the mobile phone, or data sent from the mobile phone, etc. The protocol stack first receives the data and does some processing, and then packages the data (such as link requests, or ordinary data, etc.) into a structure and attaches the event ID, such as BLE_GAP_EVT_CONNECTED or BLE_GATTS_EVT_WRITE to tell the upper-layer app respectively about the event. The event represented by the structure.
For example, BLE_GAP_EVT_CONNECTED represents a link event, then the data contained in this event structure is connection parameters and other data.
And BLE_GATTS_EVT_WRITE represents a write event, so the data in the structure is the data written by the peer device (such as a mobile phone) to the board.
For example, the dispatch dispatch function in the uart demo
static void ble_evt_dispatch (ble_evt_t *p_ble_evt)
{
ble_conn_params_on_ble_evt(p_ble_evt);
ble_nus_on_ble_evt(&m_nus, p_ble_evt);
on_ble_evt(p_ble _evt);
}
When any BLE related event is thrown up the protocol stack to the app, ble_evt_dispatch will be called. Thereby throwing the event to each service function or processing module, here the event is thrown to the
connection parameter management processing function ble_conn_params_on_ble_evt
Uart service event processing function ble_nus_on_ble_evt (nus is Nordicuart server)
General event processing function on_ble_evt
Different events are distinguished by id in the event structure ble_evt_t. The difference is that the event processing function usually only handles events related to one's own emotions. Let's take a look at the internals of the ble_nus_on_ble_evt event processing function
voidble_nus_on_ble_evt(ble_nus_t * p_nus,ble_evt_t * p_ble_evt)
{
if ((p_nus == NULL) || (p_ble_evt == NULL))
{
return;
}
switch (p_ble_evt- >header.evt_id)
{
caseBLE_GAP_EVT_CONNECTED:
on_connect(p_nus, p_ble_evt);
break;
caseBLE_GAP_EVT_DISCONNECTED:
on_disconnect(p_nus, p_ble_evt);
break;
caseBLE_GATTS_EVT_WRITE:
on_write(p_nus, p_ble_evt);
break;
default:
// No implementation needed.
break;
}
}
As you can see, the uart service event processing function only cares about three events, link events, disconnection events and write events (the peer device sends data). Different events are handled differently. This is done by the developer The personnel themselves implemented it. For example, for connection events, the connection handle in the event structure should usually be recorded, because subsequent BLE operations are basically based on the connection handle (which can be regarded as the channel ID for communication between two devices, but is actually the data access in the link layer) address concept).
PS: Events are handed over to dispatch to dispatch to various services and modules. For the process of how to hand over lower-level events to the dispatch function, please refer to the 51822 tutorial in the group announcement. -Protocol stack overview tutorial.
After solving the so-called event drive, let’s solve it again: If you want to create a service, where should you add it?
There is a services_init() during the initialization process of the main function; inside this function is the code to add services, add characteristic values, etc.
The inside of the function actually registers the callback function nus_data_handler for a while (this function will print out the data from the computer serial port when the mobile phone sends data to the board) and then executes the real initialization function ble_nus_init .
Internally, this function will call the api interface of the sd_ble_gatts_service_add protocol stack to add services.
The api interface of the sd_ble_gatts_characteristic_add protocol stack will also be called later to add characteristic values.
The hierarchical relationship is as follows:
That is to say, to complete a complete service establishment function, there are only two core functions, sd_ble_gatts_service_add() and sd_ble_gatts_characteristic_add().
Usually establishing a service does not require writing it from scratch. Instead, directly assign the official services_init() function and then make some small changes. For example, modify the uuid, modify the read/write attributes, add one more characteristic value, etc. There is actually very little to modify.
Let’s solve the last two questions: Where is the data sent from the mobile phone? How do I send data to a mobile phone?
To understand these two questions, let’s first take a look at several questions related to the above that are often asked in the group:
Ask:
In which function does the data sent by the mobile phone to the 51822 device come out?
Answer:
There is no function
The protocol stack will throw up an event structure
The received data is in the structure
Question:
Are the Bluetooth upload function and the download function the same? Are they all service API functions?
Answer:
Only the upload function is used by the server to pass data to the client.
When sending data, after the Bluetooth chip receives the data, the protocol stack will throw up an event structure with data. For details, please refer to the data of various event processing functions in the dispatch dispatch program in the sample code.
Q:
The function sd_ble_gatts_hvx() is the sending function of Bluetooth. Does anyone know the receiving function of Bluetooth?
Answer:
Bluetooth does not have a receiving function. Bluetooth data is received at the bottom layer. After receiving, the event will be returned to the upper layer's ble_evt_dispatch distribution function, which will distribute the event to various services or event processing functions. The service or processing function will capture whether there is a write event caseBLE_GATTS_EVT_WRITE: if it exists, perform corresponding processing. The received data is all in the returned event structure
In fact, after reading these three questions, the above problem has almost been solved. As a slave device, BLE has an API interface for sending data to the mobile phone, which is the sd_ble_gatts_hvx() asked above. You can set whether to send it in notification mode or instruction mode through parameters (notification does not require a reply confirmation, instruction does). But there is no receiving function for the data sent by the mobile phone. Why? Because the protocol stack is event-driven! Therefore, after receiving the data, the protocol stack will give the upper-layer app a write event (indicating that the peer device has written data), and the written data is in this event structure. We just need to extract it. So there is no receiving function API.
On the other hand, it can also explain why there is no receiving data function. Because when sending data, it is "synchronous" and is called actively when you want to send data. But when receiving data, it is "asynchronous", and the data may arrive at any time. It is better to call a function and wait for the data to arrive. If the data does not come, nothing can be done. So reception is event-driven. If there is data, then transfer it to process.
Use a diagram to explain:
If it still feels a bit abstract, go back and look at the explanation of the protocol stack operation. . You should be more aware of the so-called event-driven