From 5211ddf9ef88cdaea4ef07fd56ce0f916a6e5e6a Mon Sep 17 00:00:00 2001 From: nopnop2002 Date: Thu, 22 Aug 2024 14:13:50 +0900 Subject: [PATCH] added MouseIconDemo --- KeyboardDemo/main/usb_hid.c | 1 - MouseIconDemo/CMakeLists.txt | 8 + MouseIconDemo/README.md | 68 +++ MouseIconDemo/images/mouse_all.jpg | Bin 0 -> 2001 bytes MouseIconDemo/images/mouse_left.jpg | Bin 0 -> 1992 bytes MouseIconDemo/images/mouse_left_middle.jpg | Bin 0 -> 1991 bytes MouseIconDemo/images/mouse_left_right.jpg | Bin 0 -> 2017 bytes MouseIconDemo/images/mouse_middle.jpg | Bin 0 -> 2021 bytes MouseIconDemo/images/mouse_none.jpg | Bin 0 -> 1455 bytes MouseIconDemo/images/mouse_right.jpg | Bin 0 -> 1989 bytes MouseIconDemo/images/mouse_right_middle.jpg | Bin 0 -> 1981 bytes MouseIconDemo/main/CMakeLists.txt | 1 + MouseIconDemo/main/component.mk | 8 + MouseIconDemo/main/idf_component.yml | 4 + MouseIconDemo/main/main.c | 410 ++++++++++++++ MouseIconDemo/main/usb_hid.c | 598 ++++++++++++++++++++ MouseIconDemo/main/usb_hid.h | 28 + MouseIconDemo/sdkconfig.defaults | 18 + MouseMoveDemo/main/usb_hid.c | 1 - 19 files changed, 1143 insertions(+), 2 deletions(-) create mode 100644 MouseIconDemo/CMakeLists.txt create mode 100644 MouseIconDemo/README.md create mode 100644 MouseIconDemo/images/mouse_all.jpg create mode 100644 MouseIconDemo/images/mouse_left.jpg create mode 100644 MouseIconDemo/images/mouse_left_middle.jpg create mode 100644 MouseIconDemo/images/mouse_left_right.jpg create mode 100644 MouseIconDemo/images/mouse_middle.jpg create mode 100644 MouseIconDemo/images/mouse_none.jpg create mode 100644 MouseIconDemo/images/mouse_right.jpg create mode 100644 MouseIconDemo/images/mouse_right_middle.jpg create mode 100644 MouseIconDemo/main/CMakeLists.txt create mode 100644 MouseIconDemo/main/component.mk create mode 100644 MouseIconDemo/main/idf_component.yml create mode 100644 MouseIconDemo/main/main.c create mode 100644 MouseIconDemo/main/usb_hid.c create mode 100644 MouseIconDemo/main/usb_hid.h create mode 100644 MouseIconDemo/sdkconfig.defaults diff --git a/KeyboardDemo/main/usb_hid.c b/KeyboardDemo/main/usb_hid.c index b7f2934..75b0763 100644 --- a/KeyboardDemo/main/usb_hid.c +++ b/KeyboardDemo/main/usb_hid.c @@ -16,7 +16,6 @@ #include "esp_err.h" #include "esp_log.h" #include "usb/usb_host.h" -//#include "errno.h" #include "driver/gpio.h" #include "usb/hid_host.h" diff --git a/MouseIconDemo/CMakeLists.txt b/MouseIconDemo/CMakeLists.txt new file mode 100644 index 0000000..2aa16fe --- /dev/null +++ b/MouseIconDemo/CMakeLists.txt @@ -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) diff --git a/MouseIconDemo/README.md b/MouseIconDemo/README.md new file mode 100644 index 0000000..3a38266 --- /dev/null +++ b/MouseIconDemo/README.md @@ -0,0 +1,68 @@ +# MouseIconDemo for SSD1306 +Demo of changing images using the mouse. +I used [this](https://github.com/espressif/esp-idf/tree/master/examples/peripherals/usb/host/hid) as a reference. + +The image changes according to mouse clicks. +![usb-mouse-icon-1](https://github.com/user-attachments/assets/d997d144-cecc-4ba0-85c7-368da0d8d8ed) +![usb-mouse-icon-2](https://github.com/user-attachments/assets/af54ffc9-533a-4a00-a2d3-704c81d3f597) +![usb-mouse-icon-3](https://github.com/user-attachments/assets/b576d55f-5e3e-4dfd-b433-6a92771a5b03) + +I borrowed the BIT MAP data from here. +https://thenounproject.com/icon/mouse-6617048/ + +# 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 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). + diff --git a/MouseIconDemo/images/mouse_all.jpg b/MouseIconDemo/images/mouse_all.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4891d3d8f9d1ef36c091ff5cc91265208e6e3f87 GIT binary patch literal 2001 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 nM(gt!nteN)5pkfv_f5BHzu?8! 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 MJQtW%=K^TvR|EoN`Tzg` literal 0 HcmV?d00001 diff --git a/MouseIconDemo/images/mouse_none.jpg b/MouseIconDemo/images/mouse_none.jpg new file mode 100644 index 0000000000000000000000000000000000000000..10eb60506d39d7fab779fb3039fa41cfa18a9095 GIT binary patch literal 1455 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 literal 0 HcmV?d00001 diff --git a/MouseIconDemo/images/mouse_right_middle.jpg b/MouseIconDemo/images/mouse_right_middle.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7e5ef1ce7dfc91e8672d6af1c0b893f2eb217abb GIT binary patch literal 1981 zcmbW1e>l|H9>>qumzlwgF=IkanUG%
mkDh(ltHW}(-Yb&W08%B*8)GEa8Y*wXP zgVEv&H#a}p){j9*?M=vp-OLPa6q)g>!Hn7O?C!JsJp0$Z`#$G$p3ig6=bZC-ozL?e z)k~EK==*v5dIJc8KqS(DN({W|%;;kP1O$MM000cogopq}JP2tZNMAi7@yHNF0Ghwf z16_k4;-5Y;2UNqr3ur))y8kX%3swuIsR?VLQE0T7>o`Ejn={G=;&e*p|$n! zIIN!9S0AF@uHJ=oEC!8HNBn{r-qSaiG zMiOE$K~u|g3yQcS2ptt?VCIm9A?@TA-4ke=I|fTveG>m%$8dv_*g~d8`<3i}155u~ zWPgDD$u$J9FoYBjCIA{xDvGnbx00YyUL9wuO+r#|h@L4uLIxRSq_ zjg#L>i527Z8IBZ7`hz^57*97;x`dw6ekRAB!Wx5@K{0nP-4>99EBwX2@@l2eY#~0A zCK?euT+trJRzAJTeAj_DH>nztel>#S?Qf|%vZ6;;<|S})cr_HoW?Pf+ZO!666R%7M zoEse^*7&uyxv?@GQhl1M)xxkt%vK#gI(DT=JjJpsZmV z$!UTax$u!$pZ|adY*(HH=fq3>!s3#QBYRPiF1W(9t5<}LiX+NQ6*$ewjli&iM3tW} ztk+GTYj>GCX=F`dmug z&2PsGQtntPS(ZJh7!VK&g{x@PrKhmChv{Qb?ZUTb@BRDz%9X< zR=#rfEwE7+pmd)%9k9Gq$PZ6Dt^(;C-zdu$-}g4HXLj_yHUChU$4sBkvY$ND%^^g@ z9(+^UMq3w#l-!yl;@@_W(ynX>popGLeI#*}anfrSbD!YMA2}9R-6=Wb#||x+;D=v! ztPQ=kBj1Wrhw~e!eGhWxV!e}3K=XI$meoMGdz8UJ$-&_2raF;p0OZ& zQ{Vn<-4Jq7C{4s?YfF7Dj2%8AdNwJLILSCU&hov>xQIvg=5{wr!n-{gVJ}KzGGz}A zq?@)uU*UT$u9PnJmBAWWz{XW)XWmU5h~t^Cf!uY0Cl9Y+QY7e%xn@IV;GyitjeQ9i zR@a@?T~R&!^0rOo*t<|L<_Ffb669)!CJ*)x=^wd@e5MXd0w{t+MHn+&Vs&Y~EN{&@ z4mRXNhot<8Fh zZRiV;{RZ;lhDL_vL*}7R8LRr%b8pYjSGVv|J#otGY|?}$TFwzSQd`-ip5mEP_kZ%F f+F5(YhtAtg#y_3(cPEB^?OQdJ1+0s+fNJm;ie*x4 literal 0 HcmV?d00001 diff --git a/MouseIconDemo/main/CMakeLists.txt b/MouseIconDemo/main/CMakeLists.txt new file mode 100644 index 0000000..660507f --- /dev/null +++ b/MouseIconDemo/main/CMakeLists.txt @@ -0,0 +1 @@ +idf_component_register(SRCS "main.c" "usb_hid.c" INCLUDE_DIRS "." REQUIRED_IDF_TARGETS esp32s2 esp32s3) diff --git a/MouseIconDemo/main/component.mk b/MouseIconDemo/main/component.mk new file mode 100644 index 0000000..61f8990 --- /dev/null +++ b/MouseIconDemo/main/component.mk @@ -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. +# diff --git a/MouseIconDemo/main/idf_component.yml b/MouseIconDemo/main/idf_component.yml new file mode 100644 index 0000000..0c3620e --- /dev/null +++ b/MouseIconDemo/main/idf_component.yml @@ -0,0 +1,4 @@ +## IDF Component Manager Manifest File +dependencies: + idf: ">=4.4" + usb_host_hid: "^1.0.1" diff --git a/MouseIconDemo/main/main.c b/MouseIconDemo/main/main.c new file mode 100644 index 0000000..30ee054 --- /dev/null +++ b/MouseIconDemo/main/main.c @@ -0,0 +1,410 @@ +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "esp_log.h" + +#include "ssd1306.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" + +#define IMAGES 8 +// https://thenounproject.com/icon/mouse-6617048/ +uint8_t mouse[IMAGES][512] = { +{ +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0x82, 0x41, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3e, 0x7c, 0x7f, 0xff, 0xff, +0xff, 0xff, 0xfc, 0xfe, 0x7f, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xfe, 0x7f, 0x9f, 0xff, 0xff, +0xff, 0xff, 0xf3, 0xfe, 0x7f, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xfe, 0x7f, 0xe7, 0xff, 0xff, +0xff, 0xff, 0xcf, 0xfe, 0x7f, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xfc, 0x3f, 0xf3, 0xff, 0xff, +0xff, 0xff, 0xdf, 0xf9, 0x9f, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xfb, 0xdf, 0xf9, 0xff, 0xff, +0xff, 0xff, 0x9f, 0xf3, 0xcf, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xf3, 0xcf, 0xfd, 0xff, 0xff, +0xff, 0xff, 0xbf, 0xf3, 0xcf, 0xfd, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xf3, 0xcf, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xfb, 0xdf, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xf9, 0x9f, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xf8, 0x1f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xfe, 0x7f, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xfe, 0x7f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xfe, 0x7f, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xfe, 0x7f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xfe, 0x7f, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x1f, 0xfe, 0x7f, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0xbf, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xfd, 0xff, 0xff, +0xff, 0xff, 0x9f, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xf9, 0xff, 0xff, +0xff, 0xff, 0xdf, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xf3, 0xff, 0xff, +0xff, 0xff, 0xe7, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xe7, 0xff, 0xff, +0xff, 0xff, 0xf3, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0x9f, 0xff, 0xff, +0xff, 0xff, 0xfc, 0x7f, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x1f, 0xf8, 0x7f, 0xff, 0xff, +0xff, 0xff, 0xff, 0x81, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}, +{ +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0x80, 0x41, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x7c, 0x7f, 0xff, 0xff, +0xff, 0xff, 0xfc, 0x00, 0x7e, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x7f, 0x9f, 0xff, 0xff, +0xff, 0xff, 0xf0, 0x00, 0x7f, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x7f, 0xe7, 0xff, 0xff, +0xff, 0xff, 0xc0, 0x00, 0x7f, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x3f, 0xf3, 0xff, 0xff, +0xff, 0xff, 0xc0, 0x01, 0x9f, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x80, 0x03, 0xdf, 0xf9, 0xff, 0xff, +0xff, 0xff, 0x80, 0x03, 0xdf, 0xf9, 0xff, 0xff, 0xff, 0xff, 0x80, 0x03, 0xcf, 0xfd, 0xff, 0xff, +0xff, 0xff, 0x80, 0x03, 0xcf, 0xfd, 0xff, 0xff, 0xff, 0xff, 0x80, 0x03, 0xcf, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x00, 0x03, 0xdf, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x9f, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x00, 0x00, 0x1f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x7f, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x00, 0x00, 0x7f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x7f, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x00, 0x00, 0x7f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x7f, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x00, 0x00, 0x7f, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0xbf, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xfd, 0xff, 0xff, +0xff, 0xff, 0x9f, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xf9, 0xff, 0xff, +0xff, 0xff, 0xdf, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xf3, 0xff, 0xff, +0xff, 0xff, 0xe7, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xe7, 0xff, 0xff, +0xff, 0xff, 0xf3, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0x9f, 0xff, 0xff, +0xff, 0xff, 0xfc, 0x7f, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x1f, 0xf8, 0x7f, 0xff, 0xff, +0xff, 0xff, 0xff, 0x81, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}, +{ +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0x82, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3e, 0x00, 0x7f, 0xff, 0xff, +0xff, 0xff, 0xfc, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xfe, 0x00, 0x1f, 0xff, 0xff, +0xff, 0xff, 0xf3, 0xfe, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xfe, 0x00, 0x07, 0xff, 0xff, +0xff, 0xff, 0xcf, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xfc, 0x00, 0x03, 0xff, 0xff, +0xff, 0xff, 0xdf, 0xf9, 0x80, 0x03, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xfb, 0xc0, 0x01, 0xff, 0xff, +0xff, 0xff, 0x9f, 0xf3, 0xc0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xf3, 0xc0, 0x01, 0xff, 0xff, +0xff, 0xff, 0xbf, 0xf3, 0xc0, 0x01, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xf3, 0xc0, 0x01, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xfb, 0xc0, 0x00, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xf9, 0x80, 0x00, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xf8, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xfe, 0x00, 0x00, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xfe, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xfe, 0x00, 0x00, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xfe, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xfe, 0x00, 0x00, 0xff, 0xff, +0xff, 0xff, 0x1f, 0xfe, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0xbf, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xfd, 0xff, 0xff, +0xff, 0xff, 0x9f, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xf9, 0xff, 0xff, +0xff, 0xff, 0xdf, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xf3, 0xff, 0xff, +0xff, 0xff, 0xe7, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xe7, 0xff, 0xff, +0xff, 0xff, 0xf3, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0x9f, 0xff, 0xff, +0xff, 0xff, 0xfc, 0x7f, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x1f, 0xf8, 0x7f, 0xff, 0xff, +0xff, 0xff, 0xff, 0x81, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}, +{ +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0x82, 0x41, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3e, 0x7c, 0x7f, 0xff, 0xff, +0xff, 0xff, 0xfc, 0xfe, 0x7e, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xfe, 0x7f, 0x9f, 0xff, 0xff, +0xff, 0xff, 0xf3, 0xfe, 0x7f, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xfe, 0x7f, 0xe7, 0xff, 0xff, +0xff, 0xff, 0xcf, 0xfe, 0x7f, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xfc, 0x3f, 0xf3, 0xff, 0xff, +0xff, 0xff, 0xdf, 0xf8, 0x1f, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xf8, 0x1f, 0xf9, 0xff, 0xff, +0xff, 0xff, 0x9f, 0xf0, 0x0f, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xf0, 0x0f, 0xfd, 0xff, 0xff, +0xff, 0xff, 0xbf, 0xf0, 0x0f, 0xfd, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xf0, 0x0f, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xf0, 0x1f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xf8, 0x1f, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xf8, 0x1f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xfe, 0x7f, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xfe, 0x7f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xfe, 0x7f, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xfe, 0x7f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xfe, 0x7f, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x1f, 0xfe, 0x7f, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0xbf, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xfd, 0xff, 0xff, +0xff, 0xff, 0x9f, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xf9, 0xff, 0xff, +0xff, 0xff, 0xdf, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xf3, 0xff, 0xff, +0xff, 0xff, 0xe7, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xe7, 0xff, 0xff, +0xff, 0xff, 0xf3, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0x9f, 0xff, 0xff, +0xff, 0xff, 0xfc, 0x7f, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x1f, 0xf8, 0x7f, 0xff, 0xff, +0xff, 0xff, 0xff, 0x81, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}, +{ +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0x81, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x01, 0x80, 0x7f, 0xff, 0xff, +0xff, 0xff, 0xfc, 0x01, 0x80, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x01, 0x80, 0x1f, 0xff, 0xff, +0xff, 0xff, 0xf0, 0x01, 0x80, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x01, 0x80, 0x07, 0xff, 0xff, +0xff, 0xff, 0xc0, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x03, 0xff, 0xff, +0xff, 0xff, 0xc0, 0x01, 0x80, 0x03, 0xff, 0xff, 0xff, 0xff, 0x80, 0x03, 0xc0, 0x01, 0xff, 0xff, +0xff, 0xff, 0x80, 0x03, 0xc0, 0x01, 0xff, 0xff, 0xff, 0xff, 0x80, 0x03, 0xc0, 0x01, 0xff, 0xff, +0xff, 0xff, 0x80, 0x03, 0xc0, 0x01, 0xff, 0xff, 0xff, 0xff, 0x80, 0x03, 0xc0, 0x01, 0xff, 0xff, +0xff, 0xff, 0x00, 0x03, 0xc0, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x80, 0x00, 0xff, 0xff, +0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, +0xff, 0xff, 0x00, 0x01, 0x80, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x80, 0x00, 0xff, 0xff, +0xff, 0xff, 0x00, 0x01, 0x80, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x80, 0x00, 0xff, 0xff, +0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0xbf, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xfd, 0xff, 0xff, +0xff, 0xff, 0x9f, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xf9, 0xff, 0xff, +0xff, 0xff, 0xdf, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xf3, 0xff, 0xff, +0xff, 0xff, 0xe7, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xe7, 0xff, 0xff, +0xff, 0xff, 0xf3, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0x9f, 0xff, 0xff, +0xff, 0xff, 0xfc, 0x7f, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x1f, 0xf8, 0x7f, 0xff, 0xff, +0xff, 0xff, 0xff, 0x81, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}, +{ +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0x00, 0x41, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x7c, 0x7f, 0xff, 0xff, +0xff, 0xff, 0xfc, 0x00, 0x7e, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x7f, 0x9f, 0xff, 0xff, +0xff, 0xff, 0xf0, 0x00, 0x7f, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x7f, 0xe7, 0xff, 0xff, +0xff, 0xff, 0xc0, 0x00, 0x7f, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x3f, 0xf3, 0xff, 0xff, +0xff, 0xff, 0xc0, 0x01, 0x9f, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x80, 0x02, 0x5f, 0xf9, 0xff, 0xff, +0xff, 0xff, 0x80, 0x02, 0x4f, 0xf9, 0xff, 0xff, 0xff, 0xff, 0x80, 0x02, 0x4f, 0xfd, 0xff, 0xff, +0xff, 0xff, 0x80, 0x02, 0x4f, 0xfd, 0xff, 0xff, 0xff, 0xff, 0x80, 0x02, 0x4f, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x00, 0x02, 0x5f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x9f, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x00, 0x00, 0x1f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x7f, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x00, 0x00, 0x7f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x7f, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x00, 0x00, 0x7f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x7f, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x00, 0x00, 0x7f, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0xbf, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xfd, 0xff, 0xff, +0xff, 0xff, 0x9f, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xf9, 0xff, 0xff, +0xff, 0xff, 0xdf, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xf3, 0xff, 0xff, +0xff, 0xff, 0xe7, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xe7, 0xff, 0xff, +0xff, 0xff, 0xf3, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0x9f, 0xff, 0xff, +0xff, 0xff, 0xfc, 0x7f, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x1f, 0xf8, 0x7f, 0xff, 0xff, +0xff, 0xff, 0xff, 0x81, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}, +{ +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0x82, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3e, 0x00, 0x7f, 0xff, 0xff, +0xff, 0xff, 0xfc, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xfe, 0x00, 0x1f, 0xff, 0xff, +0xff, 0xff, 0xf3, 0xfe, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xfe, 0x00, 0x07, 0xff, 0xff, +0xff, 0xff, 0xcf, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xfc, 0x00, 0x03, 0xff, 0xff, +0xff, 0xff, 0xdf, 0xf9, 0x80, 0x03, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xfa, 0x40, 0x01, 0xff, 0xff, +0xff, 0xff, 0x9f, 0xf2, 0x40, 0x01, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xf2, 0x40, 0x01, 0xff, 0xff, +0xff, 0xff, 0xbf, 0xf2, 0x40, 0x01, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xf2, 0x40, 0x01, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xfa, 0x40, 0x00, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xf9, 0x80, 0x00, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xf8, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xfe, 0x00, 0x00, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xfe, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xfe, 0x00, 0x00, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xfe, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xfe, 0x00, 0x00, 0xff, 0xff, +0xff, 0xff, 0x1f, 0xfe, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0xbf, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xfd, 0xff, 0xff, +0xff, 0xff, 0x9f, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xf9, 0xff, 0xff, +0xff, 0xff, 0xdf, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xf3, 0xff, 0xff, +0xff, 0xff, 0xe7, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xe7, 0xff, 0xff, +0xff, 0xff, 0xf3, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0x9f, 0xff, 0xff, +0xff, 0xff, 0xfc, 0x7f, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x1f, 0xf8, 0x7f, 0xff, 0xff, +0xff, 0xff, 0xff, 0x81, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}, +{ +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0x81, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x01, 0x80, 0x7f, 0xff, 0xff, +0xff, 0xff, 0xfc, 0x01, 0x80, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x01, 0x80, 0x1f, 0xff, 0xff, +0xff, 0xff, 0xf0, 0x01, 0x80, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x01, 0x80, 0x07, 0xff, 0xff, +0xff, 0xff, 0xc0, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x03, 0xff, 0xff, +0xff, 0xff, 0xc0, 0x01, 0x80, 0x03, 0xff, 0xff, 0xff, 0xff, 0x80, 0x02, 0x40, 0x01, 0xff, 0xff, +0xff, 0xff, 0x80, 0x02, 0x40, 0x01, 0xff, 0xff, 0xff, 0xff, 0x80, 0x02, 0x40, 0x01, 0xff, 0xff, +0xff, 0xff, 0x80, 0x02, 0x40, 0x01, 0xff, 0xff, 0xff, 0xff, 0x80, 0x02, 0x40, 0x01, 0xff, 0xff, +0xff, 0xff, 0x00, 0x02, 0x40, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x80, 0x00, 0xff, 0xff, +0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, +0xff, 0xff, 0x00, 0x01, 0x80, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x80, 0x00, 0xff, 0xff, +0xff, 0xff, 0x00, 0x01, 0x80, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x80, 0x00, 0xff, 0xff, +0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, +0xff, 0xff, 0xbf, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xfd, 0xff, 0xff, +0xff, 0xff, 0x9f, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xf9, 0xff, 0xff, +0xff, 0xff, 0xdf, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xf3, 0xff, 0xff, +0xff, 0xff, 0xe7, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xe7, 0xff, 0xff, +0xff, 0xff, 0xf3, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0x9f, 0xff, 0xff, +0xff, 0xff, 0xfc, 0x7f, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x1f, 0xf8, 0x7f, 0xff, 0xff, +0xff, 0xff, 0xff, 0x81, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +} +}; + +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_FLIP + dev._flip = true; + ESP_LOGW(TAG, "Flip upside down"); +#endif + +#if CONFIG_SSD1306_128x64 + ESP_LOGI(TAG, "Panel is 128x64"); + ssd1306_init(&dev, 128, 64); +#endif // CONFIG_SSD1306_128x64 +#if CONFIG_SSD1306_128x32 + ESP_LOGE(TAG, "Panel is 128x32. This demo cannot be run."); + while(1) { vTaskDelay(1); } +#endif // CONFIG_SSD1306_128x32 + + // Allocate memory + uint8_t *buffer = (uint8_t *)malloc(IMAGES*8*128); // 8 page 128 pixel + if (buffer == NULL) { + ESP_LOGE(TAG, "malloc failed"); + while(1) { vTaskDelay(1); } + } + + // Convert from segmentDisplay to segmentImage + int index = 0; + for (int i=0;i +#include +#include +#include +#include +#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); +} diff --git a/MouseIconDemo/main/usb_hid.h b/MouseIconDemo/main/usb_hid.h new file mode 100644 index 0000000..dead819 --- /dev/null +++ b/MouseIconDemo/main/usb_hid.h @@ -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; diff --git a/MouseIconDemo/sdkconfig.defaults b/MouseIconDemo/sdkconfig.defaults new file mode 100644 index 0000000..27d6f75 --- /dev/null +++ b/MouseIconDemo/sdkconfig.defaults @@ -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 + diff --git a/MouseMoveDemo/main/usb_hid.c b/MouseMoveDemo/main/usb_hid.c index b7f2934..75b0763 100644 --- a/MouseMoveDemo/main/usb_hid.c +++ b/MouseMoveDemo/main/usb_hid.c @@ -16,7 +16,6 @@ #include "esp_err.h" #include "esp_log.h" #include "usb/usb_host.h" -//#include "errno.h" #include "driver/gpio.h" #include "usb/hid_host.h"