StepanovPlaton

BLE Serial и BLE HidKeyboard на ESP32 одновременно

Jun 1st, 2021
769
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.01 KB | None | 0 0
  1. /*
  2.  * Sample program for ESP32 acting as a Bluetooth keyboard
  3.  *
  4.  * Copyright (c) 2019 Manuel Bl
  5.  *
  6.  * Licensed under MIT License
  7.  * https://opensource.org/licenses/MIT
  8.  */
  9.  
  10. //
  11. // This program lets an ESP32 act as a keyboard connected via Bluetooth.
  12. // When a button attached to the ESP32 is pressed, it will generate the key strokes for a message.
  13. //
  14. // For the setup, a momentary button should be connected to pin 2 and to ground.
  15. // Pin 2 will be configured as an input with pull-up.
  16. //
  17. // In order to receive the message, add the ESP32 as a Bluetooth keyboard of your computer
  18. // or mobile phone:
  19. //
  20. // 1. Go to your computers/phones settings
  21. // 2. Ensure Bluetooth is turned on
  22. // 3. Scan for Bluetooth devices
  23. // 4. Connect to the device called "ESP32 Keyboard"
  24. // 5. Open an empty document in a text editor
  25. // 6. Press the button attached to the ESP32
  26.  
  27. #define US_KEYBOARD 1
  28.  
  29. #include <Arduino.h>
  30. #include "BLEDevice.h"
  31. #include "BLEHIDDevice.h"
  32. #include "HIDTypes.h"
  33. #include "HIDKeyboardTypes.h"
  34.  
  35.  
  36. // Change the below values if desired
  37. #define MESSAGE "Hello from ESP32\n"
  38. #define DEVICE_NAME "ESP32"
  39.  
  40.  
  41. // Forward declarations
  42. void bluetoothTask(void*);
  43. void typeText(const char* text);
  44.  
  45.  
  46. bool isBleConnected = false;
  47.  
  48.  
  49. #define SERVICE_UUID           "de16b533-9650-4457-9717-7c5d087c8f58" // UART service UUID
  50. #define CHARACTERISTIC_UUID_RX "de16b533-9650-4457-9717-7c5d087c8f58"
  51. #define CHARACTERISTIC_UUID_TX "de16b533-9650-4457-9717-7c5d087c8f58"
  52.  
  53. BLEServer *pServer = NULL;
  54. BLECharacteristic * pTxCharacteristic;
  55.  
  56.  
  57. void setup() {
  58.     Serial.begin(115200);
  59.  
  60.     // start Bluetooth task
  61.     xTaskCreate(bluetoothTask, "bluetooth", 20000, NULL, 5, NULL);
  62. }
  63.  
  64.  
  65. void loop() {  
  66.     delay(100);
  67. }
  68.  
  69.  
  70. // Message (report) sent when a key is pressed or released
  71. struct InputReport {
  72.     uint8_t modifiers;       // bitmask: CTRL = 1, SHIFT = 2, ALT = 4
  73.     uint8_t reserved;        // must be 0
  74.     uint8_t pressedKeys[6];  // up to six concurrenlty pressed keys
  75. };
  76.  
  77. // Message (report) received when an LED's state changed
  78. struct OutputReport {
  79.     uint8_t leds;            // bitmask: num lock = 1, caps lock = 2, scroll lock = 4, compose = 8, kana = 16
  80. };
  81.  
  82.  
  83. // The report map describes the HID device (a keyboard in this case) and
  84. // the messages (reports in HID terms) sent and received.
  85. static const uint8_t REPORT_MAP[] = {
  86.     USAGE_PAGE(1),      0x01,       // Generic Desktop Controls
  87.     USAGE(1),           0x06,       // Keyboard
  88.     COLLECTION(1),      0x01,       // Application
  89.     REPORT_ID(1),       0x01,       //   Report ID (1)
  90.     USAGE_PAGE(1),      0x07,       //   Keyboard/Keypad
  91.     USAGE_MINIMUM(1),   0xE0,       //   Keyboard Left Control
  92.     USAGE_MAXIMUM(1),   0xE7,       //   Keyboard Right Control
  93.     LOGICAL_MINIMUM(1), 0x00,       //   Each bit is either 0 or 1
  94.     LOGICAL_MAXIMUM(1), 0x01,
  95.     REPORT_COUNT(1),    0x08,       //   8 bits for the modifier keys
  96.     REPORT_SIZE(1),     0x01,      
  97.     HIDINPUT(1),        0x02,       //   Data, Var, Abs
  98.     REPORT_COUNT(1),    0x01,       //   1 byte (unused)
  99.     REPORT_SIZE(1),     0x08,
  100.     HIDINPUT(1),        0x01,       //   Const, Array, Abs
  101.     REPORT_COUNT(1),    0x06,       //   6 bytes (for up to 6 concurrently pressed keys)
  102.     REPORT_SIZE(1),     0x08,
  103.     LOGICAL_MINIMUM(1), 0x00,
  104.     LOGICAL_MAXIMUM(1), 0x65,       //   101 keys
  105.     USAGE_MINIMUM(1),   0x00,
  106.     USAGE_MAXIMUM(1),   0x65,
  107.     HIDINPUT(1),        0x00,       //   Data, Array, Abs
  108.     REPORT_COUNT(1),    0x05,       //   5 bits (Num lock, Caps lock, Scroll lock, Compose, Kana)
  109.     REPORT_SIZE(1),     0x01,
  110.     USAGE_PAGE(1),      0x08,       //   LEDs
  111.     USAGE_MINIMUM(1),   0x01,       //   Num Lock
  112.     USAGE_MAXIMUM(1),   0x05,       //   Kana
  113.     LOGICAL_MINIMUM(1), 0x00,
  114.     LOGICAL_MAXIMUM(1), 0x01,
  115.     HIDOUTPUT(1),       0x02,       //   Data, Var, Abs
  116.     REPORT_COUNT(1),    0x01,       //   3 bits (Padding)
  117.     REPORT_SIZE(1),     0x03,
  118.     HIDOUTPUT(1),       0x01,       //   Const, Array, Abs
  119.     END_COLLECTION(0)               // End application collection
  120. };
  121.  
  122.  
  123. BLEHIDDevice* hid;
  124. BLECharacteristic* input;
  125. BLECharacteristic* output;
  126.  
  127. const InputReport NO_KEY_PRESSED = { };
  128.  
  129.  
  130. /*
  131.  * Callbacks related to BLE connection
  132.  */
  133. class ServerCallbacks : public BLEServerCallbacks {
  134.  
  135.     void onConnect(BLEServer* server) {
  136.         isBleConnected = true;
  137.  
  138.         // Allow notifications for characteristics
  139.         BLE2902* cccDesc = (BLE2902*)input->getDescriptorByUUID(BLEUUID((uint16_t)0x2902));
  140.         cccDesc->setNotifications(true);
  141.  
  142.         Serial.println("Client has connected");
  143.     }
  144.  
  145.     void onDisconnect(BLEServer* server) {
  146.         isBleConnected = false;
  147.  
  148.         // Disallow notifications for characteristics
  149.         BLE2902* cccDesc = (BLE2902*)input->getDescriptorByUUID(BLEUUID((uint16_t)0x2902));
  150.         cccDesc->setNotifications(false);
  151.  
  152.         Serial.println("Client has disconnected");
  153.     }
  154. };
  155.  
  156.  
  157. /*
  158.  * Called when the client (computer, smart phone) wants to turn on or off
  159.  * the LEDs in the keyboard.
  160.  *
  161.  * bit 0 - NUM LOCK
  162.  * bit 1 - CAPS LOCK
  163.  * bit 2 - SCROLL LOCK
  164.  */
  165.  class KeyboardOutputCallbacks : public BLECharacteristicCallbacks {
  166.     void onWrite(BLECharacteristic* characteristic) {
  167.         OutputReport* report = (OutputReport*) characteristic->getData();
  168.         Serial.print("LED state: ");
  169.         Serial.print((int) report->leds);
  170.         Serial.println();
  171.     }
  172. };
  173.  
  174. class UARTRXCallbacks: public BLECharacteristicCallbacks {
  175.     void onWrite(BLECharacteristic *pCharacteristic) {
  176.       std::string rxValue = pCharacteristic->getValue();
  177.  
  178.       if (rxValue.length() > 0) {
  179.         Serial.println("*********");
  180.         Serial.print("Received Value: ");
  181.         for (int i = 0; i < rxValue.length(); i++)
  182.           Serial.print(rxValue[i]);
  183.  
  184.         Serial.println();
  185.         Serial.println("*********");
  186.       }
  187.     }
  188. };
  189.  
  190. void bluetoothTask(void*) {
  191.  
  192.     // initialize the device
  193.     BLEDevice::init(DEVICE_NAME);
  194.     BLEServer* server = BLEDevice::createServer();
  195.     server->setCallbacks(new ServerCallbacks());
  196.  
  197.     // create an HID device
  198.     hid = new BLEHIDDevice(server);
  199.     input = hid->inputReport(1); // report ID
  200.     output = hid->outputReport(1); // report ID
  201.     output->setCallbacks(new KeyboardOutputCallbacks());
  202.  
  203.     // set manufacturer name
  204.     hid->manufacturer()->setValue("Maker Community");
  205.     // set USB vendor and product ID
  206.     hid->pnp(0x02, 0xe502, 0xa111, 0x0210);
  207.     // information about HID device: device is not localized, device can be connected
  208.     hid->hidInfo(0x00, 0x02);
  209.  
  210.     // Security: device requires bonding
  211.     BLESecurity* security = new BLESecurity();
  212.     security->setAuthenticationMode(ESP_LE_AUTH_BOND);
  213.  
  214.     // set report map
  215.     hid->reportMap((uint8_t*)REPORT_MAP, sizeof(REPORT_MAP));
  216.     hid->startServices();
  217.  
  218.     // set battery level to 100%
  219.     hid->setBatteryLevel(100);
  220.  
  221.  
  222.  
  223.     BLEService *pService = server->createService(SERVICE_UUID);
  224.  
  225.     // Create a BLE Characteristic
  226.     pTxCharacteristic = pService->createCharacteristic(
  227.                                         CHARACTERISTIC_UUID_TX,
  228.                                         BLECharacteristic::PROPERTY_NOTIFY
  229.                                     );
  230.                      
  231.     pTxCharacteristic->addDescriptor(new BLE2902());
  232.  
  233.     BLECharacteristic * pRxCharacteristic = pService->createCharacteristic(
  234.                                               CHARACTERISTIC_UUID_RX,
  235.                                               BLECharacteristic::PROPERTY_WRITE
  236.                                           );
  237.  
  238.     pRxCharacteristic->setCallbacks(new UARTRXCallbacks());
  239.  
  240.     // Start the service
  241.     pService->start();
  242.  
  243.  
  244.  
  245.  
  246.     // advertise the services
  247.     BLEAdvertising* advertising = server->getAdvertising();
  248.     advertising->setAppearance(HID_KEYBOARD);
  249.     advertising->addServiceUUID(hid->hidService()->getUUID());
  250.     advertising->addServiceUUID(hid->deviceInfo()->getUUID());
  251.     advertising->addServiceUUID(hid->batteryService()->getUUID());
  252.     advertising->addServiceUUID(pService->getUUID());
  253.     advertising->start();
  254.  
  255.     Serial.println("BLE ready");
  256.     delay(portMAX_DELAY);
  257. };
  258.  
  259.  
  260. void typeText(const char* text) {
  261.     int len = strlen(text);
  262.     for (int i = 0; i < len; i++) {
  263.  
  264.         // translate character to key combination
  265.         uint8_t val = (uint8_t)text[i];
  266.         if (val > KEYMAP_SIZE)
  267.             continue; // character not available on keyboard - skip
  268.         KEYMAP map = keymap[val];
  269.  
  270.         // create input report
  271.         InputReport report = {
  272.             .modifiers = map.modifier,
  273.             .reserved = 0,
  274.             .pressedKeys = {
  275.                 map.usage,
  276.                 0, 0, 0, 0, 0
  277.             }
  278.         };
  279.  
  280.         // send the input report
  281.         input->setValue((uint8_t*)&report, sizeof(report));
  282.         input->notify();
  283.  
  284.         delay(5);
  285.  
  286.         // release all keys between two characters; otherwise two identical
  287.         // consecutive characters are treated as just one key press
  288.         input->setValue((uint8_t*)&NO_KEY_PRESSED, sizeof(NO_KEY_PRESSED));
  289.         input->notify();
  290.  
  291.         delay(5);
  292.     }
  293. }
Advertisement
Add Comment
Please, Sign In to add comment