This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

How to send 2byte consumer control code (in 'HidAdvRemote') ?

Other Parts Discussed in Thread: CC2540, CC2541DK-MINI

Hi,


USB HID usage table for Consumer Devices (pg.12 = 0x0C), eg:

  0x01      : Consumer Control

  0x02      : Numeric Keypad

  0x30      : Power

  0x40      : Menu

  0xE2      : Mute

  0xE9      : Volume Up

  0xEA      : Volume Down

  0x221     : AC Search

  0x223     : AC Home

  etc.

In the BLE stack v1.4.0 source code (‘hidAdvRemote’ sample code), all the HID_CONSUMER_xxxxx (defined in hiddev.h) supported in BLE stack is single-Byte code (1byte code).

eg:   #define HID_CONSUMER_POWER          48  // 0x30 - Power

      #define HID_CONSUMER_MENU           64  // 0x40 - Menu

      #define HID_CONSUMER_MUTE           226 // 0xE2 - Mute

      #define HID_CONSUMER_VOLUME_UP      233 // 0xE9 - Volume Increment

      #define HID_CONSUMER_VOLUME_DOWN    234 // 0xEA - Volume Decrement

The way it’s declared in the keycodeMap_t keycodeMap[] table is also based on 1byte code array.

// Keycode mapping table

typedef struct

{

  uint8 keycode;

  uint8 usagePage;

} keycodeMap_t;

However, it’s converted into 2bytes buffer ‘pBuf[1:0] (below table) by ‘hidCCBuildReport()’ in ‘hidCCSendReport()’ routine, before the report data is sent out. These 2bytes code are totally different with the HID Consumer Control codes (above).

Debugging the ‘HIDAdvRemoteDongle’, found that the Dongle indeed receive the pBuf[1:0] values below (not the HID Consumer Control code/values).

Key

keycode

HID_CC_RPT_SET_xxxxxx (s, x)

pBuf[1:0]

HID_CONSUMER_CHANNEL_UP

0x9C

(s)[0] &= HID_CC_RPT_CHANNEL_BITS;   \
(s)[0] |= ((x) & 0x03) << 4

0x00,0x10

HID_CONSUMER_CHANNEL_DOWN

0x9D

(s)[0] &= HID_CC_RPT_CHANNEL_BITS;   \
(s)[0] |= ((x) & 0x03) << 4

0x00,0x30

HID_CONSUMER_VOLUME_UP

0xE9

(s)[0] &= HID_CC_RPT_VOLUME_BITS;    \
(s)[0] |= 0x40

0x00,0x40

HID_CONSUMER_VOLUME_DOWN

0xEA

(s)[0] &= HID_CC_RPT_VOLUME_BITS;    \
(s)[0] |= 0x80

0x00,0x80

HID_CONSUMER_MUTE

0xE2

(s)[1] &= HID_CC_RPT_BUTTON_BITS;    \
(s)[1] |= (x)

0x01,0x00

HID_CONSUMER_POWER

0x30

(s)[1] &= HID_CC_RPT_BUTTON_BITS;    \
(s)[1] |= (x)

0x02,0x00

HID_CONSUMER_RECALL_LAST

0x83

(s)[1] &= HID_CC_RPT_BUTTON_BITS;    \
(s)[1] |= (x)

0x03,0x00

HID_CONSUMER_ASSIGN_SEL

0x81

(s)[1] &= HID_CC_RPT_BUTTON_BITS;    \
(s)[1] |= (x)

0x04,0x00

HID_CONSUMER_PLAY

0xB0

(s)[1] &= HID_CC_RPT_BUTTON_BITS;    \
(s)[1] |= (x)

0x05,0x00

HID_CONSUMER_PAUSE

0xB1

(s)[1] &= HID_CC_RPT_BUTTON_BITS;    \
(s)[1] |= (x)

0x06,0x00

HID_CONSUMER_RECORD

0xB2

(s)[1] &= HID_CC_RPT_BUTTON_BITS;    \
(s)[1] |= (x)

0x07,0x00

HID_CONSUMER_FAST_FORWARD

0xB3

(s)[1] &= HID_CC_RPT_BUTTON_BITS;    \
(s)[1] |= (x)

0x08,0x00

HID_CONSUMER_REWIND

0xB4

(s)[1] &= HID_CC_RPT_BUTTON_BITS;    \
(s)[1] |= (x)

0x09,0x00

HID_CONSUMER_SCAN_NEXT_TRK

0xB5

(s)[1] &= HID_CC_RPT_BUTTON_BITS;    \
(s)[1] |= (x)

0x0A,0x00

HID_CONSUMER_SCAN_PREV_TRK

0xB6

(s)[1] &= HID_CC_RPT_BUTTON_BITS;    \
(s)[1] |= (x)

0x0B,0x00

HID_CONSUMER_STOP

0xB7

(s)[1] &= HID_CC_RPT_BUTTON_BITS;    \
(s)[1] |= (x)

0x0C,0x00

 

[Q1]: After checking with the ‘entity1Desc’ (Consumer report descriptor in ‘usb_hid_descriptor.s51’), is it correct that the data format follow the following format ?

            pBuf[1]

pBuf[0]

7

6

5

4

3

2

1

0

7

6

5

4

3

2

1

0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

not used (reserved)

selection
(3 buttons ?)

Buttons: (Mute / Power / … / Stop / etc).

vol.

down

vol.

up

chnl. up/dn

numeric keys

 

[Q2]: the above data format shows that the consumer report descriptor does not support 2bytes consumer control code (eg: 0x221 = AC Search, or 0x223 = AC Home, etc).

            Does TI BLE stack (incl. Audio version) supports 2bytes HID Consumer Control code ?    How / what values should be declared in the report descriptor ?

         If not supported, how to handle the 2bytes HID Consumer Control key code ?

 

Thank you in advance.

 

  • Hi,

    If you see the report map that is registered as an attribute you will see that the report map defines the report descriptor as below

    0x05, 0x0C, // Usage Pg (Consumer Devices)
    0x09, 0x01, // Usage (Consumer Control)
    0xA1, 0x01, // Collection (Application)
    0x85, 0x03, // Report Id (3)
    0x09, 0x02, // Usage (Numeric Key Pad)
    0xA1, 0x02, // Collection (Logical)
    0x05, 0x09, // Usage Pg (Button)
    0x19, 0x01, // Usage Min (Button 1)
    0x29, 0x0A, // Usage Max (Button 10)
    0x15, 0x01, // Logical Min (1)
    0x25, 0x0A, // Logical Max (10)
    0x75, 0x04, // Report Size (4)
    0x95, 0x01, // Report Count (1)
    0x81, 0x00, // Input (Data, Ary, Abs)
    0xC0, // End Collection
    0x05, 0x0C, // Usage Pg (Consumer Devices)
    0x09, 0x86, // Usage (Channel)
    0x15, 0xFF, // Logical Min (-1)
    0x25, 0x01, // Logical Max (1)
    0x75, 0x02, // Report Size (2)
    0x95, 0x01, // Report Count (1)
    0x81, 0x46, // Input (Data, Var, Rel, Null)
    0x09, 0xE9, // Usage (Volume Up)
    0x09, 0xEA, // Usage (Volume Down)
    0x15, 0x00, // Logical Min (0)
    0x75, 0x01, // Report Size (1)
    0x95, 0x02, // Report Count (2)
    0x81, 0x02, // Input (Data, Var, Abs)
    0x09, 0xE2, // Usage (Mute)
    0x09, 0x30, // Usage (Power)
    0x09, 0x83, // Usage (Recall Last)
    0x09, 0x81, // Usage (Assign Selection)
    0x09, 0xB0, // Usage (Play)
    0x09, 0xB1, // Usage (Pause)
    0x09, 0xB2, // Usage (Record)
    0x09, 0xB3, // Usage (Fast Forward)
    0x09, 0xB4, // Usage (Rewind)
    0x09, 0xB5, // Usage (Scan Next)
    0x09, 0xB6, // Usage (Scan Prev)
    0x09, 0xB7, // Usage (Stop)
    0x15, 0x01, // Logical Min (1)
    0x25, 0x0C, // Logical Max (12)
    0x75, 0x04, // Report Size (4)
    0x95, 0x01, // Report Count (1)
    0x81, 0x00, // Input (Data, Ary, Abs)
    0x09, 0x80, // Usage (Selection)
    0xA1, 0x02, // Collection (Logical)
    0x05, 0x09, // Usage Pg (Button)
    0x19, 0x01, // Usage Min (Button 1)
    0x29, 0x03, // Usage Max (Button 3)
    0x15, 0x01, // Logical Min (1)
    0x25, 0x03, // Logical Max (3)
    0x75, 0x02, // Report Size (2)
    0x81, 0x00, // Input (Data, Ary, Abs)
    0xC0, // End Collection
    0x81, 0x03, // Input (Const, Var, Abs)
    0xC0 // End Collection

    This means in the CC report format is as follows.

    Byte 0 - 4 LSB(bits 0,1,2,3) are used by Keypad

    Byte 0 - bits 4 & 5 are used for Channel Up/Down

    Byte 0 - bits 6 & 7 are used for Volume Up/Down

    Byte 1 - 4 LSB(bits 0,1,2,3) are used for Media keys(Play,Pause, mute etc..)

    Byte 1 - bits 4 & 5 are used for Button state information.

    Byt 1 bits 6 & 7 are not defined in report map and hence ignored by host.

    So to the answer to your question 1 is yes. the pBuf format that you have described is correct.

    Q2: You can modify the report map descriptor to include these other consumer report keys you want to transmit( you can use bits 6 & 7 in byte 1)  For example. 

    0x09, 0xDC, // Usage (AC Find & Replace)
    0x09, 0xDD, // Usage (AC Search )
    0x09, 0xDE, // Usage (AC Go To)
    0x09, 0xDF, // Usage (AC Home)
    0x15, 0x01, // Logical Min (1)
    0x25, 0x0C, // Logical Max (4)
    0x75, 0x04, // Report Size (2)
    0x95, 0x01, // Report Count (1)

    0x81, 0x00,   //   Input (Data, Ary, Abs)

    Now you can transfer the generic GUI application controls using bits 6 & 7 of Byte 1.

     

    Note: If you need more commands to be inserted, then, you can edit report map further to include them, but then the CC report may take more than 2 bytes. 

    Regards,

    Arun

  • Hi Arun,

    Thank you very much for your reply.

    Regarding Q2, as per your suggestion by using 0xDC/DD/DE/DF, then send from Dongle to Host (either PC's Windows OS or Android Host), How does the Host  recognise/know that 0xDC/DD/DE/DF is actually represents the following buttons: AC Find Replace (0x220) / AC Search (0x221) / AC GoTo (0x222) / AC home (0x223) ?

    note: there is no declaration which explains the relation between 0xDD = AC Search (0x221), 0xDF = AC Home (0x223), etc.

    Thank you.

  • Hi,

    Actually HID Usage Table 1.12v2  defines these usages with specific HID usages. 

    Note: there is a mistake in my earlier table as the earlier table can only support 3 usages and not 4(default 0,0 should not be used). So modify the table as below.

    0x09, 0xDD, // Usage (AC Search )
    0x09, 0xDE, // Usage (AC Go To)
    0x09, 0xDF, // Usage (AC Home)
    0x15, 0x01, // Logical Min (1)
    0x25, 0x0C, // Logical Max (3)
    0x75, 0x04, // Report Size (2)
    0x95, 0x01, // Report Count (1)

    So when you define these usages in your report map and then assign them to specific bits(report map descriptor), the host reads these reports and understands the CC usage for each bit position.

    So if your report sets bits[7:6] as 0:1 -> Host understands that user requested 0xDD which is Usage AC Search.

    similarly bits[7:6] as 1:0 -> Host interprets from report descriptor map as 'AC Go To'

    similarly bits[7:6] as 1:1 -> Host interprets from report descriptor map as 'AC Home'

    Regards,

    Arun

  • Hi Arun,

    Thanks.

    Searched on usb.org, but can only find the HID Usage Table v1.12.

     

    Since only 3 buttons, Instead of bits[7:6], can we add into bits[3:0] (as below) ?

      0x09, 0xE2,   //   Usage (Mute)
      0x09, 0x30,   //   Usage (Power)
      0x09, 0x83,   //   Usage (Recall Last)
      0x09, 0x81,   //   Usage (Assign Selection)
      0x09, 0xB0,   //   Usage (Play)
      0x09, 0xB1,   //   Usage (Pause)
      0x09, 0xB2,   //   Usage (Record)
      0x09, 0xB3,   //   Usage (Fast Forward)
      0x09, 0xB4,   //   Usage (Rewind)
      0x09, 0xB5,   //   Usage (Scan Next)
      0x09, 0xB6,   //   Usage (Scan Prev)
      0x09, 0xB7,   //   Usage (Stop)

      0x09, 0xDD, // Usage (AC Search )
      0x09, 0xDE, // Usage (AC Go To)
      0x09, 0xDF, // Usage (AC Home)
      0x15, 0x01,   //   Logical Min (1)
      0x25, 0x0C,   //   Logical Max (15)
      0x75, 0x04,   //   Report Size (4)
      0x95, 0x01,   //   Report Count (1)
      0x81, 0x00,   //   Input (Data, Ary, Abs)

    Thanks & Best Regards,

    William

  • Hi,

    Q1: Yes. The usages are defined in that document(HID Usage Table v1.12).

    Q2: Yes, you can modify the report amp as described too.

    Regards,

    Arun

  • Hi Arun,

    Thank you for your reply.

     

    a)      In the HID Usage Table 1.12 specification (dated 10/28/2004), 0xCF – 0xDF is still reserved.

    No information/definition of those usages with specific HID usages, which describes whether 0xDC/DD/DE/DF can be interpreted as AC Find Replace (0x220) / AC Search (0x221) / AC Go To (0x222) / AC home (0x223).

     Can you let me know from which link that the HID Usage Table 1.12v2 specification can be downloaded ?

     

    b)      After modified the report descriptor as per above (add the 3 additional buttons in Byte1 – bits[3:0]), do we also need to modify the ‘entity1Desc’ accordingly (in file ‘usb_hid_descriptor.a51’ of ‘HIDAdvRemoteDongle’ sample code) ? 

    entity1Desc:    ; Consumer report descriptor
                    DB 005H, 00CH   ; Usage Pg (Consumer Devices)
                    DB 009H, 001H   ; Usage (Consumer Control)
                    DB 0A1H, 001H   ; Collection (Application)
                    DB 009H, 002H   ;   Usage (Numeric Key Pad)
                    DB 0A1H, 002H   ;   Collection (Logical)
                    DB 005H, 009H   ;     Usage Pg (Button)
                    DB 019H, 001H   ;     Usage Min (Button 1)
                    DB 029H, 00AH   ;     Usage Max (Button 10)
                    DB 015H, 001H   ;     Logical Min (1)
                    DB 025H, 00AH   ;     Logical Max (10)
                    DB 075H, 004H   ;     Report Size (4)
                    DB 095H, 001H   ;     Report Count (1)
                    DB 081H, 000H   ;     Input (Data, Ary, Abs)
                    DB 0C0H         ;   End Collection
                    DB 005H, 00CH   ;   Usage Pg (Consumer Devices)
                    DB 009H, 086H   ;   Usage (Channel)
                    DB 015H, 0FFH   ;   Logical Min (-1)
                    DB 025H, 001H   ;   Logical Max (1)
                    DB 075H, 002H   ;   Report Size (2)
                    DB 095H, 001H   ;   Report Count (1)
                    DB 081H, 046H   ;   Input (Data, Var, Rel, Null)
                    DB 009H, 0E9H   ;   Usage (Volume Up)
                    DB 009H, 0EAH   ;   Usage (Volume Down)
                    DB 015H, 000H   ;   Logical Min (0)
                    DB 075H, 001H   ;   Report Size (1)
                    DB 095H, 002H   ;   Report Count (2)
                    DB 081H, 002H   ;   Input (Data, Var, Abs)
                    DB 009H, 0E2H   ;   Usage (Mute)
                    DB 009H, 030H   ;   Usage (Power)
                    DB 009H, 083H   ;   Usage (Recall Last)
                    DB 009H, 081H   ;   Usage (Assign Selection)
                    DB 009H, 0CDH   ;   Usage (Play/Pause)      // HACKED CHANGE
                    DB 009H, 040H   ;   Usage (Menu)            // HACKED CHANGE
                    DB 009H, 0B2H   ;   Usage (Record)
                    DB 009H, 0B3H   ;   Usage (Fast Forward)
                    DB 009H, 0B4H   ;   Usage (Rewind)
                    DB 009H, 0B5H   ;   Usage (Scan Next)
                    DB 009H, 0B6H   ;   Usage (Scan Prev)
                    DB 009H, 0B7H   ;   Usage (Stop)
                    DB 009H, 0DDH   ;   Usage (AC Search)
                    DB 009H, 0DEH   ;   Usage (AC Go To)
                    DB 009H, 0DFH   ;   Usage (AC Home)
                    DB 015H, 001H   ;   Logical Min (1)
                    DB 025H, 00FH   ;   Logical Max (15)
                    DB 075H, 004H   ;   Report Size (4)
                    DB 095H, 001H   ;   Report Count (1)
                    DB 081H, 000H   ;   Input (Data, Ary, Abs)
                    DB 009H, 080H   ;   Usage (Selection)
                    DB 0A1H, 002H   ;   Collection (Logical)
                    DB 005H, 009H   ;     Usage Pg (Button)
                    DB 019H, 001H   ;     Usage Min (Button 1)
                    DB 029H, 003H   ;     Usage Max (Button 3)
                    DB 015H, 001H   ;     Logical Min (1)
                    DB 025H, 003H   ;     Logical Max (3)
                    DB 075H, 002H   ;     Report Size (2)
                    DB 081H, 000H   ;     Input (Data, Ary, Abs)
                    DB 0C0H         ;   End Collection
                    DB 081H, 003H   ;   Input (Const, Var, Abs)
                    DB 0C0H         ; End Collection
    entity1DescEnd:
     

    Thanks & Best Regards,

    William

  • Hi,

    I am sorry, the AC search, AC Home etc. are defined as Usage ID 0x221 and not decimal 221 as I had thought earlier. Hence replace 0xDD, 0xDE, 0xDF etc with 0x221, 0x222, 0x223 etc.

    I found this in Chapter 15.16 in http://www.usb.org/developers/hidpage/Hut1_12v2.pdf.

    Q2: I am not sure about HidRemoteDongle code as I have not checked it out. But according to the Readme.txt that can with BLE SDK v1.40 the HidRemoteDongle is made to match with HidAdvRemote only. So the changes you have mentioned might be required. But other HID hosts(like Android, iOS or Windows phone) should work with the new report map.

    From Readme.txt

    "The HidAdvRemoteDongle project has been added. This application runs on the
    CC2540USB dongle, and implements partial functionality of HID-over-GATT
    (HOGP) host with a fixed report descriptor to match that of the descriptor
    of the HidAdvRemote Project. This means that the HidAdvRemoteDongle was
    designed only to work with the HidAdvRemote, and will not be compatible
    with any other HOGP devices. This project was created to allow users who
    are using a host device that does not have native Bluetooth Smart Ready
    support and/or does not have HOGP support to use the BLE Advanced Remote
    Control with their system."

    Regards,

    Arun

  • Hi Arun 
    Noted with thanks.
    And, can not use Byte1 – bits[3:0] to handle mix of both 1byte and 2bytes code.
    Thus, should modify the report descriptor (use Byte1 – bits[7:6]) by adding additional usages below ?
    0x0A, 0x21, 0x02, // Usage (AC Search)
    0x0A, 0x22, 0x02, // Usage (AC Go To)
    0x0A, 0x23, 0x02, // Usage (AC Home)
    0x15, 0x01, // Logical Min (1)
    0x25, 0x03, // Logical Max (3)
    0x75, 0x02, // Report Size (2)
    0x95, 0x01, // Report Count (1)
    Please correct me if wrong ?
     
     
    May I know your email address, so that can communicate offline (by email) ?
    For the modification related to the Dongle source code, whom in TI can I consult ?
     
    Thanks & Best Regards,
    William
  • Hi William,

    Regarding your question of separate bits for report map, I believe so, but I am not sure about it.

    You can contact me at arun-menon@ti.com. But it would be better to communicate via forum as others can also pitch in with their answers. 

    I will check with within TI who can answer the HID Remote Dongle questions.

    Regards,

    Arun

  • Hi,
    Modify the report descriptor (use Byte1 – bits[7:6]) by adding additional usages as follow:
    0x0A, 0x21, 0x02, // Usage (AC Search)
    0x0A, 0x22, 0x02, // Usage (AC Go To)
    0x0A, 0x23, 0x02, // Usage (AC Home)
    0x15, 0x01, // Logical Min (1)
    0x25, 0x03, // Logical Max (3)
    0x75, 0x02, // Report Size (2)
    0x95, 0x01, // Report Count (1)
    0x81, 0x00, // Input (Data, Ary, Abs)
    [Q1]: Is the above modification correct ?     if wrong, how should it be ?
    From below picture, captured using BTools, shown that the correct code (11xx-xxxxb = 0xC0) is received by the CC2540 Dongle, when Home’ key (AC Home = 0x0223) is pressed.
    However, no action on the Host side, which means the code passed from Dongle to the Host is not a valid key.
     
     

    [Q2]: Please advise, what modification required on the Dongle side (‘HIDAdvRemoteDongle’ sample code) to accommodate the above changes ?

     

    Thank you in advance.

  • Hi William,

    Let me try out the AC search here. I don't have a HIDAdvRemoteDongle here, but I will try this on iOS/Nexus device first.

    Regards,

    Arun

  • Hi Arun.

    Have you tried the above 2Bytes CC keycode (eg: AC Search / GoTo / Home) on iOS/Nexus device ?
    Any update ?

    Thanks\William
  • Sorry William,

    I was busy with other stuff and could not try this. I will try today and update you of the status.

    Regards,
    Arun
  • William,

    I just tried this out. It works with iOS,

    Please find my report map

    // HID Report Map characteristic value

    static CONST uint8 hidReportMap[] =
    {
    0x05, 0x01, // Usage Page (Generic Desktop)
    0x09, 0x02, // Usage (Mouse)
    0xA1, 0x01, // Collection (Application)
    0x85, 0x01, // Report Id (1)
    0x09, 0x01, // Usage (Pointer)
    0xA1, 0x00, // Collection (Physical)
    0x05, 0x09, // Usage Page (Buttons)
    0x19, 0x01, // Usage Minimum (01) - Button 1
    0x29, 0x03, // Usage Maximum (03) - Button 3
    0x15, 0x00, // Logical Minimum (0)
    0x25, 0x01, // Logical Maximum (1)
    0x75, 0x01, // Report Size (1)
    0x95, 0x03, // Report Count (3)
    0x81, 0x02, // Input (Data, Variable, Absolute) - Button states
    0x75, 0x05, // Report Size (5)
    0x95, 0x01, // Report Count (1)
    0x81, 0x01, // Input (Constant) - Padding or Reserved bits
    0x05, 0x01, // Usage Page (Generic Desktop)
    0x09, 0x30, // Usage (X)
    0x09, 0x31, // Usage (Y)
    0x09, 0x38, // Usage (Wheel)
    0x15, 0x81, // Logical Minimum (-127)
    0x25, 0x7F, // Logical Maximum (127)
    0x75, 0x08, // Report Size (8)
    0x95, 0x03, // Report Count (3)
    0x81, 0x06, // Input (Data, Variable, Relative) - X & Y coordinate
    0xC0, // End Collection
    0xC0, // End Collection

    0x05, 0x01, // Usage Pg (Generic Desktop)
    0x09, 0x06, // Usage (Keyboard)
    0xA1, 0x01, // Collection: (Application)
    0x85, 0x02, // Report ID (2)
    //
    0x05, 0x07, // Usage Pg (Key Codes)
    0x19, 0xE0, // Usage Min (224)
    0x29, 0xE7, // Usage Max (231)
    0x15, 0x00, // Log Min (0)
    0x25, 0x01, // Log Max (1)
    //
    // Modifier byte
    0x75, 0x01, // Report Size (1)
    0x95, 0x08, // Report Count (8)
    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 Pg (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, // Log Min (0)
    0x25, 0x65, // Log Max (101)
    0x05, 0x07, // Usage Pg (Key Codes)
    0x19, 0x00, // Usage Min (0)
    0x29, 0x65, // Usage Max (101)
    0x81, 0x00, // Input: (Data, Array)
    //
    0xC0, // End Collection
    //
    0x05, 0x0C, // Usage Pg (Consumer Devices)
    0x09, 0x01, // Usage (Consumer Control)
    0xA1, 0x01, // Collection (Application)
    0x85, 0x03, // Report Id (3)
    0x09, 0x02, // Usage (Numeric Key Pad)
    0xA1, 0x02, // Collection (Logical)
    0x05, 0x09, // Usage Pg (Button)
    0x19, 0x01, // Usage Min (Button 1)
    0x29, 0x0A, // Usage Max (Button 10)
    0x15, 0x01, // Logical Min (1)
    0x25, 0x0A, // Logical Max (10)
    0x75, 0x04, // Report Size (4)
    0x95, 0x01, // Report Count (1)
    0x81, 0x00, // Input (Data, Ary, Abs)
    0xC0, // End Collection
    0x05, 0x0C, // Usage Pg (Consumer Devices)
    0x09, 0x86, // Usage (Channel)
    0x15, 0xFF, // Logical Min (-1)
    0x25, 0x01, // Logical Max (1)
    0x75, 0x02, // Report Size (2)
    0x95, 0x01, // Report Count (1)
    0x81, 0x46, // Input (Data, Var, Rel, Null)
    0x09, 0xE9, // Usage (Volume Up)
    0x09, 0xEA, // Usage (Volume Down)
    0x15, 0x00, // Logical Min (0)
    0x75, 0x01, // Report Size (1)
    0x95, 0x02, // Report Count (2)
    0x81, 0x02, // Input (Data, Var, Abs)
    0x09, 0xE2, // Usage (Mute)
    0x09, 0x30, // Usage (Power)
    0x09, 0x32, // Usage (Sleep)
    0x09, 0xB4, // Usage (Rewind)
    0x09, 0xB0, // Usage (Play)
    0x09, 0xB1, // Usage (Pause)
    0x09, 0xB3, // Usage (Fast Forward)
    0x09, 0xB5, // Usage (Scan Next)
    0x09, 0xB6, // Usage (Scan Prev)
    0x09, 0xB7, // Usage (Stop)
    0x15, 0x01, // Logical Min (1)
    0x25, 0x0C, // Logical Max (10)
    0x75, 0x04, // Report Size (4)
    0x95, 0x01, // Report Count (1)
    0x81, 0x00, // Input (Data, Ary, Abs)
    // Sel usages 1
    0x0a, 0x00, 0x02, // USAGE (Generating GUI Application Buttons)
    0xa1, 0x02, // COLLECTION (Logical)
    0x15, 0x01, // LOGICAL_MINIMUM (1)
    0x25, 0x03, // LOGICAL_MAXIMUM (2)
    0x75, 0x02, // REPORT_SIZE (2)
    0x95, 0x01, // REPORT_COUNT (1)
    0x0a, 0x21, 0x02, // USAGE (AC Search) - index 1
    0x0a, 0x23, 0x02, // USAGE (AC Home) - index 2
    0x81, 0x00, // INPUT (Data,Ary,Abs) - index 0 means none of above is selected
    0xc0, // END_COLLECTION
    0xC0 // End Collection
    };

    and I fill up consumer report as shown below,

    /*********************************************************************
    * @fn HidKeyBoardMediaSendReport
    *
    * @brief Build and send a HID Consumer report.
    *
    * @param keycode - key pressed on Keyboard( Depends upon keyboard layout)
    *
    * @return none
    */
    static void HidKeyBoardMediaSendReport( uint8 keycode )
    {
    uint8_t buf[HID_CC_IN_RPT_LEN] = {0, 0};
    switch(keycode) {

    case HID_KEYBOARD_F1: //mute
    buf[1] = 0x01;
    break;
    case HID_KEYBOARD_F2: //vol down
    buf[0] = 0x80;
    break;
    case HID_KEYBOARD_F3: //vol up
    buf[0] = 0x40;
    break;
    case HID_KEYBOARD_F4: //Scan Prev
    buf[1] = 0x09;
    break;
    case HID_KEYBOARD_F5:
    {
    if(gKeyInfo.play == TRUE)
    {
    buf[1] = 0x06; //Pause
    gKeyInfo.play = FALSE;
    }
    else
    {
    buf[1] = 0x05; //Play
    gKeyInfo.play = TRUE;
    }
    }
    break;
    case HID_KEYBOARD_F6: //Scan Next
    buf[1] = 0x08;
    break;
    case HID_KEYBOARD_F7: //AC Search
    buf[1] = 0x10;
    break;
    case HID_KEYBOARD_F8: //AC Home
    buf[1] = 0x20;
    break;
    case HID_KEYBOARD_F9: // Record
    buf[1] = 0x0A;
    break;
    case HID_KEYBOARD_F10: //Record
    buf[1] = 0x0A;
    break;
    case HID_KEYBOARD_F11: //Sleep
    buf[1] = 0x03;
    break;
    case HID_KEYBOARD_F12: //Power
    buf[1] = 0x02;
    break;
    default:
    buf[0] = 0x00;
    break;
    }

    HidDev_Report( HID_RPT_ID_CC_IN, HID_REPORT_TYPE_INPUT, HID_CC_IN_RPT_LEN, buf );

    }

    With iPAD, When I pressed, F7 on keyboard, the search pane opened up. But I don't know how AC Home works on iPAD.
  • HIDEmuKbd project and CC2541DK-MINI


    To Complete BLE HID Consumer Control  


    Change in hidemukbd.c:
        #include "hidkbdservice.h" 
    to 
        #include "hidkbmservice.h"



    change to 4
        // HID mouse input report length
        #define HID_MOUSE_IN_RPT_LEN        4


    add define:
        // HID consumer control input report length
        #define HID_CC_IN_RPT_LEN           2


    in project remove files hidkbdservice.h hidkbdservice.c 
    in project add file hidkbmservice.h hidkbmservice.c
    in project options compilator change path from $PROJ_DIR$\..\..\Profiles\HidDevKbd
    to
    $PROJ_DIR$\..\..\Profiles\HidDevKbM



    in hidkbmservice.c make new hidReportMap with new Consumer Control


     // HID Report Map characteristic value
        // Keyboard report descriptor (using format for Boot interface descriptor)
        static CONST uint8 hidReportMap[] =
        {
          0x05, 0x01,  // Usage Page (Generic Desktop)
          0x09, 0x02,  // Usage (Mouse)
          0xA1, 0x01,  // Collection (Application)
          
          0x85, 0x01,  // Report Id (1) в этой реализации  MOUSE,
          
          0x09, 0x01,  //   Usage (Pointer)
            0xA1, 0x00,  //   Collection (Physical)
          
              0x05, 0x09,  //     Usage Page (Buttons) это кнопки, (1-й байт из 4-х)
              0x19, 0x01,  //     Usage Minimum (01) - Button 1   биты от 1-го до
              0x29, 0x03,  //     Usage Maximum (03) - Button 3   третьего, три кнопки
              0x15, 0x00,  //     Logical Minimum (0)  состояния кнопок
              0x25, 0x01,  //     Logical Maximum (1) у каждой кнопки два состояния 0 и 1
              0x75, 0x01,  //     Report Size (1)   один бит
              0x95, 0x03,  //     Report Count (3)  три раза
              0x81, 0x02,  //     Input (Data, Variable, Absolute) - Button states, send to host
              0x75, 0x05,  //     Report Size (5)  добивка еще 5 бит в байте кнопок до байта
              0x95, 0x01,  //     Report Count (1) один раз, итого 8 бит или 1 байт
              0x81, 0x01,  //     Input (Constant) - Padding or Reserved bits
            
              0x05, 0x01,  //     Usage Page (Generic Desktop)
              0x09, 0x30,  //     Usage (X)
              0x09, 0x31,  //     Usage (Y)
              0x09, 0x38,  //     Usage (Wheel)
              0x15, 0x81,  //     Logical Minimum (-127)
              0x25, 0x7F,  //     Logical Maximum (127)
              0x75, 0x08,  //     Report Size (8)  8 бит
              0x95, 0x03,  //     Report Count (3) три раза - итого 3 байта   (2-й, 3-й и 4-й байт)
              0x81, 0x06,  //     Input (Data, Variable, Relative) - X & Y coordinate
            
            0xC0,        //   End Collection
          0xC0,        // End Collection
        
          0x05, 0x01,  // Usage Pg (Generic Desktop)
          0x09, 0x06,  // Usage (Keyboard)
          0xA1, 0x01,  // Collection: (Application)
          
          0x85, 0x02,  // Report Id (2)                   
                       //
          0x05, 0x07,  //   Usage Pg (Key Codes)
          0x19, 0xE0,  //   Usage Min (224)
          0x29, 0xE7,  //   Usage Max (231)
          0x15, 0x00,  //   Log Min (0)
          0x25, 0x01,  //   Log Max (1)
                       //
                       //   Modifier byte                                       1-й байт
          0x75, 0x01,  //   Report Size (1)   1 бит
          0x95, 0x08,  //   Report Count (8)    8 раз, 1 байт      
          0x81, 0x02,  //   Input: (Data, Variable, Absolute)
                       //
                       //   Reserved byte                                       2-й байт
          0x95, 0x01,  //   Report Count (1) 1 бит 
          0x75, 0x08,  //   Report Size (8)  8 раз, 1 байт константа
          0x81, 0x01,  //   Input: (Constant)
                       //
                           //   LED report
              0x95, 0x05,  //   Report Count (5) 5 раз
              0x75, 0x01,  //   Report Size (1)  1 бита
              0x05, 0x08,  //   Usage Pg (LEDs)
              0x19, 0x01,  //   Usage Min (1)
              0x29, 0x05,  //   Usage Max (5)
              0x91, 0x02,  //   Output: (Data, Variable, Absolute)
                           //   LED report padding              добивка 3-х бит до байта
              0x95, 0x01,  //   Report Count (1) 1 раз
              0x75, 0x03,  //   Report Size (3)  3 бита
              0x91, 0x01,  //   Output: (Constant)
                       //
                                                               //   Key arrays (6 bytes)
          0x95, 0x06,  //   Report Count (6)  6 раз
          0x75, 0x08,  //   Report Size (8)   8 бит
          0x15, 0x00,  //   Log Min (0)
          0x25, 0x65,  //   Log Max (101)
          0x05, 0x07,  //   Usage Pg (Key Codes)
          0x19, 0x00,  //   Usage Min (0)
          0x29, 0x65,  //   Usage Max (101)
          0x81, 0x00,  //   Input: (Data, Array)
                       //
          0xC0,        // End Collection
                       //
          
          0x05, 0x0C,       // (GLOBAL) USAGE_PAGE         0x000C Consumer Device Page
          0x09, 0x01,       // (LOCAL)  USAGE              0x000C0001 Consumer Control
          0xA1, 0x01,       // (MAIN)   COLLECTION         0x01 Application
    
          0x85, 0x03,       //   (GLOBAL) REPORT_ID          3
            
            0x19, 0x00,       //   (LOCAL)  USAGE_MINIMUM 
            0x2A, 0x9C, 0x02, //   (LOCAL)  USAGE_MAXIMUM
            0x15, 0x00,       //   (GLOBAL) LOGICAL_MINIMUM 
            0x26, 0x9C, 0x02, //   (GLOBAL) LOGICAL_MAXIMUM    0x029C (668)
            0x95, 0x01,       //   (GLOBAL) REPORT_COUNT       0x01 (1) Number of fields
            0x75, 0x10,       //   (GLOBAL) REPORT_SIZE        0x10 (16) Number of bits per field
            0x81, 0x00,       //   (MAIN)   INPUT 
            
          0xC0              // (MAIN)   END_COLLECTION     Application
          
        };
    


    Now we can send any 2byte Consumer Control report to host use Hut1_12v2.pdf Table 17


    static void hidEmuKbd_HandleKeys( uint8 shift, uint8 keys )
    {
      static uint8 prevKey1 = 0;
      static uint8 prevKey2 = 0;
      
      static uint8 buf_CC[HID_CC_IN_RPT_LEN] = { 0, 0 };
    
      (void)shift;  // Intentionally unreferenced parameter
    
                            if ( (keys & HAL_KEY_SW_1) && (prevKey1 == 0) ) {
                              // pressed
        
                                    buf_CC[0] = 0xB5;  // next track
                                    buf_CC[1] = 0x00;
    
                                    HidDev_Report( HID_RPT_ID_CC_IN, HID_REPORT_TYPE_INPUT,
                                                   HID_CC_IN_RPT_LEN, buf_CC ); 
                                    
                                    buf_CC[0] = 0x00; // clear buffer
                                    buf_CC[1] = 0x00;                  
                              
                              prevKey1 = 1;
                            }//if
                            else if ( !(keys & HAL_KEY_SW_1) && (prevKey1 == 1) ) {
                              // released
    
                                    buf_CC[0] = 0x00; 
                                    buf_CC[1] = 0x00;
    
                                    HidDev_Report( HID_RPT_ID_CC_IN, HID_REPORT_TYPE_INPUT,
                                                   HID_CC_IN_RPT_LEN, buf_CC );                  
    
                              prevKey1 = 0;
                            }//else
    
                                          
                            if ( (keys & HAL_KEY_SW_2) && (prevKey2 == 0) ) {
                              // pressed
        
                                    buf_CC[0] = 0xCD;  // play/pause
                                    buf_CC[1] = 0x00;
    
                                    HidDev_Report( HID_RPT_ID_CC_IN, HID_REPORT_TYPE_INPUT,
                                                   HID_CC_IN_RPT_LEN, buf_CC ); 
                                    
                                    buf_CC[0] = 0x00; // clear buffer
                                    buf_CC[1] = 0x00;                  
                              
                              prevKey2 = 1;
                            }//if
                            else if ( !(keys & HAL_KEY_SW_2) && (prevKey2 == 1) ) {
                              // released
    
                                    buf_CC[0] = 0x00; 
                                    buf_CC[1] = 0x00;
    
                                    HidDev_Report( HID_RPT_ID_CC_IN, HID_REPORT_TYPE_INPUT,
                                                   HID_CC_IN_RPT_LEN, buf_CC );                  
    
                              prevKey2 = 0;
                            }//else
    }
    



    test on
    MAC OS X 10.10.2 MacBook Air mid2012, iOS 8.1.3 iPhone 4s