Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

microbit-dal: Minimalist Keyboard HID Service #249

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
145 changes: 145 additions & 0 deletions inc/bluetooth/MicroBitDeviceInformationService.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 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.
*/

#ifndef __BLE_HID_DEVICE_INFORMATION_SERVICE_H__
#define __BLE_HID_DEVICE_INFORMATION_SERVICE_H__

#include "ble/BLE.h"

typedef struct
{
uint8_t vendorID_source;
uint16_t vendorID;
uint16_t productID;
uint16_t productVersion;
} PnPID_t;

/**
* @class HIDDeviceInformationService
* @brief BLE Device Information Service <br>
* Service: https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.device_information.xml <br>
* Manufacturer Name String Char: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.manufacturer_name_string.xml
*/
class HIDDeviceInformationService {
public:
/**
* @brief Device Information Service Constructor.
*
* @param[ref] _ble
* BLE object for the underlying controller.
* @param[in] manufacturersName
* This characteristic represents the name of the
* manufacturer of the device. The name is copied into the
* BLE stack during this constructor.
* @param[in] modelNumber
* This characteristic represents the model number that is
* assigned by the device vendor. The value is copied into
* the BLE stack during this constructor.
* @param[in] serialNumber
* This characteristic represents the serial number for a
* particular instance of the device. The value is copied
* into the BLE stack during this constructor.
* @param[in] hardwareRevision
* This characteristic represents the hardware revision for
* the hardware within the device. The value is copied
* into the BLE stack during this constructor.
* @param[in] firmwareRevision
* This characteristic represents the firmware revision for
* the firmware within the device. The value is copied
* into the BLE stack during this constructor.
* @param[in] softwareRevision
* This characteristic represents the software revision for
* the software within the device. The value is copied
* into the BLE stack during this constructor.
* @param[in] pnpID
* This characteristic represents HID-specific information,
* such as vendor id, product id and version.
*/
HIDDeviceInformationService(BLE &_ble,
const char *manufacturersName = NULL,
const char *modelNumber = NULL,
const char *serialNumber = NULL,
const char *hardwareRevision = NULL,
const char *firmwareRevision = NULL,
const char *softwareRevision = NULL,
PnPID_t *PnPID = NULL) :
ble(_ble)
{
static bool serviceAdded = false; /* We should only ever need to add the information service once. */
if (serviceAdded) {
return;
}

GattCharacteristic manufacturersNameStringCharacteristic(GattCharacteristic::UUID_MANUFACTURER_NAME_STRING_CHAR,
(uint8_t *)manufacturersName,
(manufacturersName != NULL) ? strlen(manufacturersName) : 0, /* minLength */
(manufacturersName != NULL) ? strlen(manufacturersName) : 0, /* maxLength */
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);

GattCharacteristic modelNumberStringCharacteristic(GattCharacteristic::UUID_MODEL_NUMBER_STRING_CHAR,
(uint8_t *)modelNumber,
(modelNumber != NULL) ? strlen(modelNumber) : 0, /* minLength */
(modelNumber != NULL) ? strlen(modelNumber) : 0, /* maxLength */
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);

GattCharacteristic serialNumberStringCharacteristic(GattCharacteristic::UUID_SERIAL_NUMBER_STRING_CHAR,
(uint8_t *)serialNumber,
(serialNumber != NULL) ? strlen(serialNumber) : 0, /* minLength */
(serialNumber != NULL) ? strlen(serialNumber) : 0, /* maxLength */
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);

GattCharacteristic hardwareRevisionStringCharacteristic(GattCharacteristic::UUID_HARDWARE_REVISION_STRING_CHAR,
(uint8_t *)hardwareRevision,
(hardwareRevision != NULL) ? strlen(hardwareRevision) : 0, /* minLength */
(hardwareRevision != NULL) ? strlen(hardwareRevision) : 0, /* maxLength */
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);

GattCharacteristic firmwareRevisionStringCharacteristic(GattCharacteristic::UUID_FIRMWARE_REVISION_STRING_CHAR,
(uint8_t *)firmwareRevision,
(firmwareRevision != NULL) ? strlen(firmwareRevision) : 0, /* minLength */
(firmwareRevision != NULL) ? strlen(firmwareRevision) : 0, /* maxLength */
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);

GattCharacteristic softwareRevisionStringCharacteristic(GattCharacteristic::UUID_SOFTWARE_REVISION_STRING_CHAR,
(uint8_t *)softwareRevision,
(softwareRevision != NULL) ? strlen(softwareRevision) : 0, /* minLength */
(softwareRevision != NULL) ? strlen(softwareRevision) : 0, /* maxLength */
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);

GattCharacteristic pnpIDCharacteristic(GattCharacteristic::UUID_PNP_ID_CHAR, (uint8_t *)PnPID, 7,7,GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);

GattCharacteristic *charTable[] = {&manufacturersNameStringCharacteristic,
&modelNumberStringCharacteristic,
&serialNumberStringCharacteristic,
&hardwareRevisionStringCharacteristic,
&firmwareRevisionStringCharacteristic,
&softwareRevisionStringCharacteristic,
&pnpIDCharacteristic};

GattService deviceInformationService(GattService::UUID_DEVICE_INFORMATION_SERVICE, charTable,
sizeof(charTable) / sizeof(GattCharacteristic *));

// for some reason, this causes the micro:bit build to break.
// pnpIDCharacteristic.requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM);
ble.addService(deviceInformationService);
serviceAdded = true;
}

protected:
BLE &ble;
};

#endif /* #ifndef __BLE_HID_DEVICE_INFORMATION_SERVICE_H__*/
123 changes: 123 additions & 0 deletions inc/bluetooth/MicroBitKeyboardService.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#ifndef MICROBIT_KEYBOARD_SERVICE_H
#define MICROBIT_KEYBOARD_SERVICE_H

#include "hid/BluetoothHIDTypes.h"
#include "hid/BluetoothHIDKeys.h"
#include "ble/services/BatteryService.h"
#include "ManagedString.h"
#include "ble/BLE.h"
#include "ScanParametersService.h"

#include "MicroBitComponent.h"

#define MICROBIT_HID_ADVERTISING_INT 100
#define MICROBIT_HID_STATE_IN_USE 0x02

/**
* This class represents a Bluetooth HID device, specifically, a keyboard instance.
*
* A few things to note:
* - HID devices require a battery service (automatically instantiated with this class)
* - Security is required, this class has only been tested using Just Works pairing.
* - On mac to get it to pair, you may have to interrogate a secure characteristic of the micro:bit via LightBlue
* in order to initiate pairing.
* - It is designed to be as light weight as possible, and employs tactics like the stack allocation of
* gatt characteristics to alleviate RAM pressures.
*/
class MicroBitKeyboardService : public MicroBitComponent
{
private:
BLEDevice& ble;
BatteryService* batteryService;
ScanParametersService* paramsService;

uint16_t inputDescriptorHandle;
uint16_t outputDescriptorHandle;
uint16_t featureDescriptorHandle;
uint16_t pmCharacteristicHandle;
uint16_t kInCharacteristicHandle;
uint16_t kOutCharacteristicHandle;
uint16_t rMapCharacteristicHandle;
uint16_t infoCharacteristicHandle;
uint16_t cpCharacteristicHandle;

GattAttribute* inputDescriptor;
GattAttribute* outputDescriptor;
GattAttribute* featureDescriptor;
GattAttribute* reportMapExternalRef;

GattCharacteristic* protocolModeCharacteristic;
GattCharacteristic* controlPointCharacteristic;
GattCharacteristic* keyboardInCharacteristic;
GattCharacteristic* bootInCharacteristic;

/**
* A simple helper function that "returns" our most recently "pressed" key to
* the up position.
*/
void keyUp();

/**
* Places and translates a single ascii character into a keyboard
* value, placing it in our input buffer.
*/
int putc(const char c);

public:

/**
* Constructor for our keyboard service.
*
* Creates a collection of characteristics, instantiates a battery service,
* and modifies advertisement data.
*/
MicroBitKeyboardService(BLEDevice& _ble, bool pairing);

/**
* Send a "Special" non-ascii keyboard key, defined in BluetoothHIDKeys.h
*/
int send(MediaKey key);

/**
* Send a single character to our host.
*
* @param c the character to send
*
* @return MICROBIT_NOT_SUPPORTED if the micro:bit is not connected to a host.
*/
int send(const char c);

/**
* Send a buffer of characters to our host.
*
* @param data the characters to send
*
* @param len the number of characters in the buffer.
*
* @return MICROBIT_NOT_SUPPORTED if the micro:bit is not connected to a host.
*/
int send(const char* data, int len);

/**
* Send a ManagedString to our host.
*
* @param data the string to send
*
* @return MICROBIT_NOT_SUPPORTED if the micro:bit is not connected to a host.
*/
int send(ManagedString data);

void debugRead(const GattReadCallbackParams *params);

void debugWrite(const GattWriteCallbackParams *params);

/**
* Destructor.
*
* Frees our heap allocated characteristic and service, and remove this instance
* from our system timer interrupt.
*/
~MicroBitKeyboardService();
};

#endif
58 changes: 58 additions & 0 deletions inc/bluetooth/ScanParametersService.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#ifndef __BLE_SCAN_PARAMETERS_SERVICE_H__
#define __BLE_SCAN_PARAMETERS_SERVICE_H__

#include "ble/BLE.h"

#pragma pack(push, 1)
typedef struct {
uint16_t LE_Scan_Interval;
uint16_t LE_Scan_Window;
} ScanIntervalWindow_t;
#pragma pack(pop)

class ScanParametersService {
public:
ScanParametersService(
BLE &_ble
) :
ble(_ble),
scanIntervalWindowCharacteristic(
GattCharacteristic::UUID_SCAN_INTERVAL_WINDOW_CHAR,
(uint8_t*)&scanIntervalWindowData,
sizeof(scanIntervalWindowData),
sizeof(scanIntervalWindowData),
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE
),
scanRefreshCharacteristic(
GattCharacteristic::UUID_SCAN_REFRESH_CHAR,
&scanRefreshData,
sizeof(scanIntervalWindowData),
sizeof(scanIntervalWindowData),
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY
)
{
GattCharacteristic *charTable[] = {
&scanIntervalWindowCharacteristic,
&scanRefreshCharacteristic
};

GattService scanParametersService(
GattService::UUID_SCAN_PARAMETERS_SERVICE,
charTable,
sizeof(charTable) / sizeof(GattCharacteristic *)
);

ble.addService(scanParametersService);
}

protected:
BLE& ble;

ScanIntervalWindow_t scanIntervalWindowData;
uint8_t scanRefreshData;

GattCharacteristic scanIntervalWindowCharacteristic;
GattCharacteristic scanRefreshCharacteristic;
};

#endif
Loading