ble nano hid over gatt

Dependencies:   BLE_API mbed-dev nRF51822

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();
+		}
+	}
+};
+
+