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.

MSP430F5527: Modifying MPS430 Keyboard Project: Changing Consumer Control Report Usage ID from 8-bit to 16-bit

Part Number: MSP430F5527
Other Parts Discussed in Thread: HID2

Tool/software:

Hello, 

I'm currently working with an example keyboard project based on the MPS430, and I need some guidance on modifying the code. The project uses a consumer report to interact with Windows, and I want to change the Usage ID from an 8-bit to a 16-bit value to accommodate more usage IDs.

I’m using the original library and would like to know the best approach for handling the transition from the 8-bit to the 16-bit Usage ID. 

I have currently narrowed down my modifications to the following HID2 report descriptor and associated size

#define report_desc_size_HID2 51

uint8_t const report_desc_HID2[]=
{
    0x05, 0x0C,               // Usage Page (Consumer)
    0x09, 0x01,               // Usage (Consumer Control)
    0xA1, 0x01,               // Collection (Application)
    0x85, 0x03,               // Report Id 
    0x75, 0x01,               // Report Size (1)
    0x95, 0x01,               // Report Count (1)     
    0x15, 0x00,               // Logical Minimum (0)
    0x25, 0x01,               // Logical Maximum (1)  
    0x09, 0xE9,               // Usage (Volume Increment)
    0x81, 0x06,               // Input(Data, Value, Relative, BitField) Bit0
    0x09, 0xEA,               // Usage (Volume Decrement)
    0x81, 0x06,               // Input(Data, Value, Relative, BitField) Bit1
    0x09, 0xE2,               // Usage (Mute)
    0x81, 0x06,               // Input(Data, Value, Relative, BitField) Bit2     
    0x0A, 0x94, 0x01,         // Usage AL Local Machine Browser (App1) 
    0x81, 0x06,               // Input(Data, Value, Relative, BitField) Bit3
    0x0A, 0x92, 0x01,         // Usage AL Calculator (App2) 
    0x81, 0x06,               // Input(Data, Value, Relative, BitField) Bit4
    0x09, 0xCD,               // Usage (Play/Pause)
    0x81, 0x06,               // Input(Data, Value, Relative, BitField) Bit5
    0x09, 0x6F,               // Usage (Brightness Increase)
    0x81, 0x06,               // Input(Data, Value, Relative, BitField) Bit6
    0x09, 0x70,               // Usage (Brightness Decrease)
    0x81, 0x06,               // Input(Data, Value, Relative, BitField) Bit7
    0xC0,                     // End Collection
};

When I change the from the 8 bit tag and data  {0x09, 0xFF} to 16-bit  {0x0A, 0x92, 0x01} on lines 17 and 19, where 0xFF is just a place holder for any Usage ID which is constrained to 8-bits. I also changed report_desc_size_HID2 from 49 to 51 to account for the two extra bytes of data in the report.

My code stops using the consumer report all together, the keyboard buttons for volume and brightness interact with Windows perfectly as long as I bind all IDs to 8-bit. As soon as I change to 16-bit of any ID from 0x100 and onwards all the consumer report buttons stop working.

Has anyone worked with modifying the Usage ID in a similar context? Any advice or pointers would be greatly appreciated!

Thank you!

  • How are you sending the usage id to the computer? Do you send two bytes? Is the computer expecting 2 bytes?

  • There is an output buffer of 2 byes, the first byte is not used, the second byte is or'ed as a bitmap. The #defines are in the same order as the descriptor lists them.

    #define CONSREP_DATA_OFFSET     (1)
    
    #define hidUsageVolumeUp            0x1101  //bit 0 of Consumer Control Input Report
    #define hidUsageVolumeDown          0x1102  //bit 1 of Consumer Control Input Report
    #define hidUsageConsumerMute        0x1104  //bit 2 of Consumer Control Input Report
    #define hidUsageApp1                0x1108  //bit 3 of Consumer Control Input Report
    #define hidUsageApp2                0x1110  //bit 4 of Consumer Control Input Report
    #define hidUsagePlay                0x1120  //bit 5 of Consumer Control Input Report
    #define hidUsageBrightnessUp        0x1140  //bit 6 of Consumer Control Input Report
    #define hidUsageBrightnessDown      0x1180  //bit 7 of Consumer Control Input Report
    
    
    //in KBD320_Keyboard.c
    if ((keycode & 0xFF00) == CONSUMER_KEY(0))
    {
        #ifdef USE_CONSUMER_REPORT
        // Add key to Consumer Report
        KBD430_ConsReport_Addkey((keycode & 0x00FF));
        #endif
    }
    
    //in KBD430_report.c
    /******************************************************************************
     * @brief  Adds key to the consumer report
     *   Note that the consumer report is bit-based, so it sets/clears bits when
     *   a key is pressed
     *
     * @param key   Bits being set in the report (value will be ORed with the report)
     *
     * @return  true 
     *****************************************************************************/
    #ifdef USE_CONSUMER_REPORT
    bool KBD430_ConsReport_Addkey( uint8_t key )
    {
        ConsReport_buff.Buff[CONSREP_DATA_OFFSET] |= key;
        ConsReport_buff.Update = true;
        return true;
    }
    #endif

    This buffer is then passed to a function that send it

    #ifdef USE_CONSUMER_REPORT    
        if (ConsReport_buff.Update == true)
        {
            if (KBD430_ReportSend((uint8_t *)&ConsReport_buff.Buff[0], HID_Consumer) == true)
            {
                // Clear flag if the report was sent correctly
                ConsReport_buff.Update = false;
            }
        }
    #endif
    
    bool KBD430_ReportSend(uint8_t * reportData, uint8_t intfNum)
    {
        if (USBHID_sendReport(reportData, intfNum) == kUSBHID_sendComplete)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    
    uint8_t USBHID_sendReport (const uint8_t * reportData, uint8_t intfNum)
    {
        uint8_t byte_count;
        uint8_t * pEP1;
        uint8_t * pCT1;
    
        uint8_t edbIndex;
    
        edbIndex = stUsbHandle[intfNum].edb_Index;
    
        //do not access USB memory if suspended (PLL off). It may produce BUS_ERROR
        if ((bFunctionSuspended) ||
            (bEnumerationStatus != ENUMERATION_COMPLETE)){
            return (kUSBHID_busNotAvailable);
        }
    
        if (HidWriteCtrl[INTFNUM_OFFSET(intfNum)].bCurrentBufferXY == X_BUFFER){
            //this is the active EP buffer
            pEP1 = (uint8_t*)stUsbHandle[intfNum].iep_X_Buffer;
            pCT1 = &tInputEndPointDescriptorBlock[edbIndex].bEPBCTX;
        } else {
            //this is the active EP buffer
            pEP1 = (uint8_t*)stUsbHandle[intfNum].iep_Y_Buffer;
            pCT1 = &tInputEndPointDescriptorBlock[edbIndex].bEPBCTY;
        }
    
        byte_count = report_len_input[INTFNUM_OFFSET(intfNum)];
    
        if (*pCT1 & EPBCNT_NAK){                                                        //if this EP is empty
            USB_TX_memcpy(pEP1, reportData, byte_count);                                //copy data into IEP X or Y buffer
            uint8_t au8HIDReportDebug[10] = {0};
            memcpy(au8HIDReportDebug, reportData, byte_count);                                //copy data into IEP X or Y buffer
            *pCT1 = byte_count;                                                         //Set counter for usb In-Transaction
            HidWriteCtrl[INTFNUM_OFFSET(intfNum)].bCurrentBufferXY =
                (HidWriteCtrl[INTFNUM_OFFSET(intfNum)].bCurrentBufferXY + 1) & 0x01;    //switch buffer
            return (kUSBHID_sendComplete);
        }
        return (kUSBHID_intfBusyError);
    }

    So I assume it is always sending a single 8-bit bitmap of which the usages are defined during the descriptor creation. The size of the usages should not matter to the code.

  • Hi Pillip,

    I do not have the experience on this library development.

    One suggestion from my perspective is to check then whole send message logic to see whether its array counter is messed up with the increased data in the report_desc_HID2[].

    B.R.

    Sal

  • I have found the solution. Thank you both for replying, your input helped my accidentally stumble upon the solution.

    In descriptors.c there is an array of interface sizes which does not pull the #defines. This array is used by the host.

    uint16_t const report_desc_size[HID_NUM_INTERFACES] =
    {
    63,
    36,
    49,
    25
    };
    

    This array should be updated to use the #defines from descriptors.h

    //***********************************************************************************************
    // DESCRIPTOR CONSTANTS
    //***********************************************************************************************
    #define SIZEOF_DEVICE_DESCRIPTOR  0x12
    #define MAX_STRING_DESCRIPTOR_INDEX 8
    #define report_desc_size_HID0 63
    #define report_desc_size_HID1 36
    #define report_desc_size_HID2 51
    #define report_desc_size_HID3 25
    //#define SIZEOF_REPORT_DESCRIPTOR  36
    //#define USBHID_REPORT_LENGTH      64  // length of whole HID report (including Report ID)
    #define CONFIG_STRING_INDEX       4
    #define INTF_STRING_INDEX         5
    #define USB_CONFIG_VALUE          0x01
    
    
    //In descriptors.c
    uint16_t const report_desc_size[HID_NUM_INTERFACES] =
    {
    report_desc_size_HID0,
    report_desc_size_HID1,
    report_desc_size_HID2,
    report_desc_size_HID3
    };

**Attention** This is a public forum