BLE-NRF51822教程11-手机动态修改设备名
該教程講解如何實(shí)現(xiàn)用手機(jī)來動(dòng)態(tài)修改設(shè)備名,達(dá)到手機(jī)連接設(shè)備后修改設(shè)備名稱,然后斷開連接再掃描能夠看到新的設(shè)備名。
?
教程基于sdk9.0?下的uartdemo,如下目錄中xxx\Keil_v5\ARM\Pack\NordicSemiconductor\nRF_Examples\9.0.0\ble_peripheral\ble_app_uart
?
Nordic的協(xié)議棧實(shí)現(xiàn)中默認(rèn)都會(huì)有一個(gè)?Generic Access服務(wù)和Generic Attribute服務(wù)(有的BLE app可能顯示不了名字,只顯示這兩個(gè)服務(wù)的UUID,分別是0x1800和0x1801)。
即一個(gè)工程中即使沒有定義任何服務(wù),燒寫到板子上后,手機(jī)連接上也能看到這兩個(gè)服務(wù)。
?
我們動(dòng)態(tài)修改設(shè)備名就是利用了第一個(gè)服務(wù)Generic Access。
該服務(wù)為通用屬性規(guī)范服務(wù),改服務(wù)為設(shè)備提供了一種確定信息的方式,包括設(shè)備自身的名稱,外觀特性,首先連接參數(shù)等。
使用其中的 設(shè)備名屬性,就能實(shí)現(xiàn)我們需要的動(dòng)態(tài)修改設(shè)備名。
實(shí)現(xiàn)方式就是??手機(jī)連接上設(shè)備后訪問這個(gè)服務(wù)下的設(shè)備名屬性,然后通過這個(gè)屬性寫新的名字,設(shè)備這邊判斷手機(jī)發(fā)送過來的寫是不是對Generic Access服務(wù)下的 設(shè)備名 屬性的寫操作。如果是就保存名字到flash中。并且更新設(shè)備名,這樣當(dāng)設(shè)備重啟或者斷開連接后 手機(jī)這邊再掃描就能看到新的設(shè)備名字了。
?
PS:當(dāng)然你也可以專門建立一個(gè)服務(wù)然后添加一個(gè)特征值用來當(dāng)做修改名字用。接收手機(jī)發(fā)送過來的新名字然后存儲(chǔ)修改。 不過既然默認(rèn)存在的Generic Access服務(wù)中已經(jīng)有了設(shè)備名屬性,這里就直接用,不再去專門創(chuàng)建服務(wù)
?
?
因?yàn)樯婕暗絝lash的存儲(chǔ)首先 添加flash相關(guān)的處理(關(guān)于flash的操作看前面的教程 如何在協(xié)議棧中使用flash)
?
//添加?sys_evt事件處理
static void sys_evt_dispatch(uint32_t sys_evt)
{
??? pstorage_sys_event_handler(sys_evt);
}
?
//協(xié)議棧初始化中注冊上面的派發(fā)函數(shù)
static void ble_stack_init(void)
{
??? uint32_t err_code;
???
??? // Initialize SoftDevice.
??? SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, NULL);
??? ………………
??? ………………
??? ………………
??? // Subscribe for BLE events.
??? err_code = softdevice_ble_evt_handler_set(ble_evt_dispatch);
??? APP_ERROR_CHECK(err_code);
???
?? //添加?sys_evt事件處理函數(shù) 注冊。?flash需要用到
?? err_code = softdevice_sys_evt_handler_set(sys_evt_dispatch);
??? APP_ERROR_CHECK(err_code);
}
?
?
首先初始化flash,并且定義自己的flash操作完成后的回調(diào)函數(shù),在main.c文件的最上面添加如下代碼
?
//第一個(gè)字節(jié)存放的是標(biāo)識(shí)符表示?flash中的數(shù)據(jù)是否是有效的?name
//device_name[0]=0xAA 表示是有效name,device_name[1]表示name的長度
?
#define NAME_SIZE 32
uint8_t device_name[NAME_SIZE];
pstorage_handle_t my_name_addr; //記錄name存放的flash地址
?
?
//flash操作完成后的回調(diào)函數(shù)。 并沒有做什么有用的事,但是注冊flash塊//的時(shí)候需要有回調(diào)函數(shù)所以這里需要定義
static void my_cb(pstorage_handle_t? * handle,
?????????????????????????????? uint8_t????????????? op_code,
?????????????????????????????? uint32_t???????????? result,
?????????????????????????????? uint8_t??????????? * p_data,
?????????????????????????????? uint32_t???????????? data_len)
{
??? switch(op_code)
??? {??????
?????? case PSTORAGE_UPDATE_OP_CODE:
?????????? if (result == NRF_SUCCESS)
?????????? {
?????????? ?? printf("update end");?
?????????? }
?????????? break;
??? }
}
?
?
//定義flash初始化函數(shù)
void my_flash_init(void){
??? uint32_t err_code;
??? pstorage_module_param_t param;
//申請一個(gè)塊 用來存放name
??? param.block_count = 1;
??? param.block_size = NAME_SIZE;
??? param.cb = my_cb;
???
??? err_code = pstorage_init();
??? printf("init err_code:%d\r\n",err_code);
??? err_code = pstorage_register(¶m, &my_name_addr);
??? printf("register err_code:%d\r\n",err_code);
??? //加載flash內(nèi)容。后面會(huì)判斷name是否有效,如果有效就會(huì)用改name
??? //否則使用默認(rèn)name
??? err_code = pstorage_load(device_name, &my_name_addr, NAME_SIZE, 0);
??? printf("load err_code:%d\r\n",err_code);
?
}
?
?
然后將該flash初始化函數(shù)放到main函數(shù)中
?
int main(void)
{
??? uint32_t err_code;
??? bool erase_bonds;
??? uint8_t? start_string[] = START_STRING;
???
??? // Initialize.
??? APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_MAX_TIMERS, APP_TIMER_OP_QUEUE_SIZE, false);
????uart_init();
???
?? //添加flash初始化,因?yàn)橛玫搅舜蛴⌒枰诺?/span>uart_init函數(shù)之后
?? //因?yàn)?/span>gap_params_init函數(shù)中會(huì)判斷使用flash中的名字還是默認(rèn)名字
?? //所以需要放到該函數(shù)之前
???my_flash_init();
???
??? buttons_leds_init(&erase_bonds);
??? ble_stack_init();
????gap_params_init();
??? services_init();
? ??advertising_init();
??? conn_params_init();
?? ?printf("%s\r\n",start_string);
??? err_code = ble_advertising_start(BLE_ADV_MODE_FAST);
??? APP_ERROR_CHECK(err_code);
??? // Enter main loop.
??? for (;;)
??? {
??????? power_manage();
??? }
}
?
然后修改?main函數(shù)中調(diào)用的gap_params_init函數(shù)。該函數(shù)中判斷my_flash_init?函數(shù)中加載的flash內(nèi)容是否是有效name,是就使用,不是就用默認(rèn)name.
?
static void gap_params_init(void)
{
??? uint32_t??????????????? err_code;
??? ble_gap_conn_params_t?? gap_conn_params;
??? ble_gap_conn_sec_mode_t sec_mode;
??? BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
???
?
??? //flash數(shù)據(jù)有效則使用flash中的名字
??? if ( device_name[0] == 0xaa ){
?????? //有效 使用新名字
?????? //device_name[1]為名字長度
?????? printf("update name\r\n");
?????? err_code = sd_ble_gap_device_name_set(&sec_mode,
?????????? ?????????????????????????(const uint8_t *) device_name+2,
???????? ??????????????????????????????device_name[1]);
???
??? }else{
?????? printf("default name\r\n");
?????? err_code = sd_ble_gap_device_name_set(&sec_mode,
????????????? ?????????????????????????(const uint8_t *) DEVICE_NAME,
????????????????????????????????????????? strlen(DEVICE_NAME));
??? }
?????????????????????????????????? ?
??? APP_ERROR_CHECK(err_code);
?? ? memset(&gap_conn_params, 0, sizeof(gap_conn_params));
? ? gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;
? ? gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;
?? ……………
??? …………
}
?
?
關(guān)于flash中的內(nèi)容添加完了,然后是處理手機(jī)發(fā)送過來的新名字。
定義事件處理函數(shù)
?
static void name_change(ble_evt_t * p_ble_evt)
{
??? ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
???
??? //通過UUID來判斷事件是不是寫Generic Access服務(wù)中的名字屬性
??? if((p_evt_write->context.char_uuid.uuid == BLE_UUID_GAP_CHARACTERISTIC_DEVICE_NAME) &&?
?????????????????????(p_ble_evt->header.evt_id == BLE_GATTS_EVT_WRITE))
??? {
?????? printf("name change \r\n");
?????? device_name[0] = 0xaa;
?????? device_name[1] = p_evt_write->len;
?????? memcpy(device_name+2, p_evt_write->data, p_evt_write->len);
?????? pstorage_update(&my_name_addr, device_name, NAME_SIZE, 0 );
?
??? }
?
}
?
?
然后再將這個(gè)事件處理函數(shù)加到 事件派發(fā)函數(shù)ble_evt_dispatch中
static void ble_evt_dispatch(ble_evt_t * p_ble_evt)
{
????name_change(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);
??? ble_advertising_on_ble_evt(p_ble_evt);
??? bsp_btn_ble_on_ble_evt(p_ble_evt);?
}
?
到這里基本實(shí)現(xiàn)了 手機(jī)修改設(shè)備名字。不過連接上修改名字后斷開然后點(diǎn)擊掃描發(fā)現(xiàn)名字并未更新,需要復(fù)位一下硬件設(shè)備才能看到設(shè)備名字變了。
?
想在不復(fù)位的情況下,斷開連接然后點(diǎn)掃描就能看到新的設(shè)備名還需要在斷開連接后重新初始化 廣播數(shù)據(jù)。
?
?
繼續(xù)修改事件派發(fā)函數(shù)ble_evt_dispatch
?
//應(yīng)為該函數(shù)是在下面定義的,這里使用到,所以要聲明一下
void advertising_init(void);
?
static void ble_evt_dispatch(ble_evt_t * p_ble_evt)
{
????name_change(p_ble_evt);
???
????//添加代碼,在斷開連接事件后初始化廣播數(shù)據(jù)
?? if ( p_ble_evt->header.evt_id == BLE_GAP_EVT_DISCONNECTED ){
????? advertising_init();
?? }
??
??? 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);
??? ble_advertising_on_ble_evt(p_ble_evt);
??? bsp_btn_ble_on_ble_evt(p_ble_evt);
? ?
}
?
?
現(xiàn)在編譯后燒寫到板子,手機(jī)連接后進(jìn)入?Generic Access服務(wù)(有的可能只看到UUID 0x1800),然后點(diǎn)擊device name(UUID?0x2A00)屬性,寫新名字。
然后斷開連接。 點(diǎn)擊掃描按鍵就可以看到新的設(shè)備名字了
總結(jié)
以上是生活随笔為你收集整理的BLE-NRF51822教程11-手机动态修改设备名的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 蓝牙协议分析(6)_BLE地址类型(蜗窝
- 下一篇: BLE-NRF51822教程4-串口BL