Bluetooth HID issue

I am trying to get wio terminal working as a hid bluetooth device.
I tried to use ESP32-BLE-Keyboard, but failed.
And I have just found the code about Bluetooth HID devices in the wio terminal official Bluetooth library. But I didn’t see any documents about them. How do I use official libraries to create HID devices?

I’m also trying to use the Wio Terminal as a hid bluetooth device with no success.
Like @Zhou mentioned, is it possible to provide an example on how to use the Seeed_Arduino_rpcBLE and the Seeed_Arduino_rpcUnified libraries in order to do that?

My understanding was that the two libraries mentioned above were supposed to “implement BLE function compatibility with Arduino-ESP32” in order to enable code written for the ESP32’s bluetooth feature to run in the Wio Terminal. However, it does not seem to be that simple and details are not provided on how to make it work. @edw brought up the same issue on another post. Are there any guides on how to use ESP32 HID bluetooth code with the Wio Terminal?

Just like Zhou, I tried to use ESP32-BLE-Keyboard but had many compilation errors. For example, the library BLEUtils.h and driver/adc.h are missing from rpcBLE and rpcUnified. I found a version of BLEUtils.h in the dev-server branch of rpcBLE but when I imported it to my project I got a few errors such as BLEUtils.h:21:28: error: expected ';' at end of member declaration static const char* addressTypeToString(esp_ble_addr_type_t type);. The syntax looks ok to me so I don’t know how to move forward.

Any help is greatly appreciated. Thanks.

Just to follow up, I found code from Github user manuelbl for the ESP32 that seems to almost work. However, I cannot pair the Wio Terminal and it keeps disconnecting. I’m suspecting it’s a security or bonding issue. I had to comment out the lines with:
BLESecurity *security = new BLESecurity(); security->setAuthenticationMode(ESP_LE_AUTH_BOND);
because the library BLESecurity is not implemented for Seeed’s rpcUnified or rpcBLE. I’ll post my code below, if anyone had an idea that would be greatly appreciated.

/*
  Based on Github user manuelbl: https://gist.github.com/manuelbl/66f059effc8a7be148adb1f104666467
*/
#include <HIDTypes.h>
#include <rpcBLEDevice.h>
#include <BLEServer.h>
#include <BLEHIDDevice.h>
#include <HIDKeyboardTypes.h>

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#define US_KEYBOARD 1

#define MESSAGE "Hello from Wio Terminal\n"
#define DEVICE_NAME "Wio Terminal"

bool isBleConnected = false;

BLEHIDDevice *hid;
BLECharacteristic *input;
BLECharacteristic *output;

struct InputReport
{
  uint8_t modifiers;      // bitmask: CTRL = 1, SHIFT = 2, ALT = 4
  uint8_t reserved;       // must be 0
  uint8_t pressedKeys[6]; // up to six concurrenlty pressed keys
};

// Message (report) received when an LED's state changed
struct OutputReport
{
  uint8_t leds; // bitmask: num lock = 1, caps lock = 2, scroll lock = 4, compose = 8, kana = 16
};

const InputReport NO_KEY_PRESSED = {};

/*
 * Callbacks related to BLE connection
 */
class BleKeyboardCallbacks : public BLEServerCallbacks
{

  void onConnect(BLEServer *server)
  {
    isBleConnected = true;

    // Allow notifications for characteristics
    BLE2902 *cccDesc = (BLE2902 *)input->getDescriptorByUUID(BLEUUID((uint16_t)0x2902));
    cccDesc->setNotifications(true);

    Serial.println("Client has connected");
  }

  void onDisconnect(BLEServer *server)
  {
    isBleConnected = false;

    // Disallow notifications for characteristics
    BLE2902 *cccDesc = (BLE2902 *)input->getDescriptorByUUID(BLEUUID((uint16_t)0x2902));
    cccDesc->setNotifications(false);

    Serial.println("Client has disconnected");
  }
};

/*
 * Called when the client (computer, smart phone) wants to turn on or off
 * the LEDs in the keyboard.
 * 
 * bit 0 - NUM LOCK
 * bit 1 - CAPS LOCK
 * bit 2 - SCROLL LOCK
 */
class OutputCallbacks : public BLECharacteristicCallbacks
{
  void onWrite(BLECharacteristic *characteristic)
  {
    OutputReport *report = (OutputReport *)characteristic->getData();
    Serial.println("Value received from Host");
    Serial.print("LED state: ");
    Serial.print((int)report->leds);
    Serial.println();
  }
};

// The report map describes the HID device (a keyboard in this case) and
// the messages (reports in HID terms) sent and received.
static const uint8_t REPORT_MAP[] = {
    USAGE_PAGE(1), 0x01,      // Generic Desktop Controls
    USAGE(1), 0x06,           // Keyboard
    COLLECTION(1), 0x01,      // Application
    REPORT_ID(1), 0x01,       //   Report ID (1)
    USAGE_PAGE(1), 0x07,      //   Keyboard/Keypad
    USAGE_MINIMUM(1), 0xE0,   //   Keyboard Left Control
    USAGE_MAXIMUM(1), 0xE7,   //   Keyboard Right Control
    LOGICAL_MINIMUM(1), 0x00, //   Each bit is either 0 or 1
    LOGICAL_MAXIMUM(1), 0x01,
    REPORT_COUNT(1), 0x08, //   8 bits for the modifier keys
    REPORT_SIZE(1), 0x01,
    HIDINPUT(1), 0x02,     //   Data, Var, Abs
    REPORT_COUNT(1), 0x01, //   1 byte (unused)
    REPORT_SIZE(1), 0x08,
    HIDINPUT(1), 0x01,     //   Const, Array, Abs
    REPORT_COUNT(1), 0x06, //   6 bytes (for up to 6 concurrently pressed keys)
    REPORT_SIZE(1), 0x08,
    LOGICAL_MINIMUM(1), 0x00,
    LOGICAL_MAXIMUM(1), 0x65, //   101 keys
    USAGE_MINIMUM(1), 0x00,
    USAGE_MAXIMUM(1), 0x65,
    HIDINPUT(1), 0x00,     //   Data, Array, Abs
    REPORT_COUNT(1), 0x05, //   5 bits (Num lock, Caps lock, Scroll lock, Compose, Kana)
    REPORT_SIZE(1), 0x01,
    USAGE_PAGE(1), 0x08,    //   LEDs
    USAGE_MINIMUM(1), 0x01, //   Num Lock
    USAGE_MAXIMUM(1), 0x05, //   Kana
    LOGICAL_MINIMUM(1), 0x00,
    LOGICAL_MAXIMUM(1), 0x01,
    HIDOUTPUT(1), 0x02,    //   Data, Var, Abs
    REPORT_COUNT(1), 0x01, //   3 bits (Padding)
    REPORT_SIZE(1), 0x03,
    HIDOUTPUT(1), 0x01, //   Const, Array, Abs
    END_COLLECTION(0)   // End application collection
};

void setup()
{
  Serial.begin(115200);
  while (!Serial)
  {
  };
  Serial.println("Starting BLE work!");

  pinMode(WIO_KEY_A, INPUT_PULLUP);

  BLEDevice::init(DEVICE_NAME);
  BLEServer *server = BLEDevice::createServer();
  server->setCallbacks(new BleKeyboardCallbacks());

  // create an HID device
  hid = new BLEHIDDevice(server);
  input = hid->inputReport(1);   // report ID
  output = hid->outputReport(1); // report ID
  output->setCallbacks(new OutputCallbacks());

  // set manufacturer name
  hid->manufacturer()->setValue("Maker Community");
  // set USB vendor and product ID
  hid->pnp(0x02, 0xe502, 0xa111, 0x0210);
  // information about HID device: device is not localized, device can be connected
  hid->hidInfo(0x00, 0x02);

  // Security: device requires bonding
  // BLESecurity *security = new BLESecurity();
  // security->setAuthenticationMode(ESP_LE_AUTH_BOND);

  // set report map
  hid->reportMap((uint8_t *)REPORT_MAP, sizeof(REPORT_MAP));
  hid->startServices();

  // set battery level to 100%
  hid->setBatteryLevel(100);

  // advertise the services
  BLEAdvertising *advertising = server->getAdvertising();
  advertising->setAppearance(HID_KEYBOARD);
  advertising->addServiceUUID(hid->hidService()->getUUID());
  advertising->addServiceUUID(hid->deviceInfo()->getUUID());
  advertising->addServiceUUID(hid->batteryService()->getUUID());
  advertising->start();

  Serial.println("Characteristic defined! Now you can read it in your phone!");
  Serial.println("BLE ready");
  delay(portMAX_DELAY);
}

void loop()
{
  Serial.print("BLE Conneciton state: ");
  Serial.println(isBleConnected);

  if (isBleConnected && digitalRead(WIO_KEY_A) == LOW)
  {
    // button has been pressed: type message
    Serial.println(MESSAGE);
    typeText(MESSAGE);
  }

  delay(100);
}

void typeText(const char *text)
{
  int len = strlen(text);
  for (int i = 0; i < len; i++)
  {

    // translate character to key combination
    uint8_t val = (uint8_t)text[i];
    if (val > KEYMAP_SIZE)
      continue; // character not available on keyboard - skip
    KEYMAP map = keymap[val];

    // create input report
    InputReport report = {
        .modifiers = map.modifier,
        .reserved = 0,
        .pressedKeys = {
            map.usage,
            0, 0, 0, 0, 0}};

    // send the input report
    input->setValue((uint8_t *)&report, sizeof(report));
    input->notify();

    delay(5);

    // release all keys between two characters; otherwise two identical
    // consecutive characters are treated as just one key press
    input->setValue((uint8_t *)&NO_KEY_PRESSED, sizeof(NO_KEY_PRESSED));
    input->notify();

    delay(5);
  }
}

I had this problem too…
It looks like seeed just have given up technical support for wio terminal

Wio Terminal is currently our key product and will not stop its technical support. You can see an example of Wio Termianl using Bluetooth on this page: https://wiki.seeedstudio.com/Wio-Terminal-Bluetooth-Overview/

In the Bluetooth library of ESP32, “BLESecurity” calls “esp_gap_ble_api”, which seems to be related to ESP32 hardware. So now Seeed may need to adapt BLESecurity for wio terminal.

But this issue has been raised for more than three months and it is obvious that no one has tried to answer us :confused: