1 /* This example code is in the Public Domain (or CC0 licensed, at your option.)
2    Unless required by applicable law or agreed to in writing, this software is
3    distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
4    CONDITIONS OF ANY KIND, either express or implied.
5  */
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 
11 #include "freertos/FreeRTOS.h"
12 #include "freertos/task.h"
13 #include "freertos/event_groups.h"
14 #include "esp_system.h"
15 #include "esp_wifi.h"
16 #include "esp_event.h"
17 #include "esp_log.h"
18 #include "nvs_flash.h"
19 #include "esp_bt.h"
20 #include "esp_bt_defs.h"
21 #include "esp_gap_ble_api.h"
22 #include "esp_gatts_api.h"
23 #include "esp_gatt_defs.h"
24 #include "esp_bt_main.h"
25 #include "esp_bt_device.h"
26 
27 #include "esp_hidh.h"
28 #include "esp_hid_gap.h"
29 
30 static const char *TAG = "ESP_HIDH_DEMO";
31 
hidh_callback(void * handler_args,esp_event_base_t base,int32_t id,void * event_data)32 void hidh_callback(void *handler_args, esp_event_base_t base, int32_t id, void *event_data)
33 {
34     esp_hidh_event_t event = (esp_hidh_event_t)id;
35     esp_hidh_event_data_t *param = (esp_hidh_event_data_t *)event_data;
36 
37     switch (event) {
38     case ESP_HIDH_OPEN_EVENT: {
39         if (param->open.status == ESP_OK) {
40             const uint8_t *bda = esp_hidh_dev_bda_get(param->open.dev);
41             ESP_LOGI(TAG, ESP_BD_ADDR_STR " OPEN: %s", ESP_BD_ADDR_HEX(bda), esp_hidh_dev_name_get(param->open.dev));
42             esp_hidh_dev_dump(param->open.dev, stdout);
43         } else {
44             ESP_LOGE(TAG, " OPEN failed!");
45         }
46         break;
47     }
48     case ESP_HIDH_BATTERY_EVENT: {
49         const uint8_t *bda = esp_hidh_dev_bda_get(param->battery.dev);
50         ESP_LOGI(TAG, ESP_BD_ADDR_STR " BATTERY: %d%%", ESP_BD_ADDR_HEX(bda), param->battery.level);
51         break;
52     }
53     case ESP_HIDH_INPUT_EVENT: {
54         const uint8_t *bda = esp_hidh_dev_bda_get(param->input.dev);
55         ESP_LOGI(TAG, ESP_BD_ADDR_STR " INPUT: %8s, MAP: %2u, ID: %3u, Len: %d, Data:", ESP_BD_ADDR_HEX(bda), esp_hid_usage_str(param->input.usage), param->input.map_index, param->input.report_id, param->input.length);
56         ESP_LOG_BUFFER_HEX(TAG, param->input.data, param->input.length);
57         break;
58     }
59     case ESP_HIDH_FEATURE_EVENT: {
60         const uint8_t *bda = esp_hidh_dev_bda_get(param->feature.dev);
61         ESP_LOGI(TAG, ESP_BD_ADDR_STR " FEATURE: %8s, MAP: %2u, ID: %3u, Len: %d", ESP_BD_ADDR_HEX(bda),
62                  esp_hid_usage_str(param->feature.usage), param->feature.map_index, param->feature.report_id,
63                  param->feature.length);
64         ESP_LOG_BUFFER_HEX(TAG, param->feature.data, param->feature.length);
65         break;
66     }
67     case ESP_HIDH_CLOSE_EVENT: {
68         const uint8_t *bda = esp_hidh_dev_bda_get(param->close.dev);
69         ESP_LOGI(TAG, ESP_BD_ADDR_STR " CLOSE: %s", ESP_BD_ADDR_HEX(bda), esp_hidh_dev_name_get(param->close.dev));
70         break;
71     }
72     default:
73         ESP_LOGI(TAG, "EVENT: %d", event);
74         break;
75     }
76 }
77 
78 #define SCAN_DURATION_SECONDS 5
79 
hid_demo_task(void * pvParameters)80 void hid_demo_task(void *pvParameters)
81 {
82     size_t results_len = 0;
83     esp_hid_scan_result_t *results = NULL;
84     ESP_LOGI(TAG, "SCAN...");
85     //start scan for HID devices
86     esp_hid_scan(SCAN_DURATION_SECONDS, &results_len, &results);
87     ESP_LOGI(TAG, "SCAN: %u results", results_len);
88     if (results_len) {
89         esp_hid_scan_result_t *r = results;
90         esp_hid_scan_result_t *cr = NULL;
91         while (r) {
92             printf("  %s: " ESP_BD_ADDR_STR ", ", (r->transport == ESP_HID_TRANSPORT_BLE) ? "BLE" : "BT ", ESP_BD_ADDR_HEX(r->bda));
93             printf("RSSI: %d, ", r->rssi);
94             printf("USAGE: %s, ", esp_hid_usage_str(r->usage));
95 #if CONFIG_BT_BLE_ENABLED
96             if (r->transport == ESP_HID_TRANSPORT_BLE) {
97                 cr = r;
98                 printf("APPEARANCE: 0x%04x, ", r->ble.appearance);
99                 printf("ADDR_TYPE: '%s', ", ble_addr_type_str(r->ble.addr_type));
100             }
101 #endif /* CONFIG_BT_BLE_ENABLED */
102 #if CONFIG_BT_HID_HOST_ENABLED
103             if (r->transport == ESP_HID_TRANSPORT_BT) {
104                 cr = r;
105                 printf("COD: %s[", esp_hid_cod_major_str(r->bt.cod.major));
106                 esp_hid_cod_minor_print(r->bt.cod.minor, stdout);
107                 printf("] srv 0x%03x, ", r->bt.cod.service);
108                 print_uuid(&r->bt.uuid);
109                 printf(", ");
110             }
111 #endif /* CONFIG_BT_HID_HOST_ENABLED */
112             printf("NAME: %s ", r->name ? r->name : "");
113             printf("\n");
114             r = r->next;
115         }
116         if (cr) {
117             //open the last result
118             esp_hidh_dev_open(cr->bda, cr->transport, cr->ble.addr_type);
119         }
120         //free the results
121         esp_hid_scan_results_free(results);
122     }
123     vTaskDelete(NULL);
124 }
125 
app_main(void)126 void app_main(void)
127 {
128     esp_err_t ret;
129 #if HID_HOST_MODE == HIDH_IDLE_MODE
130     ESP_LOGE(TAG, "Please turn on BT HID host or BLE!");
131     return;
132 #endif
133     ret = nvs_flash_init();
134     if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
135         ESP_ERROR_CHECK(nvs_flash_erase());
136         ret = nvs_flash_init();
137     }
138     ESP_ERROR_CHECK( ret );
139     ESP_LOGI(TAG, "setting hid gap, mode:%d", HID_HOST_MODE);
140     ESP_ERROR_CHECK( esp_hid_gap_init(HID_HOST_MODE) );
141 #if CONFIG_BT_BLE_ENABLED
142     ESP_ERROR_CHECK( esp_ble_gattc_register_callback(esp_hidh_gattc_event_handler) );
143 #endif /* CONFIG_BT_BLE_ENABLED */
144     esp_hidh_config_t config = {
145         .callback = hidh_callback,
146         .event_stack_size = 4096,
147         .callback_arg = NULL,
148     };
149     ESP_ERROR_CHECK( esp_hidh_init(&config) );
150 
151     xTaskCreate(&hid_demo_task, "hid_task", 6 * 1024, NULL, 2, NULL);
152 }
153