| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390 |
- /* This example code is in the Public Domain (or CC0 licensed, at your option.)
- Unless required by applicable law or agreed to in writing, this software is
- distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
- CONDITIONS OF ANY KIND, either express or implied.
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "freertos/FreeRTOS.h"
- #include "freertos/task.h"
- #include "freertos/event_groups.h"
- #include "esp_system.h"
- #include "esp_wifi.h"
- #include "esp_event.h"
- #include "esp_log.h"
- #include "nvs_flash.h"
- #include "esp_bt.h"
- #include "esp_bt_defs.h"
- #include "esp_gap_ble_api.h"
- #include "esp_gatts_api.h"
- #include "esp_gatt_defs.h"
- #include "esp_bt_main.h"
- #include "esp_bt_device.h"
- #include "esp_hidd.h"
- #include "esp_hid_gap.h"
- static const char *TAG = "HID_DEV_DEMO";
- const unsigned char hidapiReportMap[] = { //8 bytes input, 8 bytes feature
- 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
- 0x0A, 0x00, 0x01, // Usage (0x0100)
- 0xA1, 0x01, // Collection (Application)
- 0x85, 0x01, // Report ID (1)
- 0x15, 0x00, // Logical Minimum (0)
- 0x26, 0xFF, 0x00, // Logical Maximum (255)
- 0x75, 0x08, // Report Size (8)
- 0x95, 0x08, // Report Count (8)
- 0x09, 0x01, // Usage (0x01)
- 0x82, 0x02, 0x01, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Buffered Bytes)
- 0x95, 0x08, // Report Count (8)
- 0x09, 0x02, // Usage (0x02)
- 0xB2, 0x02, 0x01, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile,Buffered Bytes)
- 0x95, 0x08, // Report Count (8)
- 0x09, 0x03, // Usage (0x03)
- 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
- 0xC0, // End Collection
- // 38 bytes
- };
- const unsigned char mediaReportMap[] = {
- 0x05, 0x0C, // Usage Page (Consumer)
- 0x09, 0x01, // Usage (Consumer Control)
- 0xA1, 0x01, // Collection (Application)
- 0x85, 0x03, // Report ID (3)
- 0x09, 0x02, // Usage (Numeric Key Pad)
- 0xA1, 0x02, // Collection (Logical)
- 0x05, 0x09, // Usage Page (Button)
- 0x19, 0x01, // Usage Minimum (0x01)
- 0x29, 0x0A, // Usage Maximum (0x0A)
- 0x15, 0x01, // Logical Minimum (1)
- 0x25, 0x0A, // Logical Maximum (10)
- 0x75, 0x04, // Report Size (4)
- 0x95, 0x01, // Report Count (1)
- 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
- 0xC0, // End Collection
- 0x05, 0x0C, // Usage Page (Consumer)
- 0x09, 0x86, // Usage (Channel)
- 0x15, 0xFF, // Logical Minimum (-1)
- 0x25, 0x01, // Logical Maximum (1)
- 0x75, 0x02, // Report Size (2)
- 0x95, 0x01, // Report Count (1)
- 0x81, 0x46, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,Null State)
- 0x09, 0xE9, // Usage (Volume Increment)
- 0x09, 0xEA, // Usage (Volume Decrement)
- 0x15, 0x00, // Logical Minimum (0)
- 0x75, 0x01, // Report Size (1)
- 0x95, 0x02, // Report Count (2)
- 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
- 0x09, 0xE2, // Usage (Mute)
- 0x09, 0x30, // Usage (Power)
- 0x09, 0x83, // Usage (Recall Last)
- 0x09, 0x81, // Usage (Assign Selection)
- 0x09, 0xB0, // Usage (Play)
- 0x09, 0xB1, // Usage (Pause)
- 0x09, 0xB2, // Usage (Record)
- 0x09, 0xB3, // Usage (Fast Forward)
- 0x09, 0xB4, // Usage (Rewind)
- 0x09, 0xB5, // Usage (Scan Next Track)
- 0x09, 0xB6, // Usage (Scan Previous Track)
- 0x09, 0xB7, // Usage (Stop)
- 0x15, 0x01, // Logical Minimum (1)
- 0x25, 0x0C, // Logical Maximum (12)
- 0x75, 0x04, // Report Size (4)
- 0x95, 0x01, // Report Count (1)
- 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
- 0x09, 0x80, // Usage (Selection)
- 0xA1, 0x02, // Collection (Logical)
- 0x05, 0x09, // Usage Page (Button)
- 0x19, 0x01, // Usage Minimum (0x01)
- 0x29, 0x03, // Usage Maximum (0x03)
- 0x15, 0x01, // Logical Minimum (1)
- 0x25, 0x03, // Logical Maximum (3)
- 0x75, 0x02, // Report Size (2)
- 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
- 0xC0, // End Collection
- 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
- 0xC0, // End Collection
- };
- static esp_hid_raw_report_map_t report_maps[] = {
- {
- .data = hidapiReportMap,
- .len = sizeof(hidapiReportMap)
- },
- {
- .data = mediaReportMap,
- .len = sizeof(mediaReportMap)
- }
- };
- static esp_hid_device_config_t hid_config = {
- .vendor_id = 0x16C0,
- .product_id = 0x05DF,
- .version = 0x0100,
- .device_name = "ESP BLE HID2",
- .manufacturer_name = "Espressif",
- .serial_number = "1234567890",
- .report_maps = report_maps,
- .report_maps_len = 2
- };
- static esp_hidd_dev_t *hid_dev = NULL;
- static bool dev_connected = false;
- #define HID_CC_RPT_MUTE 1
- #define HID_CC_RPT_POWER 2
- #define HID_CC_RPT_LAST 3
- #define HID_CC_RPT_ASSIGN_SEL 4
- #define HID_CC_RPT_PLAY 5
- #define HID_CC_RPT_PAUSE 6
- #define HID_CC_RPT_RECORD 7
- #define HID_CC_RPT_FAST_FWD 8
- #define HID_CC_RPT_REWIND 9
- #define HID_CC_RPT_SCAN_NEXT_TRK 10
- #define HID_CC_RPT_SCAN_PREV_TRK 11
- #define HID_CC_RPT_STOP 12
- #define HID_CC_RPT_CHANNEL_UP 0x10
- #define HID_CC_RPT_CHANNEL_DOWN 0x30
- #define HID_CC_RPT_VOLUME_UP 0x40
- #define HID_CC_RPT_VOLUME_DOWN 0x80
- // HID Consumer Control report bitmasks
- #define HID_CC_RPT_NUMERIC_BITS 0xF0
- #define HID_CC_RPT_CHANNEL_BITS 0xCF
- #define HID_CC_RPT_VOLUME_BITS 0x3F
- #define HID_CC_RPT_BUTTON_BITS 0xF0
- #define HID_CC_RPT_SELECTION_BITS 0xCF
- // Macros for the HID Consumer Control 2-byte report
- #define HID_CC_RPT_SET_NUMERIC(s, x) (s)[0] &= HID_CC_RPT_NUMERIC_BITS; (s)[0] = (x)
- #define HID_CC_RPT_SET_CHANNEL(s, x) (s)[0] &= HID_CC_RPT_CHANNEL_BITS; (s)[0] |= ((x) & 0x03) << 4
- #define HID_CC_RPT_SET_VOLUME_UP(s) (s)[0] &= HID_CC_RPT_VOLUME_BITS; (s)[0] |= 0x40
- #define HID_CC_RPT_SET_VOLUME_DOWN(s) (s)[0] &= HID_CC_RPT_VOLUME_BITS; (s)[0] |= 0x80
- #define HID_CC_RPT_SET_BUTTON(s, x) (s)[1] &= HID_CC_RPT_BUTTON_BITS; (s)[1] |= (x)
- #define HID_CC_RPT_SET_SELECTION(s, x) (s)[1] &= HID_CC_RPT_SELECTION_BITS; (s)[1] |= ((x) & 0x03) << 4
- // HID Consumer Usage IDs (subset of the codes available in the USB HID Usage Tables spec)
- #define HID_CONSUMER_POWER 48 // Power
- #define HID_CONSUMER_RESET 49 // Reset
- #define HID_CONSUMER_SLEEP 50 // Sleep
- #define HID_CONSUMER_MENU 64 // Menu
- #define HID_CONSUMER_SELECTION 128 // Selection
- #define HID_CONSUMER_ASSIGN_SEL 129 // Assign Selection
- #define HID_CONSUMER_MODE_STEP 130 // Mode Step
- #define HID_CONSUMER_RECALL_LAST 131 // Recall Last
- #define HID_CONSUMER_QUIT 148 // Quit
- #define HID_CONSUMER_HELP 149 // Help
- #define HID_CONSUMER_CHANNEL_UP 156 // Channel Increment
- #define HID_CONSUMER_CHANNEL_DOWN 157 // Channel Decrement
- #define HID_CONSUMER_PLAY 176 // Play
- #define HID_CONSUMER_PAUSE 177 // Pause
- #define HID_CONSUMER_RECORD 178 // Record
- #define HID_CONSUMER_FAST_FORWARD 179 // Fast Forward
- #define HID_CONSUMER_REWIND 180 // Rewind
- #define HID_CONSUMER_SCAN_NEXT_TRK 181 // Scan Next Track
- #define HID_CONSUMER_SCAN_PREV_TRK 182 // Scan Previous Track
- #define HID_CONSUMER_STOP 183 // Stop
- #define HID_CONSUMER_EJECT 184 // Eject
- #define HID_CONSUMER_RANDOM_PLAY 185 // Random Play
- #define HID_CONSUMER_SELECT_DISC 186 // Select Disk
- #define HID_CONSUMER_ENTER_DISC 187 // Enter Disc
- #define HID_CONSUMER_REPEAT 188 // Repeat
- #define HID_CONSUMER_STOP_EJECT 204 // Stop/Eject
- #define HID_CONSUMER_PLAY_PAUSE 205 // Play/Pause
- #define HID_CONSUMER_PLAY_SKIP 206 // Play/Skip
- #define HID_CONSUMER_VOLUME 224 // Volume
- #define HID_CONSUMER_BALANCE 225 // Balance
- #define HID_CONSUMER_MUTE 226 // Mute
- #define HID_CONSUMER_BASS 227 // Bass
- #define HID_CONSUMER_VOLUME_UP 233 // Volume Increment
- #define HID_CONSUMER_VOLUME_DOWN 234 // Volume Decrement
- #define HID_RPT_ID_CC_IN 3 // Consumer Control input report ID
- #define HID_CC_IN_RPT_LEN 2 // Consumer Control input report Len
- void esp_hidd_send_consumer_value(uint8_t key_cmd, bool key_pressed)
- {
- uint8_t buffer[HID_CC_IN_RPT_LEN] = {0, 0};
- if (key_pressed) {
- switch (key_cmd) {
- case HID_CONSUMER_CHANNEL_UP:
- HID_CC_RPT_SET_CHANNEL(buffer, HID_CC_RPT_CHANNEL_UP);
- break;
- case HID_CONSUMER_CHANNEL_DOWN:
- HID_CC_RPT_SET_CHANNEL(buffer, HID_CC_RPT_CHANNEL_DOWN);
- break;
- case HID_CONSUMER_VOLUME_UP:
- HID_CC_RPT_SET_VOLUME_UP(buffer);
- break;
- case HID_CONSUMER_VOLUME_DOWN:
- HID_CC_RPT_SET_VOLUME_DOWN(buffer);
- break;
- case HID_CONSUMER_MUTE:
- HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_MUTE);
- break;
- case HID_CONSUMER_POWER:
- HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_POWER);
- break;
- case HID_CONSUMER_RECALL_LAST:
- HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_LAST);
- break;
- case HID_CONSUMER_ASSIGN_SEL:
- HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_ASSIGN_SEL);
- break;
- case HID_CONSUMER_PLAY:
- HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_PLAY);
- break;
- case HID_CONSUMER_PAUSE:
- HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_PAUSE);
- break;
- case HID_CONSUMER_RECORD:
- HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_RECORD);
- break;
- case HID_CONSUMER_FAST_FORWARD:
- HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_FAST_FWD);
- break;
- case HID_CONSUMER_REWIND:
- HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_REWIND);
- break;
- case HID_CONSUMER_SCAN_NEXT_TRK:
- HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_SCAN_NEXT_TRK);
- break;
- case HID_CONSUMER_SCAN_PREV_TRK:
- HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_SCAN_PREV_TRK);
- break;
- case HID_CONSUMER_STOP:
- HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_STOP);
- break;
- default:
- break;
- }
- }
- esp_hidd_dev_input_set(hid_dev, 1, HID_RPT_ID_CC_IN, buffer, HID_CC_IN_RPT_LEN);
- return;
- }
- static void hidd_event_callback(void *handler_args, esp_event_base_t base, int32_t id, void *event_data)
- {
- esp_hidd_event_t event = (esp_hidd_event_t)id;
- esp_hidd_event_data_t *param = (esp_hidd_event_data_t *)event_data;
- switch (event) {
- case ESP_HIDD_START_EVENT: {
- ESP_LOGI(TAG, "START");
- esp_hid_ble_gap_adv_start();
- break;
- }
- case ESP_HIDD_CONNECT_EVENT: {
- ESP_LOGI(TAG, "CONNECT");
- dev_connected = true;//todo: this should be on auth_complete (in GAP)
- break;
- }
- case ESP_HIDD_PROTOCOL_MODE_EVENT: {
- ESP_LOGI(TAG, "PROTOCOL MODE[%u]: %s", param->protocol_mode.map_index, param->protocol_mode.protocol_mode ? "REPORT" : "BOOT");
- break;
- }
- case ESP_HIDD_CONTROL_EVENT: {
- ESP_LOGI(TAG, "CONTROL[%u]: %sSUSPEND", param->control.map_index, param->control.control ? "EXIT_" : "");
- break;
- }
- case ESP_HIDD_OUTPUT_EVENT: {
- ESP_LOGI(TAG, "OUTPUT[%u]: %8s ID: %2u, Len: %d, Data:", param->output.map_index, esp_hid_usage_str(param->output.usage), param->output.report_id, param->output.length);
- ESP_LOG_BUFFER_HEX(TAG, param->output.data, param->output.length);
- break;
- }
- case ESP_HIDD_FEATURE_EVENT: {
- ESP_LOGI(TAG, "FEATURE[%u]: %8s ID: %2u, Len: %d, Data:", param->feature.map_index, esp_hid_usage_str(param->feature.usage), param->feature.report_id, param->feature.length);
- ESP_LOG_BUFFER_HEX(TAG, param->feature.data, param->feature.length);
- break;
- }
- case ESP_HIDD_DISCONNECT_EVENT: {
- ESP_LOGI(TAG, "DISCONNECT: %s", esp_hid_disconnect_reason_str(esp_hidd_dev_transport_get(param->disconnect.dev), param->disconnect.reason));
- dev_connected = false;
- esp_hid_ble_gap_adv_start();
- break;
- }
- case ESP_HIDD_STOP_EVENT: {
- ESP_LOGI(TAG, "STOP");
- break;
- }
- default:
- break;
- }
- return;
- }
- void hid_demo_task(void *pvParameters)
- {
- static bool send_volum_up = false;
- while (1) {
- if (dev_connected) {
- ESP_LOGI(TAG, "Send the volume");
- if (send_volum_up) {
- esp_hidd_send_consumer_value(HID_CONSUMER_VOLUME_UP, true);
- vTaskDelay(100 / portTICK_PERIOD_MS);
- esp_hidd_send_consumer_value(HID_CONSUMER_VOLUME_UP, false);
- } else {
- esp_hidd_send_consumer_value(HID_CONSUMER_VOLUME_DOWN, true);
- vTaskDelay(100 / portTICK_PERIOD_MS);
- esp_hidd_send_consumer_value(HID_CONSUMER_VOLUME_DOWN, false);
- }
- send_volum_up = !send_volum_up;
- }
- vTaskDelay(2000 / portTICK_PERIOD_MS);
- }
- }
- void app_main(void)
- {
- esp_err_t ret;
- ret = nvs_flash_init();
- if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
- ESP_ERROR_CHECK(nvs_flash_erase());
- ret = nvs_flash_init();
- }
- ESP_ERROR_CHECK( ret );
- #if CONFIG_BT_CLASSIC_ENABLED
- ret = esp_hid_gap_init(ESP_BT_MODE_BTDM);
- #else
- ret = esp_hid_gap_init(ESP_BT_MODE_BLE);
- #endif
- ESP_ERROR_CHECK( ret );
- ret = esp_hid_ble_gap_adv_init(ESP_HID_APPEARANCE_GENERIC, hid_config.device_name);
- ESP_ERROR_CHECK( ret );
- if ((ret = esp_ble_gatts_register_callback(esp_hidd_gatts_event_handler)) != ESP_OK) {
- ESP_LOGE(TAG, "GATTS register callback failed: %d", ret);
- return;
- }
- ESP_ERROR_CHECK( esp_hidd_dev_init(&hid_config, ESP_HID_TRANSPORT_BLE, hidd_event_callback, &hid_dev) );
- xTaskCreate(&hid_demo_task, "hid_task", 2048, NULL, 2, NULL);
- }
|