基于W801开发板 蓝牙 ble HID实现

蓝牙hid协议:

蓝牙ble通过软件实现 HID,需要实现两个方面,广播和服务及特性

广播,HID广播数据要求如下

int wm_ble_hid_api_demo_adv(bool enable)
{
    int rc;
    if(enable) {
        struct ble_hs_adv_fields fields;
        const char *name;
        /**
         *  Set the advertisement data included in our advertisements:
         *     o Flags (indicates advertisement type and other general info).
         *     o Device name.
         *     o user specific field (winner micro).
         */
        memset(&fields, 0, sizeof fields);
        /* Advertise two flags:
         *     o Discoverability in forthcoming advertisement (general)
         *     o BLE-only (BR/EDR unsupported).
         */
		 
        fields.flags = BLE_HS_ADV_F_DISC_LTD |
                       BLE_HS_ADV_F_BREDR_UNSUP; //ble设备,有限发现模式
        name = "mykeybord8"; //设备名称 广播时显示的设备名称
        fields.name = (uint8_t *)name;
        fields.name_len = strlen(name);
        fields.name_is_complete = 1;
        fields.uuids16 = (ble_uuid16_t[]) {
            BLE_UUID16_INIT(WM_GATT_HID_UUID)
        }; //hid服务UUID1218
        fields.num_uuids16 = 1;
        fields.uuids16_is_complete = 1;		
		fields.appearance = 0x03c1; //键盘外观
		fields.appearance_is_present = 1;		
		rc = ble_gap_adv_set_fields(&fields);		

        if(rc != 0) {
            TLS_BT_APPL_TRACE_ERROR("error setting advertisement data; rc=%d\r\n", rc);
            return rc;
        }

        /* As own address type we use hard-coded value, because we generate
              NRPA and by definition it's random */
        rc = tls_nimble_gap_adv(WM_BLE_ADV_IND, 0);

        if(rc != 0) {
            TLS_BT_APPL_TRACE_ERROR("tls_nimble_gap_adv; rc=%d\r\n", rc);
            return rc;
        }
    } else {
        rc = tls_nimble_gap_adv(WM_BLE_ADV_STOP, 0);
    }

    return rc;
}

以上代码实现了,HID键盘的广播数据。

服务特性 如下

uint16_t g_ble_hid_attr_2a4a_handle;
uint16_t g_ble_hid_attr_2a4b_handle;

uint16_t g_ble_hid_attr_2a4c_handle;
uint16_t g_ble_hid_attr_2a4d_handle;

uint16_t g_ble_hid_attr_2a4d2_handle;
uint16_t g_ble_hid_attr_2a4e_handle;

uint16_t g_ble_demo_conn_handle ;
//以上为句柄定义,
#define WM_GATT_HID_UUID       0x1812 //hid服务 uuid
#define WM_GATT_HID_UUID1      0x2A4A //HID Information 的特性UUID
#define WM_GATT_HID_UUID2      0x2A4B //Report Map的特性UUID
#define WM_GATT_HID_UUID3      0x2A4C //Control Point的特性UUID
#define WM_GATT_HID_UUID4      0x2A4D //HID设备与HID主机之间交互数据(Report)的特性UUID
#define WM_GATT_HID_UUID5      0x2A4D //HID设备与HID主机之间交互数据(Report)的特性UUID
#define WM_GATT_HID_UUID6      0x2A4F //协议模式的特性UUID

static const struct ble_gatt_svc_def gatt_hid_svr_svcs[] = {
    {
        /* Service: uart */
        .type = BLE_GATT_SVC_TYPE_PRIMARY,
        .uuid = BLE_UUID16_DECLARE(WM_GATT_HID_UUID),
        .characteristics = (struct ble_gatt_chr_def[])
        { {
                .uuid = BLE_UUID16_DECLARE(WM_GATT_HID_UUID1),
                .val_handle = &g_ble_hid_attr_2a4a_handle,
                .access_cb = gatt_svr_chr_hid_access_func,
                .flags = BLE_GATT_CHR_F_READ,
            }, {
                .uuid = BLE_UUID16_DECLARE(WM_GATT_HID_UUID2),
                .val_handle = &g_ble_hid_attr_2a4b_handle,
                .access_cb = gatt_svr_chr_hid_access_func,
                .flags = BLE_GATT_CHR_F_READ,
            },{
                .uuid = BLE_UUID16_DECLARE(WM_GATT_HID_UUID3),
                .val_handle = &g_ble_hid_attr_2a4c_handle,
                .access_cb = gatt_svr_chr_hid_access_func,
                .flags = BLE_GATT_CHR_F_WRITE,
            },
            {
                .uuid = BLE_UUID16_DECLARE(WM_GATT_HID_UUID4),
                .val_handle = &g_ble_hid_attr_2a4d_handle,
                .access_cb = gatt_svr_chr_hid_access_func,
                .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
				.descriptors = (struct ble_gatt_dsc_def[])
				{
					{
						.uuid = BLE_UUID16_DECLARE(0x2908),
						.att_flags = 1,
						.access_cb  = gatt_svr_chr_hid_access_func,
					},
					{
						0,
					}									
				},
            }, 
			{
                .uuid = BLE_UUID16_DECLARE(WM_GATT_HID_UUID5),
                .val_handle = &g_ble_hid_attr_2a4d2_handle,
                .access_cb = gatt_svr_chr_hid_access_func,
                .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE,
				.descriptors = (struct ble_gatt_dsc_def[])
				{
					{
						.uuid = BLE_UUID16_DECLARE(0x2908),
						.att_flags = 2,
						.access_cb  = gatt_svr_chr_hid_access_func,
					},
					{
						0,
					}
				},				
            }, 
			{
                .uuid = BLE_UUID16_DECLARE(WM_GATT_HID_UUID6),
                .val_handle = &g_ble_hid_attr_2a4e_handle,
                .access_cb = gatt_svr_chr_hid_access_func,
                .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE,
            }, {
                0, /* No more characteristics in this service */
            }
        },
    },

    {
        0, /* No more services */
    },
};

回调函数

static int gatt_svr_chr_hid_access_func(uint16_t conn_handle, uint16_t attr_handle,
                              struct ble_gatt_access_ctxt *ctxt, void *arg)
{
    int rc;
    struct os_mbuf *om = ctxt->om;

    switch(ctxt->op) {
        case BLE_GATT_ACCESS_OP_WRITE_CHR://收到数据
           printf("BLE_GATT_ACCESS_OP_WRITE_CHR attr_handle = %d\r\n",attr_handle);
		    while(om){
				 tls_print_bytes("op write", om->om_data, om->om_len);
				 om = SLIST_NEXT(om, om_next);				
			}
            return 0;
        case BLE_GATT_ACCESS_OP_READ_CHR:
			printf("readattr_handle = %d\r\n",attr_handle);
			if(attr_handle == g_ble_hid_attr_2a4a_handle)
			{
				printf("2a4a\r\n");
				gatt_svc_test_read_value[0] = 0x01;
				gatt_svc_test_read_value[1] = 0x01;
				gatt_svc_test_read_value[2] = 0x00;
				gatt_svc_test_read_value[3] = 0x02;
				rc = os_mbuf_append(ctxt->om, &gatt_svc_test_read_value,4);           
				return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
                /*HID的信息,其值为4个字节:
                    前两个字节是HID版本,一般填入0x01,0x01,表示版本号为1.1
                    第三个字节是Country Code,一般填入0x00
                    第四个字节是HID Flags,一般填入0x02,表示Normally Connectable。*/		
			} 
			else if(attr_handle == g_ble_hid_attr_2a4b_handle)
			{
				printf("2a4b\r\n"); 
				rc = os_mbuf_append(ctxt->om, &bord_rep,sizeof (bord_rep));           
				return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;	
                //HID设备与HID主机数据交互的方式
				
			}
			else if(attr_handle == g_ble_hid_attr_2a4d_handle)
			{
				printf("2a4d\r\n");
				gatt_svc_test_read_value[0] = 0x01;
				gatt_svc_test_read_value[1] = 0x01;
				rc = os_mbuf_append(ctxt->om, &gatt_svc_test_read_value,2);           
				return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;	
			}
			else if(attr_handle == g_ble_hid_attr_2a4d2_handle)
			{
				printf("2a4d2\r\n");
				gatt_svc_test_read_value[0] = 0x01;
				gatt_svc_test_read_value[1] = 0x02;
				rc = os_mbuf_append(ctxt->om, &gatt_svc_test_read_value,2);           
				return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;	
			}
			else if(attr_handle == g_ble_hid_attr_2a4e_handle)
			{
				printf("2a4e\r\n");				
				gatt_svc_test_read_value[0] = 0x01;				
				rc = os_mbuf_append(ctxt->om, &gatt_svc_test_read_value,1);           
				return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;	
                //0x00表示Boot模式,0x01表示Report模式	
			
			}

		return 0;
		
		case BLE_GATT_ACCESS_OP_READ_DSC://表示读写特征描述符 01 02
			printf("type is = BLE_GATT_ACCESS_OP_READ_DSC\r\n");
			printf("readattr_handle = %d\r\n",attr_handle);
			if(attr_handle == 11)
			{
				printf("2a4d dsc\r\n");
				gatt_svc_test_read_value[0] = 0x01;
				gatt_svc_test_read_value[1] = 0x01;
				rc = os_mbuf_append(ctxt->om, &gatt_svc_test_read_value,2);           
				return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;	
			}else if (attr_handle == 14)
			{
				printf("2a4d2 dsc\r\n");
				gatt_svc_test_read_value[0] = 0x01;
				gatt_svc_test_read_value[1] = 0x02;
				rc = os_mbuf_append(ctxt->om, &gatt_svc_test_read_value,2);           
				return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;	
			}	//同名UUID用2908特征描述符区分,一个发送一个接收
		
		return 0;	
        default:
			printf("type is = %d\r\n",ctxt->op);
            assert(0);
            return BLE_ATT_ERR_UNLIKELY;
    }
}

启动HID

int start_hid()
{
	tls_appl_trace_level = TLS_BT_LOG_VERBOSE;
	tls_bt_init(0xff);
    CHECK_SYSTEM_READY();
    tls_ble_hid_demo_api_init(NULL,NULL);
	return 0;

}

tls_bt_init(0xff); 08版本sdk不用改变。

tls_ble_hid_demo_api_init 函数按照08版本sdk来写。配置服务,添加服务,启动广播。

int tls_ble_hid_demo_api_init(tls_ble_uart_output_ptr uart_output_ptr, tls_ble_uart_sent_ptr uart_in_and_sent_ptr)
{
    int rc = BLE_HS_EAPP;

    CHECK_SYSTEM_READY();

    TLS_BT_APPL_TRACE_DEBUG("%s, state=%d\r\n", __FUNCTION__, g_ble_hid_state);

    if(g_ble_hid_state == BLE_SERVER_MODE_IDLE) {
        //step 0: reset other services. Note
        rc = ble_gatts_reset();

        if(rc != 0) {
            TLS_BT_APPL_TRACE_ERROR("tls_ble_server_demo_api_init failed rc=%d\r\n", rc);
            return rc;
        }

        //step 1: config/adding  the services
        rc = wm_ble_hid_demo_gatt_svr_init();

        if(rc == 0) {
            ble_gap_event_listener_register(&ble_server_event_listener,
                                            ble_gap_evt_cb, NULL);

            TLS_BT_APPL_TRACE_DEBUG("tls_ble_server_demo_api_init register success\r\n");
            
            /*step 2: start the service*/
            rc = ble_gatts_start();
            assert(rc == 0);
            /*step 3: start advertisement*/
            rc = wm_ble_hid_api_demo_adv(true);

            if(rc == 0) {
                g_ble_hid_state = BLE_SERVER_MODE_ADVERTISING;
               
            }
        } else {
            TLS_BT_APPL_TRACE_ERROR("tls_ble_server_demo_api_init failed(rc=%d)\r\n", rc);
        }
    } else {
        TLS_BT_APPL_TRACE_WARNING("tls_ble_server_demo_api_init registered\r\n");
        rc = BLE_HS_EALREADY;
    }

    return rc;
}

启动广播后,在安卓手机端就应该能看到 ,自定义名称的蓝牙设备了,可以配对成功。

发送键码 1 测试

int send_key(void)
{
	uint8_t key_a[] = {0x00,0x00,0x1e,0x00,0x00,0x00,0x00,0x00};
	tls_ble_hid_demo_api_send_msg_notify(key_a,8);
	uint8_t key_aa[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
	tls_ble_hid_demo_api_send_msg_notify(key_aa,8);
	return 0;
}

report map 定义

static uint8_t bord_rep[] = {0x05, 0x01,      // USAGE_PAGE (Generic Desktop)
            0x09, 0x06,      // USAGE (Keyboard)
            0xa1, 0x01,      // COLLECTION (Application)
            0x85, 0x01,      //     REPORT_ID (1)
            0x75, 0x01,      //     Report Size (1)
            0x95, 0x08,      //     Report Count (8)
            0x05, 0x07,      //     Usage Page (Key Codes)
            0x19, 0xE0,      //     Usage Minimum (224)
            0x29, 0xE7,      //     Usage Maximum (231)
            0x15, 0x00,      //     Logical Minimum (0)
            0x25, 0x01,      //     Logical Maximum (1)
            0x81, 0x02,      //     Input (Data, Variable, Absolute); Modifier byte
            0x95, 0x01,      //     Report Count (1)
            0x75, 0x08,      //     Report Size (8)
            0x81, 0x01,      //     Input (Constant); Reserved byte
            0x95, 0x05,      //     Report Count (5)
            0x75, 0x01,      //     Report Size (1)
            0x05, 0x08,      //     Usage Page (LEDs)
            0x19, 0x01,      //     Usage Minimum (1)
            0x29, 0x05,      //     Usage Maximum (5)
            0x91, 0x02,      //     Output (Data, Variable, Absolute); LED report
            0x95, 0x01,      //     Report Count (1)
            0x75, 0x03,      //     Report Size (3)
            0x91, 0x01,      //     Output (Constant); LED report padding
            0x95, 0x06,      //     Report Count (6)
            0x75, 0x08,      //     Report Size (8)
            0x15, 0x00,      //     Logical Minimum (0)
            0x25, 0x65,      //     Logical Maximum (101)
            0x05, 0x07,      //     Usage Page (Key Codes)
            0x19, 0x00,      //     Usage Minimum (0)
            0x29, 0x65,      //     Usage Maximum (101)
            0x81, 0x00,      //     Input (Data, Array); Key array (6 bytes)
            0xc0       
};

其他流程处理参照 sdk   wm_ble_server_api_demo.c

挖坑,1:配对后,安卓取消配对,或者w801复位,都不能再次连接,只能取消配对和复位同时进行,才能再次连接。未能实现配对后自动连接

        2:win11 连接失败,提示驱动错误,应该是hid协议处理上有点问题,

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
基于W801单片机的智能手机充电器是一种能够更加智能化管理和保护手机充电的设计方案。这款充电器采用了W801单片机作为主控芯片,通过其强大的计算和控制能力,实现了多种功能和优化。 首先,基于W801单片机的充电器可以根据手机电池的容量和电压等信息,智能调节充电电流和电压。通过与手机之间的通信,充电器可以了解手机电池的具体状态,并根据需要进行快速充电或是低电流充电,以达到最佳充电效果,同时避免过度充电对手机电池的损害。 其次,充电器还具备安全保护功能。例如,基于W801单片机的充电器可以实现过充保护,当手机电池充满后自动停止充电,避免过度充电导致手机电池损坏。另外,充电器还可以监测电流和电压的异常情况,一旦发现异常即刻停止充电,确保手机充电安全。 此外,基于W801单片机的充电器还可以具备智能管理功能。它可以通过内置的计时器功能,记录手机充电时间和充电历史,帮助用户了解充电习惯和充电特点。同时,它还可以与用户的手机APP进行连接,实现远程控制和监测。用户可以通过手机APP查看充电器状态、调整充电参数等。 综上所述,基于W801单片机的智能手机充电器设计具备智能调节充电电流和电压、安全保护功能以及智能管理等特点,能够更好地满足用户对手机充电的需求,提供更加智能和安全的充电体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值