User | Revision | Line number | New contents of line |
xx316 |
1:032b96b05e51
|
1
|
/* mbed Microcontroller Library
|
xx316 |
1:032b96b05e51
|
2
|
* Copyright (c) 2015 ARM Limited
|
xx316 |
1:032b96b05e51
|
3
|
*
|
xx316 |
1:032b96b05e51
|
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
xx316 |
1:032b96b05e51
|
5
|
* you may not use this file except in compliance with the License.
|
xx316 |
1:032b96b05e51
|
6
|
* You may obtain a copy of the License at
|
xx316 |
1:032b96b05e51
|
7
|
*
|
xx316 |
1:032b96b05e51
|
8
|
* http://www.apache.org/licenses/LICENSE-2.0
|
xx316 |
1:032b96b05e51
|
9
|
*
|
xx316 |
1:032b96b05e51
|
10
|
* Unless required by applicable law or agreed to in writing, software
|
xx316 |
1:032b96b05e51
|
11
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
xx316 |
1:032b96b05e51
|
12
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
xx316 |
1:032b96b05e51
|
13
|
* See the License for the specific language governing permissions and
|
xx316 |
1:032b96b05e51
|
14
|
* limitations under the License.
|
xx316 |
1:032b96b05e51
|
15
|
*/
|
xx316 |
1:032b96b05e51
|
16
|
|
xx316 |
1:032b96b05e51
|
17
|
#include "mbed.h"
|
xx316 |
1:032b96b05e51
|
18
|
#include "HIDServiceBase.h"
|
xx316 |
1:032b96b05e51
|
19
|
|
xx316 |
1:032b96b05e51
|
20
|
HIDServiceBase::HIDServiceBase(BLE &_ble,
|
xx316 |
1:032b96b05e51
|
21
|
report_map_t reportMap,
|
xx316 |
1:032b96b05e51
|
22
|
uint8_t reportMapSize,
|
xx316 |
1:032b96b05e51
|
23
|
report_t inputReport,
|
xx316 |
1:032b96b05e51
|
24
|
report_t outputReport,
|
xx316 |
1:032b96b05e51
|
25
|
report_t featureReport,
|
xx316 |
1:032b96b05e51
|
26
|
uint8_t inputReportLength,
|
xx316 |
1:032b96b05e51
|
27
|
uint8_t outputReportLength,
|
xx316 |
1:032b96b05e51
|
28
|
uint8_t featureReportLength,
|
xx316 |
1:032b96b05e51
|
29
|
uint8_t inputReportTickerDelay) :
|
xx316 |
1:032b96b05e51
|
30
|
ble(_ble),
|
xx316 |
1:032b96b05e51
|
31
|
connected (false),
|
xx316 |
1:032b96b05e51
|
32
|
reportMapLength(reportMapSize),
|
xx316 |
1:032b96b05e51
|
33
|
|
xx316 |
1:032b96b05e51
|
34
|
inputReport(inputReport),
|
xx316 |
1:032b96b05e51
|
35
|
outputReport(outputReport),
|
xx316 |
1:032b96b05e51
|
36
|
featureReport(featureReport),
|
xx316 |
1:032b96b05e51
|
37
|
|
xx316 |
1:032b96b05e51
|
38
|
inputReportLength(inputReportLength),
|
xx316 |
1:032b96b05e51
|
39
|
outputReportLength(outputReportLength),
|
xx316 |
1:032b96b05e51
|
40
|
featureReportLength(featureReportLength),
|
xx316 |
1:032b96b05e51
|
41
|
|
xx316 |
1:032b96b05e51
|
42
|
protocolMode(REPORT_PROTOCOL),
|
xx316 |
1:032b96b05e51
|
43
|
|
xx316 |
1:032b96b05e51
|
44
|
inputReportReferenceDescriptor(BLE_UUID_DESCRIPTOR_REPORT_REFERENCE,
|
xx316 |
1:032b96b05e51
|
45
|
(uint8_t *)&inputReportReferenceData, 2, 2),
|
xx316 |
1:032b96b05e51
|
46
|
outputReportReferenceDescriptor(BLE_UUID_DESCRIPTOR_REPORT_REFERENCE,
|
xx316 |
1:032b96b05e51
|
47
|
(uint8_t *)&outputReportReferenceData, 2, 2),
|
xx316 |
1:032b96b05e51
|
48
|
featureReportReferenceDescriptor(BLE_UUID_DESCRIPTOR_REPORT_REFERENCE,
|
xx316 |
1:032b96b05e51
|
49
|
(uint8_t *)&featureReportReferenceData, 2, 2),
|
xx316 |
1:032b96b05e51
|
50
|
|
xx316 |
1:032b96b05e51
|
51
|
protocolModeCharacteristic(GattCharacteristic::UUID_PROTOCOL_MODE_CHAR, &protocolMode, 1, 1,
|
xx316 |
1:032b96b05e51
|
52
|
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ
|
xx316 |
1:032b96b05e51
|
53
|
| GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE),
|
xx316 |
1:032b96b05e51
|
54
|
|
xx316 |
1:032b96b05e51
|
55
|
inputReportCharacteristic(GattCharacteristic::UUID_REPORT_CHAR,
|
xx316 |
1:032b96b05e51
|
56
|
(uint8_t *)inputReport, inputReportLength, inputReportLength,
|
xx316 |
1:032b96b05e51
|
57
|
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ
|
xx316 |
1:032b96b05e51
|
58
|
| GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY
|
xx316 |
1:032b96b05e51
|
59
|
| GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE,
|
xx316 |
1:032b96b05e51
|
60
|
inputReportDescriptors(), 1),
|
xx316 |
1:032b96b05e51
|
61
|
|
xx316 |
1:032b96b05e51
|
62
|
outputReportCharacteristic(GattCharacteristic::UUID_REPORT_CHAR,
|
xx316 |
1:032b96b05e51
|
63
|
(uint8_t *)outputReport, outputReportLength, outputReportLength,
|
xx316 |
1:032b96b05e51
|
64
|
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ
|
xx316 |
1:032b96b05e51
|
65
|
| GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE
|
xx316 |
1:032b96b05e51
|
66
|
| GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE,
|
xx316 |
1:032b96b05e51
|
67
|
outputReportDescriptors(), 1),
|
xx316 |
1:032b96b05e51
|
68
|
|
xx316 |
1:032b96b05e51
|
69
|
featureReportCharacteristic(GattCharacteristic::UUID_REPORT_CHAR,
|
xx316 |
1:032b96b05e51
|
70
|
(uint8_t *)featureReport, featureReportLength, featureReportLength,
|
xx316 |
1:032b96b05e51
|
71
|
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ
|
xx316 |
1:032b96b05e51
|
72
|
| GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE,
|
xx316 |
1:032b96b05e51
|
73
|
featureReportDescriptors(), 1),
|
xx316 |
1:032b96b05e51
|
74
|
|
xx316 |
1:032b96b05e51
|
75
|
/*
|
xx316 |
1:032b96b05e51
|
76
|
* We need to set reportMap content as const, in order to let the compiler put it into flash
|
xx316 |
1:032b96b05e51
|
77
|
* instead of RAM. The characteristic is read-only so it won't be written, but
|
xx316 |
1:032b96b05e51
|
78
|
* GattCharacteristic constructor takes non-const arguments only. Hence the cast.
|
xx316 |
1:032b96b05e51
|
79
|
*/
|
xx316 |
1:032b96b05e51
|
80
|
reportMapCharacteristic(GattCharacteristic::UUID_REPORT_MAP_CHAR,
|
xx316 |
1:032b96b05e51
|
81
|
const_cast<uint8_t*>(reportMap), reportMapLength, reportMapLength,
|
xx316 |
1:032b96b05e51
|
82
|
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ),
|
xx316 |
1:032b96b05e51
|
83
|
|
xx316 |
1:032b96b05e51
|
84
|
HIDInformationCharacteristic(GattCharacteristic::UUID_HID_INFORMATION_CHAR, HIDInformation()),
|
xx316 |
1:032b96b05e51
|
85
|
HIDControlPointCharacteristic(GattCharacteristic::UUID_HID_CONTROL_POINT_CHAR,
|
xx316 |
1:032b96b05e51
|
86
|
&controlPointCommand, 1, 1,
|
xx316 |
1:032b96b05e51
|
87
|
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE),
|
xx316 |
1:032b96b05e51
|
88
|
|
xx316 |
1:032b96b05e51
|
89
|
reportTickerDelay(inputReportTickerDelay),
|
xx316 |
1:032b96b05e51
|
90
|
reportTickerIsActive(false)
|
xx316 |
1:032b96b05e51
|
91
|
{
|
xx316 |
1:032b96b05e51
|
92
|
static GattCharacteristic *characteristics[] = {
|
xx316 |
1:032b96b05e51
|
93
|
&HIDInformationCharacteristic,
|
xx316 |
1:032b96b05e51
|
94
|
&reportMapCharacteristic,
|
xx316 |
1:032b96b05e51
|
95
|
&protocolModeCharacteristic,
|
xx316 |
1:032b96b05e51
|
96
|
&HIDControlPointCharacteristic,
|
xx316 |
1:032b96b05e51
|
97
|
NULL,
|
xx316 |
1:032b96b05e51
|
98
|
NULL,
|
xx316 |
1:032b96b05e51
|
99
|
NULL,
|
xx316 |
1:032b96b05e51
|
100
|
NULL,
|
xx316 |
1:032b96b05e51
|
101
|
NULL
|
xx316 |
1:032b96b05e51
|
102
|
};
|
xx316 |
1:032b96b05e51
|
103
|
|
xx316 |
1:032b96b05e51
|
104
|
unsigned int charIndex = 4;
|
xx316 |
1:032b96b05e51
|
105
|
/*
|
xx316 |
1:032b96b05e51
|
106
|
* Report characteristics are optional, and depend on the reportMap descriptor
|
xx316 |
1:032b96b05e51
|
107
|
* Note: at least one should be present, but we don't check that at the moment.
|
xx316 |
1:032b96b05e51
|
108
|
*/
|
xx316 |
1:032b96b05e51
|
109
|
if (inputReportLength)
|
xx316 |
1:032b96b05e51
|
110
|
characteristics[charIndex++] = &inputReportCharacteristic;
|
xx316 |
1:032b96b05e51
|
111
|
if (outputReportLength)
|
xx316 |
1:032b96b05e51
|
112
|
characteristics[charIndex++] = &outputReportCharacteristic;
|
xx316 |
1:032b96b05e51
|
113
|
if (featureReportLength)
|
xx316 |
1:032b96b05e51
|
114
|
characteristics[charIndex++] = &featureReportCharacteristic;
|
xx316 |
1:032b96b05e51
|
115
|
|
xx316 |
1:032b96b05e51
|
116
|
/* TODO: let children add some more characteristics, namely boot keyboard and mouse (They are
|
xx316 |
1:032b96b05e51
|
117
|
* mandatory as per HIDS spec.) Ex:
|
xx316 |
1:032b96b05e51
|
118
|
*
|
xx316 |
1:032b96b05e51
|
119
|
* addExtraCharacteristics(characteristics, int& charIndex);
|
xx316 |
1:032b96b05e51
|
120
|
*/
|
xx316 |
1:032b96b05e51
|
121
|
|
xx316 |
1:032b96b05e51
|
122
|
GattService service(GattService::UUID_HUMAN_INTERFACE_DEVICE_SERVICE,
|
xx316 |
1:032b96b05e51
|
123
|
characteristics, charIndex);
|
xx316 |
1:032b96b05e51
|
124
|
|
xx316 |
1:032b96b05e51
|
125
|
ble.gattServer().addService(service);
|
xx316 |
1:032b96b05e51
|
126
|
|
xx316 |
1:032b96b05e51
|
127
|
ble.gap().onConnection(this, &HIDServiceBase::onConnection);
|
xx316 |
1:032b96b05e51
|
128
|
ble.gap().onDisconnection(this, &HIDServiceBase::onDisconnection);
|
xx316 |
1:032b96b05e51
|
129
|
|
xx316 |
1:032b96b05e51
|
130
|
ble.gattServer().onDataSent(this, &HIDServiceBase::onDataSent);
|
xx316 |
1:032b96b05e51
|
131
|
|
xx316 |
1:032b96b05e51
|
132
|
/*
|
xx316 |
1:032b96b05e51
|
133
|
* Change preferred connection params, in order to optimize the notification frequency. Most
|
xx316 |
1:032b96b05e51
|
134
|
* OSes seem to respect this, even though they are not required to.
|
xx316 |
1:032b96b05e51
|
135
|
*
|
xx316 |
1:032b96b05e51
|
136
|
* Some OSes don't handle reconnection well, at the moment, so we set the maximum possible
|
xx316 |
1:032b96b05e51
|
137
|
* timeout, 32 seconds
|
xx316 |
1:032b96b05e51
|
138
|
*/
|
xx316 |
1:032b96b05e51
|
139
|
uint16_t minInterval = Gap::MSEC_TO_GAP_DURATION_UNITS(reportTickerDelay / 2);
|
xx316 |
1:032b96b05e51
|
140
|
if (minInterval < 6)
|
xx316 |
1:032b96b05e51
|
141
|
minInterval = 6;
|
xx316 |
1:032b96b05e51
|
142
|
uint16_t maxInterval = minInterval * 2;
|
xx316 |
1:032b96b05e51
|
143
|
Gap::ConnectionParams_t params = {minInterval, maxInterval, 0, 3200};
|
xx316 |
1:032b96b05e51
|
144
|
|
xx316 |
1:032b96b05e51
|
145
|
ble.gap().setPreferredConnectionParams(¶ms);
|
xx316 |
1:032b96b05e51
|
146
|
|
xx316 |
1:032b96b05e51
|
147
|
SecurityManager::SecurityMode_t securityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM;
|
xx316 |
1:032b96b05e51
|
148
|
protocolModeCharacteristic.requireSecurity(securityMode);
|
xx316 |
1:032b96b05e51
|
149
|
reportMapCharacteristic.requireSecurity(securityMode);
|
xx316 |
1:032b96b05e51
|
150
|
inputReportCharacteristic.requireSecurity(securityMode);
|
xx316 |
1:032b96b05e51
|
151
|
outputReportCharacteristic.requireSecurity(securityMode);
|
xx316 |
1:032b96b05e51
|
152
|
featureReportCharacteristic.requireSecurity(securityMode);
|
xx316 |
1:032b96b05e51
|
153
|
}
|
xx316 |
1:032b96b05e51
|
154
|
|
xx316 |
1:032b96b05e51
|
155
|
void HIDServiceBase::startReportTicker(void) {
|
xx316 |
1:032b96b05e51
|
156
|
if (reportTickerIsActive)
|
xx316 |
1:032b96b05e51
|
157
|
return;
|
xx316 |
1:032b96b05e51
|
158
|
reportTicker.attach_us(this, &HIDServiceBase::sendCallback, reportTickerDelay * 1000);
|
xx316 |
1:032b96b05e51
|
159
|
reportTickerIsActive = true;
|
xx316 |
1:032b96b05e51
|
160
|
}
|
xx316 |
1:032b96b05e51
|
161
|
|
xx316 |
1:032b96b05e51
|
162
|
void HIDServiceBase::stopReportTicker(void) {
|
xx316 |
1:032b96b05e51
|
163
|
reportTicker.detach();
|
xx316 |
1:032b96b05e51
|
164
|
reportTickerIsActive = false;
|
xx316 |
1:032b96b05e51
|
165
|
}
|
xx316 |
1:032b96b05e51
|
166
|
|
xx316 |
1:032b96b05e51
|
167
|
void HIDServiceBase::onDataSent(unsigned count) {
|
xx316 |
1:032b96b05e51
|
168
|
startReportTicker();
|
xx316 |
1:032b96b05e51
|
169
|
}
|
xx316 |
1:032b96b05e51
|
170
|
|
xx316 |
1:032b96b05e51
|
171
|
GattAttribute** HIDServiceBase::inputReportDescriptors() {
|
xx316 |
1:032b96b05e51
|
172
|
inputReportReferenceData.ID = 0;
|
xx316 |
1:032b96b05e51
|
173
|
inputReportReferenceData.type = INPUT_REPORT;
|
xx316 |
1:032b96b05e51
|
174
|
|
xx316 |
1:032b96b05e51
|
175
|
static GattAttribute * descs[] = {
|
xx316 |
1:032b96b05e51
|
176
|
&inputReportReferenceDescriptor,
|
xx316 |
1:032b96b05e51
|
177
|
};
|
xx316 |
1:032b96b05e51
|
178
|
return descs;
|
xx316 |
1:032b96b05e51
|
179
|
}
|
xx316 |
1:032b96b05e51
|
180
|
|
xx316 |
1:032b96b05e51
|
181
|
GattAttribute** HIDServiceBase::outputReportDescriptors() {
|
xx316 |
1:032b96b05e51
|
182
|
outputReportReferenceData.ID = 0;
|
xx316 |
1:032b96b05e51
|
183
|
outputReportReferenceData.type = OUTPUT_REPORT;
|
xx316 |
1:032b96b05e51
|
184
|
|
xx316 |
1:032b96b05e51
|
185
|
static GattAttribute * descs[] = {
|
xx316 |
1:032b96b05e51
|
186
|
&outputReportReferenceDescriptor,
|
xx316 |
1:032b96b05e51
|
187
|
};
|
xx316 |
1:032b96b05e51
|
188
|
return descs;
|
xx316 |
1:032b96b05e51
|
189
|
}
|
xx316 |
1:032b96b05e51
|
190
|
|
xx316 |
1:032b96b05e51
|
191
|
GattAttribute** HIDServiceBase::featureReportDescriptors() {
|
xx316 |
1:032b96b05e51
|
192
|
featureReportReferenceData.ID = 0;
|
xx316 |
1:032b96b05e51
|
193
|
featureReportReferenceData.type = FEATURE_REPORT;
|
xx316 |
1:032b96b05e51
|
194
|
|
xx316 |
1:032b96b05e51
|
195
|
static GattAttribute * descs[] = {
|
xx316 |
1:032b96b05e51
|
196
|
&featureReportReferenceDescriptor,
|
xx316 |
1:032b96b05e51
|
197
|
};
|
xx316 |
1:032b96b05e51
|
198
|
return descs;
|
xx316 |
1:032b96b05e51
|
199
|
}
|
xx316 |
1:032b96b05e51
|
200
|
|
xx316 |
1:032b96b05e51
|
201
|
|
xx316 |
1:032b96b05e51
|
202
|
HID_information_t* HIDServiceBase::HIDInformation() {
|
xx316 |
1:032b96b05e51
|
203
|
static HID_information_t info = {HID_VERSION_1_11, 0x00, 0x03};
|
xx316 |
1:032b96b05e51
|
204
|
printf("read hid information\n");
|
xx316 |
1:032b96b05e51
|
205
|
|
xx316 |
1:032b96b05e51
|
206
|
return &info;
|
xx316 |
1:032b96b05e51
|
207
|
}
|
xx316 |
1:032b96b05e51
|
208
|
|
xx316 |
1:032b96b05e51
|
209
|
ble_error_t HIDServiceBase::send(const report_t report) {
|
xx316 |
1:032b96b05e51
|
210
|
return ble.gattServer().write(inputReportCharacteristic.getValueHandle(),
|
xx316 |
1:032b96b05e51
|
211
|
report,
|
xx316 |
1:032b96b05e51
|
212
|
inputReportLength);
|
xx316 |
1:032b96b05e51
|
213
|
}
|
xx316 |
1:032b96b05e51
|
214
|
|
xx316 |
1:032b96b05e51
|
215
|
ble_error_t HIDServiceBase::read(report_t report) {
|
xx316 |
1:032b96b05e51
|
216
|
// TODO. For the time being, we'll just have HID input reports...
|
xx316 |
1:032b96b05e51
|
217
|
printf("read not implemented\n");
|
xx316 |
1:032b96b05e51
|
218
|
return BLE_ERROR_NOT_IMPLEMENTED;
|
xx316 |
1:032b96b05e51
|
219
|
}
|
xx316 |
1:032b96b05e51
|
220
|
|
xx316 |
1:032b96b05e51
|
221
|
void HIDServiceBase::onConnection(const Gap::ConnectionCallbackParams_t *params)
|
xx316 |
1:032b96b05e51
|
222
|
{
|
xx316 |
1:032b96b05e51
|
223
|
this->connected = true;
|
xx316 |
1:032b96b05e51
|
224
|
}
|
xx316 |
1:032b96b05e51
|
225
|
|
xx316 |
1:032b96b05e51
|
226
|
void HIDServiceBase::onDisconnection(const Gap::DisconnectionCallbackParams_t *params)
|
xx316 |
1:032b96b05e51
|
227
|
{
|
xx316 |
1:032b96b05e51
|
228
|
this->connected = false;
|
xx316 |
1:032b96b05e51
|
229
|
}
|
xx316 |
1:032b96b05e51
|
230
|
|