510
个编辑
更改
→MTU更新实验
==== 实验简介 ====
MTU是我们的最大传输单元(Maximum Transmission Unit),也就是我们大家常说的一包数据最大可以多少字节。
在BLE4.1往后的协议中,为了提高BLE的通信速率,我们可以配置MTU最大为251byte,但是这个251byte中有4字节的BLE通信数据包的协议头。也就是我们用户的一包数据最大是247字节,但是在nordic的NUS(串口服务)中,他又占用了3个字节作为特殊用途,这样我们用户可用的数据包长度就仅剩下244字节。
这边我们需要注意的是,BLE协议头的4字节我们是不能占用的,但是例如NUS服务的3字节(这个相当于用户的私有协议,不是必须存在)。
{{Note|text=1、主机和从机都可以主动配置MTU大小
2、如果主从机配置的MTU大小不同,则取小的数值|type=tips}}
==== 实验现象 ====
主机上电之后扫描周围的从机,一旦扫描到符合的过滤的从设备,就会打印扫描到的信息,并且发起连接,连接成功之后,打印连接的参数以及对方设备的信息。
连接成功之后,会打印Data len的大小,也就是我们的MTU。
[[文件:Nrf rtt 18.png|边框|居中|无框|657x657像素]]
从机上电之后广播,被主机连接之后,打印主机的设备信息以及连接参数。
并且会打印Data len的大小,也就是我们的MTU。
[[文件:Nrf tft 28.png|边框|居中|无框|648x648像素]]
==== 工程及源码讲解 ====
===== 主机部分 =====
主机部分,我们仅仅新增了有关MTU大小设置的部分,也就是在我们的gatt_init()函数中。
====== gatt_init()函数 ======
在gatt初始化的函数中,我们调用nrf_ble_gatt_att_mtu_central_set()函数去配置我们的MTU大小,在主机中我们配置MTU大小为100byte。
并且最终的MTU大小的gatt的事件回调函数中展示,携带的任务ID为NRF_BLE_GATT_EVT_ATT_MTU_UPDATED。<syntaxhighlight lang="c" line="1" start="224">
//******************************************************************
// fn : gatt_init
//
// brief : 初始化GATT
//
// param : none
//
// return : none
void gatt_init(void)
{
ret_code_t err_code;
err_code = nrf_ble_gatt_init(&m_gatt, gatt_evt_handler);
APP_ERROR_CHECK(err_code);
err_code = nrf_ble_gatt_att_mtu_central_set(&m_gatt, 100);
APP_ERROR_CHECK(err_code);
}
</syntaxhighlight>
====== gatt_evt_handler()回调函数 ======
在gatt的事件回调函数中,我们接收到任务ID为NRF_BLE_GATT_EVT_ATT_MTU_UPDATED的事件之后,可以获取到我们的MTU大小。
这边打印的Data len,是我们MTU减掉NUS占用的3个特殊字节之后的大小。<syntaxhighlight lang="c" line="1" start="205">
//******************************************************************
// fn : gatt_evt_handler
//
// brief : GATT事件回调
//
// param : p_gatt gatt类型结构体
// p_evt gatt事件
//
// return : none
void gatt_evt_handler(nrf_ble_gatt_t * p_gatt, nrf_ble_gatt_evt_t const * p_evt)
{
if ((m_conn_handle == p_evt->conn_handle) && (p_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED))
{
NRF_LOG_INFO("Data len is set to 0x%X(%d)",
p_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH,
p_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH);
}
}
</syntaxhighlight>
===== 从机部分 =====
从机部分与主机部分是一样的,我们都是新增了一个gatt的初始化。
====== gatt_init()函数 ======
在从机的gatt初始化函数中,我们配置MTU的大小是80字节(由于主机是100字节,所以最终的MTU大小已从机的80字节为准)。<syntaxhighlight lang="c" line="1" start="174">
//******************************************************************
// fn : gatt_init
//
// brief : 初始化GATT
//
// param : none
//
// return : none
void gatt_init(void)
{
ret_code_t err_code;
err_code = nrf_ble_gatt_init(&m_gatt, gatt_evt_handler);
APP_ERROR_CHECK(err_code);
err_code = nrf_ble_gatt_att_mtu_periph_set(&m_gatt, 80);
APP_ERROR_CHECK(err_code);
}
</syntaxhighlight>
====== gatt_evt_handler()回调函数 ======
当我们在gatt的回调函数中,接收到NRF_BLE_GATT_EVT_ATT_MTU_UPDATED的事件ID,我们可以获取到当前的MTU的大小。
这边的Data len是MTU减掉NUS中的3个特殊字节后的大小。<syntaxhighlight lang="c" line="1" start="155">
//******************************************************************
// fn : gatt_evt_handler
//
// brief : GATT事件回调
//
// param : p_gatt gatt类型结构体
// p_evt gatt事件
//
// return : none
void gatt_evt_handler(nrf_ble_gatt_t * p_gatt, nrf_ble_gatt_evt_t const * p_evt)
{
if ((m_conn_handle == p_evt->conn_handle) && (p_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED))
{
NRF_LOG_INFO("Data len is set to 0x%X(%d)",
p_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH,
p_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH);
}
}
</syntaxhighlight>
==== 实验总结 ====
MTU的大小和连接参数,与我们的通信速率息息相关。有关MTU大小的配置,有如下几个要点:
1、主机和从机都可以配置MTU大小
2、大部分情况下,我们根据从机的服务来确定MTU大小
3、MTU越大,我们可以发送的数据包就越大
4、当主从机配置的MTU大小不同时,我们以小的数值作准。
=== NUS服务获取实验 ===