主机模块
从main说起
app_trace_init()
ble_stack_init()
client_handling_init()
device_manager_init
scan_start
从机模块
从main说起
gap_params_init()
advertising_init()
services_init()
advertising_start()
以串口的收发为例
从机端
主机端
主机模块从main说起:
以\nrf51822\Board\nrf6310\s120\experimental\ble_app_multilink_central为例。工作流程(从main看起):初始化了参数之后,开启扫描,然后就进入循环。其中led,buttons的内容非开发所需,此处忽略。此外,需要说明的是,所有的sd_开头的函数均为nrf51822系统函数,具体的使用可以参考官网sdk的文档说明。
--------------------------------main--------------------------------------------------------------------------------------
int main(void)
{
//Initialization of various modules.
app_trace_init();
leds_init();
buttons_init();
ble_stack_init();
client_handling_init();
device_manager_init();
// Startscanning for devices.
scan_start();
for (;;)
{
power_manage();
}
}
--------------------------------main-------------------------------------------------------------------------------------
simple_uart_config(RTS_PIN_NUMBER,TX_PIN_NUMBER,CTS_PIN_NUMBER,RX_PIN_NUMBER,HWFC);
如果需要在串口设置输入中断,需要添加如下代码:NRF_UART0->INTENSET= UART_INTENSET_RXDRDY_Enabled << UART_INTENSET_RXDRDY_Pos;
NVIC_SetPriority(UART0_IRQn,APP_IRQ_PRIORITY_LOW);// APP_IRQ_PRIORITY_HIGH
NVIC_EnableIRQ(UART0_IRQn);
并在main函数中添加中断处理函数的实现:void UART0_IRQHandler(void){}uint32_t err_code;
// Initialize the SoftDevicehandler module.
SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM,false);
// Register with theSoftDevice handler module for BLE events.
err_code =softdevice_ble_evt_handler_set(ble_evt_dispatch);
APP_ERROR_CHECK(err_code);
// Register with theSoftDevice handler module for System events.
err_code =softdevice_sys_evt_handler_set(sys_evt_dispatch);
APP_ERROR_CHECK(err_code);
--------------------------------ble_stack_init()-------------------------------------------------------------------------
2.2.1) dm_ble_evt_handler(p_ble_evt);<----模块管理
2.2.2) client_handling_ble_evt_handler(p_ble_evt); <---注册的服务处理switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_ADV_REPORT:
{
data_t adv_data;
data_t type_data;
// Initializeadvertisement report for parsing.
adv_data.p_data =p_ble_evt->evt.gap_evt.params.adv_report.data;
adv_data.data_len =p_ble_evt->evt.gap_evt.params.adv_report.dlen;
err_code =adv_report_parse(BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME,
&adv_data,
&type_data);
if (err_code != NRF_SUCCESS)
{
// Compare shortlocal name in case complete name does not match.
err_code =adv_report_parse(BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME,
&adv_data,
&type_data);
}
// Verify if short orcomplete name matches target.
if ((err_code ==NRF_SUCCESS) &&
(0 ==memcmp(TARGET_DEV_NAME,type_data.p_data,type_data.data_len)))
{
err_code =sd_ble_gap_scan_stop();
if (err_code !=NRF_SUCCESS)
{
APPL_LOG("[APPL]: Scan stop failed, reason %d\r\n", err_code);
}
err_code =sd_ble_gap_connect(&p_ble_evt->evt.gap_evt.params.adv_report.\
peer_addr,
&m_scan_param,
&m_connection_param);
if (err_code !=NRF_SUCCESS)
{
APPL_LOG("[APPL]: Connection Request Failed, reason %d\r\n",err_code);
}
}
break;
}
case BLE_GAP_EVT_TIMEOUT:
if(p_ble_evt->evt.gap_evt.params.timeout.src ==BLE_GAP_TIMEOUT_SRC_SCAN)
{
APPL_LOG("[APPL]: Scan Timedout.\r\n");
}
else if(p_ble_evt->evt.gap_evt.params.timeout.src == BLE_GAP_TIMEOUT_SRC_CONN)
{
APPL_LOG("[APPL]: Connection Request Timedout.\r\n");
}
break;
default:
break;
}
--------------------------------on_ble_evt(p_ble_evt)-----------------------------------------------------------------
uint32_t err_code;
uint32_t i;
ble_uuid128_t base_uuid = MULTILINK_PERIPHERAL_BASE_UUID;
err_code =sd_ble_uuid_vs_add(&base_uuid, &m_base_uuid_type);
APP_ERROR_CHECK(err_code);
nrf_gpio_range_cfg_output(8, 15);
for (i = 0; i < MAX_CLIENTS; i++)
{
m_client.state = IDLE;
}
m_client_count = 0;
db_discovery_init();
// Register with discovery module for thediscovery of the service.
ble_uuid_t uuid;
uuid.type = m_base_uuid_type;
uuid.uuid =MULTILINK_PERIPHERAL_SERVICE_UUID;
err_code =ble_db_discovery_register(&uuid,
db_discovery_evt_handler);
APP_ERROR_CHECK(err_code);
--------------------------------client_handling_init()-----------------------------------------------------------------
uuid.uuid= MULTILINK_PERIPHERAL_SERVICE_UUID;添加4bit服务,相当于起别名。
ble_db_discovery_register(&uuid,db_discovery_evt_handler);注册服务发现处理函数。
device_manager_init 设备管理处理化至此,全部准备工作完毕,接来下主机就会进入循环的监听模式,当有相应的事件到来就会自动调用协议栈中相应的模块进行调度。
从机模块从main说起:
以\nrf51822\Board\nrf6310\s120\experimental\ble_app_multilink_peripheral为例。与主机的工作流程类似(从main看起):初始化了参数之后,开启广播,然后就进入循环。只是从机需要初始化的东西有部分与主机会有些不同,其中led,buttons,gpio的内容非开发所需,此处忽略。此外,由于主从设备是配合使用的。ble_stack_init(); device_manager_init();这两个的初始化与主机的初始化基本一致,只是相应的处理方式和参数名定义会不同。需要查看差异的话,可以对比查看。(比如,从机会有广播包的事情处理,而主机则没有。)这里只对其他函数进行说明。
--------------------------------main-------------------------------------------------------------------------int main(void)
{
ble_stack_init();
leds_init();
timers_init();
gpiote_init();
buttons_init();
device_manager_init();
gap_params_init();
advertising_init();
services_init();
advertising_start();
for (;;)
{
power_manage();
}
--------------------------------main-------------------------------------------------------------------------
-------------------------------- services_init()-----------------------------------------------------------
uint32_t err_code;
ble_uuid_t uuid;
ble_gatts_char_md_t char_md;
ble_gatts_attr_t attr;
ble_gatts_attr_md_t attr_md;
ble_gatts_attr_md_t cccd_md;
ble_gatts_attr_md_t char_ud_md;
uint16_t svc_test;
static uint8_t multilink_peripheral_data;
static uint8_t multilink_peripheral_ud[] ="Modifiable multilink_peripheral Data";
ble_uuid128_t base_uuid =MULTILINK_PERIPHERAL_BASE_UUID;
err_code =sd_ble_uuid_vs_add(&base_uuid, &m_base_uuid_type);
APP_ERROR_CHECK(err_code);
uuid.type = m_base_uuid_type;
uuid.uuid = MULTILINK_PERIPHERAL_SERVICE_UUID;
err_code =sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &uuid,&svc_test);
APP_ERROR_CHECK(err_code);
uuid.uuid = MULTILINK_PERIPHERAL_CHAR_UUID;
memset(&attr, 0,sizeof(ble_gatts_attr_t));
attr.p_uuid = &uuid;
attr.p_attr_md = &attr_md;
attr.max_len = 1;
attr.p_value = &multilink_peripheral_data;
attr.init_len = sizeof(multilink_peripheral_data);
memset(&attr_md, 0,sizeof(ble_gatts_attr_md_t));
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&attr_md.write_perm);
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.vlen = 0;
memset(&cccd_md, 0,sizeof(ble_gatts_attr_md_t));
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&cccd_md.write_perm);
cccd_md.vloc = BLE_GATTS_VLOC_STACK;
memset(&char_md, 0,sizeof(ble_gatts_char_md_t));
char_md.p_cccd_md = &cccd_md;
char_md.char_props.notify = 1;
char_md.char_props.indicate = 1;
char_md.char_props.read = 1;
char_md.char_props.write = 1;
char_md.char_ext_props.wr_aux = 1;
char_md.p_user_desc_md = &char_ud_md;
char_md.p_char_user_desc = multilink_peripheral_ud;
char_md.char_user_desc_size = (uint8_t)strlen((char*)multilink_peripheral_ud);
char_md.char_user_desc_max_size =(uint8_t)strlen((char *)multilink_peripheral_ud);
memset(&char_ud_md, 0,sizeof(ble_gatts_attr_md_t));
char_ud_md.vloc = BLE_GATTS_VLOC_STACK;
char_ud_md.vlen = 1;
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&char_ud_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&char_ud_md.write_perm);
err_code =sd_ble_gatts_characteristic_add(BLE_GATT_HANDLE_INVALID,
&char_md,
&attr,
&m_char_handles);
APP_ERROR_CHECK(err_code);
--------------------------------
services_init()-----------------------------------------------------------
sd_ble_uuid_vs_add(&base_uuid,&m_base_uuid_type);
其次,将该服务设置为主服务列表当中。sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,&uuid, &svc_test);
再者,设置服务之后,需要在这个服务中添加相应的特征。至此,全部准备工作完毕,接来下从机就会进入循环的广播模式,当有相应的事件到来就会自动调用协议栈中相应的模块进行调度。
-------------------------------- voidUART0_IRQHandler(void)-----------------------------------------
{
static uint8_tdata_array[BLE_NUS_MAX_DATA_LEN];
static uint8_t index = 0;
uint32_t err_code;
/**@snippet [Handling the data receivedover UART] */
data_array[index] = simple_uart_get();
index++;
if ((data_array[index - 1] == '\n') ||(index >= (BLE_NUS_MAX_DATA_LEN - 1)))
{
err_code = ble_nus_send_string(&m_nus,data_array, index + 1);
if (err_code !=NRF_ERROR_INVALID_STATE)
{
APP_ERROR_CHECK(err_code);
}
index = 0;
}
/**@snippet [Handling the data receivedover UART] */
}
-------------------------------- voidUART0_IRQHandler(void)---- -------------------------------------
接收串口中的消息,当遇到回车或者字符数够了之后,将数据发送出去。ble_nus_send_string(&m_nus,data_array, index + 1);这条语句中的m_nus的参数就是数据发送的句柄。会发现根本就没有对这个参数进行任何的设置,数据是发不出去的。因此要对这个参数进行相应的处理。这里就需要用到services_init()
串口中断函数。同样的。将参考代码的串口中断函数复制过来。同样是缺乏m_nus这个发送的句柄,因此这里也同样需要添加服务。此外,由于主从机发送数据所调用的函数不同。这里还需要修改ble_nus_send_string(&m_nus,data_array, index + 1)这个函数。修改后的内容如下,(参考\Board\nrf6310\s120\experimental\ble_app_uart_c中的tx_send()的代码。)
----------tx_send(ble_ecg_c_t* p_ble_ecg_c,char *str ,unsigned char len)------------
void tx_send(ble_ecg_c_t *p_ble_ecg_c,char *str ,unsigned char len){
tx_message_t * p_msg;
if (len > WRITE_MESSAGE_LENGTH) {
return ;
}
p_msg =&m_tx_buffer[m_tx_insert_index++];
m_tx_insert_index &= TX_BUFFER_MASK;
strncpy(p_msg->req.write_req.gattc_value,str,len);
p_msg->req.write_req.gattc_params.handle = p_ble_ecg_c->ecg_rx_handle;
p_msg->req.write_req.gattc_params.len = len;
p_msg->req.write_req.gattc_params.p_value = (uint8_t*)p_msg->req.write_req.gattc_value;
p_msg->req.write_req.gattc_params.offset = 0;
p_msg->req.write_req.gattc_params.write_op = BLE_GATT_OP_WRITE_REQ;
p_msg->conn_handle =p_ble_ecg_c->conn_handle;
p_msg->type = WRITE_REQ;
tx_buffer_process();
}
----------tx_send(ble_ecg_c_t* p_ble_ecg_c,char *str ,unsigned char len)------------
static voidhrs_c_init(void)
{
ble_hrs_c_init_t hrs_c_init_obj;
hrs_c_init_obj.evt_handler =hrs_c_evt_handler;
uint32_t err_code = ble_hrs_c_init(&m_ble_hrs_c,&hrs_c_init_obj);
APP_ERROR_CHECK(err_code);
}
-------------------------------- hrs_c_init()-----------------------------------------
uint32_tble_hrs_c_init(ble_hrs_c_t * p_ble_hrs_c, ble_hrs_c_init_t * p_ble_hrs_c_init)
{
if ((p_ble_hrs_c == NULL) ||(p_ble_hrs_c_init == NULL))
{
return NRF_ERROR_NULL;
}
ble_uuid_t hrs_uuid;
hrs_uuid.type = BLE_UUID_TYPE_BLE;
hrs_uuid.uuid = BLE_UUID_HEART_RATE_SERVICE;
mp_ble_hrs_c = p_ble_hrs_c;
mp_ble_hrs_c->evt_handler = p_ble_hrs_c_init->evt_handler;
mp_ble_hrs_c->conn_handle = BLE_CONN_HANDLE_INVALID;
mp_ble_hrs_c->hrm_cccd_handle =BLE_GATT_HANDLE_INVALID;
returnble_db_discovery_register(&hrs_uuid, db_discover_evt_handler);
}
-------------------------------- ble_hrs_c_init()-----------------------------------------
ble_uuid128_t nus_base_uuid = {0x9E, 0xCA, 0xDC, 0x24,0x0E, 0xE5, 0xA9, 0xE0,
0x93,0xF3, 0xA3, 0xB5, 0x00, 0x00, 0x40, 0x6E};
mp_ble_hrs_c = p_ble_hrs_c;
err_code =sd_ble_uuid_vs_add(&nus_base_uuid, &m_base_uuid_type);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
ble_uuid_t hrs_uuid;
hrs_uuid.type = m_base_uuid_type;
hrs_uuid.uuid = BLE_UUID_NUS_SERVICE;
需要注意的是,uuid必须与从机的uuid一致。BLE_UUID_NUS_SERVICE与从机的一致。这样才能确保主机能找到从机的服务。
再修改db_discover_evt_handler服务发现处理函数。
-------------------------------- db_discover_evt_handler-----------------------------------------
static voiddb_discover_evt_handler(ble_db_discovery_evt_t * p_evt)
{
// Check if the Heart Rate Service wasdiscovered.
if (p_evt->evt_type ==BLE_DB_DISCOVERY_COMPLETE
&& p_evt->params.discovered_db.srv_uuid.uuid ==BLE_UUID_HEART_RATE_SERVICE
&& p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE)
{
mp_ble_hrs_c->conn_handle =p_evt->conn_handle;
// Find the CCCD Handle of the HeartRate Measurement characteristic.
uint8_t i;
for (i = 0; i params.discovered_db.char_count; i++)
{
if(p_evt->params.discovered_db.charateristics.characteristic.uuid.uuid
== BLE_UUID_HEART_RATE_MEASUREMENT_CHAR)
{
// Found Heart Ratecharacteristic. Store CCCD handle and break.
mp_ble_hrs_c->hrm_cccd_handle =
p_evt->params.discovered_db.charateristics.cccd_handle;
mp_ble_hrs_c->hrm_handle= p_evt->params.discovered_db.charateristics.characteristic.handle_value;
break;
}
}
LOG("[HRS_C]: Heart Rate Servicediscovered at peer.\r\n");
ble_hrs_c_evt_t evt;
evt.evt_type =BLE_HRS_C_EVT_DISCOVERY_COMPLETE;
mp_ble_hrs_c->evt_handler(mp_ble_hrs_c, &evt);
}
}
--------------------------------db_discover_evt_handler-----------------------------------------
这里是发现服务后的处理函数。先确保找到的是正确的服务。然后将服务里的特征与主机定义的特征进行匹配,匹配成功后获取相应的参数值。具体修改如下:void ble_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;
case BLE_GAP_EVT_DISCONNECTED:
on_disconnect(p_nus,p_ble_evt);
break;
case BLE_GATTS_EVT_WRITE:
on_write(p_nus,p_ble_evt);
break;
caseBLE_GATTC_EVT_WRITE_RSP:
on_write_rsp(p_nus, p_ble_evt);
break;
default:
// No implementationneeded.
break;
}
}
-------------------------------ble_nus_on_ble_evt-----------------------------------------