Giter VIP home page Giter VIP logo

esp32_mouse_keyboard's Introduction

ESP32 Mouse/Keyboard for BLE HID

ESP32 implementation for HID over GATT Keyboard and Mouse (Bluetooth Low Energy). Including serial API for external modules (compatible to Adafruit EZKey HID).

Compatibility

Due to the wide variety of hardware & software combinations, it is hard to guarantee compatibility. Nevertheless, we try to test this project with as much devices as possible.

Tested devices by the AsTeRICS team:

Device Mouse Keyboard
PC with CSR 4.0 BT dongle, Debian Bullseye yes yes
Lenovo T440s, Debian Buster yes yes
MacBook Pro (Mid 2012) - macOS Mojave 10.14 yes yes
PC with CSR 4.0 BT dongle, Win10 Build 2004 yes yes
Lenovo T440s, Win10 Build 2004 in VirtualBox no no
Xiaomi Mi A1 - LineageOS 16.0 (Android 9) yes yes
Asus Nexus 7 (2013) - Android 6.0.1 yes yes
iPad Air 2 (MGL12FD/A9 - iOS 13.3.1 yes (Assistive Touch) yes (Text input & accessible switch interface)
iPad Air 2 (MGL12FD/A9 - iOS 13.5.1 yes (Assistive Touch) yes (Text input & accessible switch interface)
iPad Pro 10.5" (MPHG2TY/A) - iOS 13.5.1 yes (Assistive Touch) yes (Text input & accessible switch interface)
iPad 6th Gen (MR7J2FD/A) - iOS 13.5.1 yes (Assistive Touch) yes (Text input & accessible switch interface)

Note: On some iPad devices, there might show up a notification in the Bluetooth menu, that this device may affect WiFi or Bluetooth performance. You could ignore this error, according to StackOverflow there is no clear reason for this message, maybe it is related to the additional WiFi interface of the ESP32 (other user report this error if a normal mouse has an additional USB-dongle).

Note: If you can report the compatibility status for a device, we would be happy to add a list of community tested devices, just open an issue with the label device-testreport.

Building the ESP32 firmware

Please follow the step-by-step instructions of Espressif's ESP-IDF manual to setup the build infrastructure: Setup Toolchain

With idf.py build or make you can build this project.

With idf.py -p (PORT) flash or make flash you can upload this build to an ESP32

With idf.py -p (PORT) monitor or make monitor you can see the debug output (please use this output if you open an issue) or trigger basic test commands (mouse movement or a keyboard key press) on a connected target.

Note: Currently tested IDF version: release/v5.0 (other ones won't be supported!)

esp32miniBT vs. Arduino Nano Connect

This firmware is used on 2 different devices in context of our assistive devices:

  • esp32miniBT module: This board is located in this repository and is used as addon for v2 FLipMouse, FABI and FLipPad PCBs which use either a TeensyLC or a ProMicro controller.
  • Arduino Nano RP2040 Connect: Version 3 of FLipMouse and FLipPad (maybe FABI as well) use this Arduino board, where we have a RP2040 controller AND the ESP32 on the same board (more RAM, more flash, cheaper than 2 boards).

Note: Please select the correct type of board in idf.py menuconfig!

Note: If you want to use this firmware on a custom board, you can select the external UART interface settings in menuconfig; for our boards the pinning, baudrate and UART config is pre-defined.

Usage via Console or second UART

Control via stdin (make monitor)

For basic mouse and keyboard testing, some Bluetooth HID reports can be triggered via the keyboard when the make monitor console is running (see Espressif IDF docs: https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/tools/idf-monitor.html ).

Key Function Description
a Mouse left Move mouse left by 30px (MOUSE_SPEED define)
s Mouse down Move mouse down by 30px (MOUSE_SPEED define)
d Mouse right Move mouse right by 30px (MOUSE_SPEED define)
w Mouse up Move mouse up by 30px (MOUSE_SPEED define)
l Click left Mouse click right
r Click right Mouse click left
q Type 'y' (US layout) just for testing keyboard reports

Control via 2nd UART

This interface is primarily used to control mouse / keyboard activities via an external microcontroller.

Commands

Each command is started with a '$' character, followed by a command name (uppercase letters) and a variable number of parameters. A command must be terminated by a '\n' character (LF, ASCII value 10)!

Note: We do not test these on a regular basis!

Command Function Parameters Description
$ID Get ID -- Prints out the ID of this module (firmware version number)
$GP Get BLE pairings -- Prints out all paired devices' MAC adress. The order is used for DP as well, starting with 0
$GC Get active BLE connections -- Prints out connected paired devices' MAC adress. Ordered by connection occurance (first connected device is listed first)
$SW Switch between devices BT addr (001122334455) Switch between connected devices, the given BT addr will receive the HID packets
$DP Delete one pairing (or all) number of pairing, given as ASCII-characer '0'-'9' Deletes one pairing. The pairing number is determined by the command GP. If no parameter is given, all pairings are removed!
$PM Set pairing mode '0' / '1' Enables (1) or disables (0) discovery/advertising and terminates an exisiting connection if enabled
$NAME Set BLE device name name as ASCII string Set the device name to the given name. Restart required.
$UG Initiating firmware update -- Boot partition is set to 'factory', if available. Device is restarted and expects firmware (.bin) via UART2
$SV Set a key/value pair key value Set a value to ESP32 NVS storage, e.g. "$SV testkey This is a testvalue". Note: no spaces in the key! Returns "OK xx/yy used/free" on success, NVS:"error code" otherwise.
$GV Get a key/value pair key Get a value from ESP32 NVS storage, e.g. "$GV testkey". Note: no spaces in the key!
$CV Clear all key/value pairs -- Delete all stored key/value pairs from $SV.

HID input

We use a format which is compatible to the Adafruit EZKey module, and added a few backwards compatible features.

Mouse:

Byte 0 Byte 1 Byte 2 Byte 3 Byte 4 Byte 5 Byte 6 Byte 7 Byte 8
0xFD don't care 0x03 button mask X-axis Y-axis wheel don't care don't care

Keyboard:

Note: currently we only support the US keyboard layout.

Byte 0 Byte 1 Byte 2 Byte 3 Byte 4 Byte 5 Byte 6 Byte 7 Byte 8
0xFD modifier mask 0x00 keycode 1 keycode 2 keycode 3 keycode 4 keycode 5 keycode 6

Joystick:

Byte 0 Byte 1 Byte 2 Byte 3-8 Byte 9 Byte 10 Byte 11 Byte 12 Byte 13
0xFD don't care 0x01 X,Y,Z,Rz,Rx,Ry axis (each int8_t) hat switch (0 is rest position; 1-8 are directions) buttons 0-7 buttons 8-15 buttons 16-23 buttons 24-31

RAW HID input from sourcecode

If you want to change anything within the sourcecode, it is possible to send an HID report directly via:

hid_dev_send_report(hidd_le_env.gatt_if, hid_conn_id,
                  HID_RPT_ID_MOUSE_IN, HID_REPORT_TYPE_INPUT, HID_MOUSE_IN_RPT_LEN, mouse_report);

Use according HID_RPT_ID_*/HID_*_IN_RPT_LEN, depending on input type (mouse, keyboard). The HID report data is located in array, passed as last parameter of hid_dev_send_report.

Mouse & Keyboard input from sourcecode

Please use the functions provided by esp_hidd_prf_api.c.

Credits and many thanks to:

  • Paul Stoffregen for the implementation of the keyboard layouts for his Teensyduino project: www.pjrc.com
  • Neil Kolban for his great contributions to the ESP32 SW (in particular the Bluetooth support): https://github.com/nkolban
  • Chegewara for help and support

and to Espressif for providing the HID implementation within the esp-idf.

esp32_mouse_keyboard's People

Contributors

benjaminaigner avatar chrisveigl avatar hotice0 avatar junaidwien avatar maxr1998 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

esp32_mouse_keyboard's Issues

Suggestion

If i may suggest something. Now report map and all application functions related to this definition (mouse, joystick and keyboard) are based on preprocessor define :
https://github.com/asterics/esp32_mouse_keyboard/blob/newBLE/components/nkolban_BLE/HID_kbdmousejoystick.cpp#L53

It is possible, maybe for test purpose only or maybe for finale product, to use dip switch and based on GPIO level on esp32 reboot to have different devices available. This will speed up and help with windows drivers compatibility. No need to recompile application to test which report map part is broken.

How to swipe

I test two kinds, don't work.
I think should have mouse down and mouse up.

kind 1:

esp_hidd_send_mouse_value(active_hid_conn_ids[i],(1<<0),0,0,0);
esp_hidd_send_mouse_value(active_hid_conn_ids[i],0,-MOUSE_SPEED,0,0);

kind 2:

esp_hidd_send_mouse_value(active_hid_conn_ids[i],(1<<0),0,MOUSE_SPEED,0);

nkolban_BLE with some errors

HotIce0-mac:esp32_mouse_keyboard HotIce0$ make flash
Toolchain path: /Users/HotIce0/esp/xtensa-esp32-elf/bin/xtensa-esp32-elf-gcc
Toolchain version: crosstool-ng-1.22.0-80-g6c4433a
Compiler version: 5.2.0
Python requirements from /Users/HotIce0/esp/esp-idf/requirements.txt are satisfied.
CXX build/nkolban_BLE/BLEUtils.o
/Users/HotIce0/esp/esp32_mouse_keyboard/components/nkolban_BLE/BLEUtils.cpp: In static member function 'static std::__cxx11::string BLEUtils::gattServerEventTypeToString(esp_gatts_cb_event_t)':
/Users/HotIce0/esp/esp32_mouse_keyboard/components/nkolban_BLE/BLEUtils.cpp:988:8: error: enumeration value 'ESP_GATTS_SEND_SERVICE_CHANGE_EVT' not handled in switch [-Werror=switch]
  switch(eventType) {
        ^
cc1plus: some warnings being treated as errors
make[1]: *** [BLEUtils.o] Error 1
make: *** [component-nkolban_BLE-build] Error 2

So, I add the code to handled.

/**
 * @brief Return a string representation of a GATT server event code.
 * @param [in] eventType A GATT server event code.
 * @return A string representation of the GATT server event code.
 */
std::string BLEUtils::gattServerEventTypeToString(esp_gatts_cb_event_t eventType) {
	switch(eventType) {
	case ESP_GATTS_REG_EVT:
		return "ESP_GATTS_REG_EVT";
		
	case ESP_GATTS_SEND_SERVICE_CHANGE_EVT:
		return "ESP_GATTS_SEND_SERVICE_CHANGE_EVT";

iPhone 12 Pro iOS 14.7.1 - no devices in the list

I am using ESP WROOM 32 DEVKIT V1 and when I run the program the device does not appear in the list of bluetooth devices on my iPhone.

esp logs

ets Jun  8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0030,len:6724
load:0x40078000,len:14812
load:0x40080400,len:3784
0x40080400: _init at ??:?

entry 0x40080694
I (27) boot: ESP-IDF v4.4-dev-3235-g3e370c4296 2nd stage bootloader
I (27) boot: compile time 11:09:35
I (27) boot: chip revision: 1
I (31) boot_comm: chip revision: 1, min. bootloader chip revision: 0
I (38) boot.esp32: SPI Speed      : 40MHz
I (43) boot.esp32: SPI Mode       : DIO
I (47) boot.esp32: SPI Flash Size : 4MB
I (52) boot: Enabling RNG early entropy source...
I (57) boot: Partition Table:
I (61) boot: ## Label            Usage          Type ST Offset   Length
I (68) boot:  0 nvs              WiFi data        01 02 00009000 00006000
I (76) boot:  1 phy_init         RF data          01 01 0000f000 00001000
I (83) boot:  2 factory          factory app      00 00 00010000 00100000
I (91) boot: End of partition table
I (95) boot_comm: chip revision: 1, min. application chip revision: 0
I (102) esp_image: segment 0: paddr=00010020 vaddr=3f400020 size=20094h (131220) map
I (158) esp_image: segment 1: paddr=000300bc vaddr=3ffbdb60 size=04a30h ( 18992) load
I (166) esp_image: segment 2: paddr=00034af4 vaddr=40080000 size=0b524h ( 46372) load
I (185) esp_image: segment 3: paddr=00040020 vaddr=400d0020 size=807cch (526284) map
I (376) esp_image: segment 4: paddr=000c07f4 vaddr=4008b524 size=0c5e0h ( 50656) load
I (397) esp_image: segment 5: paddr=000ccddc vaddr=50000000 size=00010h (    16) load
I (409) boot: Loaded app from partition at offset 0x10000
I (409) boot: Disabling RNG early entropy source...
I (420) cpu_start: Pro cpu up.
I (421) cpu_start: Starting app cpu, entry point is 0x4008128c
0x4008128c: call_start_cpu1 at /Users/feed4rz/esp/esp-idf/components/esp_system/port/cpu_start.c:155

I (0) cpu_start: App cpu up.
I (437) cpu_start: Pro cpu start user code
I (437) cpu_start: cpu freq: 160000000
I (437) cpu_start: Application information:
I (441) cpu_start: Project name:     esp32_mouse_keyboard
I (447) cpu_start: App version:      v0.3-3-g6fbe015
I (453) cpu_start: Compile time:     Oct 10 2021 11:11:41
I (459) cpu_start: ELF file SHA256:  f6e08d5054a1c8c9...
I (465) cpu_start: ESP-IDF:          v4.4-dev-3235-g3e370c4296
I (472) heap_init: Initializing. RAM available for dynamic allocation:
I (479) heap_init: At 3FFAFF10 len 000000F0 (0 KiB): DRAM
I (485) heap_init: At 3FFB6388 len 00001C78 (7 KiB): DRAM
I (491) heap_init: At 3FFB9A20 len 00004108 (16 KiB): DRAM
I (497) heap_init: At 3FFC6F78 len 00019088 (100 KiB): DRAM
I (503) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (510) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (516) heap_init: At 40097B04 len 000084FC (33 KiB): IRAM
I (524) spi_flash: detected chip: generic
I (527) spi_flash: flash io: dio
I (532) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (542) HID_DEMO: pairing enabled by default
I (582) BTDM_INIT: BT controller compile version [078d492]
I (592) system_api: Base MAC address is not set
I (592) system_api: read default base MAC address from EFUSE
I (592) phy_init: phy_version 4670,719f9f6,Feb 18 2021,17:07:07
I (1022) MAIN: opening NVS handle for BT names
I (1022) MAIN: opening NVS handle for key/value storage
I (1032) MAIN: loading configuration from NVS
I (1032) MAIN: bt device name is: esp32_mouse_keyboard
I (1042) MAIN: error reading NVS - locale, setting to US_INTERNATIONAL
W (1052) BT_BTM: BTM_BleWriteAdvData, Partial data write into ADV
I (1052) gpio: GPIO[17]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 1| Intr:0 
I (1052) UART: console UART processing task started
W (1072) EXT_UART: Switching pins!
I (1072) EXT_UART: external UART processing task started
I (1082) HID_LE_PRF: esp_hidd_prf_cb_hdl(), start added the hid service to the stack database. incl_handle = 40
I (1092) HID_LE_PRF: hid svc handle = 2d
I (1092) HID_LE_PRF: GATT EVT 12
I (1112) HID_LE_PRF: GATT EVT 12
W (1202) BT_LOG: esp_ble_gatts_send_indicate, The connection not created.
I (1202) HID_DEMO: Idle...
W (1502) BT_LOG: esp_ble_gatts_send_indicate, The connection not created.
I (1502) HID_DEMO: Idle...

I ve also tried it with an older iPhone 8 but with the same iOS installed and a Macbook Pro on the Apple Silicon running Big Sur 11.6 with no luck.

Seems to be working on some old Lenovo laptop running Win10 tho.

Test y keycode does not registers on android

I played with demo code a bit, after compilation - I can see FLIPMOUSE device appeared on my android phone, but entering q to send y keycode seems to make nothing. Although I see it sends it in serial monitor: before connection appears I see:

Serial_client > q
I (15574) CONSOLE_UART: Not connected, ignoring 'q'

Serial_client > I (15574) CONSOLE_UART: Not connected, ignoring '

'

after esp32 paired with my phone I see following:

Serial_client > q
I (124554) CONSOLE_UART: received q: sending key y for test purposes

Serial_client > I (124554) HAL_BLE: Keyboard received: 2/28

I (124554) CONSOLE_UART: received: 10

but no y appears as input, I tried in notes and sms apps - the same. Does output looks right, especially "2/28" part?

Also no matter what I tried - my windows 10 laptop does not see esp32 as bt device to connect, it sees android phone where esp32 is visible with no problem though.

I didn't changed demo code, all I did is changed python to python2 in sdkconfig file, I'm on archlinux virtual machine, and it compiles with no problems. Running make flash first time though it asks me ~20 questions about settings, but all I did is pressed enter to all of them for it to take default value.

How to get or set mouse position?

I want to click on a specific place on the screen, is there a way to get the position of the mouse on the screen, or click on a certain place?

Basic example

Hi, sorry, I know its not very polite, and just suggestion, but is there any chance to get super basic up and running demo for library? Like after flashing you get infinite "quick brown fox" output keypress loop, that you can instantly pair with phone, see output and start playing with? I'm very new to esp32 world, looking into demo c file, it leaves in me quite a bit of frustration, I guess those processCommand commands are some kind of input you make to trigger keypress sending, but I'm not sure how you input those..

esp-idf:esp_ble_gap_update_whitelist has an update

appears not to be working with latest esp-idf; seems declaration for esp_ble_gap_update_whitelist used in [BLEDevice.cpp] got updated late march, tried supplying BLE_WL_ADDR_TYPE_PUBLIC, how ever I was not able to make this work.

Module undetectable as BT device with builds between 332c30d and 625440c

Built with 09509cd , FABI device is visible by default.
With any of the commits from the 625440c merge, no BT device is found (on Ubuntu or Windows).

Does something else need to be done first?

Monitor, boot log:

HEAD detached at 232ce4f

[redacted]/esp32_mouse_keyboard$ make monitor
MONITOR
--- idf_monitor on /dev/ttyUSB0 115200 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
ets Jun 8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:5552
ho 0 tail 12 room 4
load:0x40078000,len:0
load:0x40078000,len:12632
entry 0x40078fe4
I (30) boot: ESP-IDF v3.1-dev-661-gf586f5e 2nd stage bootloader
I (30) boot: compile time 20:32:05
I (30) boot: Enabling RNG early entropy source...
I (36) boot: SPI Speed : 40MHz
I (40) boot: SPI Mode : DIO
I (44) boot: SPI Flash Size : 4MB
I (48) boot: Partition Table:
I (52) boot: ## Label Usage Type ST Offset Length
I (59) boot: 0 nvs WiFi data 01 02 00009000 00004000
I (66) boot: 1 otadata OTA data 01 00 0000d000 00002000
I (74) boot: 2 phy_init RF data 01 01 0000f000 00001000
I (81) boot: 3 factory factory app 00 00 00010000 00200000
I (89) boot: End of partition table

Same from a working build:

HEAD detached at 09509cd

[redacted]/esp32_mouse_keyboard$ make monitor
MONITOR
--- idf_monitor on /dev/ttyUSB0 115200 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
etsRչ ���16����2��j
!��:0� �]ER�}IESQU�I��t:��3 �*��F�*�e1�Hߨ��Uj
c�K�gsZ� 0,�A�W�'��e��,k�E�v���0,\E�v:��0,�E��:��0,c.��r�'�A0�
}�r�'��0��}dr�����C!�
�iDɊ�����k�V��2�!�+�i0x&֙0�Lbb��i4�!�+��0x&��00L,�+�i5��j
I (30) boot: ESP-IDF v3.1-dev-661-gf586f5e 2nd stage bootloader���00�2�8
I (30) boot: compile time 19:35:44
I (30) boot: Enabling RNG early entropy source...
I (36) boot: SPI Speed : 40MHz
I (40) boot: SPI Mode : DIO
I (44) boot: SPI Flash Size : 4MB
I (48) boot: Partition Table:
I (51) boot: ## Label Usage Type ST Offset Length
I (59) boot: 0 nvs WiFi data 01 02 00009000 00006000
I (66) boot: 1 phy_init RF data 01 01 0000f000 00001000
I (74) boot: 2 factory factory app 00 00 00010000 00100000
I (81) boot: End of partition table
I (85) esp_image: segment 0: paddr=0x00010020 vaddr=0x3f400020 size=0x378c4 (227524) map
I (174) esp_image: segment 1: paddr=0x000478ec vaddr=0x3ffc0000 size=0x03384 ( 13188) load
I (179) esp_image: segment 2: paddr=0x0004ac78 vaddr=0x40080000 size=0x00400 ( 1024) load
0x40080000: _iram_start at /home/mamert/esp/esp-idf/components/freertos/./xtensa_vectors.S:1685

I (181) esp_image: segment 3: paddr=0x0004b080 vaddr=0x40080400 size=0x04f90 ( 20368) load
I (198) esp_image: segment 4: paddr=0x00050018 vaddr=0x400d0018 size=0x81d0c (531724) map
0x400d0018: _stext at ??:?

I (385) esp_image: segment 5: paddr=0x000d1d2c vaddr=0x40085390 size=0x0ab34 ( 43828) load
0x40085390: r_ld_fm_frame_isr at ??:?

I (403) esp_image: segment 6: paddr=0x000dc868 vaddr=0x400c0000 size=0x00000 ( 0) load
I (413) boot: Loaded app from partition at offset 0x10000
I (413) boot: Disabling RNG early entropy source...
I (415) cpu_start: Pro cpu up.
I (418) cpu_start: Starting app cpu, entry point is 0x40080fb8
0x40080fb8: call_start_cpu1 at /home/mamert/esp/esp-idf/components/esp32/./cpu_start.c:225

I (0) cpu_start: App cpu up.
I (429) heap_init: Initializing. RAM available for dynamic allocation:
I (436) heap_init: At 3FFAFF10 len 000000F0 (0 KiB): DRAM
I (442) heap_init: At 3FFCDCB8 len 00012348 (72 KiB): DRAM
I (448) heap_init: At 3FFE0440 len 00003BC0 (14 KiB): D/IRAM
I (454) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (461) heap_init: At 4008FEC4 len 0001013C (64 KiB): IRAM
I (467) cpu_start: Pro cpu start user code
I (149) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
E (238) MAIN: error reading NVS - bt name, setting to FABI
E (238) MAIN: error reading NVS - locale, setting to US_INTERNATIONAL
I (248) BTDM_INIT: BT controller compile version [ae44fa3]

I (248) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
I (598) phy: phy_version: 383.0, 79a622c, Jan 30 2018, 15:38:06, 0, 0
I (638) HID_DEVICE: esp_hidd_prf_cb_hdl(), start added the hid service to the stack database. incl_handle = 40
I (648) HID_DEVICE: hid svc handle = 2d```

MacOS Catalina does not reconnect

I'm having issues getting reliable connections to my MacBook Pro. I can get the ESP to connect once but when the ESP is restarted or the device is disconnected, then it will not connect again. I can only get it to pair again by restarting my MacBook. Any ideas on how to tackle this?

ESP32-S3 support

Dear all,

if you want to compile this repository for the ESP32-S3 (not officially supported by us, because we are not using it), please note following things:

  • BLE4.2 features are not activated by default in esp-idf and will result in many undefined reference errors on linking. I've added the flag to sdkconfig.defaults, so this should not happen
  • There is a funny behavior of an endless reset loop with the reason E (427) spi_flash: Detected size(512k) smaller than the size in the binary image header(2048k). Probe failed. This is related to a wrong SPI flash mode. Please set `enable octal flash' in idf.py menuconfig, it works. We will not set the it in sdkconfig.defaults, because it is not tested with the original ESP32.

Windows 10 does not register key reports

It seems that while the ESP32 manages to properly connect to windows, key reports do not seem to register. the log does not seem any different from the log while sending reports to Linux/Android. I think this might be related to the device descriptor windows requires:
from QMK :
"Mac OS-X and Linux automatically load the correct drivers. On Windows, even though driver is supplied by Microsoft, an INF file is needed to load the driver. "

https://github.com/qmk/qmk_firmware/blob/master/tmk_core/protocol/pjrc/usb.c

Demo Connects but then Disconnects / can't pass keys

I'm able to connect ESP32 to Windows as HID BT Keyboard / but then it disconnects.

I added some basic debug to the GAP callback / HIDD Callback. I'm getting a ESP_GAP_BLE_AUTH_CMPL_EVT then a few seconds later ESP_HIDD_EVENT_BLE_DISCONNECT.

Log (added basic logs to callback):
..
HIDD Callback Event:'0'
E (335) BT: esp_hidd_prf_cb_hdl(), start added the hid service to the stack database. incl_handle = 40
GAP Callback Event:'0' (ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT)
E (340) BT: hid svc handle = 2d
GAP Callback Event:'6' (When start advertising complete, the event comes)
GAP Callback Event:'10' (BLE security request)
GAP Callback Event:'20' (When update connection parameters complete, the event comes)
GAP Callback Event:'9' (BLE key event for peer device keys)
GAP Callback Event:'9' (BLE key event for peer device keys)
GAP Callback Event:'8' (Authentication complete indication.)
:) E (22567) BT: status = success, ESP_GAP_BLE_AUTH_CMPL_EVT
GAP Callback Event:'20' (When update connection parameters complete, the event comes)
GAP Callback Event:'20' (When update connection parameters complete, the event comes)
GAP Callback Event:'20' (When update connection parameters complete, the event comes)
:( HIDD Callback Event:'4' (ESP_HIDD_EVENT_BLE_DISCONNECT) ***
E (29028) BT: hidd_event_callback(), ESP_HIDD_EVENT_BLE_DISCONNECT

Pairing problems on Win8.1

Using Firmware version 0.3.0, I cannot pair with a Lenovo Yoga Pro Laptop running Win8.1
(where pairing works with Win10/Linux PC and Android/Linage Smartphone)

iOS support

When I connect this to my iPad I get the following error and nothing works afterwards (see last line)

I (29) boot: ESP-IDF v3.1-dev-241-gf4009b94 2nd stage bootloader
I (29) boot: compile time 21:02:23
I (29) boot: Enabling RNG early entropy source...
I (35) boot: SPI Speed      : 40MHz
I (39) boot: SPI Mode       : DIO
I (43) boot: SPI Flash Size : 4MB
I (47) boot: Partition Table:
I (50) boot: ## Label            Usage          Type ST Offset   Length
I (58) boot:  0 nvs              WiFi data        01 02 00009000 00006000
I (65) boot:  1 phy_init         RF data          01 01 0000f000 00001000
I (73) boot:  2 factory          factory app      00 00 00010000 00100000
I (80) boot: End of partition table
I (84) esp_image: segment 0: paddr=0x00010020 vaddr=0x3f400020 size=0x36598 (222616) map
I (171) esp_image: segment 1: paddr=0x000465c0 vaddr=0x3ffc0000 size=0x02ec0 ( 11968) load
I (175) esp_image: segment 2: paddr=0x00049488 vaddr=0x40080000 size=0x00400 (  1024) load
0x40080000: _iram_start at /home/juan/Documents/programming/esp/esp-idf/components/freertos/./xtensa_vectors.S:1685

I (178) esp_image: segment 3: paddr=0x00049890 vaddr=0x40080400 size=0x06780 ( 26496) load
I (197) esp_image: segment 4: paddr=0x00050018 vaddr=0x400d0018 size=0x78fd0 (495568) map
0x400d0018: _stext at ??:?

I (369) esp_image: segment 5: paddr=0x000c8ff0 vaddr=0x40086b80 size=0x0d614 ( 54804) load
0x40086b80: vhci_recv_end at vhci.c:?

I (392) esp_image: segment 6: paddr=0x000d660c vaddr=0x400c0000 size=0x00000 (     0) load
I (404) boot: Loaded app from partition at offset 0x10000
I (404) boot: Disabling RNG early entropy source...
I (405) cpu_start: Pro cpu up.
I (408) cpu_start: Starting app cpu, entry point is 0x4008113c
0x4008113c: call_start_cpu1 at /home/juan/Documents/programming/esp/esp-idf/components/esp32/./cpu_start.c:215

I (0) cpu_start: App cpu up.
I (419) heap_init: Initializing. RAM available for dynamic allocation:
I (426) heap_init: At 3FFAFF10 len 000000F0 (0 KiB): DRAM
I (432) heap_init: At 3FFCD6F0 len 00012910 (74 KiB): DRAM
I (438) heap_init: At 3FFE0440 len 00003BC0 (14 KiB): D/IRAM
I (444) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (450) heap_init: At 40094194 len 0000BE6C (47 KiB): IRAM
I (457) cpu_start: Pro cpu start user code
I (139) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
E (182) MAIN: error reading NVS - bt name, setting to FABI
E (182) MAIN: error reading NVS - locale, setting to US_INTERNATIONAL
I (182) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
I (462) phy: phy_version: 366.0, ba9923d, Dec 29 2017, 14:25:06, 0, 0
E (502) BT: esp_hidd_prf_cb_hdl(), start added the hid service to the stack database. incl_handle = 40
E (512) BT: hid svc handle = 2d
E (3542) BT: Call back not found for application conn_id=3

Tell me if you want me to get verbose logs

Enable notifications for LED reports

Can you enable notifications for LED reports? At the moment, when I turn on/off Capslock, Numlock and Scrolllock, the ESP32 isn't notifying me.

Question about code

Hi Benjamin,
Would you please help me to explain the following lines of code?

For sending key code, a zero keycode is sent after sending 'y'. Why a zero key code is needed? When is it needed?

                    keycode = 28;
                    esp_hidd_send_keyboard_value(hid_conn_id,0,&keycode,1);
                    keycode = 0;
                    esp_hidd_send_keyboard_value(hid_conn_id,0,&keycode,1);

Similar to mouse click, a zero mouse value is sent after sending mouse click value. Why and when is zero mouse value needed?

              case 'r':
                   esp_hidd_send_mouse_value(hid_conn_id,0x02,0,0,0);
                   esp_hidd_send_mouse_value(hid_conn_id,0x00,0,0,0);

Thank you!

ESP32 gets warm, WIFI stops working

Hi!

Thanks for the code, it almost works for me. There are a few issues I noticed.

  1. WIFI on my laptop almost stops working when I connect to ESP32. May it happen it somehow starts transmitting all the time polluting?

  2. The module becomes noticeably warm while working. I'm not sure what power consumption is, but definitely it will not last long from the battery.

  3. (Not sure if relevant) I have "Call back not found for application conn_id=3" error. This happened after I disconnected and re-connected laptop. I had to do make erase_flash, otherwise somehow esp32 was still remembering my laptop and re-pairing/reconnecting didn't work.

Additional info

  1. ESP-IDF is latest from git
  2. ESP32 module revision is 0.
  3. This is the module itself

How I see wifi problem:

With esp32 (notice packet loss and max ping, this is not the worst case):

--- 192.168.2.1 ping statistics ---
548 packets transmitted, 483 received, 11% packet loss, time 55687ms
rtt min/avg/max/mdev = 0.732/129.743/1004.019/253.840 ms, pipe 10

Without (esp32 connected):

--- 192.168.2.254 ping statistics ---
761 packets transmitted, 760 received, 0% packet loss, time 76603ms
rtt min/avg/max/mdev = 0.820/4.813/88.536/9.019 ms

How do you send key commands

I can send regular commands to rename the esp but I cannot send the hex code. GPIO17/16 doesn't work and I also hooked directly up with the rx/tx pins. what could I be missing

esp-idf version

Hey, thanks for sharing this. Just wondering which version of esp-idf this should be compiled against. Would prefer to go with the esp-idf version that is known to not have any issues with this. Latest stable?

Thank you!

Cannot build using cmake

Hello @benjaminaigner, i was trying to build the latest master branch code (new BLE stack) using cmake but i'm not sure about what changes are need to make it compatible with cmake or is it even possible ?

Thanks for the reply on last issue
sorry for such silly question

Compilation issue.

I am getting compilation issue, am i missing something basic.

ble_hidd_demo_main.c:340: undefined reference to `esp_ble_gap_start_advertising'

Switch between devices/hosts

Getting an ESP32 and want to wire my broken keyboard.
Having a MX vertical switching between hosts/computers is ideal.
Figured out the BluetoothDeviceAddress in the windows properties is different when connecting to another id of the mouse: fc5cabc8e5a2 vs fc5cabc8e5a4. ProductId (20 B0), Vendor(6D 04), VenderSource (2) remains equal.

So using above switching from host would/should require disconnect current connection, set another MAC address and setup (new) connection.

Alternatively one can setup/allow multiple connection at the same time, and send keys to only one (or more) selected connection(s).
https://github.com/espressif/esp-idf/tree/master/examples/bluetooth/bluedroid/ble/gattc_multi_connect

Have to wait for my board and setup a build environment using my limited time and other projects, but for now maybe ideas for others.

Reconnection takes very long and seems unstable

I was testing the Bluetooth pairing and re-connection (with BT-stack by Neil Kolban).
It seems that the reconnection takes very long (up to several minutes !) if the ESP32 was connected to a BT-client but got out-of-range or was restarted. (The devices were paired and bonded before - then the clients was moved out-of-range and brought back several times.)

Shortly after the devices get in range after disconnection, the "client connected" message appears - but the connection breaks down immediatley with "reason=0x003d" and advertising is restarted. Then it takes ages .... and then the client reconnects successfully. see screenshot:

reconnection_of_paired_module

This is repeatable and happens every time when the connection is lost.

Sometimes another problem occurred: after a connection is lost and is re-established, the client (in this case tested with an Android Nexus 5X phone) claims to be "connected" but the registration of the BT-services never completes successfully (so no mouse/keyboard interaction is possible). when this happens, also a reset of the esp32 + reboot of the client does not help - can be cured only by unpairing the devices and starting a new pairing sequence (!)

GATT_INSUF_AUTHENTICATION problem

at first I can connect to the MacBook without any problem.
after I deep_sleep the esp32 then shutdown the MacBook.
the active the esp32,the turn on the MacBook.
esp32 shows that

I (636) BTDM_INIT: BT controller compile version [d9cc6b1]
I (636) system_api: Base MAC address is not set
I (646) system_api: read default base MAC address from EFUSE
I (666) phy: phy_version: 4180, cb3948e, Sep 12 2019, 16:39:13, 0, 1
I (1086) HID_LE_PRF: esp_hidd_prf_cb_hdl(), start added the hid service to the stack database. incl_handle = 40
I (1086) HID_LE_PRF: hid svc handle = 2d
I (1096) HID_LE_PRF: GATT EVT 12
I (1096) HIDD: MAIN finished...
I (1096) Keyboard task: initializezd
I (1106) Sleep: initializezd
I (1116) HID_LE_PRF: GATT EVT 12
I (1226) HID_LE_PRF: HID connection establish, conn_id = 0
I (1226) hal_ble: ESP_HIDD_EVENT_BLE_CONNECT

W (34986) BT_BTM: btm_sec_clr_temp_auth_service() - no dev CB

I (34986) hal_ble: remote BD_ADDR: aaaaaaaaaaaa
I (34986) hal_ble: address type = 0
I (34986) hal_ble: pair status = fail
E (34996) hal_ble: fail reason = 0x63
I (34996) hal_ble: ESP_HIDD_EVENT_BLE_DISCONNECT
E (35016) BT_BTM: Device not found

I (66716) HID_LE_PRF: HID connection establish, conn_id = 0
I (66716) hal_ble: ESP_HIDD_EVENT_BLE_CONNECT
I (66726) HID_LE_PRF: GATT EVT 4
I (66846) HID_LE_PRF: GATT EVT 1
E (66966) BT_GATT: gatts_write_attr_perm_check - GATT_INSUF_AUTHENTICATION
I (97476) hal_ble: remote BD_ADDR: aaaaaaaaaaaa
I (97476) hal_ble: address type = 0
I (97476) hal_ble: pair status = fail
E (97476) hal_ble: fail reason = 0x63

and what is the problem?and how can I improve it. thanks for the great job.

Replacement parts

Currently, supply chains are a little bit tricky. If you cannot find a specific part for this project,
you might consult this issue to find replacements.

MCP1603T-330I/P

DC/DC converter, can be replaced with TPS62203, but according to the datasheet, a 10uH inductor is necessary.
UNTESTED

CMM4030D

If no speech processing is used (currently in early development), this part can be DNP (do not place).

All other parts are either standard components or not replaceable (ESP32).

Connection indication LED does not work correctly

after removing the pairing with a host device, the led still indicates a paired state (blinking slowly).
This does not change even if BT is deactivated on the host device or if the host device is powered off.
(tested with firmware version 0.3.0 and Android/Win10 host connections)

Sending mouse commands

Hi,

In the readme.md, it was stated that Mouse command starts with a command byte that needs to be set to 'M', however I don't see that in the definition. Can explain and point out to me where 'M' is inserted? Thank you.

typedef struct mouse_command
{
    int8_t x;
    int8_t y;
    int8_t wheel;
    uint8_t buttons;
} mouse_command_t;

Not showing on HID device in Windows 10

"Good morning, I'm trying to use the code on an ESP32-S3. When I connect it to my Android phone, everything works correctly, but when I connect it to the PC, it doesn't work. In particular, I noticed that it doesn't appear among the HID devices (which instead happens with another similar example Arduino arduino-switcheroonie). Any ideas about this?"

Win 10/iOS

Reading through the closed issues and I saw that iOS and Win 10 support has been definitely working at some point, but I wasn't able to get it to work with the latest commit on master. Going to try on Android next and will report back, but wanted to see if anyone had a similar experience or how I can go about debugging this.

Thanks!

Media keys

Is it possible to send Media keystrokes like Play/Pause/Next?
Could you please provide an example?
And if i get it right, UART2 is not enabled on pins, right? How can I enable it?

BLE - GATT transmission rate limiting

On some phones (currently observed on one older Android device),
the received GATT HID reports are processed slower, which leads to noticeable delayed movements.

A possible solution would be a rate limitation for sending GATT data.

Open for discussion:

Relative data (mouse movements):

Should we discard received UART HID data if sent too fast
OR
should the ESP32 sum up mouse movement values & send them accumulated in one report?

Absolute data (mouse clicks & keyboard keys):

I think these should be sent ASAP (when the rate limiting timeout is finished), without further modification.

@ChrisVeigl what's your opinion?

With latest IDF 3.0, compile fails for esp_gatts_api.h and other BT headers

  1. IDF3.0 10.Jan.2018 toolchain is 1.22.0-80-g6c4433a, so warning is shown as required toolchain is lower: 1.22-0-8-75. Need to update to latest toolchain

WARNING: Toolchain version is not supported: 1.22.0-80-g6c4433a
Expected to see version: 1.22.0-75-gbaf03c2
Please check ESP-IDF setup instructions and update the toolchain, or proceed at your own risk.
WARNING: Toolchain version is not supported: 1.22.0-80-g6c4433a
Expected to see version: 1.22.0-75-gbaf03c2
Please check ESP-IDF setup instructions and update the toolchain, or proceed at your own risk.

  1. esp_gatts_api.h and other bluedroid headers are not getting included as the sdkconfig has a new item CONFIG_BLUEDROID_ENABLED=y. Need to enable this to get the files included.

CC build/main/hid_dev.o
In file included from C:/optimus/esp32/esp32_mouse_keyboard/main/hid_dev.h:18:0,
from C:/optimus/esp32/esp32_mouse_keyboard/main/hid_dev.c:15:
C:/optimus/esp32/esp32_mouse_keyboard/main/hidd_le_prf_int.h:19:27: fatal error: esp_gatts_api.h: No such file or directory
compilation terminated.
make[1]: *** [/c/optimus/esp-idf-v3.0-rc1/make/component_wrapper.mk:243: hid_dev.o] Error 1
make: *** [C:/optimus/esp-idf-v3.0-rc1/make/project.mk:448: component-main-build] Error 2

help with HID braille for open source devices for people with disabilities

Hello, I am developing a device for people with disabilities. I need to use the HID braille protocol but I am not getting anything with HID for esp32, could you help me with a sample code of how I can implement the HID braille protocol?

here are the braille HID references

https://usb.org/sites/default/files/hutrr78_-_creation_of_a_braille_display_usage_page_0.pdf

https://github.com/nvaccess/nvda/blob/00cd67b737bc5b23a6f5e31cf28110b64ebf2fee/devDocs/hidBrailleTechnicalNotes.md

my repository is the following
https://github.com/brailletouch/Brailletouch

Not enough poll rate with mouse commands

I have made an air mouse using your code and MPU6050 (6 axis gyro and accelerometer)
the sensor is able to report at 100hz, but when i send mouse commands at higher speeds than 10hz the commands get queued and i get heavy latency (near 1 sec), but at slow speeds (10hz or lower) there is fairly low latency but the cursor movements are very choppy.
So, i wanted to know if it's possible to increase the report rate of mouse commands in your code ?
i'm a total newbie to all this and need help here's my repo.

and thank you for making this, its awesome

What's the best bluetooth module for a DIY keyboard? BC417(HC-05), CC2540, CC2650, or ESP32?

What's the best bluetooth module for a DIY keyboard? BC417(HC-05), CC2540, CC2650, or ESP32?

I'm thinking about making a DIY bluetooth keyboard.

I searched and found many different modules that can do this. For example:

One is the BC417 (HC-05) module: https://mitxela.com/projects/bluetooth_hid_gamepad

Another one is the CC2540 module: https://hackaday.com/2017/05/20/the-tiniest-mechanical-keyboard-ever/
Or the newer CC2650 :https://e2e.ti.com/support/wireless-connectivity/bluetooth/f/538/t/659154

Another is this the ESP32 one: https://github.com/asterics/esp32_mouse_keyboard/

Are there anyother modules that can be used for a keyboard not listed? And how to choose, which one is the best? What are the advantages or disadvantages?

I also want the keyboard to have a function like the logitech's easy switch https://www.logitech.com/en-us/product/illuminated-keyboard-for-mac-ipad-iphone (using the same keyboard to pair with different computers and switch among them with one click). So can these modules do this?

iOS 17 compatibility

Dear @tiny1990 ,

if you have a problem, please open a new issue.
It was hard to find your comment in a 2 year old closed issue.

Please describe the problem a little bit more in detail, "not working" is neither helping me nor helping you.

So, please check following or give us feedback on following aspects:

  • Hardware platform, are you using our devices or a different ESP32 board?
  • Please post as attachment your sdkconfig file
  • Do you applied any changes on the sourcecode?
  • Is the device visible in iOS pairing menu?
  • Is the device pairing properly and shows "connected"?

Thank you, I'll try to get an iOS device for testing.

Greetings

How to compile w/ platformio of w/out

Hi there,

This looks very promising. I've used ESP32 on Windows with PlatformIO before but I don't know how to compile these files. I'm used to using the Arduino framework but this uses ESP-IDF correct? I'm trying to build this with PIO but it complains about esp_bt.h. I'm not sure how to resolve this, it's quite confusing. PIO identifies boards, platforms, frameworks and libraries. ESP-IDF qualifies as a framework and cannot easily be updated to the latest version I believe.

I'm not seeking on guidance on how to do this with PIO perse. Can you provide some guidance on how to get up and running on Windows 10? Where do I find the toolchain and make monitor console? If you can just point me to a good resource that would be fine!

In any case, I was glad to find this repo. This would be ideal as a bluetooth/hid proxy for environments that don't support bluetooth (don't get me started on my employer).

Thanks

Enable / disable pairing+bonding

Currently, it is not possible to deny any pairing requests.

We should include the possibility to deny pairing requests by default and enable them by a command via the external UART.

As there is no useful documentation how to do that,
I think it should be sufficient to deny an authentication request here

esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true);

by returning false.

Nevertheless, if we switch OFF pairing by default, it would break compatibility.
So I suggest we enable this feature by a new KConfig file.

iOS: Assistive Touch & Switch interface

After a very long try&error phase with this undocumented stuff from iOS,
I can finally announce that this repository works with iOS in assistive touch mode (mouse cursor) AND switch interface (button controlled scanning).

For future references (or maybe the esp32_snippets repository), following issues were resolved:

  • If the HID report map (and the corresponding attribute table) lists the mouse first, everything works fine. But iOS does NOT recognize any keyboard input as assistive switch input.
  • If the report map is built up: keyboard - keyboard LEDs - consumer control - mouse; everything works exactly the same, but iOS recognizes key presses as assistive switch.
  • The slave connection interval must have a value higher than 11.25ms (documented), we changed it to 12.5ms. This was no issue for normal keyboard operation & assistive touch mouse control.
  • The MTU does not have any effect on the connection.

I did not find any of this behaviour documented, if somebody can show me an official guideline for this, I'm fine. Otherwise, this is another example of undocumented and senseless behaviour of Apple devices 👎

EDIT: I used this branch:
https://github.com/asterics/esp32_mouse_keyboard/tree/bumpEspressifExample
with this commit 74a9328

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.