ble nano hid over gatt

Dependencies:   BLE_API mbed-dev nRF51822

Revision:
86:e0fab77e669d
Parent:
83:2e940d154f8b
--- a/KeyboardService.h	Thu Sep 15 08:48:57 2016 +0900
+++ b/KeyboardService.h	Thu Sep 15 09:31:05 2016 +0900
@@ -28,6 +28,7 @@
 	USAGE_PAGE(1),      0x01,       // Generic Desktop Ctrls
 	USAGE(1),           0x06,       // Keyboard
 	COLLECTION(1),      0x01,       // Application
+		REPORT_ID(1),       0x01,
 		USAGE_PAGE(1),      0x07,       //   Kbrd/Keypad
 		USAGE_MINIMUM(1),   0xE0,
 		USAGE_MAXIMUM(1),   0xE7,
@@ -61,13 +62,36 @@
 		USAGE_MAXIMUM(1),   0x65,
 		INPUT(1),           0x00,       //   Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position
 
-		USAGE_PAGE(1),      0x00,       //   Undefined
-		USAGE_MINIMUM(1),   0x00,
-		USAGE_MAXIMUM(1),   0xFF,
-		REPORT_COUNT(1),    0x01,       //   1 byte 
-		REPORT_SIZE(1),     0x08,
-		FEATURE(1),         0x02,       //   Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile
+		USAGE_PAGE(1),      0x0C,       //   Consumer
+		USAGE(1),           0x00,
+		COLLECTION(1),      0x02,       // Logical
+			REPORT_ID(1),       0x01,
+			USAGE_MINIMUM(1),   0x00,
+			USAGE_MAXIMUM(1),   0xFF,
+			REPORT_COUNT(1),    0x01,       //   1 byte 
+			REPORT_SIZE(1),     0x08,
+			FEATURE(1),         0x02,       //   Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile
+		END_COLLECTION(0),
 	END_COLLECTION(0),
+
+	USAGE_PAGE(1),      0x0C,
+	USAGE(1),           0x01,
+	COLLECTION(1),      0x01,
+		REPORT_ID(1),       0x03,
+		REPORT_SIZE(1), 0x10,
+		REPORT_COUNT(1), 0x01,
+		LOGICAL_MINIMUM(1), 1,
+		LOGICAL_MAXIMUM(2), 0xFF, 0x03,
+		USAGE_MINIMUM(1), 1,
+		USAGE_MAXIMUM(2), 0xFF, 0x03,
+		INPUT(1), 0x60,
+	END_COLLECTION(0),
+};
+
+static const report_reference_t consumerInputReportReferenceData = { 3, INPUT_REPORT };
+static const GattAttribute consumerInputReportReferenceDescriptor(BLE_UUID_DESCRIPTOR_REPORT_REFERENCE, (uint8_t *)&consumerInputReportReferenceData, 2, 2, false);
+static const GattAttribute * consumerInputReportDescriptors[] = {
+	&consumerInputReportReferenceDescriptor,
 };
 
 class KeyboardService : public HIDServiceBase {
@@ -89,12 +113,18 @@
 		uint8_t raw[1];
 	};
 
+	union ConsumerInputReportData {
+		uint8_t raw[2];
+		uint16_t key;
+	};
+
 	/**
 	 * Boot Protocol
 	 * Share input/output report with Report Protocol for memmory saving
 	 */
 	GattCharacteristic bootKeyboardInputReportCharacteristic;
 	GattCharacteristic bootKeyboardOutputReportCharacteristic;
+	GattCharacteristic consumerInputReportCharacteristic;
 
 	InputReportData inputReportDataPublished;
 	InputReportData inputReportData;
@@ -110,6 +140,9 @@
 	FeatureReportData featureReportData;
 	bool isSending;
 
+	ConsumerInputReportData consumerInputReportData;
+	bool hasPendingConsumerInputReport;
+
 	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;
@@ -149,7 +182,16 @@
 			| GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE
 			| GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE
 		),
+		consumerInputReportCharacteristic(
+			GattCharacteristic::UUID_REPORT_CHAR,
+			(uint8_t *)&consumerInputReportData, sizeof(consumerInputReportData), sizeof(consumerInputReportData),
+			GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ
+			| GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY
+			| GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE,
+			const_cast<GattAttribute**>(consumerInputReportDescriptors), 1
+		),
 		isSending(false),
+		hasPendingConsumerInputReport(false),
 		sendAvailable(false),
 		bufferCount(0)
 	{
@@ -165,6 +207,7 @@
 		DEBUG_PRINTF_BLE("addExtraCharacteristics %d\r\n", charIndex);
 		characteristics[charIndex++] = &bootKeyboardInputReportCharacteristic;
 		characteristics[charIndex++] = &bootKeyboardOutputReportCharacteristic;
+		characteristics[charIndex++] = &consumerInputReportCharacteristic;
 	}
 
 	virtual ble_error_t send(const report_t report) {
@@ -216,6 +259,18 @@
 		}
 	}
 
+	void pressConsumerKey(const uint16_t key) {
+		consumerInputReportData.key = key;
+		hasPendingConsumerInputReport = true;
+		sendAvailable = true;
+	}
+
+	void releaseConsumerKey() {
+		consumerInputReportData.key = 0;
+		hasPendingConsumerInputReport = true;
+		sendAvailable = true;
+	}
+
 	void queueCurrentReportData() {
 		DEBUG_PRINTF_BLE("Q %d\r\n", bufferCount);
 		bufferCount++;
@@ -251,6 +306,15 @@
 			return;
 		}
 		sendAvailable = false;
+
+		if (hasPendingConsumerInputReport) {
+			ble.gattServer().write(
+				consumerInputReportCharacteristic.getValueHandle(),
+				(uint8_t*)&consumerInputReportData,
+				sizeof(consumerInputReportData)
+			);
+			hasPendingConsumerInputReport = false;
+		}
 		
 		// isSending の場合現在送信中の report があり、再送中である可能性がある
 		// そうではない場合のみ queue から pop して新しく send する