ble nano hid over gatt
Dependencies: BLE_API mbed-dev nRF51822
Diff: KeyboardService.h
- Revision:
- 5:65d4e94735b6
- Child:
- 6:f1c3ea8bc850
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/KeyboardService.h Thu Jul 21 00:38:09 2016 +0900 @@ -0,0 +1,173 @@ +/* mbed Microcontroller Library + * Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "HIDServiceBase.h" +#include "keyboard.h" + +/** + * Report descriptor for a standard 101 keys keyboard, following the HID specification example: + * - 8 bytes input report (1 byte for modifiers and 6 for keys) + * - 1 byte output report (LEDs) + */ +report_map_t KEYBOARD_REPORT_MAP = { + USAGE_PAGE(1), 0x01, // Generic Desktop Ctrls + USAGE(1), 0x06, // Keyboard + COLLECTION(1), 0x01, // Application + USAGE_PAGE(1), 0x07, // Kbrd/Keypad + USAGE_MINIMUM(1), 0xE0, + USAGE_MAXIMUM(1), 0xE7, + LOGICAL_MINIMUM(1), 0x00, + LOGICAL_MAXIMUM(1), 0x01, + REPORT_SIZE(1), 0x01, // 1 byte (Modifier) + REPORT_COUNT(1), 0x08, + INPUT(1), 0x02, // Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position + REPORT_COUNT(1), 0x01, // 1 byte (Reserved) + REPORT_SIZE(1), 0x08, + INPUT(1), 0x01, // Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position + 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 + OUTPUT(1), 0x02, // Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile + REPORT_COUNT(1), 0x01, // 3 bits (Padding) + REPORT_SIZE(1), 0x03, + OUTPUT(1), 0x01, // Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile + REPORT_COUNT(1), 0x06, // 6 bytes (Keys) + REPORT_SIZE(1), 0x08, + LOGICAL_MINIMUM(1), 0x00, + LOGICAL_MAXIMUM(1), 0x65, // 101 keys + USAGE_PAGE(1), 0x07, // Kbrd/Keypad + USAGE_MINIMUM(1), 0x00, + USAGE_MAXIMUM(1), 0x65, + INPUT(1), 0x00, // Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position + END_COLLECTION(0), +}; + +class KeyboardService : public HIDServiceBase { + union { + uint8_t raw[8]; + struct { + uint8_t modifier; + uint8_t padding; + uint8_t keycode[6]; + } data; + } inputReportData; + + union { + uint8_t raw[1]; + } outputReportData; + + static const uint8_t MODIFIER_LEFT_CONTROL = 1<<0; + static const uint8_t MODIFIER_LEFT_SHIFT = 1<<1; + static const uint8_t MODIFIER_LEFT_ALT = 1<<2; + static const uint8_t MODIFIER_LEFT_GUI = 1<<3; + static const uint8_t MODIFIER_RIGHT_CONTROL = 1<<4; + static const uint8_t MODIFIER_RIGHT_SHIFT = 1<<5; + static const uint8_t MODIFIER_RIGHT_ALT = 1<<6; + static const uint8_t MODIFIER_RIGHT_GUI = 1<<7; + +public: + KeyboardService(BLE& _ble) : + HIDServiceBase( + _ble, + KEYBOARD_REPORT_MAP, + sizeof(KEYBOARD_REPORT_MAP), + inputReport = inputReportData.raw, + outputReport = outputReportData.raw, + featureReport = NULL, + inputReportLength = sizeof(inputReportData), + outputReportLength = sizeof(outputReportData), + featureReportLength = 0, + reportTickerDelay = 24 + ) + { + } + + void appendReportData(uint8_t keycode) { + uint8_t modifier = toModifierBit(keycode); + if (modifier) { + inputReportData.data.modifier |= modifier; + startReportTicker(); + return; + } + + + for (int i = 0; i < 6; i++) { + if (inputReportData.data.keycode[i] == 0) { + inputReportData.data.keycode[i] = keycode; + startReportTicker(); + return; + } + } + + // TODO: report data is full + } + + void deleteReportData(uint8_t keycode) { + uint8_t modifier = toModifierBit(keycode); + if (modifier) { + inputReportData.data.modifier &= ~modifier; + startReportTicker(); + return; + } + + for (int i = 0; i < 6; i++) { + if (inputReportData.data.keycode[i] == keycode) { + inputReportData.data.keycode[i] = 0; + startReportTicker(); + return; + } + } + } + + uint8_t toModifierBit(uint8_t keycode) const { + switch (keycode) { + case KEY_LeftControl: return MODIFIER_LEFT_CONTROL; + case KEY_LeftShift: return MODIFIER_LEFT_SHIFT; + case KEY_LeftAlt: return MODIFIER_LEFT_ALT; + case KEY_LeftGUI: return MODIFIER_LEFT_GUI; + case KEY_RightControl: return MODIFIER_RIGHT_CONTROL; + case KEY_RightShift: return MODIFIER_RIGHT_SHIFT; + case KEY_RightAlt: return MODIFIER_RIGHT_ALT; + case KEY_RightGUI: return MODIFIER_RIGHT_GUI; + } + return 0; + } + + bool isKeyPressed() { + for (int i = 0; i < 8; i++) { + if (inputReportData.raw[i]) { + return 1; + } + } + return 0; + } + + virtual void sendCallback(void) { + ble_error_t error = HIDServiceBase::send(inputReportData.raw); + if (error == BLE_STACK_BUSY) { + // retry after + return; + } + + if (!isKeyPressed()) { + stopReportTicker(); + } + } +}; + +