Based on the example USB HID keyboard https://developer.mbed.org/users/jbru/code/BLE_HID_KeyboardStreamDemo/

Dependencies:   BLE_API mbed nRF51822

Fork of HID-kb by Microbug

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers HIDServiceBase.cpp Source File

HIDServiceBase.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2015 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include "mbed.h"
00018 #include "HIDServiceBase.h"
00019 
00020 HIDServiceBase::HIDServiceBase(BLE          &_ble,
00021                                report_map_t reportMap,
00022                                uint8_t      reportMapSize,
00023                                report_t     inputReport,
00024                                report_t     outputReport,
00025                                report_t     featureReport,
00026                                uint8_t      inputReportLength,
00027                                uint8_t      outputReportLength,
00028                                uint8_t      featureReportLength,
00029                                uint8_t      inputReportTickerDelay) :
00030     ble(_ble),
00031     connected (false),
00032     reportMapLength(reportMapSize),
00033 
00034     inputReport(inputReport),
00035     outputReport(outputReport),
00036     featureReport(featureReport),
00037 
00038     inputReportLength(inputReportLength),
00039     outputReportLength(outputReportLength),
00040     featureReportLength(featureReportLength),
00041 
00042     protocolMode(REPORT_PROTOCOL),
00043 
00044     inputReportReferenceDescriptor(BLE_UUID_DESCRIPTOR_REPORT_REFERENCE,
00045             (uint8_t *)&inputReportReferenceData, 2, 2),
00046     outputReportReferenceDescriptor(BLE_UUID_DESCRIPTOR_REPORT_REFERENCE,
00047             (uint8_t *)&outputReportReferenceData, 2, 2),
00048     featureReportReferenceDescriptor(BLE_UUID_DESCRIPTOR_REPORT_REFERENCE,
00049             (uint8_t *)&featureReportReferenceData, 2, 2),
00050 
00051     protocolModeCharacteristic(GattCharacteristic::UUID_PROTOCOL_MODE_CHAR, &protocolMode, 1, 1,
00052               GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ
00053             | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE),
00054 
00055     inputReportCharacteristic(GattCharacteristic::UUID_REPORT_CHAR,
00056             (uint8_t *)inputReport, inputReportLength, inputReportLength,
00057               GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ
00058             | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY
00059             | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE,
00060             inputReportDescriptors(), 1),
00061 
00062     outputReportCharacteristic(GattCharacteristic::UUID_REPORT_CHAR,
00063             (uint8_t *)outputReport, outputReportLength, outputReportLength,
00064               GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ
00065             | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE
00066             | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE,
00067             outputReportDescriptors(), 1),
00068 
00069     featureReportCharacteristic(GattCharacteristic::UUID_REPORT_CHAR,
00070             (uint8_t *)featureReport, featureReportLength, featureReportLength,
00071               GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ
00072             | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE,
00073             featureReportDescriptors(), 1),
00074 
00075     /*
00076      * We need to set reportMap content as const, in order to let the compiler put it into flash
00077      * instead of RAM. The characteristic is read-only so it won't be written, but
00078      * GattCharacteristic constructor takes non-const arguments only. Hence the cast.
00079      */
00080     reportMapCharacteristic(GattCharacteristic::UUID_REPORT_MAP_CHAR,
00081             const_cast<uint8_t*>(reportMap), reportMapLength, reportMapLength,
00082             GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ),
00083 
00084     HIDInformationCharacteristic(GattCharacteristic::UUID_HID_INFORMATION_CHAR, HIDInformation()),
00085     HIDControlPointCharacteristic(GattCharacteristic::UUID_HID_CONTROL_POINT_CHAR,
00086             &controlPointCommand, 1, 1,
00087             GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE),
00088 
00089     reportTickerDelay(inputReportTickerDelay),
00090     reportTickerIsActive(false)
00091 {
00092     static GattCharacteristic *characteristics[] = {
00093         &HIDInformationCharacteristic,
00094         &reportMapCharacteristic,
00095         &protocolModeCharacteristic,
00096         &HIDControlPointCharacteristic,
00097         NULL,
00098         NULL,
00099         NULL,
00100         NULL,
00101         NULL
00102     };
00103 
00104     unsigned int charIndex = 4;
00105     /*
00106      * Report characteristics are optional, and depend on the reportMap descriptor
00107      * Note: at least one should be present, but we don't check that at the moment.
00108      */
00109     if (inputReportLength)
00110         characteristics[charIndex++] = &inputReportCharacteristic;
00111     if (outputReportLength)
00112         characteristics[charIndex++] = &outputReportCharacteristic;
00113     if (featureReportLength)
00114         characteristics[charIndex++] = &featureReportCharacteristic;
00115 
00116     /* TODO: let children add some more characteristics, namely boot keyboard and mouse (They are
00117      * mandatory as per HIDS spec.) Ex:
00118      *
00119      * addExtraCharacteristics(characteristics, int& charIndex);
00120      */
00121 
00122     GattService service(GattService::UUID_HUMAN_INTERFACE_DEVICE_SERVICE,
00123                         characteristics, charIndex);
00124 
00125     ble.gattServer().addService(service);
00126 
00127     ble.gap().onConnection(this, &HIDServiceBase::onConnection);
00128     ble.gap().onDisconnection(this, &HIDServiceBase::onDisconnection);
00129 
00130     ble.gattServer().onDataSent(this, &HIDServiceBase::onDataSent);
00131 
00132     /*
00133      * Change preferred connection params, in order to optimize the notification frequency. Most
00134      * OSes seem to respect this, even though they are not required to.
00135      *
00136      * Some OSes don't handle reconnection well, at the moment, so we set the maximum possible
00137      * timeout, 32 seconds
00138      */
00139     uint16_t minInterval = Gap::MSEC_TO_GAP_DURATION_UNITS(reportTickerDelay / 2);
00140     if (minInterval < 6)
00141         minInterval = 6;
00142     uint16_t maxInterval = minInterval * 2;
00143     Gap::ConnectionParams_t params = {minInterval, maxInterval, 0, 3200};
00144 
00145     ble.gap().setPreferredConnectionParams(&params);
00146 
00147     SecurityManager::SecurityMode_t securityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM;
00148     protocolModeCharacteristic.requireSecurity(securityMode);
00149     reportMapCharacteristic.requireSecurity(securityMode);
00150     inputReportCharacteristic.requireSecurity(securityMode);
00151     outputReportCharacteristic.requireSecurity(securityMode);
00152     featureReportCharacteristic.requireSecurity(securityMode);
00153 }
00154 
00155 void HIDServiceBase::startReportTicker(void) {
00156     if (reportTickerIsActive)
00157         return;
00158     reportTicker.attach_us(this, &HIDServiceBase::sendCallback, reportTickerDelay * 1000);
00159     reportTickerIsActive = true;
00160 }
00161 
00162 void HIDServiceBase::stopReportTicker(void) {
00163     reportTicker.detach();
00164     reportTickerIsActive = false;
00165 }
00166 
00167 void HIDServiceBase::onDataSent(unsigned count) {
00168     startReportTicker();
00169 }
00170 
00171 GattAttribute** HIDServiceBase::inputReportDescriptors() {
00172     inputReportReferenceData.ID = 0;
00173     inputReportReferenceData.type = INPUT_REPORT;
00174 
00175     static GattAttribute * descs[] = {
00176         &inputReportReferenceDescriptor,
00177     };
00178     return descs;
00179 }
00180 
00181 GattAttribute** HIDServiceBase::outputReportDescriptors() {
00182     outputReportReferenceData.ID = 0;
00183     outputReportReferenceData.type = OUTPUT_REPORT;
00184 
00185     static GattAttribute * descs[] = {
00186         &outputReportReferenceDescriptor,
00187     };
00188     return descs;
00189 }
00190 
00191 GattAttribute** HIDServiceBase::featureReportDescriptors() {
00192     featureReportReferenceData.ID = 0;
00193     featureReportReferenceData.type = FEATURE_REPORT;
00194 
00195     static GattAttribute * descs[] = {
00196         &featureReportReferenceDescriptor,
00197     };
00198     return descs;
00199 }
00200 
00201 
00202 HID_information_t* HIDServiceBase::HIDInformation() {
00203     static HID_information_t info = {HID_VERSION_1_11, 0x00, 0x03};
00204     printf("read hid information\n");
00205 
00206     return &info;
00207 }
00208 
00209 ble_error_t HIDServiceBase::send(const report_t report) {
00210     return ble.gattServer().write(inputReportCharacteristic.getValueHandle(),
00211                                   report,
00212                                   inputReportLength);
00213 }
00214 
00215 ble_error_t HIDServiceBase::read(report_t report) {
00216     // TODO. For the time being, we'll just have HID input reports...
00217     printf("read not implemented\n");
00218     return BLE_ERROR_NOT_IMPLEMENTED;
00219 }
00220 
00221 void HIDServiceBase::onConnection(const Gap::ConnectionCallbackParams_t *params)
00222 {
00223     this->connected = true;
00224 }
00225 
00226 void HIDServiceBase::onDisconnection(const Gap::DisconnectionCallbackParams_t *params)
00227 {
00228     this->connected = false;
00229 }
00230