很久没有更新过了,最近在忙一些关于电容触控的东西,感觉又回到了大学的时候,玩了一段时间的STC15W系列的芯片。有对比才会有伤害,为了实现一些功能,不得不去优化代码,STC15W201S的FLASH只有1K大小,如果你的代码稍微冗余一点就无法烧录了。反观NORDIC的芯片,真香。废话不多说,进入今天正题,聊一聊NORDIC的关于BLE GAP、连接参数、HIDS和广播参数初始化问题。(基于SDK15.2来说明)
1、 首先是GAP参数的初始化,其实在SDK中就有很多的案例来参考,而GAP作为BLE连接的先行者,必不可少需要去配置一些初始化的参数,即为BLE连接搭桥。
static void gap_params_init(void) /**<GAP参数初始化*/
{
ret_code_t err_code;
ble_gap_conn_params_t gap_conn_params; /**<定义一个GAP结构体参数*/
ble_gap_conn_sec_mode_t sec_mode; /**<定义安全模式*/
char device_name[30]; /**<选择设备名称,内容长度可更改*/
memset(device_name,0,30);
strcpy(device_name,"NORDIC-HUNTER"); /**<这里设置你的设备名称*/
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); /**<打开连接安全模式*/
err_code = sd_ble_gap_device_name_set(&sec_mode,
(const uint8_t *)device_name,
strlen(device_name)); /**<在底层设置好刚才所设定 的设备名称*/
APP_ERROR_CHECK(err_code);
err_code = sd_ble_gap_appearance_set(BLE_APPEARANCE_HID_Device); /**<这个相当于选择你的设备是什么类型的,比如鼠标、键盘等*/
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; /**<最大连接间隔*/
gap_conn_params.slave_latency = SLAVE_LATENCY; /**<从属延迟*/
gap_conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT; /**<超时*/
err_code = sd_ble_gap_ppcp_set(&gap_conn_params); /**<Peripheral Preferred Connection Parameters 可选*/
APP_ERROR_CHECK(err_code);
}
根据上面我给出的代码可以看到,其实在GAP阶段设置的参数信息基本上都是表示这个连接设备的信息和连接信息,比如设备名称、外设、类型等。当然,在GAP阶段回去选择安全模式,但是这个安全模式不是绝对的,需要根据自己开发项目的实际需求去设定。如果要更详细的初始化设备的基本信息,需要去调用dis_init(void)函数,下面我给一个例子来看看
static void dis_init(void)
{
ret_code_t err_code;
ble_dis_init_t dis_init_obj;
ble_dis_pnp_id_t pnp_id;
pnp_id.vendor_id_source = PNP_ID_VENDOR_ID_SOURCE; /**<供应商信息ID*/
pnp_id.vendor_id = PNP_ID_VENDOR_ID; /**<供应商ID*/
pnp_id.product_id = PNP_ID_PRODUCT_ID; /**<产品ID*/
pnp_id.product_version = PNP_ID_PRODUCT_VERSION; /**<产品版本*/
memset(&dis_init_obj, 0, sizeof(dis_init_obj));
Device_Info_Pack(); /**<设备信息*/
ble_srv_ascii_to_utf8(&dis_init_obj.manufact_name_str, MANUFACTURER_NAME);
dis_init_obj.p_pnp_id = &pnp_id;
dis_init_obj.fw_rev_str.p_str = Firmware_Ver; /**<固件信息设置*/
dis_init_obj.fw_rev_str.length = Firmware_Ver_Len;
dis_init_obj.hw_rev_str.p_str = Hardware_Ver; /**<硬件信息设置*/
dis_init_obj.hw_rev_str.length = Hardware_Ver_Len;
dis_init_obj.serial_num_str.p_str = Serial_Ver; /**<序列号信息设置*/
dis_init_obj.serial_num_str.length = Serial_Ver_Len;
/**<安全模式设置*/
BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&dis_init_obj.dis_attr_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&dis_init_obj.dis_attr_md.write_perm);
dis_init_obj.dis_char_rd_sec = SEC_JUST_WORKS;
err_code = ble_dis_init(&dis_init_obj);
APP_ERROR_CHECK(err_code);
}
这上面就会有更多关于设备信息的设置,而这些信息都可以通过BLE上传到用户手机上或者其他设备上进行查看。NORDIC中的BLE还有更详细的连接参数初始化,主要用于连接时的处理
static void conn_params_init(void)
{
ret_code_t err_code;
ble_conn_params_init_t cp_init;
memset(&cp_init, 0, sizeof(cp_init));
cp_init.p_conn_params = NULL;
cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;/**<连接参数跟新延时*/
cp_init.next_conn_params_update_delay = NEXT_CONN_PARAMS_UPDATE_DELAY;
cp_init.max_conn_params_update_count = MAX_CONN_PARAMS_UPDATE_COUNT;
cp_init.start_on_notify_cccd_handle = BLE_GATT_HANDLE_INVALID;
cp_init.disconnect_on_fail = false;
cp_init.evt_handler = NULL;
cp_init.error_handler = conn_params_error_handler;
err_code = ble_conn_params_init(&cp_init);
APP_ERROR_CHECK(err_code);
}
连接参数可以根据这个来修改,一般没有太大的改变。
2、其次我来简要说一下HID相关的参数初始化设置,HID协议是基于USB协议的,需要看USB简要协议的,我的资源里面会有个“常见且常用的协议”里面包含了很多协议,需要的朋友可以去看看。HID服务在我的项目中主要应用于与Android相配合,去实现一些控制。而在HID协议中,它的报告设置在NORDIC中有三种,分别是输入报文、输出报文和特征报文,用于发送和接收相应的信息。在使用的时候需要去设置一些参数,如KEY索引值,最大长度,ID和类型,这些信息主要用于表达该报文的作用,与GAP连接类似,都需要去设置相应的安全模式,保证传输的可靠性和安全性。下面我再给一个例子说明一下(省略了HID_MAP,SDK的案例中会有相应的说明)
static void hids_init(void)
{
ret_code_t err_code;
ble_hids_init_t hids_init_obj;
ble_hids_inp_rep_init_t * p_input_report; /**<输入报告*/
ble_hids_outp_rep_init_t * p_output_report; /**<输出报告*/
ble_hids_feature_rep_init_t * p_feature_report; /**<特征报告*/
uint8_t hid_info_flags;
static ble_hids_inp_rep_init_t input_report_array[1];
static ble_hids_outp_rep_init_t output_report_array[1];
static ble_hids_feature_rep_init_t feature_report_array[1];
static uint8_t report_map_data[] =
{
/**<根据自己的需求来配置(可参照SDK中这一部分的内容)*/
};
memset((void *)input_report_array, 0, sizeof(ble_hids_inp_rep_init_t));
memset((void *)output_report_array, 0, sizeof(ble_hids_outp_rep_init_t));
memset((void *)feature_report_array, 0, sizeof(ble_hids_feature_rep_init_t));
// Initialize HID Service 下面是对三种报告进行配置和安全模式的设置
p_input_report = &input_report_array[INPUT_REPORT_KEYS_INDEX];
p_input_report->max_len = INPUT_REPORT_KEYS_MAX_LEN;
p_input_report->rep_ref.report_id = INPUT_REP_REF_ID;
p_input_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_INPUT;
p_input_report->sec.cccd_wr = SEC_JUST_WORKS;
p_input_report->sec.wr = SEC_JUST_WORKS;
p_input_report->sec.rd = SEC_JUST_WORKS;
p_output_report = &output_report_array[OUTPUT_REPORT_INDEX];
p_output_report->max_len = OUTPUT_REPORT_MAX_LEN;
p_output_report->rep_ref.report_id = OUTPUT_REP_REF_ID;
p_output_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_OUTPUT;
p_output_report->sec.wr = SEC_JUST_WORKS;
p_output_report->sec.rd = SEC_JUST_WORKS;
p_feature_report = &feature_report_array[FEATURE_REPORT_INDEX];
p_feature_report->max_len = FEATURE_REPORT_MAX_LEN;
p_feature_report->rep_ref.report_id = FEATURE_REP_REF_ID;
p_feature_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_FEATURE;
p_feature_report->sec.rd = SEC_JUST_WORKS;
p_feature_report->sec.wr = SEC_JUST_WORKS;
hid_info_flags = HID_INFO_FLAG_REMOTE_WAKE_MSK | HID_INFO_FLAG_NORMALLY_CONNECTABLE_MSK;
memset(&hids_init_obj, 0, sizeof(hids_init_obj));
hids_init_obj.evt_handler = on_hids_evt;
hids_init_obj.error_handler = service_error_handler;
hids_init_obj.is_kb = true; /**<这里选择了设备类型是键盘*/
hids_init_obj.is_mouse = false;
hids_init_obj.inp_rep_count = 1;
hids_init_obj.p_inp_rep_array = input_report_array;
hids_init_obj.outp_rep_count = 1;
hids_init_obj.p_outp_rep_array = output_report_array;
hids_init_obj.feature_rep_count = 1;
hids_init_obj.p_feature_rep_array = feature_report_array;
hids_init_obj.rep_map.data_len = sizeof(report_map_data);
hids_init_obj.rep_map.p_data = report_map_data;
hids_init_obj.hid_information.bcd_hid = BASE_USB_HID_SPEC_VERSION;
hids_init_obj.hid_information.b_country_code = 0;
hids_init_obj.hid_information.flags = hid_info_flags;
hids_init_obj.included_services_count = 0;
hids_init_obj.p_included_services_array = NULL;
hids_init_obj.rep_map.rd_sec = SEC_JUST_WORKS;
hids_init_obj.hid_information.rd_sec = SEC_JUST_WORKS;
hids_init_obj.boot_kb_inp_rep_sec.cccd_wr = SEC_JUST_WORKS;
hids_init_obj.boot_kb_inp_rep_sec.rd = SEC_JUST_WORKS;
hids_init_obj.boot_kb_outp_rep_sec.rd = SEC_JUST_WORKS;
hids_init_obj.boot_kb_outp_rep_sec.wr = SEC_JUST_WORKS;
hids_init_obj.protocol_mode_rd_sec = SEC_JUST_WORKS;
hids_init_obj.protocol_mode_wr_sec = SEC_JUST_WORKS;
hids_init_obj.ctrl_point_wr_sec = SEC_JUST_WORKS;
err_code = ble_hids_init(&m_hids, &hids_init_obj);
APP_ERROR_CHECK(err_code);
}
这个我是直接采用了SDK给出的代码来清晰的展示HID相关的初始化信息,可以根据自己的需要进行相应的修改。接下来给出两张简明扼要的框架图,方便大家理解HID协议的作用和流程。
3、Advertising 我放到最后来简要说一下,所谓压轴。广播在整个BLE连接的启动器,没有广播和扫描就没有后续的连接和数据传输。广播也有四种主要的方式,根据实际需求进行选择。
static void advertising_init(void)
{
uint32_t err_code;
uint8_t adv_flags;
ble_advertising_init_t init;
// Build and set advertising data
memset(&init, 0, sizeof(init));
adv_flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
init.advdata.name_type = BLE_ADVDATA_FULL_NAME;
init.advdata.include_appearance = (BLE_Android_HID != mode) ? true:false;
init.advdata.flags = adv_flags;
/**<配置需要的广播模式*/
init.config.ble_adv_whitelist_enabled = true; /**<白名单配置*/
init.config.ble_adv_directed_high_duty_enabled = true;
init.config.ble_adv_directed_enabled = false;
init.config.ble_adv_directed_interval = 0;
init.config.ble_adv_directed_timeout = 0;
init.config.ble_adv_fast_enabled = true;
init.config.ble_adv_fast_interval = APP_ADV_FAST_INTERVAL;
init.config.ble_adv_fast_timeout = APP_ADV_FAST_DURATION;
init.config.ble_adv_slow_enabled = true;
init.config.ble_adv_slow_interval = APP_ADV_SLOW_INTERVAL;
init.config.ble_adv_slow_timeout = APP_ADV_SLOW_DURATION;
init.evt_handler = on_adv_evt;
init.error_handler = ble_advertising_error_handler;
err_code = ble_advertising_init(&m_advertising, &init);
APP_ERROR_CHECK(err_code);
ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);
}
在广播参数初始化函数中可以添加一些自己特定的信息,以此信息去连接相应的设备会更加安全和可靠。比如可以自己加一些连接模式判断或者广播自己想要的服务信息,让其他设备进行识别判断和连接。
希望有错的地方,大家能够指正出来,一起共进步,同成长。(备注:主要参考BLE SDK案例中的方法和函数)