键盘特征值初始化示例
void BleKeyboard::begin(void)
{BLEDevice::init(deviceName);BLEServer* pServer = BLEDevice::createServer();pServer->setCallbacks(this);hid = new BLEHIDDevice(pServer);inputKeyboard = hid->inputReport(KEYBOARD_ID); // <-- input REPORTID from report mapoutputKeyboard = hid->outputReport(KEYBOARD_ID);inputMediaKeys = hid->inputReport(MEDIA_KEYS_ID);outputKeyboard->setCallbacks(this);hid->manufacturer()->setValue(deviceManufacturer);hid->pnp(0x02, vid, pid, version);hid->hidInfo(0x00, 0x01);#if defined(USE_NIMBLE)BLEDevice::setSecurityAuth(true, true, true);#elseBLESecurity* pSecurity = new BLESecurity();pSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_MITM_BOND);#endif // USE_NIMBLEhid->reportMap((uint8_t*)_hidReportDescriptor, sizeof(_hidReportDescriptor));hid->startServices();onStarted(pServer);advertising = pServer->getAdvertising();advertising->setAppearance(HID_KEYBOARD);advertising->addServiceUUID(hid->hidService()->getUUID());advertising->setScanResponse(false);advertising->start();hid->setBatteryLevel(batteryLevel);ESP_LOGD(LOG_TAG, "Advertising started!");
}
2901:用户描述,如上图:My Counter
2902:特征值配置(需要主动推送notify、indicate就需要增加)
Bluetooth Low Energy (BLE) 中的这两个服务具有基本而重要的功能,它们为 BLE 设备提供基础支持。下面是关于这两个服务的详细介绍:
-
0x1800 - Generic Access Service (通用访问服务):
这个服务包含了许多跟 BLE 设备的连接和设备本身信息相关的属性。这些属性包括设备名称(Device Name,0x2A00)、外观(Appearance,0x2A01)、外设连接参数(Peripheral Preferred Connection Parameters,0x2A04)等。用户可以通过访问这些属性,获取和设置与 BLE 设备相关的信息,从而实现连接设置、设备信息展示等功能。 -
0x1801 - Generic Attribute Service (通用属性服务):
这个服务是 BLE 中其他服务和特征数据交互的基础,它提供了一个框架以支持其他服务和特征值的查找、读取、写入等操作。这个服务通常包含了服务修改变更特征(Service Change, 0x2A05)。这个特征会在服务或特征发生变更时触发,通知其他相关的设备需要重新发现服务、特征等。
总之,这两个服务在 BLE 通信过程中起到了基础和桥接的作用,支持设备建立连接,获取属性信息,以及实现其他自定义服务的数据通信。
实际示例中,蓝牙鼠标、耳机等典型设备会设置这些值来描述设备的基本信息和配置:
- 蓝牙鼠标:
-
通用访问服务(Generic Access Service,0x1800):
- 设备名称(Device Name,0x2A00):例如 “WeTab Wireless Mouse”
- 外观(Appearance,0x2A01):鼠标的类型和类别,例如设置为 “Mouse” 类型
- 外设连接参数(Peripheral Preferred Connection Parameters,0x2A04):设置鼠标的连接参数,例如设置连接间隔为 15ms-30ms。
-
通用属性服务(Generic Attribute Service,0x1801):
- 服务修改变更特征(Service Change,0x2A05):当鼠标的其他服务或特征发生变更时,触发此特征来通知设备重新发现服务或特征。
- 蓝牙耳机:
-
通用访问服务(Generic Access Service,0x1800):
- 设备名称(Device Name,0x2A00):例如 “WeTab Bluetooth Headphones”
- 外观(Appearance,0x2A01):耳机的类型和类别,例如设置为 “Headset” 类型
- 外设连接参数(Peripheral Preferred Connection Parameters,0x2A04):设置耳机的连接参数,例如选择适合音频传输的低延迟连接间隔。
-
通用属性服务(Generic Attribute Service,0x1801):
- 服务修改变更特征(Service Change,0x2A05):当耳机的其他服务或特征发生变更时(如音频控制、电池状态等),触发此特征来通知设备重新发现服务或特征。
以上是两个典型蓝牙设备设置通用访问服务和通用属性服务的例子。设备制造商可以根据设备类型和使用场景自定义属性值,从而为用户提供正确、稳定的蓝牙连接和使用体验。
链接蓝牙耳机的数据
罗技蓝牙鼠标的特征值
按键按下与松开处理,按键值为k,经过处理通过sendReport修改inputKeyboard特征值。
this->inputKeyboard->setValue((uint8_t*)keys, sizeof(KeyReport));
//按下按键处理
size_t BleKeyboard::press(uint8_t k)
{uint8_t i;if (k >= 136) { // it's a non-printing key (not a modifier)k = k - 136;} else if (k >= 128) { // it's a modifier key_keyReport.modifiers |= (1<<(k-128));k = 0;} else { // it's a printing keyk = pgm_read_byte(_asciimap + k);if (!k) {setWriteError();return 0;}if (k & 0x80) { // it's a capital letter or other character reached with shift_keyReport.modifiers |= 0x02; // the left shift modifierk &= 0x7F;}}// Add k to the key report only if it's not already present// and if there is an empty slot.if (_keyReport.keys[0] != k && _keyReport.keys[1] != k &&_keyReport.keys[2] != k && _keyReport.keys[3] != k &&_keyReport.keys[4] != k && _keyReport.keys[5] != k) {for (i=0; i<6; i++) {if (_keyReport.keys[i] == 0x00) {_keyReport.keys[i] = k;break;}}if (i == 6) {setWriteError();return 0;}}sendReport(&_keyReport);return 1;
}
//松开按键处理
size_t BleKeyboard::release(uint8_t k)
{uint8_t i;if (k >= 136) { // it's a non-printing key (not a modifier)k = k - 136;} else if (k >= 128) { // it's a modifier key_keyReport.modifiers &= ~(1<<(k-128));k = 0;} else { // it's a printing keyk = pgm_read_byte(_asciimap + k);if (!k) {return 0;}if (k & 0x80) { // it's a capital letter or other character reached with shift_keyReport.modifiers &= ~(0x02); // the left shift modifierk &= 0x7F;}}// Test the key report to see if k is present. Clear it if it exists.// Check all positions in case the key is present more than once (which it shouldn't be)for (i=0; i<6; i++) {if (0 != k && _keyReport.keys[i] == k) {_keyReport.keys[i] = 0x00;}}sendReport(&_keyReport);return 1;
}
//发送
void BleKeyboard::sendReport(KeyReport* keys)
{if (this->isConnected()){this->inputKeyboard->setValue((uint8_t*)keys, sizeof(KeyReport));this->inputKeyboard->notify();
#if defined(USE_NIMBLE) // vTaskDelay(delayTicks);this->delay_ms(_delay_ms);
#endif // USE_NIMBLE}
}