Voice HoGP Remote
Table of Contents
- Introduction
- Hardware Prerequisites
- Software Prerequisites
- Functional Description
- Usage
Introduction
Voice HoGP Remote is a demonstration which exercises many areas of the BLE stack in a single application. The application demonstrates an implementation of the (Human Interface Device) HID over GATT profile (HoGP) where Keyboard, Consumer Control and Voice reports are used.
This document discusses the procedure use the Voice HoGP Remote for evaluation, as well as how various systems within in demo function.
Hardware Prerequisites
The default Voice HoGP Remote configuration requires the modified configuration of an CC2650RC kit, where the CC2650 is replaced by a CC2640R2F. The hardware is shown below:
Additionally, to program/debug the Voice HoGP Remote Project, a Debugger DevPack should be used. Attach this as shown below, where the JTAG connector and Groove Connector are exposed.
For custom hardware, see the Running the SDK on Custom Boards section of the BLE-Stack User’s Guide for Bluetooth 4.2.
To test Voice over HID-Over-GATT, an evaluation script can be used. The voice.py
script is available on GitHub
To test the HID Profile’s keyboard and consumer control reports, a BLE capable smart phone may be utilized.
Software Prerequisites
For information on what versions of Code Composer Studio and IAR Embedded Workbench to use, see the Release Notes located in the docs/blestack folder. For information on how to import this project into your IDE workspace and build/run, please refer to The CC2640R2F Platform section in the BLE-Stack User’s Guide for Bluetooth 4.2.
For Voice over HID over GATT testing, refer to the voice.py script.
Functional Description
Hardware Overview
Hardware Available on Remote
The following table contains information on the hardware resources and peripherals on the Remote.
Component | Manufacturer | Product |
---|---|---|
Wireless MCU | Texas Instruments | CC2650 |
Digital Microphone | Knowles | SPH0641LM4H-1 |
Motion Sensor | Invensense | MPU-9250 |
Memory | Macronix | MX25R8035F |
Load Switch | Texas Instruments | TPS22910AYZV |
Shift Register | Texas Instruments | SN74LV164A |
IR LED | Everlight | IR333-A |
Bi-Color LED | Kingbright | APHB1608SGEC |
Powering Remote
The remote can be powered in two ways, via AAA batteries, or by utilizing the Debugger DevPack.
To insert the batteries, ensure they are facing the correct direction, the positive ends of the batteries towards the bottom of the remote.
To power from the Debugger DevPack, simply connect a USB cable to the DevPack.
Software Overview
This section describes software components and the corresponding source file.
Application
Project Files | Description |
---|---|
kcb.c | Key press handling. |
util.c | This file contains utility functions commonly used by BLE applications for CC26xx with TI-RTOS. |
voice_hogp_remote.c | Top level application. Initialization of hardware, connection settings, key handling and voice streaming control. |
The main application task can be found voice_hogp_remote.c. Besides setting up advertisement and scan response data and connection related parameters in voiceHogpRemote_init, this task processes key press events and handles the API for voice streaming.
Profiles And Services
Project Files | Description |
---|---|
battservice.c | Battery Service. |
devinfoservice.c | Device Information Service. |
hiddev.c | HID Profile. Support HID reads, writes, queuing reports, register services and device states. |
hidservice.c | HID Service. Service for keyboard, consumer control, and voice reports. |
scanparamsservice.c | Scan Parameter Service. |
HID Profile
All HID over GATT Profile (HoGP) related functionality is abstracted from the application task and is handled in a separate task implemented in hiddev.c. This task handles:
- Registering of all services mentioned in GATT Services section.
- Device idle timer to terminate connection after set idle period. The default idle period DEFAULT_HID_IDLE_TIMEOUT is set in voice_hogp_remote.c to 60 seconds.
- Building and sending HID reports.
- Callbacks for read and write of characteristics in the HID service (hidservice.c).
- Advertising modes.
- Device states.
The following services are defined in the HID profile specification as either mandatory or optional. The voice_hogp_remote project includes all these services:
Service | Requirement | Supported |
---|---|---|
HID Service | Mandatory | Yes |
Battery Service | Mandatory | Yes |
Device Information Service | Mandatory | Yes |
Scan Parameter Service | Optional | Yes |
The Battery Service, Device Information Service and Scan Parameter Service are all adopted services and the specification for each service can be found at developer.bluetooth.org.
HID Terminology
Name | Description |
---|---|
HID Host | The target machine that the user interacts with (e.g. Laptop, tablet, smartphone, etc…) |
Report Host | A Report Host is a HID Host that is required to support a HID Parser and be able to handle HID reports with arbitrary formats. (e.g. Windows, Linux, Android, iOS central device) |
Boot Host | A Boot Host is a HID Host that is not required to support a HID Parser as all Reports for the Boot Protocol Mode have predefined length and format. |
HID Device | The device that is used by the user to interact with the Host (e.g. Keyboard, mouse, remote control, game controller, etc…) |
HID Report | A data message sent between the host and device. Input Reports go from HID Device to HID Host, such as a key press. Output reports go from HID Host to HID Device, such as a PC changing the caps lock LED on a keyboard. |
HID Report Descriptor | A data structure that the device sends to the host which describes the HID device’s capabilities, including the types, sizes, and directions of the reports that are supported. In HID over GATT this is also referred to as the Report Map. |
Report Map Characteristic
The Report Map characteristic contains the HID Report Descriptor which is used to define formatting information for Input Report, Output Report, and Feature Report data transferred between a HID Device and Report Host.
Each HID Service can only include one instance of the Report Map characteristic. The length of the Report Map characteristic value is limited to 512 bytes.
Report Map as shown is included in the HID Service in hidservice.c:
static CONST uint8 hidReportMap[] =
{
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x06, // USAGE (Keyboard)
0xA1, 0x01, // COLLECTION (Application)
0x85, HID_RPT_ID_KEY_IN, // REPORT_ID (1)
//
0x05, 0x07, // USAGE_PAGE (Key Codes)
0x19, 0xE0, // USAGE_MIN (224)
0x29, 0xE7, // USAGE_MAX (231)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
//
// Modifier byte
0x95, 0x08, // REPORT_COUNT (8)
0x75, 0x01, // REPORT_SIZE (1)
0x81, 0x02, // INPUT (Data, Variable, Absolute)
//
// Reserved byte
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x01, // INPUT (Constant)
//
// LED report
0x95, 0x05, // REPORT_COUNT (5)
0x75, 0x01, // REPORT_SIZE (1)
0x05, 0x08, // USAGE_PAGE (LEDs)
0x19, 0x01, // USAGE_MIN (1)
0x29, 0x05, // USAGE_MAX (5)
0x91, 0x02, // OUTPUT (Data, Variable, Absolute)
//
// LED report padding
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x03, // REPORT_SIZE (3)
0x91, 0x01, // OUTPUT (Constant)
//
// Key arrays (6 bytes)
0x95, 0x06, // REPORT_COUNT (6)
0x75, 0x08, // REPORT_SIZE (8)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x65, // LOGICAL_MAXIMUM (101)
0x05, 0x07, // USAGE_PAGE (Key Codes)
0x19, 0x00, // USAGE_MIN (0)
0x29, 0x65, // USAGE_MAX (101)
0x81, 0x00, // INPUT (Data, Array)
//
0xC0, // END_COLLECTION
//
0x05, 0x0c, // USAGE_PAGE (Consumer Devices)
0x09, 0x01, // USAGE (Consumer Control)
0xa1, 0x01, // COLLECTION (Application)
0x85, HID_RPT_ID_CC_IN, // REPORT_ID (2)
//
0x09, 0x30, // USAGE (Power)
0x09, 0xCD, // USAGE (Play/Pause)
0x09, 0xB7, // USAGE (Stop)
0x09, 0xB5, // USAGE (Skip track)
0x09, 0xB6, // USAGE (Previous track)
0x09, 0xB3, // USAGE (Fast forward)
0x09, 0xB4, // USAGE (Rewind)
0x09, 0xB2, // USAGE (Record)
0x09, 0xE9, // USAGE (Volume up)
0x09, 0xEA, // USAGE (Volume down)
0x09, 0xE2, // USAGE (Mute)
0x15, 0x01, // LOGICAL_MINIMUM (1)
0x25, 0x0B, // LOGICAL_MAXIMUM (11)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x00, // INPUT (Data,Ary,Abs)
//
0xC0, // END_COLLECTION
//Voice collection
0x05, 0x0C, // Usage Page (Consumer Devices)
0x09, 0x01, // Usage (Consumer Control)
0xA1, 0x01, // Collection (Application)
0x85, HID_RPT_ID_VOICE_START_IN, // Report ID (10)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x05, // Report Count (5)
0x09, 0x01, // Usage (Consumer Control)
0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x85, HID_RPT_ID_VOICE_DATA_IN, // Report ID (11)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x14, // Report Count (20)
0x09, 0x01, // Usage (Consumer Control)
0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0 // END_COLLECTION
};
HID Reports
The Report Reference characteristic descriptors contain the Report ID and Report Type for each Report Characteristic defined in the Report Map. This information is used on the Report Host to route USB HID class driver data into and out of GATT characteristic values.
Report IDs in hidservice.h:
// HID Report IDs for the service
#define HID_RPT_ID_LED_OUT 0 // LED output report ID
#define HID_RPT_ID_KEY_IN 1 // Keyboard input report ID
#define HID_RPT_ID_CC_IN 2 // Consumer Control input report ID
#define HID_RPT_ID_VOICE_START_IN 10 // Voice Start input report ID
#define HID_RPT_ID_VOICE_DATA_IN 11 // Voice Data input report ID
Report Types in hiddev.h:
// HID Report type
#define HID_REPORT_TYPE_INPUT 1
#define HID_REPORT_TYPE_OUTPUT 2
#define HID_REPORT_TYPE_FEATURE 3
The Report ID is not transmitted as a part of the HID Report over-the-air but is prepended by the Report Host, using the information in Report Reference characteristic descriptors, to each received HID report before passing them to a USB HID Class driver.
Key Board Input Reports
The Report Map includes the full 101-key part of the Keyboard Usage Page. This gives a one-to-one mapping between the transmitted report and the Usage ID in the usage table. The Usage IDs can be found in hiddev.c.
Consumer Control Input Reports
Only a subset of the Consumer Control Usage Page is included in this Report Map. The HID Report transmitted is in this case not the Usage ID but the index of the report as include in the Report Map.
The Consumer Control reports that can be sent can be found in voice_hogp_remote.h as:
// HID Consumer Control keycodes
// (based on the HID Report Map characteristic value)
#define HID_CC_RPT_POWER 1
#define HID_CC_RPT_PLAY_PAUSE 2
#define HID_CC_RPT_STOP 3
#define HID_CC_RPT_SCAN_NEXT_TRK 4
#define HID_CC_RPT_SCAN_PREV_TRK 5
#define HID_CC_RPT_FAST_FWD 6
#define HID_CC_RPT_REWIND 7
#define HID_CC_RPT_RECORD 8
#define HID_CC_RPT_VOLUME_UP 9
#define HID_CC_RPT_VOLUME_DOWN 10
#define HID_CC_RPT_MUTE 11
LED Output Reports
The LED Output reports are set in the Report Map to be a 5 bit bit-vector where each bit represents a report value. When an output is received on the CC2650RC it will be passed to the application callback in voice_hogp_remote.c:
static uint8_t voiceHogpRemote_handleReportCB(uint8_t id, uint8_t type,
uint16_t uuid, uint8_t oper,
uint16_t *pLen, uint8_t *pData)
{
// Intentionally left blank
return SUCCESS;
}
No specific handling of received Output Reports is implanted into the voice_hogp_remote project so the correct handling must be added to use the information in the LED Output Report.
Voice Output Reports
The audio data is transmitted using 2 HID Output reports:
Name | Report ID | Description |
---|---|---|
HID_RPT_ID_VOICE_START_IN |
0x0A (10) |
This HID report is used to transmit a start command before the streaming starts and stop command as the last packet of a stream. |
HID_RPT_ID_VOICE_DATA_IN |
0x0B (11) |
This HID report is used to transmit all voice data. |
The main advantage in transporting data over the HID is that modern Operating Systems typically natively support the HID-Over-GATT (HoGP) profile, simplifying the application development by not having to develop custom GATT profiles.
- BlueZ users on Linux do not need to recompile the kernel to support a custom GATT profile.
- Windows 8.1 or later also supports HoGP natively
Applications using HoGP only need to collect voice frames using HID reports generated by the Operating System.
The HID reports used to transport voice frames follow the a similar paradigm as with TI’s custom GATT Voice Profile. The HID_RPT_ID_VOICE_START_IN
report is used to indicate the start and stop of the voice data stream, whereas the voice data itself is sent via the HID_RPT_ID_VOICE_DATA_IN
report.
The basic flow of a voice transmission is:
- Voice HoGP Remote sends a start command (0x04) on
HID_RPT_ID_VOICE_START_IN
. - Voice HoGP Remote starts streaming voice data on
HID_RPT_ID_VOICE_DATA_IN
. See Voice over HID over GATT Profile section for more details. - Voice HoGP Remote sends a stop command (0x00) on
HID_RPT_ID_VOICE_START_IN
.
Key Scanning
This section describes the key scanner.
There are 32 buttons on the Remote Control that are scanned with a 3x11 matrix.
- 3 columns
- 11 rows
Normally, a total of 14 IOs would be required to perform key scanning in this configuration. To save IOs, shift registers are used to extend the number of IOs. A single shift register can be used to get 8 IOs from 3. When cascading shift registers, the same 3 IOs can emulate additional IOs. The two shift registers used in this example, can support up to 16 IOs, but only 11 are used for the rows. Including 3 IOs for the columns, 6 IOs are used perform key scanning. The spare IOs are connected to the DevPack connector.
Note. that these 32 buttons could have been scanned with 12 IOs in a 6x6 matrix.
- 6 columns
- 6 rows
Algorithm
As shown in the there are 3 IOs for columns and 11 IOs for rows. When the remote is in standby the IOs are configured such that a button press generates an interrupt. The interrupt triggers on the column pins.
- Interrupt detected
- Start de-bounce timer
- Key scan is repeated periodically as long as a press is detected.
De-bounce : Refers to unintentional changes in voltage, or that the voltage “bounce”. This typically happens as the button is pressed. As the button shorts the connection between row and column the voltage can “bounce”. We don’t want to scan the keys as this happens. Thus, the keys are only scanned after some time has passed. This time is greater than the time it takes for the voltage to settle.
Implementation
The key scan algorithm discussed above is implemented in the module key_scan.c/.h
. This module has two public functions:
KeyInit(void)
KeyConfig(KeyEvtCBack_t key_cback, uint16_t initialKeyRepeatInterval, uint16_t debounceTime, uint16_t pollRate)
KeyInit
This function must be called before KeyConfig()
is called. It initializes and configures all IOs. It also constructs the timer resources the key scanner requires.
KeyConfigure
This function is called to register callbacks and configure timer values. The parameters are as follows:
debounceTime
, de-bounce periodpollRate
, scanning period.initialKeyRepeatInterval
. It determines how frequent the callbackkey_cback
is called. If a key is kept pressed for a longer duration, then the callback is called everyinitialKeyRepeatInterval
/pollRate
ms.
Key Mapping
The following shows a mapping of which key pressed on the Remote Control corresponds to which HID report or application action.
Key | Voice HoGP Remote |
---|---|
NUM_0 | HID_KEYBOARD_0 |
NUM_1 | HID_KEYBOARD_1 |
NUM_2 | HID_KEYBOARD_2 |
NUM_3 | HID_KEYBOARD_3 |
NUM_4 | HID_KEYBOARD_4 |
NUM_5 | HID_KEYBOARD_5 |
NUM_6 | HID_KEYBOARD_6 |
NUM_7 | HID_KEYBOARD_7 |
NUM_8 | HID_KEYBOARD_8 |
NUM_9 | HID_KEYBOARD_9 |
UP | HID_KEYBOARD_UP_ARROW |
DOWN | HID_KEYBOARD_DOWN_ARROW |
LEFT | HID_KEYBOARD_LEFT_ARROW |
RIGHT | HID_KEYBOARD_RIGHT_ARROW |
Power | None |
PLAY/PAUSE | HID_CC_RPT_PLAY_PAUSE |
MUTE | HID_CC_RPT_MUTE |
V+ | HID_CC_RPT_VOLUME_UP |
V- | HID_CC_RPT_VOLUME_DOWN |
REC | None |
FAST FORWARD | HID_CC_RPT_SCAN_NEXT_TRK |
FAST REWIND | HID_CC_RPT_SCAN_PREV_TRK |
MIC | Start streaming Voice |
MENU | None |
PAIR | None |
INFINITE | None |
STB | None |
BACK | None |
OK | None |
HOME | None |
(Red LED) | Indicates streaming Voice when flashing |
AV | None |
TV | None |
Usage
This section describes how to exercise various parts of the Voice HoGP Remote.
Bonding
The Voice HoGP Remote can be bonded with HID Hosts such as Android and iOS mobile devices as well as other standard HoGP-supported Operating Systems such as Windows® 8.1 or later and Linux distributions operating with the BlueZ Linux Bluetooth protocol stack.
- To evaluate the keyboard and consumer control services, you can bond with an Android or iOS device.
- To evaluate the voice service, you can bond with a Windows® 8.1 or later that supports Bluetooth LE 4.0 or later.
Windows
Keyboard, Consumer Control and Voice over HID-Over-GATT reports can be evaluated using a Windows workstation.
To evaluate the voice reports, you will need the voice.py
script that is available on the GitHub repo.
Ensure the Remote is advertising by pressing any key on the Remote. And verify that the smart phone can detect the remote.
Open Settings -> Devices -> Bluetooth. When the remote is advertising, you will see it listed as shown here:
Click on the Pair button to initiate bonding.
Under normal circumstances, Windows should prompt the user to enter in a random-generated passcode. However, there is a known issue with Windows, where it doesn’t prompt the user for a passcode if the peripheral has the Bluetooth LE Secure Connections feature enabled. Windows will look like it is unresponsive at shown here, but you need to press 000000 on the remote control to pair successfully.
After successful pairing, you should see this when the remote has connected. The remote control must be connected in order to evaluate the voice.py
script on GitHub.
Android
For Android devices, keyboard and consumer control reports are easily evaluated. In this section an Android Phone is used to connect to the device. Once connected, the remote will emulate a keyboard with various functions as HID Reports. See Key Mapping.
Ensure the Remote is advertising by pressing any key on the Remote. And verify that the smart phone can detect the remote.
To access the Bluetooth Menu of the smart phone:
Connect to the device, during pairing the phone will display a passcode to enter in the Remote.
Enter this code onto the Remote via the keypad; after a few moments, the Remote can be used as a input device.
Voice over HID over GATT Profile
For detail on how the voice sevice is implememented, see Voice over HID over GATT Profile
- Ensure that the remote control is connected to a Windows workstation
- Start the
voice.py
script. - Press and hold the
MIC
key. - Talk into the microphone
- Release the
MIC
key. - Find the generated
.wav
file generated by thevoice.py
script.
Keyboard and Consumer Control via HID over GATT Profile
Windows and Android natively support the keyboard and consumer control services.
The keys listed in the Key Mapping section describe on what behavior is to be expected upon a key press on the remote.