ble nano hid over gatt

Dependencies:   BLE_API mbed-dev nRF51822

Committer:
cho45
Date:
Thu Jul 21 07:56:04 2016 +0900
Revision:
7:b9270a37345b
Parent:
6:f1c3ea8bc850
Child:
9:d1daefbf1fbd
ble..

Who changed what in which revision?

UserRevisionLine numberNew contents of line
cho45 5:65d4e94735b6 1 /* mbed Microcontroller Library
cho45 5:65d4e94735b6 2 * Copyright (c) 2015 ARM Limited
cho45 5:65d4e94735b6 3 *
cho45 5:65d4e94735b6 4 * Licensed under the Apache License, Version 2.0 (the "License");
cho45 5:65d4e94735b6 5 * you may not use this file except in compliance with the License.
cho45 5:65d4e94735b6 6 * You may obtain a copy of the License at
cho45 5:65d4e94735b6 7 *
cho45 5:65d4e94735b6 8 * http://www.apache.org/licenses/LICENSE-2.0
cho45 5:65d4e94735b6 9 *
cho45 5:65d4e94735b6 10 * Unless required by applicable law or agreed to in writing, software
cho45 5:65d4e94735b6 11 * distributed under the License is distributed on an "AS IS" BASIS,
cho45 5:65d4e94735b6 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
cho45 5:65d4e94735b6 13 * See the License for the specific language governing permissions and
cho45 5:65d4e94735b6 14 * limitations under the License.
cho45 5:65d4e94735b6 15 */
cho45 5:65d4e94735b6 16
cho45 5:65d4e94735b6 17 #include "HIDServiceBase.h"
cho45 5:65d4e94735b6 18 #include "keyboard.h"
cho45 7:b9270a37345b 19 #include "CircularBuffer.h"
cho45 5:65d4e94735b6 20
cho45 5:65d4e94735b6 21 /**
cho45 5:65d4e94735b6 22 * Report descriptor for a standard 101 keys keyboard, following the HID specification example:
cho45 5:65d4e94735b6 23 * - 8 bytes input report (1 byte for modifiers and 6 for keys)
cho45 5:65d4e94735b6 24 * - 1 byte output report (LEDs)
cho45 5:65d4e94735b6 25 */
cho45 5:65d4e94735b6 26 report_map_t KEYBOARD_REPORT_MAP = {
cho45 5:65d4e94735b6 27 USAGE_PAGE(1), 0x01, // Generic Desktop Ctrls
cho45 5:65d4e94735b6 28 USAGE(1), 0x06, // Keyboard
cho45 5:65d4e94735b6 29 COLLECTION(1), 0x01, // Application
cho45 5:65d4e94735b6 30 USAGE_PAGE(1), 0x07, // Kbrd/Keypad
cho45 5:65d4e94735b6 31 USAGE_MINIMUM(1), 0xE0,
cho45 5:65d4e94735b6 32 USAGE_MAXIMUM(1), 0xE7,
cho45 5:65d4e94735b6 33 LOGICAL_MINIMUM(1), 0x00,
cho45 5:65d4e94735b6 34 LOGICAL_MAXIMUM(1), 0x01,
cho45 5:65d4e94735b6 35 REPORT_SIZE(1), 0x01, // 1 byte (Modifier)
cho45 5:65d4e94735b6 36 REPORT_COUNT(1), 0x08,
cho45 5:65d4e94735b6 37 INPUT(1), 0x02, // Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position
cho45 5:65d4e94735b6 38 REPORT_COUNT(1), 0x01, // 1 byte (Reserved)
cho45 5:65d4e94735b6 39 REPORT_SIZE(1), 0x08,
cho45 5:65d4e94735b6 40 INPUT(1), 0x01, // Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position
cho45 5:65d4e94735b6 41 REPORT_COUNT(1), 0x05, // 5 bits (Num lock, Caps lock, Scroll lock, Compose, Kana)
cho45 5:65d4e94735b6 42 REPORT_SIZE(1), 0x01,
cho45 5:65d4e94735b6 43 USAGE_PAGE(1), 0x08, // LEDs
cho45 5:65d4e94735b6 44 USAGE_MINIMUM(1), 0x01, // Num Lock
cho45 5:65d4e94735b6 45 USAGE_MAXIMUM(1), 0x05, // Kana
cho45 5:65d4e94735b6 46 OUTPUT(1), 0x02, // Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile
cho45 5:65d4e94735b6 47 REPORT_COUNT(1), 0x01, // 3 bits (Padding)
cho45 5:65d4e94735b6 48 REPORT_SIZE(1), 0x03,
cho45 5:65d4e94735b6 49 OUTPUT(1), 0x01, // Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile
cho45 5:65d4e94735b6 50 REPORT_COUNT(1), 0x06, // 6 bytes (Keys)
cho45 5:65d4e94735b6 51 REPORT_SIZE(1), 0x08,
cho45 5:65d4e94735b6 52 LOGICAL_MINIMUM(1), 0x00,
cho45 5:65d4e94735b6 53 LOGICAL_MAXIMUM(1), 0x65, // 101 keys
cho45 5:65d4e94735b6 54 USAGE_PAGE(1), 0x07, // Kbrd/Keypad
cho45 5:65d4e94735b6 55 USAGE_MINIMUM(1), 0x00,
cho45 5:65d4e94735b6 56 USAGE_MAXIMUM(1), 0x65,
cho45 5:65d4e94735b6 57 INPUT(1), 0x00, // Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position
cho45 5:65d4e94735b6 58 END_COLLECTION(0),
cho45 5:65d4e94735b6 59 };
cho45 5:65d4e94735b6 60
cho45 5:65d4e94735b6 61 class KeyboardService : public HIDServiceBase {
cho45 7:b9270a37345b 62 union InputReportData {
cho45 5:65d4e94735b6 63 uint8_t raw[8];
cho45 5:65d4e94735b6 64 struct {
cho45 5:65d4e94735b6 65 uint8_t modifier;
cho45 5:65d4e94735b6 66 uint8_t padding;
cho45 5:65d4e94735b6 67 uint8_t keycode[6];
cho45 5:65d4e94735b6 68 } data;
cho45 7:b9270a37345b 69 };
cho45 7:b9270a37345b 70
cho45 7:b9270a37345b 71 InputReportData inputReportData;
cho45 5:65d4e94735b6 72
cho45 5:65d4e94735b6 73 union {
cho45 5:65d4e94735b6 74 uint8_t raw[1];
cho45 5:65d4e94735b6 75 } outputReportData;
cho45 5:65d4e94735b6 76
cho45 7:b9270a37345b 77 CircularBuffer<InputReportData, 32, uint8_t> inputReportBuffer;
cho45 7:b9270a37345b 78 InputReportData inputReportDataSending;
cho45 7:b9270a37345b 79 bool isSending;
cho45 7:b9270a37345b 80
cho45 5:65d4e94735b6 81 static const uint8_t MODIFIER_LEFT_CONTROL = 1<<0;
cho45 5:65d4e94735b6 82 static const uint8_t MODIFIER_LEFT_SHIFT = 1<<1;
cho45 5:65d4e94735b6 83 static const uint8_t MODIFIER_LEFT_ALT = 1<<2;
cho45 5:65d4e94735b6 84 static const uint8_t MODIFIER_LEFT_GUI = 1<<3;
cho45 5:65d4e94735b6 85 static const uint8_t MODIFIER_RIGHT_CONTROL = 1<<4;
cho45 5:65d4e94735b6 86 static const uint8_t MODIFIER_RIGHT_SHIFT = 1<<5;
cho45 5:65d4e94735b6 87 static const uint8_t MODIFIER_RIGHT_ALT = 1<<6;
cho45 5:65d4e94735b6 88 static const uint8_t MODIFIER_RIGHT_GUI = 1<<7;
cho45 5:65d4e94735b6 89
cho45 7:b9270a37345b 90 void queueCurrentReportData() {
cho45 7:b9270a37345b 91 inputReportBuffer.push(inputReportData);
cho45 7:b9270a37345b 92 startReportTicker();
cho45 7:b9270a37345b 93 }
cho45 7:b9270a37345b 94
cho45 5:65d4e94735b6 95 public:
cho45 5:65d4e94735b6 96 KeyboardService(BLE& _ble) :
cho45 5:65d4e94735b6 97 HIDServiceBase(
cho45 5:65d4e94735b6 98 _ble,
cho45 5:65d4e94735b6 99 KEYBOARD_REPORT_MAP,
cho45 5:65d4e94735b6 100 sizeof(KEYBOARD_REPORT_MAP),
cho45 5:65d4e94735b6 101 inputReport = inputReportData.raw,
cho45 5:65d4e94735b6 102 outputReport = outputReportData.raw,
cho45 5:65d4e94735b6 103 featureReport = NULL,
cho45 5:65d4e94735b6 104 inputReportLength = sizeof(inputReportData),
cho45 5:65d4e94735b6 105 outputReportLength = sizeof(outputReportData),
cho45 5:65d4e94735b6 106 featureReportLength = 0,
cho45 5:65d4e94735b6 107 reportTickerDelay = 24
cho45 7:b9270a37345b 108 ),
cho45 7:b9270a37345b 109 isSending(false)
cho45 5:65d4e94735b6 110 {
cho45 6:f1c3ea8bc850 111 for (int i = 0; i < 8; i++) {
cho45 6:f1c3ea8bc850 112 inputReportData.raw[i] = 0;
cho45 6:f1c3ea8bc850 113 }
cho45 6:f1c3ea8bc850 114 outputReportData.raw[0] = 0;
cho45 7:b9270a37345b 115
cho45 7:b9270a37345b 116 inputReportBuffer.reset();
cho45 5:65d4e94735b6 117 }
cho45 5:65d4e94735b6 118
cho45 5:65d4e94735b6 119 void appendReportData(uint8_t keycode) {
cho45 5:65d4e94735b6 120 uint8_t modifier = toModifierBit(keycode);
cho45 5:65d4e94735b6 121 if (modifier) {
cho45 5:65d4e94735b6 122 inputReportData.data.modifier |= modifier;
cho45 7:b9270a37345b 123 queueCurrentReportData();
cho45 5:65d4e94735b6 124 return;
cho45 5:65d4e94735b6 125 }
cho45 5:65d4e94735b6 126
cho45 5:65d4e94735b6 127
cho45 5:65d4e94735b6 128 for (int i = 0; i < 6; i++) {
cho45 5:65d4e94735b6 129 if (inputReportData.data.keycode[i] == 0) {
cho45 5:65d4e94735b6 130 inputReportData.data.keycode[i] = keycode;
cho45 7:b9270a37345b 131 queueCurrentReportData();
cho45 5:65d4e94735b6 132 return;
cho45 5:65d4e94735b6 133 }
cho45 5:65d4e94735b6 134 }
cho45 5:65d4e94735b6 135
cho45 5:65d4e94735b6 136 // TODO: report data is full
cho45 5:65d4e94735b6 137 }
cho45 5:65d4e94735b6 138
cho45 5:65d4e94735b6 139 void deleteReportData(uint8_t keycode) {
cho45 5:65d4e94735b6 140 uint8_t modifier = toModifierBit(keycode);
cho45 5:65d4e94735b6 141 if (modifier) {
cho45 5:65d4e94735b6 142 inputReportData.data.modifier &= ~modifier;
cho45 7:b9270a37345b 143 queueCurrentReportData();
cho45 5:65d4e94735b6 144 return;
cho45 5:65d4e94735b6 145 }
cho45 5:65d4e94735b6 146
cho45 5:65d4e94735b6 147 for (int i = 0; i < 6; i++) {
cho45 5:65d4e94735b6 148 if (inputReportData.data.keycode[i] == keycode) {
cho45 5:65d4e94735b6 149 inputReportData.data.keycode[i] = 0;
cho45 7:b9270a37345b 150 queueCurrentReportData();
cho45 5:65d4e94735b6 151 return;
cho45 5:65d4e94735b6 152 }
cho45 5:65d4e94735b6 153 }
cho45 5:65d4e94735b6 154 }
cho45 5:65d4e94735b6 155
cho45 5:65d4e94735b6 156 uint8_t toModifierBit(uint8_t keycode) const {
cho45 5:65d4e94735b6 157 switch (keycode) {
cho45 5:65d4e94735b6 158 case KEY_LeftControl: return MODIFIER_LEFT_CONTROL;
cho45 5:65d4e94735b6 159 case KEY_LeftShift: return MODIFIER_LEFT_SHIFT;
cho45 5:65d4e94735b6 160 case KEY_LeftAlt: return MODIFIER_LEFT_ALT;
cho45 5:65d4e94735b6 161 case KEY_LeftGUI: return MODIFIER_LEFT_GUI;
cho45 5:65d4e94735b6 162 case KEY_RightControl: return MODIFIER_RIGHT_CONTROL;
cho45 5:65d4e94735b6 163 case KEY_RightShift: return MODIFIER_RIGHT_SHIFT;
cho45 5:65d4e94735b6 164 case KEY_RightAlt: return MODIFIER_RIGHT_ALT;
cho45 5:65d4e94735b6 165 case KEY_RightGUI: return MODIFIER_RIGHT_GUI;
cho45 5:65d4e94735b6 166 }
cho45 5:65d4e94735b6 167 return 0;
cho45 5:65d4e94735b6 168 }
cho45 5:65d4e94735b6 169
cho45 5:65d4e94735b6 170 bool isKeyPressed() {
cho45 5:65d4e94735b6 171 for (int i = 0; i < 8; i++) {
cho45 5:65d4e94735b6 172 if (inputReportData.raw[i]) {
cho45 5:65d4e94735b6 173 return 1;
cho45 5:65d4e94735b6 174 }
cho45 5:65d4e94735b6 175 }
cho45 5:65d4e94735b6 176 return 0;
cho45 5:65d4e94735b6 177 }
cho45 5:65d4e94735b6 178
cho45 5:65d4e94735b6 179 virtual void sendCallback(void) {
cho45 7:b9270a37345b 180 // do not call printf in this function... it cause BLE_STACK_BUSY
cho45 7:b9270a37345b 181
cho45 7:b9270a37345b 182 InputReportData data;
cho45 7:b9270a37345b 183 if (isSending) {
cho45 7:b9270a37345b 184 data = inputReportDataSending;
cho45 7:b9270a37345b 185 } else {
cho45 7:b9270a37345b 186 if (!inputReportBuffer.pop(data)) {
cho45 7:b9270a37345b 187 if (isKeyPressed()) {
cho45 7:b9270a37345b 188 data = inputReportData;
cho45 7:b9270a37345b 189 } else {
cho45 7:b9270a37345b 190 stopReportTicker();
cho45 7:b9270a37345b 191 return;
cho45 7:b9270a37345b 192 }
cho45 7:b9270a37345b 193 }
cho45 7:b9270a37345b 194 }
cho45 7:b9270a37345b 195
cho45 7:b9270a37345b 196 static uint8_t busyCount = 0;
cho45 7:b9270a37345b 197 isSending = true;
cho45 7:b9270a37345b 198 ble_error_t error = HIDServiceBase::send(data.raw);
cho45 5:65d4e94735b6 199 if (error == BLE_STACK_BUSY) {
cho45 7:b9270a37345b 200 if (busyCount++ > 10) {
cho45 7:b9270a37345b 201 busyCount = 0;
cho45 7:b9270a37345b 202 printf("BLE_STACK_BUSY is over 10-times stop\r\n");
cho45 7:b9270a37345b 203 stopReportTicker();
cho45 7:b9270a37345b 204 }
cho45 7:b9270a37345b 205 inputReportDataSending = data;
cho45 5:65d4e94735b6 206 // retry after
cho45 5:65d4e94735b6 207 return;
cho45 5:65d4e94735b6 208 }
cho45 7:b9270a37345b 209 isSending = false;
cho45 7:b9270a37345b 210 }
cho45 5:65d4e94735b6 211
cho45 7:b9270a37345b 212 virtual void onDataSent(unsigned int count) {
cho45 7:b9270a37345b 213 startReportTicker();
cho45 5:65d4e94735b6 214 }
cho45 5:65d4e94735b6 215 };
cho45 5:65d4e94735b6 216
cho45 5:65d4e94735b6 217