mirror of
https://github.com/nopnop2002/esp-idf-ssd1306.git
synced 2024-10-03 18:18:47 -04:00
added MouseSelectDemo
This commit is contained in:
parent
98c578572c
commit
9e74598fdb
8
MouseSelectDemo/CMakeLists.txt
Normal file
8
MouseSelectDemo/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS ../components/ssd1306)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(ssd1306)
|
64
MouseSelectDemo/README.md
Normal file
64
MouseSelectDemo/README.md
Normal file
@ -0,0 +1,64 @@
|
||||
# MouseSelectDemo for SSD1306
|
||||
Demo of selecting characters using the mouse.
|
||||
I used [this](https://github.com/espressif/esp-idf/tree/master/examples/peripherals/usb/host/hid) as a reference.
|
||||
|
||||
![usb-mouse-select-1](https://github.com/user-attachments/assets/c512e76d-80b3-44d5-8e18-97329abb337d)
|
||||
![usb-mouse-select-2](https://github.com/user-attachments/assets/81f37900-cf5f-4c87-b0c8-fad6d629c2a5)
|
||||
|
||||
# Hardware requirements
|
||||
|
||||
- ESP32S2/S3
|
||||
These have USB-HOST functionality.
|
||||
|
||||
- USB Connector
|
||||
I used this:
|
||||
![usb-conector-3](https://github.com/user-attachments/assets/05f3f79d-00d1-4d65-ad46-67d2e987bc88)
|
||||
|
||||
- USB mouse
|
||||
2-button or 3-button usb mouse.
|
||||
Button 2/3 is not used in this project.
|
||||
|
||||
# USB wiring
|
||||
To stabilize the power supply, I placed a 100uF electrolytic capacitor between 5V and GND.
|
||||
```
|
||||
ESP32-S2/S3 BOARD USB CONNECTOR
|
||||
+--+
|
||||
[ 5V ] +---------> | || VCC
|
||||
[GPIO 19] |---------> | || D-
|
||||
[GPIO 20] |---------> | || D+
|
||||
[ GND ] |--------+> | || GND
|
||||
| | +--+
|
||||
+---||---+
|
||||
100uF
|
||||
```
|
||||
|
||||
|
||||
# USB hot socket
|
||||
There are times when it works correctly and times when it doesn't.
|
||||
It works more stably if you connect before starting the firmware.
|
||||
When it works correctly, a log like this will be displayed.
|
||||
```
|
||||
I (1166) usb_hid: hid_host_device_callback
|
||||
I (1166) usb_hid: HID Device, protocol 'MOUSE' CONNECTED
|
||||
```
|
||||
|
||||
# Using USB-HUB
|
||||
I tried it, but it doesn't work properly via USB-HUB.
|
||||
|
||||
# Transfer failed error
|
||||
For some reason, the following error may occur in rare cases.
|
||||
This error occurs within [this](https://components.espressif.com/components/espressif/usb_host_hid) component.
|
||||
It is unclear whether it is a component bug or an effect of electrical noise.
|
||||
Some kind of stabilization circuitry may be required.
|
||||
It may come back to life if you unplugging the mouse and plugging it again.
|
||||
I would like to hear the opinion of someone who is familiar with USB electrical circuits.
|
||||
```
|
||||
E (12287696) hid-host: Transfer failed, status 1
|
||||
E (12287696) usb_hid: HID Device, protocol 'MOUSE' TRANSFER_ERROR
|
||||
E (15953516) USBH: Device 1 gone
|
||||
```
|
||||
|
||||
# Keyboard with mouse function
|
||||
I have a keyboard with mouse functionality, but the keyboard with mouse functionality does not work as a mouse.
|
||||
See [here](https://github.com/espressif/esp-idf/issues/12667).
|
||||
|
1
MouseSelectDemo/main/CMakeLists.txt
Normal file
1
MouseSelectDemo/main/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
||||
idf_component_register(SRCS "main.c" "usb_hid.c" INCLUDE_DIRS "." REQUIRED_IDF_TARGETS esp32s2 esp32s3)
|
8
MouseSelectDemo/main/component.mk
Normal file
8
MouseSelectDemo/main/component.mk
Normal file
@ -0,0 +1,8 @@
|
||||
#
|
||||
# Main component makefile.
|
||||
#
|
||||
# This Makefile can be left empty. By default, it will take the sources in the
|
||||
# src/ directory, compile them and link them into lib(subdirectory_name).a
|
||||
# in the build directory. This behaviour is entirely configurable,
|
||||
# please read the ESP-IDF documents if you need to do this.
|
||||
#
|
4
MouseSelectDemo/main/idf_component.yml
Normal file
4
MouseSelectDemo/main/idf_component.yml
Normal file
@ -0,0 +1,4 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
idf: ">=4.4"
|
||||
usb_host_hid: "^1.0.1"
|
148
MouseSelectDemo/main/main.c
Normal file
148
MouseSelectDemo/main/main.c
Normal file
@ -0,0 +1,148 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "ssd1306.h"
|
||||
#include "font8x8_basic.h"
|
||||
|
||||
#include "usb_hid.h"
|
||||
|
||||
QueueHandle_t app_event_hid = NULL;
|
||||
|
||||
void usb_hid_task(void *pvParameters);
|
||||
|
||||
/*
|
||||
You have to set this config value with menuconfig
|
||||
CONFIG_INTERFACE
|
||||
|
||||
for i2c
|
||||
CONFIG_MODEL
|
||||
CONFIG_SDA_GPIO
|
||||
CONFIG_SCL_GPIO
|
||||
CONFIG_RESET_GPIO
|
||||
|
||||
for SPI
|
||||
CONFIG_CS_GPIO
|
||||
CONFIG_DC_GPIO
|
||||
CONFIG_RESET_GPIO
|
||||
*/
|
||||
|
||||
#define TAG "SSD1306"
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
SSD1306_t dev;
|
||||
|
||||
#if CONFIG_I2C_INTERFACE
|
||||
ESP_LOGI(TAG, "INTERFACE is i2c");
|
||||
ESP_LOGI(TAG, "CONFIG_SDA_GPIO=%d",CONFIG_SDA_GPIO);
|
||||
ESP_LOGI(TAG, "CONFIG_SCL_GPIO=%d",CONFIG_SCL_GPIO);
|
||||
ESP_LOGI(TAG, "CONFIG_RESET_GPIO=%d",CONFIG_RESET_GPIO);
|
||||
i2c_master_init(&dev, CONFIG_SDA_GPIO, CONFIG_SCL_GPIO, CONFIG_RESET_GPIO);
|
||||
#endif // CONFIG_I2C_INTERFACE
|
||||
|
||||
#if CONFIG_SPI_INTERFACE
|
||||
ESP_LOGI(TAG, "INTERFACE is SPI");
|
||||
ESP_LOGI(TAG, "CONFIG_MOSI_GPIO=%d",CONFIG_MOSI_GPIO);
|
||||
ESP_LOGI(TAG, "CONFIG_SCLK_GPIO=%d",CONFIG_SCLK_GPIO);
|
||||
ESP_LOGI(TAG, "CONFIG_CS_GPIO=%d",CONFIG_CS_GPIO);
|
||||
ESP_LOGI(TAG, "CONFIG_DC_GPIO=%d",CONFIG_DC_GPIO);
|
||||
ESP_LOGI(TAG, "CONFIG_RESET_GPIO=%d",CONFIG_RESET_GPIO);
|
||||
spi_master_init(&dev, CONFIG_MOSI_GPIO, CONFIG_SCLK_GPIO, CONFIG_CS_GPIO, CONFIG_DC_GPIO, CONFIG_RESET_GPIO);
|
||||
#endif // CONFIG_SPI_INTERFACE
|
||||
|
||||
#if CONFIG_SSD1306_128x64
|
||||
ESP_LOGI(TAG, "Panel is 128x64");
|
||||
ssd1306_init(&dev, 128, 64);
|
||||
int xmax = 127;
|
||||
int ymax = 63;
|
||||
int x_current = 63;
|
||||
int y_current = 31;
|
||||
#endif // CONFIG_SSD1306_128x64
|
||||
#if CONFIG_SSD1306_128x32
|
||||
ESP_LOGI(TAG, "Panel is 128x32");
|
||||
ssd1306_init(&dev, 128, 32);
|
||||
int xmax = 127;
|
||||
int ymax = 31;
|
||||
int x_current = 63;
|
||||
int y_current = 15;
|
||||
#endif // CONFIG_SSD1306_128x32
|
||||
|
||||
// Create queue
|
||||
app_event_hid = xQueueCreate(10, sizeof(HID_EVENT_t));
|
||||
configASSERT( app_event_hid );
|
||||
|
||||
// Start tasks
|
||||
xTaskCreate(&usb_hid_task, "usb_hid_task", 1024*2, NULL, 9, NULL);
|
||||
|
||||
// Allocate memory
|
||||
uint8_t *buffer = (uint8_t *)malloc(8*128); // 8 page 128 pixel
|
||||
if (buffer == NULL) {
|
||||
ESP_LOGE(TAG, "malloc failed");
|
||||
while(1) { vTaskDelay(1); }
|
||||
}
|
||||
|
||||
ssd1306_clear_screen(&dev, false);
|
||||
ssd1306_contrast(&dev, 0xff);
|
||||
ssd1306_display_text_x3(&dev, 0, "01234", 5, false);
|
||||
#if CONFIG_SSD1306_128x64
|
||||
ssd1306_display_text_x3(&dev, 4, "56789", 5, false);
|
||||
#endif
|
||||
ssd1306_get_buffer(&dev, buffer);
|
||||
|
||||
// Draw a cursor in the center
|
||||
int radius = 4;
|
||||
ESP_LOGD(TAG, "x_current=%d", x_current);
|
||||
ESP_LOGD(TAG, "y_current=%d", y_current);
|
||||
_ssd1306_cursor(&dev, x_current, y_current, radius, false);
|
||||
ssd1306_show_buffer(&dev);
|
||||
|
||||
// Wait event
|
||||
HID_EVENT_t hidEvent;
|
||||
while (1) {
|
||||
BaseType_t received = xQueueReceive(app_event_hid, &hidEvent, portMAX_DELAY);
|
||||
ESP_LOGI(TAG, "xQueueReceive received=%d hidEvent.hid_event_type=%d", received, hidEvent.hid_event_type);
|
||||
if (hidEvent.hid_event_type == APP_EVENT_MOUSE) {
|
||||
ESP_LOGI(TAG, "mouse_event.x_displacement=%d mouse_event.y_displacement=%d",
|
||||
hidEvent.mouse_event.x_displacement, hidEvent.mouse_event.y_displacement);
|
||||
ESP_LOGI(TAG, "mouse_event.button1=%d mouse_event.button2=%d mouse_event.button3=%d",
|
||||
hidEvent.mouse_event.button1, hidEvent.mouse_event.button2, hidEvent.mouse_event.button3);
|
||||
int x_temp = x_current + hidEvent.mouse_event.x_displacement;
|
||||
if ((x_temp+radius) <= xmax && (x_temp-radius) >= 0) x_current = x_temp;
|
||||
int y_temp = y_current + hidEvent.mouse_event.y_displacement;
|
||||
if ((y_temp+radius) <= ymax && (y_temp-radius) >= 0) y_current = y_temp;
|
||||
ssd1306_set_buffer(&dev, buffer);
|
||||
_ssd1306_cursor(&dev, x_current, y_current, radius, false);
|
||||
ssd1306_show_buffer(&dev);
|
||||
if (hidEvent.mouse_event.button1 == 1) {
|
||||
printf("x_current=%d y_current=%d\n", x_current, y_current);
|
||||
if (y_current > 20 && y_current < 32) continue;
|
||||
if (y_current > 52) continue;
|
||||
int selected = -1;
|
||||
if (x_current >= 24*0 && x_current <= 24*1-5) {
|
||||
selected = 0;
|
||||
} else if (x_current >= 24*1 && x_current <= 24*2-5) {
|
||||
selected = 1;
|
||||
} else if (x_current >= 24*2 && x_current <= 24*3-5) {
|
||||
selected = 2;
|
||||
} else if (x_current >= 24*3 && x_current <= 24*4-5) {
|
||||
selected = 3;
|
||||
} else if (x_current >= 24*4 && x_current <= 24*5-5) {
|
||||
selected = 4;
|
||||
}
|
||||
if (selected == -1) continue;
|
||||
if (y_current >= 32) selected = selected + 5;
|
||||
printf("selected=%d\n", selected);
|
||||
ssd1306_clear_screen(&dev, false);
|
||||
char text[12];
|
||||
sprintf(text, "%d", selected);
|
||||
ssd1306_display_text_x3(&dev, 0, text, 1, false);
|
||||
vTaskDelay(300);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
598
MouseSelectDemo/main/usb_hid.c
Normal file
598
MouseSelectDemo/main/usb_hid.c
Normal file
@ -0,0 +1,598 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "usb/usb_host.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
#include "usb/hid_host.h"
|
||||
#include "usb/hid_usage_keyboard.h"
|
||||
#include "usb/hid_usage_mouse.h"
|
||||
|
||||
#include "usb_hid.h"
|
||||
|
||||
static const char *TAG = "usb_hid";
|
||||
|
||||
extern QueueHandle_t app_event_hid;
|
||||
QueueHandle_t app_event_queue = NULL;
|
||||
|
||||
/**
|
||||
* @brief APP event group
|
||||
*
|
||||
* Application logic can be different. There is a one among other ways to distingiush the
|
||||
* event by application event group.
|
||||
* In this example we have two event groups:
|
||||
* APP_EVENT - General event, which is APP_QUIT_PIN press event (Generally, it is IO0).
|
||||
* APP_EVENT_HID_HOST - HID Host Driver event, such as device connection/disconnection or input report.
|
||||
*/
|
||||
typedef enum {
|
||||
APP_EVENT = 0,
|
||||
APP_EVENT_HID_HOST
|
||||
} app_event_group_t;
|
||||
|
||||
/**
|
||||
* @brief APP event queue
|
||||
*
|
||||
* This event is used for delivering the HID Host event from callback to a task.
|
||||
*/
|
||||
typedef struct {
|
||||
app_event_group_t event_group;
|
||||
/* HID Host - Device related info */
|
||||
struct {
|
||||
hid_host_device_handle_t handle;
|
||||
hid_host_driver_event_t event;
|
||||
void *arg;
|
||||
} hid_host_device;
|
||||
} app_event_queue_t;
|
||||
|
||||
/**
|
||||
* @brief HID Protocol string names
|
||||
*/
|
||||
static const char *hid_proto_name_str[] = {
|
||||
"NONE",
|
||||
"KEYBOARD",
|
||||
"MOUSE"
|
||||
};
|
||||
|
||||
/* Main char symbol for ENTER key */
|
||||
#define KEYBOARD_ENTER_MAIN_CHAR '\r'
|
||||
#if 0
|
||||
/* When set to 1 pressing ENTER will be extending with LineFeed during serial debug output */
|
||||
#define KEYBOARD_ENTER_LF_EXTEND 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Scancode to ascii table
|
||||
*/
|
||||
const uint8_t keycode2ascii [57][2] = {
|
||||
{0, 0}, /* HID_KEY_NO_PRESS */
|
||||
{0, 0}, /* HID_KEY_ROLLOVER */
|
||||
{0, 0}, /* HID_KEY_POST_FAIL */
|
||||
{0, 0}, /* HID_KEY_ERROR_UNDEFINED */
|
||||
{'a', 'A'}, /* HID_KEY_A */
|
||||
{'b', 'B'}, /* HID_KEY_B */
|
||||
{'c', 'C'}, /* HID_KEY_C */
|
||||
{'d', 'D'}, /* HID_KEY_D */
|
||||
{'e', 'E'}, /* HID_KEY_E */
|
||||
{'f', 'F'}, /* HID_KEY_F */
|
||||
{'g', 'G'}, /* HID_KEY_G */
|
||||
{'h', 'H'}, /* HID_KEY_H */
|
||||
{'i', 'I'}, /* HID_KEY_I */
|
||||
{'j', 'J'}, /* HID_KEY_J */
|
||||
{'k', 'K'}, /* HID_KEY_K */
|
||||
{'l', 'L'}, /* HID_KEY_L */
|
||||
{'m', 'M'}, /* HID_KEY_M */
|
||||
{'n', 'N'}, /* HID_KEY_N */
|
||||
{'o', 'O'}, /* HID_KEY_O */
|
||||
{'p', 'P'}, /* HID_KEY_P */
|
||||
{'q', 'Q'}, /* HID_KEY_Q */
|
||||
{'r', 'R'}, /* HID_KEY_R */
|
||||
{'s', 'S'}, /* HID_KEY_S */
|
||||
{'t', 'T'}, /* HID_KEY_T */
|
||||
{'u', 'U'}, /* HID_KEY_U */
|
||||
{'v', 'V'}, /* HID_KEY_V */
|
||||
{'w', 'W'}, /* HID_KEY_W */
|
||||
{'x', 'X'}, /* HID_KEY_X */
|
||||
{'y', 'Y'}, /* HID_KEY_Y */
|
||||
{'z', 'Z'}, /* HID_KEY_Z */
|
||||
{'1', '!'}, /* HID_KEY_1 */
|
||||
{'2', '@'}, /* HID_KEY_2 */
|
||||
{'3', '#'}, /* HID_KEY_3 */
|
||||
{'4', '$'}, /* HID_KEY_4 */
|
||||
{'5', '%'}, /* HID_KEY_5 */
|
||||
{'6', '^'}, /* HID_KEY_6 */
|
||||
{'7', '&'}, /* HID_KEY_7 */
|
||||
{'8', '*'}, /* HID_KEY_8 */
|
||||
{'9', '('}, /* HID_KEY_9 */
|
||||
{'0', ')'}, /* HID_KEY_0 */
|
||||
{KEYBOARD_ENTER_MAIN_CHAR, KEYBOARD_ENTER_MAIN_CHAR}, /* HID_KEY_ENTER */
|
||||
{0, 0}, /* HID_KEY_ESC */
|
||||
{'\b', 0}, /* HID_KEY_DEL */
|
||||
{0, 0}, /* HID_KEY_TAB */
|
||||
{' ', ' '}, /* HID_KEY_SPACE */
|
||||
{'-', '_'}, /* HID_KEY_MINUS */
|
||||
{'=', '+'}, /* HID_KEY_EQUAL */
|
||||
{'[', '{'}, /* HID_KEY_OPEN_BRACKET */
|
||||
{']', '}'}, /* HID_KEY_CLOSE_BRACKET */
|
||||
{'\\', '|'}, /* HID_KEY_BACK_SLASH */
|
||||
{'\\', '|'}, /* HID_KEY_SHARP */ // HOTFIX: for NonUS Keyboards repeat HID_KEY_BACK_SLASH
|
||||
{';', ':'}, /* HID_KEY_COLON */
|
||||
{'\'', '"'}, /* HID_KEY_QUOTE */
|
||||
{'`', '~'}, /* HID_KEY_TILDE */
|
||||
{',', '<'}, /* HID_KEY_LESS */
|
||||
{'.', '>'}, /* HID_KEY_GREATER */
|
||||
{'/', '?'} /* HID_KEY_SLASH */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Makes new line depending on report output protocol type
|
||||
*
|
||||
* @param[in] proto Current protocol to output
|
||||
*/
|
||||
static void hid_print_new_device_report_header(hid_protocol_t proto)
|
||||
{
|
||||
static hid_protocol_t prev_proto_output = -1;
|
||||
|
||||
if (prev_proto_output != proto) {
|
||||
prev_proto_output = proto;
|
||||
printf("\r\n");
|
||||
if (proto == HID_PROTOCOL_MOUSE) {
|
||||
printf("Mouse\r\n");
|
||||
} else if (proto == HID_PROTOCOL_KEYBOARD) {
|
||||
printf("Keyboard\r\n");
|
||||
} else {
|
||||
printf("Generic\r\n");
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HID Keyboard modifier verification for capitalization application (right or left shift)
|
||||
*
|
||||
* @param[in] modifier
|
||||
* @return true Modifier was pressed (left or right shift)
|
||||
* @return false Modifier was not pressed (left or right shift)
|
||||
*
|
||||
*/
|
||||
static inline bool hid_keyboard_is_modifier_shift(uint8_t modifier)
|
||||
{
|
||||
if (((modifier & HID_LEFT_SHIFT) == HID_LEFT_SHIFT) ||
|
||||
((modifier & HID_RIGHT_SHIFT) == HID_RIGHT_SHIFT)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HID Keyboard get char symbol from key code
|
||||
*
|
||||
* @param[in] modifier Keyboard modifier data
|
||||
* @param[in] key_code Keyboard key code
|
||||
* @param[in] key_char Pointer to key char data
|
||||
*
|
||||
* @return true Key scancode converted successfully
|
||||
* @return false Key scancode unknown
|
||||
*/
|
||||
static inline bool hid_keyboard_get_char(uint8_t modifier,
|
||||
uint8_t key_code,
|
||||
unsigned char *key_char)
|
||||
{
|
||||
uint8_t mod = (hid_keyboard_is_modifier_shift(modifier)) ? 1 : 0;
|
||||
|
||||
if ((key_code >= HID_KEY_A) && (key_code <= HID_KEY_SLASH)) {
|
||||
*key_char = keycode2ascii[key_code][mod];
|
||||
} else {
|
||||
// All other key pressed
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HID Keyboard print char symbol
|
||||
*
|
||||
* @param[in] key_char Keyboard char to stdout
|
||||
*/
|
||||
#if 0
|
||||
static inline void hid_keyboard_print_char(unsigned int key_char)
|
||||
{
|
||||
if (!!key_char) {
|
||||
putchar(key_char);
|
||||
#if (KEYBOARD_ENTER_LF_EXTEND)
|
||||
if (KEYBOARD_ENTER_MAIN_CHAR == key_char) {
|
||||
putchar('\n');
|
||||
}
|
||||
#endif // KEYBOARD_ENTER_LF_EXTEND
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Key Event. Key event with the key code, state and modifier.
|
||||
*
|
||||
* @param[in] key_event Pointer to Key Event structure
|
||||
*
|
||||
*/
|
||||
static void key_event_callback(key_event_t *key_event)
|
||||
{
|
||||
ESP_LOGI(TAG, "key_event_callback key_event->state=%d", key_event->state);
|
||||
unsigned char key_char;
|
||||
|
||||
hid_print_new_device_report_header(HID_PROTOCOL_KEYBOARD);
|
||||
HID_EVENT_t hidEvent;
|
||||
hidEvent.hid_event_type = APP_EVENT_KEYBOARD;
|
||||
|
||||
if (KEY_STATE_PRESSED == key_event->state) {
|
||||
ESP_LOGI(TAG, "key_event_callback key_event->modifier=%d key_event->key_code=%d", key_event->modifier, key_event->key_code);
|
||||
if (hid_keyboard_get_char(key_event->modifier,
|
||||
key_event->key_code, &key_char)) {
|
||||
|
||||
hidEvent.key_event.state = KEY_STATE_PRESSED;
|
||||
hidEvent.key_event.modifier = key_event->modifier;
|
||||
hidEvent.key_event.key_code = key_event->key_code;
|
||||
hidEvent.key_event.key_char = key_char;
|
||||
xQueueSendFromISR(app_event_hid, &hidEvent, NULL);
|
||||
#if 0
|
||||
hid_keyboard_print_char(key_char);
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
if (KEY_STATE_RELEASED == key_event->state) {
|
||||
hidEvent.key_event.state = KEY_STATE_RELEASED;
|
||||
xQueueSendFromISR(app_event_hid, &hidEvent, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Key buffer scan code search.
|
||||
*
|
||||
* @param[in] src Pointer to source buffer where to search
|
||||
* @param[in] key Key scancode to search
|
||||
* @param[in] length Size of the source buffer
|
||||
*/
|
||||
static inline bool key_found(const uint8_t *const src,
|
||||
uint8_t key,
|
||||
unsigned int length)
|
||||
{
|
||||
for (unsigned int i = 0; i < length; i++) {
|
||||
ESP_LOGD(TAG, "key_found src[%d]=%d key=%d", i, src[i], key);
|
||||
if (src[i] == key) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USB HID Host Keyboard Interface report callback handler
|
||||
*
|
||||
* @param[in] data Pointer to input report data buffer
|
||||
* @param[in] length Length of input report data buffer
|
||||
*/
|
||||
static void hid_host_keyboard_report_callback(const uint8_t *const data, const int length)
|
||||
{
|
||||
hid_keyboard_input_report_boot_t *kb_report = (hid_keyboard_input_report_boot_t *)data;
|
||||
|
||||
if (length < sizeof(hid_keyboard_input_report_boot_t)) {
|
||||
return;
|
||||
}
|
||||
|
||||
static uint8_t prev_keys[HID_KEYBOARD_KEY_MAX] = { 0 };
|
||||
key_event_t key_event;
|
||||
|
||||
for (int i = 0; i < HID_KEYBOARD_KEY_MAX; i++) {
|
||||
|
||||
// key has been released verification
|
||||
if (prev_keys[i] > HID_KEY_ERROR_UNDEFINED &&
|
||||
!key_found(kb_report->key, prev_keys[i], HID_KEYBOARD_KEY_MAX)) {
|
||||
key_event.key_code = prev_keys[i];
|
||||
key_event.modifier = 0;
|
||||
key_event.state = KEY_STATE_RELEASED;
|
||||
key_event_callback(&key_event);
|
||||
}
|
||||
|
||||
// key has been pressed verification
|
||||
if (kb_report->key[i] > HID_KEY_ERROR_UNDEFINED &&
|
||||
!key_found(prev_keys, kb_report->key[i], HID_KEYBOARD_KEY_MAX)) {
|
||||
key_event.key_code = kb_report->key[i];
|
||||
key_event.modifier = kb_report->modifier.val;
|
||||
key_event.state = KEY_STATE_PRESSED;
|
||||
key_event_callback(&key_event);
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(prev_keys, &kb_report->key, HID_KEYBOARD_KEY_MAX);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USB HID Host Mouse Interface report callback handler
|
||||
*
|
||||
* @param[in] data Pointer to input report data buffer
|
||||
* @param[in] length Length of input report data buffer
|
||||
*/
|
||||
static void hid_host_mouse_report_callback(const uint8_t *const data, const int length)
|
||||
{
|
||||
hid_mouse_input_report_boot_t *mouse_report = (hid_mouse_input_report_boot_t *)data;
|
||||
|
||||
if (length < sizeof(hid_mouse_input_report_boot_t)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "hid_host_mouse_report_callback mouse_report->x_displacement=%d mouse_report->y_displacement=%d",
|
||||
mouse_report->x_displacement, mouse_report->y_displacement);
|
||||
ESP_LOGD(TAG, "hid_host_mouse_report_callback mouse_report->buttons.button1=%d mouse_report->buttons.button2=%d",
|
||||
mouse_report->buttons.button1, mouse_report->buttons.button2);
|
||||
HID_EVENT_t hidEvent;
|
||||
hidEvent.hid_event_type = APP_EVENT_MOUSE;
|
||||
hidEvent.mouse_event.x_displacement = mouse_report->x_displacement;
|
||||
hidEvent.mouse_event.y_displacement = mouse_report->y_displacement;
|
||||
hidEvent.mouse_event.button1 = mouse_report->buttons.button1;
|
||||
hidEvent.mouse_event.button2 = mouse_report->buttons.button2;
|
||||
hidEvent.mouse_event.button3 = mouse_report->buttons.button3;
|
||||
xQueueSendFromISR(app_event_hid, &hidEvent, NULL);
|
||||
|
||||
#if 0
|
||||
static int x_pos = 0;
|
||||
static int y_pos = 0;
|
||||
|
||||
// Calculate absolute position from displacement
|
||||
x_pos += mouse_report->x_displacement;
|
||||
y_pos += mouse_report->y_displacement;
|
||||
|
||||
hid_print_new_device_report_header(HID_PROTOCOL_MOUSE);
|
||||
|
||||
printf("X: %06d\tY: %06d\t|%c|%c|\r",
|
||||
x_pos, y_pos,
|
||||
(mouse_report->buttons.button1 ? 'o' : ' '),
|
||||
(mouse_report->buttons.button2 ? 'o' : ' '));
|
||||
fflush(stdout);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USB HID Host Generic Interface report callback handler
|
||||
*
|
||||
* 'generic' means anything else than mouse or keyboard
|
||||
*
|
||||
* @param[in] data Pointer to input report data buffer
|
||||
* @param[in] length Length of input report data buffer
|
||||
*/
|
||||
static void hid_host_generic_report_callback(const uint8_t *const data, const int length)
|
||||
{
|
||||
hid_print_new_device_report_header(HID_PROTOCOL_NONE);
|
||||
for (int i = 0; i < length; i++) {
|
||||
printf("%02X", data[i]);
|
||||
}
|
||||
putchar('\r');
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USB HID Host interface callback
|
||||
*
|
||||
* @param[in] hid_device_handle HID Device handle
|
||||
* @param[in] event HID Host interface event
|
||||
* @param[in] arg Pointer to arguments, does not used
|
||||
*/
|
||||
void hid_host_interface_callback(hid_host_device_handle_t hid_device_handle,
|
||||
const hid_host_interface_event_t event,
|
||||
void *arg)
|
||||
{
|
||||
ESP_LOGD(TAG, "hid_host_interface_callback event=%d", event);
|
||||
uint8_t data[64] = { 0 };
|
||||
size_t data_length = 0;
|
||||
hid_host_dev_params_t dev_params;
|
||||
ESP_ERROR_CHECK(hid_host_device_get_params(hid_device_handle, &dev_params));
|
||||
|
||||
switch (event) {
|
||||
case HID_HOST_INTERFACE_EVENT_INPUT_REPORT:
|
||||
ESP_ERROR_CHECK(hid_host_device_get_raw_input_report_data(hid_device_handle,
|
||||
data,
|
||||
64,
|
||||
&data_length));
|
||||
|
||||
if (HID_SUBCLASS_BOOT_INTERFACE == dev_params.sub_class) {
|
||||
if (HID_PROTOCOL_KEYBOARD == dev_params.proto) {
|
||||
hid_host_keyboard_report_callback(data, data_length);
|
||||
} else if (HID_PROTOCOL_MOUSE == dev_params.proto) {
|
||||
hid_host_mouse_report_callback(data, data_length);
|
||||
}
|
||||
} else {
|
||||
hid_host_generic_report_callback(data, data_length);
|
||||
}
|
||||
|
||||
break;
|
||||
case HID_HOST_INTERFACE_EVENT_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "HID Device, protocol '%s' DISCONNECTED",
|
||||
hid_proto_name_str[dev_params.proto]);
|
||||
ESP_ERROR_CHECK(hid_host_device_close(hid_device_handle));
|
||||
break;
|
||||
case HID_HOST_INTERFACE_EVENT_TRANSFER_ERROR:
|
||||
ESP_LOGE(TAG, "HID Device, protocol '%s' TRANSFER_ERROR",
|
||||
hid_proto_name_str[dev_params.proto]);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "HID Device, protocol '%s' Unhandled event",
|
||||
hid_proto_name_str[dev_params.proto]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USB HID Host Device event
|
||||
*
|
||||
* @param[in] hid_device_handle HID Device handle
|
||||
* @param[in] event HID Host Device event
|
||||
* @param[in] arg Pointer to arguments, does not used
|
||||
*/
|
||||
void hid_host_device_event(hid_host_device_handle_t hid_device_handle,
|
||||
const hid_host_driver_event_t event,
|
||||
void *arg)
|
||||
{
|
||||
hid_host_dev_params_t dev_params;
|
||||
ESP_ERROR_CHECK(hid_host_device_get_params(hid_device_handle, &dev_params));
|
||||
|
||||
switch (event) {
|
||||
case HID_HOST_DRIVER_EVENT_CONNECTED:
|
||||
ESP_LOGI(TAG, "HID Device, protocol '%s' CONNECTED",
|
||||
hid_proto_name_str[dev_params.proto]);
|
||||
|
||||
const hid_host_device_config_t dev_config = {
|
||||
.callback = hid_host_interface_callback,
|
||||
.callback_arg = NULL
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK(hid_host_device_open(hid_device_handle, &dev_config));
|
||||
#if 1
|
||||
if (HID_SUBCLASS_BOOT_INTERFACE == dev_params.sub_class) {
|
||||
ESP_ERROR_CHECK(hid_class_request_set_protocol(hid_device_handle, HID_REPORT_PROTOCOL_BOOT));
|
||||
if (HID_PROTOCOL_KEYBOARD == dev_params.proto) {
|
||||
ESP_ERROR_CHECK(hid_class_request_set_idle(hid_device_handle, 0, 0));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
ESP_ERROR_CHECK(hid_host_device_start(hid_device_handle));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start USB Host install and handle common USB host library events while app pin not low
|
||||
*
|
||||
* @param[in] arg Not used
|
||||
*/
|
||||
static void usb_lib_task(void *arg)
|
||||
{
|
||||
const usb_host_config_t host_config = {
|
||||
.skip_phy_setup = false,
|
||||
.intr_flags = ESP_INTR_FLAG_LEVEL1,
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK(usb_host_install(&host_config));
|
||||
xTaskNotifyGive(arg);
|
||||
|
||||
while (true) {
|
||||
uint32_t event_flags;
|
||||
usb_host_lib_handle_events(portMAX_DELAY, &event_flags);
|
||||
ESP_LOGI(pcTaskGetName(NULL), "event_flags=0x%"PRIx32, event_flags);
|
||||
// In this example, there is only one client registered
|
||||
// So, once we deregister the client, this call must succeed with ESP_OK
|
||||
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) {
|
||||
ESP_ERROR_CHECK(usb_host_device_free_all());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "USB shutdown");
|
||||
// Clean up USB Host
|
||||
vTaskDelay(10); // Short delay to allow clients clean-up
|
||||
ESP_ERROR_CHECK(usb_host_uninstall());
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HID Host Device callback
|
||||
*
|
||||
* Puts new HID Device event to the queue
|
||||
*
|
||||
* @param[in] hid_device_handle HID Device handle
|
||||
* @param[in] event HID Device event
|
||||
* @param[in] arg Not used
|
||||
*/
|
||||
void hid_host_device_callback(hid_host_device_handle_t hid_device_handle,
|
||||
const hid_host_driver_event_t event,
|
||||
void *arg)
|
||||
{
|
||||
ESP_LOGI(TAG, "hid_host_device_callback");
|
||||
const app_event_queue_t evt_queue = {
|
||||
.event_group = APP_EVENT_HID_HOST,
|
||||
// HID Host Device related info
|
||||
.hid_host_device.handle = hid_device_handle,
|
||||
.hid_host_device.event = event,
|
||||
.hid_host_device.arg = arg
|
||||
};
|
||||
|
||||
if (app_event_queue) {
|
||||
xQueueSend(app_event_queue, &evt_queue, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void usb_hid_task(void *pvParameters)
|
||||
{
|
||||
BaseType_t task_created;
|
||||
app_event_queue_t evt_queue;
|
||||
ESP_LOGI(TAG, "HID Host example");
|
||||
|
||||
/*
|
||||
* Create usb_lib_task to:
|
||||
* - initialize USB Host library
|
||||
* - Handle USB Host events while APP pin in in HIGH state
|
||||
*/
|
||||
task_created = xTaskCreatePinnedToCore(usb_lib_task,
|
||||
"usb_events",
|
||||
4096,
|
||||
xTaskGetCurrentTaskHandle(),
|
||||
2, NULL, 0);
|
||||
assert(task_created == pdTRUE);
|
||||
|
||||
// Wait for notification from usb_lib_task to proceed
|
||||
ulTaskNotifyTake(false, 1000);
|
||||
|
||||
/*
|
||||
* HID host driver configuration
|
||||
* - create background task for handling low level event inside the HID driver
|
||||
* - provide the device callback to get new HID Device connection event
|
||||
*/
|
||||
const hid_host_driver_config_t hid_host_driver_config = {
|
||||
.create_background_task = true,
|
||||
.task_priority = 5,
|
||||
.stack_size = 4096,
|
||||
.core_id = 0,
|
||||
.callback = hid_host_device_callback,
|
||||
.callback_arg = NULL
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK(hid_host_install(&hid_host_driver_config));
|
||||
|
||||
// Create queue
|
||||
app_event_queue = xQueueCreate(10, sizeof(app_event_queue_t));
|
||||
configASSERT( app_event_queue );
|
||||
|
||||
ESP_LOGI(TAG, "Waiting for HID Device to be connected");
|
||||
|
||||
while (1) {
|
||||
// Wait queue
|
||||
if (xQueueReceive(app_event_queue, &evt_queue, portMAX_DELAY)) {
|
||||
if (APP_EVENT_HID_HOST == evt_queue.event_group) {
|
||||
hid_host_device_event(evt_queue.hid_host_device.handle,
|
||||
evt_queue.hid_host_device.event,
|
||||
evt_queue.hid_host_device.arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Never reach here
|
||||
ESP_LOGI(TAG, "HID Driver uninstall");
|
||||
ESP_ERROR_CHECK(hid_host_uninstall());
|
||||
xQueueReset(app_event_queue);
|
||||
vQueueDelete(app_event_queue);
|
||||
}
|
28
MouseSelectDemo/main/usb_hid.h
Normal file
28
MouseSelectDemo/main/usb_hid.h
Normal file
@ -0,0 +1,28 @@
|
||||
typedef enum {
|
||||
APP_EVENT_KEYBOARD = 0,
|
||||
APP_EVENT_MOUSE
|
||||
} hid_event_type_t;
|
||||
|
||||
typedef struct {
|
||||
enum key_state {
|
||||
KEY_STATE_PRESSED = 0x00,
|
||||
KEY_STATE_RELEASED = 0x01
|
||||
} state;
|
||||
uint8_t modifier;
|
||||
uint8_t key_code;
|
||||
unsigned char key_char;
|
||||
} key_event_t;
|
||||
|
||||
typedef struct {
|
||||
int x_displacement;
|
||||
int y_displacement;
|
||||
int button1;
|
||||
int button2;
|
||||
int button3;
|
||||
} mouse_event_t;
|
||||
|
||||
typedef struct {
|
||||
hid_event_type_t hid_event_type;
|
||||
key_event_t key_event;
|
||||
mouse_event_t mouse_event;
|
||||
} HID_EVENT_t;
|
18
MouseSelectDemo/sdkconfig.defaults
Normal file
18
MouseSelectDemo/sdkconfig.defaults
Normal file
@ -0,0 +1,18 @@
|
||||
#
|
||||
# ESP32-specific
|
||||
#
|
||||
CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
|
||||
CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240
|
||||
|
||||
#
|
||||
# ESP32S2-specific
|
||||
#
|
||||
CONFIG_ESP32S2_DEFAULT_CPU_FREQ_240=y
|
||||
CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ=240
|
||||
|
||||
#
|
||||
# ESP32S3-specific
|
||||
#
|
||||
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240=y
|
||||
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ=240
|
||||
|
Loading…
Reference in New Issue
Block a user