ble nano hid over gatt
Dependencies: BLE_API mbed-dev nRF51822
KeyboardService.h
- Committer:
- cho45
- Date:
- 2016-08-31
- Revision:
- 59:2d6c0bff2151
- Parent:
- 51:d9297f8a60b7
- Child:
- 60:b899414e1d34
File content as of revision 59:2d6c0bff2151:
/* 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" #include "CircularBuffer.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) */ const 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 InputReportData { uint8_t raw[8]; struct { uint8_t modifier; uint8_t padding; uint8_t keycode[6]; } data; }; InputReportData inputReportDataPublished; InputReportData inputReportData; union { uint8_t raw[1]; } outputReportData; CircularBuffer<InputReportData, 24, uint8_t> inputReportBuffer; InputReportData inputReportDataSending; bool isSending; 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: bool sendAvailable; KeyboardService(BLE& _ble) : HIDServiceBase( _ble, KEYBOARD_REPORT_MAP, sizeof(KEYBOARD_REPORT_MAP), inputReport = inputReportDataPublished.raw, outputReport = outputReportData.raw, featureReport = NULL, inputReportLength = sizeof(inputReportData), outputReportLength = sizeof(outputReportData), featureReportLength = 0, reportTickerDelay = 20 ), isSending(false), sendAvailable(false) { for (int i = 0; i < 8; i++) { inputReportData.raw[i] = 0; } outputReportData.raw[0] = 0; inputReportBuffer.reset(); } void appendReportData(const uint8_t keycode) { uint8_t modifier = toModifierBit(keycode); if (modifier) { inputReportData.data.modifier |= modifier; return; } for (int i = 0; i < 6; i++) { if (inputReportData.data.keycode[i] == 0) { inputReportData.data.keycode[i] = keycode; return; } } // TODO: report data is full } void deleteReportData(const uint8_t keycode) { uint8_t modifier = toModifierBit(keycode); if (modifier) { inputReportData.data.modifier &= ~modifier; return; } for (int i = 0; i < 6; i++) { if (inputReportData.data.keycode[i] == keycode) { inputReportData.data.keycode[i] = 0; return; } } } void queueCurrentReportData() { inputReportBuffer.push(inputReportData); startReportTicker(); } uint8_t toModifierBit(const 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) { // do not call printf in this function... it cause BLE_STACK_BUSY sendAvailable = true; } void processSend() { if (!sendAvailable) { return; } sendAvailable = false; // isSending の場合現在送信中の report があり、再送中である可能性がある // そうではない場合のみ queue から pop して新しく send する if (!isSending) { if (!inputReportBuffer.pop(inputReportDataSending)) { // 送るデータがないなら送信をやめる stopReportTicker(); return; } } static uint8_t busyCount = 0; isSending = true; ble_error_t error = HIDServiceBase::send(inputReportDataSending.raw); if (error == BLE_STACK_BUSY) { if (busyCount++ > 10) { busyCount = 0; stopReportTicker(); } // retry after return; } isSending = false; } virtual void onDataSent(unsigned int count) { startReportTicker(); } virtual void stopReportTicker(void) { if (reportTickerIsActive) { HIDServiceBase::stopReportTicker(); } } };