键盘特征值初始化示例
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 map
outputKeyboard = 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);
#else
BLESecurity* pSecurity = new BLESecurity();
pSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_MITM_BOND);
#endif // USE_NIMBLE
hid->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 key
k = 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 modifier
k &= 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 key
k = 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 modifier
k &= 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
}
}