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.

MSP430F5510: MSP430F5510: USB-HID Gamepad/Joystick Controller with MSP430 USB API

Part Number: MSP430F5529

Hi experts,

I am currently trying to emulate a gamepad/joystick on Windows 10 using USB-HID. The MSP430 will take in 7-14 analogue inputs and send them to Windows, where they will be seen as USB-HID game controller inputs.

I am working off the H7_Mouse example in the MSP430 USB API, as there is no example code for a traditional game controller. The descriptors were made using the USB-IF’s HID Descriptor Tool, which was then pasted into the TI USB Descriptor tool to create the necessary descriptor.c/h in the USB_config folder. I am using USB Descriptors (listed below) for a simple 4-axis 16-button gamepad to get started. 

0x05, 0x01, //		USAGE_PAGE (Generic Desktop)
0x09, 0x05, //		USAGE (Game Pad)
0xA1, 0x01, //		COLLECTION (Application)
0xA1, 0x00, //			COLLECTION (Physical)
0x05, 0x09, //				USAGE_PAGE (Button)
0x19, 0x01, //				USAGE_MINIMUM (Button 1)
0x29, 0x10, //				USAGE_MAXIMUM (Button 16)
0x15, 0x00, //				LOGICAL_MINIMUM (0)
0x25, 0x01, //				LOGICAL_MAXIMUM (1)
0x95, 0x10, //				REPORT_COUNT (16)
0x75, 0x01, //				REPORT_SIZE (1)
0x81, 0x02, //				INPUT (Data,Var,Abs)
0x05, 0x01, //				USAGE_PAGE (Generic Desktop)
0x09, 0x30, //				USAGE (X)
0x09, 0x31, //				USAGE (Y)
0x09, 0x32, //				USAGE (Z)
0x09, 0x33, //				USAGE (Rx)
0x15, 0x81, //				LOGICAL_MINIMUM (-127)
0x25, 0x7F, //				LOGICAL_MAXIMUM (127)
0x75, 0x08, //				REPORT_SIZE (8)
0x95, 0x04, //				REPORT_COUNT (4)
0x81, 0x02, //				INPUT (Data,Var,Abs)
0xC0, //			END COLLECTION
0xC0 //		END COLLECTION

The main.c file (slightly edited from the mouse example to fit the new HID report structure) is as follows:

 
 * ======== main.c ========
 * Mouse HID Demo:
 *
 * This example functions as a mouse on the host.  It causes the mouse pointer 
 * to move in a circular pattern on the screen.  Simply build and run the 
 * example.  To re-gain control of the mouse, unplug USB.  
 * Unlike the HID-Datapipe examples, this one does not communicate with the 
 * HID Demo Application
 *
 +----------------------------------------------------------------------------+
 * Please refer to the Examples Guide for more details.
 *----------------------------------------------------------------------------*/
#include <string.h>

#include "driverlib.h"

#include "USB_config/descriptors.h"
#include "USB_API/USB_Common/device.h"
#include "USB_API/USB_Common/usb.h"                 // USB-specific functions
#include "USB_API/USB_HID_API/UsbHid.h"

/*
 * NOTE: Modify hal.h to select a specific evaluation board and customize for
 * your own board.
 */
#include "hal.h"


#define LED_PORT    GPIO_PORT_P1
#define LED_PIN     GPIO_PIN0
#define BUTTON_PORT GPIO_PORT_P1
#define BUTTON_PIN GPIO_PIN1

typedef struct {

    uint16_t buttons;
    int8_t lx;
    int8_t ly;
    int8_t rx;
    int8_t ry;

} CONTROL_REPORT;

CONTROL_REPORT controlReport = { 0, 0, 0, 0, 0 };          // HID report, to be sent to the PC.
//const int16_t tableSinCosLookUp[93][2];                 // Lookup table for mouse data;
#if defined(__TI_COMPILER_VERSION__) || (__IAR_SYSTEMS_ICC__)
uint8_t index = 1;                                     // Index for lookup table
#endif
volatile uint8_t sendNewMousePosition = FALSE;        // Flag by which timer tells main
                                                    // loop to send a new report
Timer_A_initUpModeParam Timer_A_params = {0};

void initTimer (void);

volatile uint8_t buttonPressed = FALSE;

/*  
 * ======== main ========
 */
void main (void)
{
#if defined(__GNUC__) && (__MSP430__)
uint8_t index = 1;
#endif
    WDT_A_hold(WDT_A_BASE); // Stop watchdog timer

    // Minumum Vcore setting required for the USB API is PMM_CORE_LEVEL_2 .
    PMM_setVCore(PMM_CORE_LEVEL_2);
    USBHAL_initPorts();           // Config GPIOS for low-power (output low)
    USBHAL_initClocks(8000000);   // Config clocks. MCLK=SMCLK=FLL=8MHz; ACLK=REFO=32kHz
    initTimer();
    USB_setup(TRUE, TRUE); // Init USB & events; if a host is present, connect

    ///additional input button in dev kit P2.1
    GPIO_setAsInputPin(BUTTON_PORT, BUTTON_PIN);
    GPIO_setAsOutputPin(LED_PORT, LED_PIN);
    P1IES |= BIT1;
    P1IFG &= ~BIT1;
    P1IE |= BIT1;
    ///


    __enable_interrupt();                           // Enable interrupts globally
    
    while (1)
    {
        // Check the USB state and directly main loop accordingly
        switch (USB_getConnectionState())
        {
            // This case is executed while your device is enumerated on the
            // USB host
            case ST_ENUM_ACTIVE:

                // Start Timer
                Timer_A_startCounter(TIMER_A0_BASE,
                    TIMER_A_UP_MODE);

                // Enter LPM0, until the timer wakes the CPU
                __bis_SR_register(LPM0_bits + GIE);

                // Timer has awakened the CPU.  Proceed with main loop...
                if (sendNewMousePosition){
               
                    controlReport.ry += 1;
                    controlReport.buttons += 1;
                    controlReport.lx += 1;
                    controlReport.ly += 1;
                    controlReport.rx += 1;


                    // Send the report
                    USBHID_sendReport((void *)&controlReport, HID0_INTFNUM);

                    // Toggle LED on P1.0
                    GPIO_toggleOutputOnPin(LED_PORT, LED_PIN);
					
                }
                break;


            // These cases are executed while your device is disconnected from
            // the host (meaning, not enumerated); enumerated but suspended
            // by the host, or connected to a powered hub without a USB host
            // present.
            case ST_PHYS_DISCONNECTED:
            case ST_ENUM_SUSPENDED:
            case ST_PHYS_CONNECTED_NOENUM_SUSP:
                TA0CTL &= ~MC_1;
                P1OUT &= ~BIT0;
                __bis_SR_register(LPM3_bits + GIE);
                _NOP();
                break;

            // The default is executed for the momentary state
            // ST_ENUM_IN_PROGRESS.  Usually, this state only last a few
            // seconds.  Be sure not to enter LPM3 in this state; USB
            // communication is taking place here, and therefore the mode must
            // be LPM0 or active-CPU.
            case ST_ENUM_IN_PROGRESS:
            default:;
        }

    }  //while(1)
} //main()


/*  
 * ======== UNMI_ISR ========
 */
#if defined(__TI_COMPILER_VERSION__) || (__IAR_SYSTEMS_ICC__)
#pragma vector = UNMI_VECTOR
__interrupt void UNMI_ISR (void)
#elif defined(__GNUC__) && (__MSP430__)
void __attribute__ ((interrupt(UNMI_VECTOR))) UNMI_ISR (void)
#else
#error Compiler not found!
#endif
{
    switch (__even_in_range(SYSUNIV, SYSUNIV_BUSIFG ))
    {
        case SYSUNIV_NONE:
            __no_operation();
            break;
        case SYSUNIV_NMIIFG:
            __no_operation();
            break;
        case SYSUNIV_OFIFG:
            UCS_clearFaultFlag(UCS_XT2OFFG);
            UCS_clearFaultFlag(UCS_DCOFFG);
            SFR_clearInterrupt(SFR_OSCILLATOR_FAULT_INTERRUPT);
            break;
        case SYSUNIV_ACCVIFG:
            __no_operation();
            break;
        case SYSUNIV_BUSIFG:
            // If the CPU accesses USB memory while the USB module is
            // suspended, a "bus error" can occur.  This generates an NMI.  If
            // USB is automatically disconnecting in your software, set a
            // breakpoint here and see if execution hits it.  See the
            // Programmer's Guide for more information.
            SYSBERRIV = 0; //clear bus error flag
            USB_disable(); //Disable
    }
}

/*  
 * ======== TIMER0_A0_ISR ========
 */
#if defined(__TI_COMPILER_VERSION__) || (__IAR_SYSTEMS_ICC__)
#pragma vector=TIMER0_A0_VECTOR
__interrupt void TIMER0_A0_ISR (void)
#elif defined(__GNUC__) && (__MSP430__)
void __attribute__ ((interrupt(TIMER0_A0_VECTOR))) TIMER0_A0_ISR (void)
#else
#error Compiler not found!
#endif
{
sendNewMousePosition = TRUE;                 // Set flag telling main loop to send a report
__bic_SR_register_on_exit(LPM0_bits);        // Keep CPU awake after returning;
                                             // enables a run through the main loop
}

/*
 * ======== setTimer_A_Parameters ========
 */
// This function sets the timer A parameters
void setTimer_A_Parameters()
{
    Timer_A_params.clockSource = TIMER_A_CLOCKSOURCE_ACLK;
	Timer_A_params.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_1;
    Timer_A_params.timerPeriod = 547;  // 547/32768 = a period of 16.7ms
	Timer_A_params.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_DISABLE;
	Timer_A_params.captureCompareInterruptEnable_CCR0_CCIE =
		       TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE;
	Timer_A_params.timerClear = TIMER_A_DO_CLEAR;
	Timer_A_params.startTimer = false;
}



/*
 * ======== initTimer ========
 */
void initTimer (void)
{
    setTimer_A_Parameters();
    
    // Start timer
    Timer_A_clearTimerInterrupt(TIMER_A0_BASE);

    Timer_A_initUpMode(TIMER_A0_BASE, &Timer_A_params);
}
//Released_Version_5_20_06_03

Using the above code and descriptors, Windows correctly identifies the MSP430 as a gamepad with the correct inputs - visible under 'Control Panel\Set up USB Game Controllers'. However, when clicking 'Properties' on the same page and testing the inputs (the code increments each input value by 1 at regular intervals), there is no visible button press/joystick response registered by Windows from the controller. I tried using the Java_HID_Demo tool in the USB API to see if I could debug the problem by looking at what raw data is being sent, but the software was unable to connect to the Traditional USB-HID device, even when Windows is recognizing it as a gamepad.

The descriptor files are also here for a complete reference:

- descriptors.h

/* --COPYRIGHT--,BSD
 * Copyright (c) 2015, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * --/COPYRIGHT--*/


// Generated by MSP USB Descriptor Tool: Fri Jul 09 10:27:06 BST 2021


#include <stdint.h>
#include "USB_API/USB_Common/usb.h"

#ifndef _DESCRIPTORS_H_
#define _DESCRIPTORS_H_

#ifdef __cplusplus
extern "C"
{
#endif

/*-----------------------------------------------------------------------------+
| Include files                                                                |
|-----------------------------------------------------------------------------*/

//***********************************************************************************************
// CDC or HID - Define both for composite support
//***********************************************************************************************
#define _HID_          // Needed for HID interface

//***********************************************************************************************
// CONFIGURATION CONSTANTS
//***********************************************************************************************
// These constants configure the API stack and help define the USB descriptors.
// Refer to Sec. 6 of the MSP430 USB CDC API Programmer's Guide for descriptions of these constants.

// Configuration Constants that can change
// #define that relates to Device Descriptor
#define USB_VID               0x2047    // Vendor ID (VID)
#define USB_PID               0x0302        // Product ID (PID)

/*----------------------------------------------------------------------------+
| Firmware Version                                                            |
| How to detect version number of the FW running on MSP430?                   |
| on Windows Open ControlPanel->Systems->Hardware->DeviceManager->Ports->     |
|         Msp430->ApplicationUART->Details                                    |
+----------------------------------------------------------------------------*/
#define VER_FW_H              0x02          // Device release number, in binary-coded decimal
#define VER_FW_L              0x00          // Device release number, in binary-coded decimal

// If a serial number is to be reported, set this to the index within the string descriptor
//of the dummy serial number string.  It will then be automatically handled by the API.
// If no serial number is to be reported, set this to 0.
#define USB_STR_INDEX_SERNUM  3
#define PHDC_ENDPOINTS_NUMBER               2  // bulk in, bulk out


#define DESCRIPTOR_TOTAL_LENGTH            41            // wTotalLength, This is the sum of configuration descriptor length  + CDC descriptor length  + HID descriptor length
#define USB_NUM_INTERFACES                  1            //Number of implemented interfaces.

#define HID0_REPORT_INTERFACE                0              // Report interface number of HID0
#define HID0_OUTEP_ADDR                    0x01           // Output Endpoint number of HID0
#define HID0_INEP_ADDR                     0x81           // Input Endpoint number of HID0

#define CDC_NUM_INTERFACES                   0           //  Total Number of CDCs implemented. should set to 0 if there are no CDCs implemented.
#define HID_NUM_INTERFACES                   1           //  Total Number of HIDs implemented. should set to 0 if there are no HIDs implemented.
#define MSC_NUM_INTERFACES                   0           //  Total Number of MSCs implemented. should set to 0 if there are no MSCs implemented.
#define PHDC_NUM_INTERFACES                  0           //  Total Number of PHDCs implemented. should set to 0 if there are no PHDCs implemented.
// Interface numbers for the implemented CDSs and HIDs, This is to use in the Application(main.c) and in the interupt file(UsbIsr.c).
#define HID0_INTFNUM                0
#define MSC_MAX_LUN_NUMBER                   1           // Maximum number of LUNs supported

#define PUTWORD(x)      ((x)&0xFF),((x)>>8)
#define USB_OUTEP_INT_EN BIT0 | BIT1 
#define USB_INEP_INT_EN BIT0 | BIT1 
#define USB_USE_INTERNAL_3V3LDO TRUE
#define USB_XT2_BYPASS_MODE FALSE


// MCLK frequency of MCU, in Hz
// For running higher frequencies the Vcore voltage adjustment may required.
// Please refer to Data Sheet of the MSP430 device you use
#define USB_PLL_XT        2                  // Defines which XT is used by the PLL (1=XT1, 2=XT2)
#define USB_DISABLE_XT_SUSPEND 1             // If non-zero, then USB_suspend() will disable the oscillator
                                             // that is designated by USB_PLL_XT; if zero, USB_suspend won't
                                             // affect the oscillator
#define USB_DMA_CHAN           DMA_CHANNEL_0   // Set to 0xFF if no DMA channel will be used 0..7 for selected DMA channel

// Controls whether the remote wakeup feature is supported by this device.
// A value of 0x20 indicates that is it supported (this value is the mask for
// the bmAttributes field in the configuration descriptor).
// A value of zero indicates remote wakeup is not supported.
// Other values are undefined, as they will interfere with bmAttributes.
#define USB_SUPPORT_REM_WAKE 0x00
// Controls whether the application is self-powered to any degree.  Should be
// set to 0x40, unless the USB device is fully supplied by the bus.
#define USB_SUPPORT_SELF_POWERED 0x80

// Controls what the device reports to the host regarding how much power it will
// consume from VBUS.  Expressed in 2mA units; that is, the number of mA
// communicated is twice the value of this field.
#define USB_MAX_POWER 0x32
//Configuration constants that can not change ( Fixed Values)
#define CDC_CLASS  2
#define HID_CLASS  3
#define MSC_CLASS  4
#define PHDC_CLASS 5

#define MAX_PACKET_SIZE   0x40              // Max size of the USB packets.

//***********************************************************************************************
// DESCRIPTOR CONSTANTS
//***********************************************************************************************
#define SIZEOF_DEVICE_DESCRIPTOR  0x12
#define MAX_STRING_DESCRIPTOR_INDEX 5
#define report_desc_size_HID0 46
//#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
//***********************************************************************************************
// OUTWARD DECLARATIONS
//***********************************************************************************************

//Calculates the endpoint descriptor block number from given address
#define EDB(addr) ((addr&0x07)-1)

/* Structure for generic part of configuration descriptor */
struct abromConfigurationDescriptorGenric
{
    uint8_t sizeof_config_descriptor;            // bLength
     uint8_t desc_type_config;                    // bDescriptorType: 2
    uint8_t sizeof_configuration_descriptor1;    // wTotalLength
    uint8_t sizeof_configuration_descriptor2;
    uint8_t usb_num_configurations;              // bNumInterfaces
    uint8_t bconfigurationvalue;                 // bConfigurationValue
    uint8_t  config_string_index;                // iConfiguration Description offset
     uint8_t mattributes;                         // bmAttributes, bus power, remote wakeup
    uint8_t usb_max_power;                       // Max. Power Consumption at 2mA unit
};

/************************************************CDC Descriptor**************************/
struct abromConfigurationDescriptorCdc
{
// interface descriptor (9 bytes)
    uint8_t blength_intf;                          // blength: interface descriptor size
    uint8_t desc_type_interface;                  // bdescriptortype: interface
    uint8_t interface_number_cdc;                // binterfacenumber
    uint8_t balternatesetting;                   // balternatesetting: alternate setting
    uint8_t bnumendpoints;                       // bnumendpoints: three endpoints used
    uint8_t binterfaceclass;                     // binterfaceclass: communication interface class
    uint8_t binterfacesubclass;                  // binterfacesubclass: abstract control model
    uint8_t binterfaceprotocol;                  // binterfaceprotocol: common at commands 
    uint8_t intf_string_index;                      // interface:
//header functional descriptor
    uint8_t blength_header;                      // blength: endpoint descriptor size
    uint8_t bdescriptortype_header;              // bdescriptortype: cs_interface
    uint8_t bdescriptorsubtype_header;              // bdescriptorsubtype: header func desc
    uint8_t bcdcdc1;
    uint8_t bcdcdc2;                              // bcdcdc: spec release number

//call managment functional descriptor
    uint8_t bfunctionlength;                      // bfunctionlength
    uint8_t bdescriptortype_c;                      // bdescriptortype: cs_interface
    uint8_t bdescriptorsubtype_c;                  // bdescriptorsubtype: call management func desc
    uint8_t bmcapabilities;                      // bmcapabilities: d0+d1
    uint8_t intf_number_cdc;                     // bdatainterface: 0

//acm functional descriptor
    uint8_t bfunctionlength_acm;                  // bfunctionlength
    uint8_t bdescriptortype_acm;                  // bdescriptortype: cs_interface
    uint8_t bdescriptorsubtype_acm;              // bdescriptorsubtype: abstract control management desc
    uint8_t bmcapabilities_acm;                  // bmcapabilities

// Union Functional Descriptor
    uint8_t bLength_ufd;                         // Size, in bytes
    uint8_t bdescriptortype_ufd;                 // bDescriptorType: CS_INTERFACE
    uint8_t bdescriptorsubtype_ufd;              // bDescriptorSubtype: Union Functional Desc
    uint8_t bmasterinterface_ufd;                // bMasterInterface -- the controlling intf for the union
    uint8_t bslaveinterface_ufd;                 // bSlaveInterface -- the controlled intf for the union

//Interrupt end point related fields
    uint8_t sizeof_epintep_descriptor;           // blength: endpoint descriptor size
    uint8_t desc_type_epintep;                      // bdescriptortype: endpoint
    uint8_t cdc_intep_addr;                      // bendpointaddress: (in2)
    uint8_t epintep_desc_attr_type_int;          // bmattributes: interrupt
    uint8_t epintep_wmaxpacketsize1;
    uint8_t epintep_wmaxpacketsize;                 // wmaxpacketsize, 64 bytes
    uint8_t epintep_binterval;                   // binterval

// Data interface descriptor (9 bytes)
    uint8_t blength_slaveintf;                      // blength: interface descriptor size
    uint8_t desc_type_slaveinterface;              // bdescriptortype: interface
    uint8_t interface_number_slavecdc;           // binterfacenumber
    uint8_t balternatesetting_slave;             // balternatesetting: alternate setting
    uint8_t bnumendpoints_slave;                 // bnumendpoints: three endpoints used
    uint8_t binterfaceclass_slave;               // binterfaceclass: data interface class
    uint8_t binterfacesubclass_slave;            // binterfacesubclass: abstract control model
    uint8_t binterfaceprotocol_slave;            // binterfaceprotocol: common at commands
    uint8_t intf_string_index_slave;              // interface:

// Bulk out end point related fields
    uint8_t sizeof_outep_descriptor;             // blength: endpoint descriptor size
    uint8_t desc_type_outep;                      // bdescriptortype: endpoint
    uint8_t cdc_outep_addr;                      // bendpointaddress: (out3)
    uint8_t outep_desc_attr_type_bulk;              // bmattributes: bulk
    uint8_t outep_wmaxpacketsize1;
    uint8_t outep_wmaxpacketsize2;               // wmaxpacketsize, 64 bytes
    uint8_t outep_binterval;                       // binterval: ignored for bulk transfer

// Bulk in related fields
    uint8_t sizeof_inep_descriptor;              // blength: endpoint descriptor size
    uint8_t desc_type_inep;                      // bdescriptortype: endpoint
    uint8_t cdc_inep_addr;                          // bendpointaddress: (in3)
    uint8_t inep_desc_attr_type_bulk;              // bmattributes: bulk
    uint8_t inep_wmaxpacketsize1;
    uint8_t inep_wmaxpacketsize2;                // wmaxpacketsize, 64 bytes
    uint8_t inep_binterval;                      // binterval: ignored for bulk transfer
}    ;

/**************************************HID descriptor structure *************************/
struct abromConfigurationDescriptorHid
{
//INTERFACE DESCRIPTOR (9 bytes)
    uint8_t sizeof_interface_descriptor;        // Desc Length
    uint8_t desc_type_interface;                // DescriptorType
    uint8_t interface_number_hid;               // Interface number
    uint8_t balternatesetting;                  // Any alternate settings if supported
    uint8_t bnumendpoints;                      // Number of end points required
    uint8_t binterfaceclass;                    // Class ID
    uint8_t binterfacesubclass;                 // Sub class ID
    uint8_t binterfaceprotocol;                 // Protocol
    uint8_t intf_string_index;                  // String Index

//hid descriptor (9 bytes)
    uint8_t blength_hid_descriptor;             // HID Desc length
    uint8_t hid_descriptor_type;                // HID Desc Type
    uint8_t hidrevno1;                          // Rev no 
    uint8_t hidrevno2;                          // Rev no - 2nd part
    uint8_t tcountry;                              // Country code 
    uint8_t numhidclasses;                      // Number of HID classes to follow    
    uint8_t report_descriptor_type;             // Report desc type 
    uint8_t tlength;                            // Total length of report descriptor
    uint8_t size_rep_desc;

//input end point descriptor (7 bytes)
    uint8_t size_inp_endpoint_descriptor;       // End point desc size
    uint8_t desc_type_inp_endpoint;             // Desc type
    uint8_t hid_inep_addr;                      // Input end point address
    uint8_t ep_desc_attr_type_inp_int;          // Type of end point
    uint8_t  inp_wmaxpacketsize1;               // Max packet size
    uint8_t  inp_wmaxpacketsize2;
    uint8_t inp_binterval;                      // bInterval in ms

 // Output end point descriptor; (7 bytes)
    uint8_t size_out_endpoint_descriptor;       // Output endpoint desc size
    uint8_t desc_type_out_endpoint;             // Desc type
    uint8_t hid_outep_addr;                     // Output end point address
    uint8_t ep_desc_attr_type_out_int;          // End point type
    uint8_t out_wmaxpacketsize1;                // Max packet size
    uint8_t out_wmaxpacketsize2;
    uint8_t out_binterval;                      // bInterval in ms
};

/**************************************MSC descriptor structure *************************/
struct abromConfigurationDescriptorMsc
{
// INTERFACE DESCRIPTOR (9 bytes)
    uint8_t sizeof_interface_descriptor;         // Desc Length
    uint8_t desc_type_interface;                 // DescriptorType
    uint8_t interface_number_hid;                // Interface number
    uint8_t balternatesetting;                   // Any alternate settings if supported
    uint8_t bnumendpoints;                       // Number of end points required
    uint8_t binterfaceclass;                     // Class ID
    uint8_t binterfacesubclass;                  // Sub class ID
    uint8_t binterfaceprotocol;                  // Protocol
    uint8_t intf_string_index;                   // String Index

// input end point descriptor (7 bytes)
    uint8_t size_inp_endpoint_descriptor;        // End point desc size
    uint8_t desc_type_inp_endpoint;              // Desc type
    uint8_t hid_inep_addr;                       // Input end point address
    uint8_t ep_desc_attr_type_inp_int;           // Type of end point
    uint8_t  inp_wmaxpacketsize1;                // Max packet size
    uint8_t  inp_wmaxpacketsize2;
    uint8_t inp_binterval;                       // bInterval in ms

// Output end point descriptor; (7 bytes)
    uint8_t size_out_endpoint_descriptor;        // Output endpoint desc size
    uint8_t desc_type_out_endpoint;              // Desc type
    uint8_t hid_outep_addr;                      // Output end point address
    uint8_t ep_desc_attr_type_out_int;           // End point type
    uint8_t out_wmaxpacketsize1;                 // Max packet size
    uint8_t out_wmaxpacketsize2;
    uint8_t out_binterval;                       // bInterval in ms
};

/* Global structure having Generic,CDC,HID, MSC structures */
struct  abromConfigurationDescriptorGroup
{
    /* Generic part of config descriptor */
    const struct abromConfigurationDescriptorGenric abromConfigurationDescriptorGenric;
#ifdef _MSC_
    /* MSC descriptor structure */
    const struct abromConfigurationDescriptorMsc stMsc[MSC_NUM_INTERFACES];
#endif
#ifdef _CDC_ 
    /* CDC descriptor structure */
    const struct abromConfigurationDescriptorCdc stCdc[CDC_NUM_INTERFACES];
#endif
#ifdef _HID_
    /* HID descriptor structure */
    const struct abromConfigurationDescriptorHid stHid[HID_NUM_INTERFACES];
#endif
#ifdef _PHDC_
/* PDC descriptor structure */
    const struct abromConfigurationDescriptorPhdc stPhdc[PHDC_NUM_INTERFACES];
#endif
};

extern const struct  abromConfigurationDescriptorGroup abromConfigurationDescriptorGroup;
extern uint8_t const abromDeviceDescriptor[SIZEOF_DEVICE_DESCRIPTOR];
extern uint8_t const abromStringDescriptor[];
//extern uint8_t const abromReportDescriptor[SIZEOF_REPORT_DESCRIPTOR];

/* Handle Structure - Will be populated in descriptors.c based on number of CDC,HID interfaces */
struct tUsbHandle
{
    uint8_t ep_In_Addr;               // Input EP Addr 
    uint8_t ep_Out_Addr;              // Output EP Addr 
    uint8_t edb_Index;                // The EDB index 
    uint8_t dev_Class;                // Device Class- 2 for CDC, 3 for HID 
    uint16_t intepEP_X_Buffer;         // Interupt X Buffer Addr 
    uint16_t intepEP_Y_Buffer;         // Interupt Y Buffer Addr 
    uint16_t oep_X_Buffer;             // Output X buffer Addr 
    uint16_t oep_Y_Buffer;             // Output Y buffer Addr 
    uint16_t iep_X_Buffer;             // Input X Buffer Addr 
    uint16_t iep_Y_Buffer;             // Input  Y Buffer Addr 
};

extern const struct tUsbHandle stUsbHandle[CDC_NUM_INTERFACES + HID_NUM_INTERFACES + MSC_NUM_INTERFACES + PHDC_NUM_INTERFACES]; 
extern const tDEVICE_REQUEST_COMPARE tUsbRequestList[];

#ifdef __cplusplus
}
#endif

#endif

/*------------------------ Nothing Below This Line --------------------------*/

//Released_Version_5_20_06_03

- descriptors.c

/* --COPYRIGHT--,BSD
 * Copyright (c) 2015, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * --/COPYRIGHT--*/


// Generated by MSP USB Descriptor Tool: Fri Jul 09 10:27:06 BST 2021

/*-----------------------------------------------------------------------------+
| Include files 
|-----------------------------------------------------------------------------*/
#include <USB_API/USB_Common/device.h>
#include <USB_API/USB_Common/defMSP430USB.h>
#include <USB_API/USB_Common/usb.h>              // USB-specific Data Structures
#include "descriptors.h"
#include <USB_API/USB_CDC_API/UsbCdc.h>
#include <USB_API/USB_HID_API/UsbHidReq.h>

uint16_t const report_desc_size[HID_NUM_INTERFACES] =
{
    46
};
uint8_t const report_len_input[HID_NUM_INTERFACES] =
{
    48
};

/*-----------------------------------------------------------------------------+
| Device Descriptor 
|-----------------------------------------------------------------------------*/
uint8_t const abromDeviceDescriptor[SIZEOF_DEVICE_DESCRIPTOR] = {
    SIZEOF_DEVICE_DESCRIPTOR,               // Length of this descriptor
    DESC_TYPE_DEVICE,                       // Type code of this descriptor
    0x00, 0x02,                             // Release of USB spec
    0x00,                                   // Device's base class code
    0x00,                                   // Device's sub class code
    0x00,                                   // Device's protocol type code
    EP0_PACKET_SIZE,                        // End point 0's packet size
    USB_VID&0xFF, USB_VID>>8,               // Vendor ID for device, TI=0x0451
                                            // You can order your own VID at www.usb.org"
    USB_PID&0xFF, USB_PID>>8,               // Product ID for device,
                                            // this ID is to only with this example
    VER_FW_L, VER_FW_H,                     // Revision level of device
    1,                                      // Index of manufacturer name string desc
    2,                                      // Index of product name string desc
    USB_STR_INDEX_SERNUM,                   // Index of serial number string desc
    1                                       //  Number of configurations supported
};

/*-----------------------------------------------------------------------------+
| Configuration Descriptor                                                     |
|-----------------------------------------------------------------------------*/
const struct abromConfigurationDescriptorGroup abromConfigurationDescriptorGroup=
{
    /* Generic part */
    {
        // CONFIGURATION DESCRIPTOR (9 bytes)
        SIZEOF_CONFIG_DESCRIPTOR,                          // bLength
        DESC_TYPE_CONFIG,                                  // bDescriptorType
        DESCRIPTOR_TOTAL_LENGTH, 0x00,                     // wTotalLength
        USB_NUM_INTERFACES,                                // bNumInterfaces
        USB_CONFIG_VALUE,                                  // bConfigurationvalue
        CONFIG_STRING_INDEX,                               // iConfiguration Description offset
        USB_SUPPORT_SELF_POWERED | USB_SUPPORT_REM_WAKE,   // bmAttributes, bus power, remote wakeup
        USB_MAX_POWER                                      // Max. Power Consumption
    },
    /******************************************************* start of HID*************************************/
    {
    /*start HID[0] Here */
        {
            //-------- Descriptor for HID class device -------------------------------------
            // INTERFACE DESCRIPTOR (9 bytes)
            SIZEOF_INTERFACE_DESCRIPTOR,        // bLength
            DESC_TYPE_INTERFACE,                // bDescriptorType: 4
            HID0_REPORT_INTERFACE,              // bInterfaceNumber
            0x00,                               // bAlternateSetting
            2,                                  // bNumEndpoints
            0x03,                               // bInterfaceClass: 3 = HID Device
            0,                                  // bInterfaceSubClass:
            0,                                  // bInterfaceProtocol:
            INTF_STRING_INDEX + 0,              // iInterface:1

            // HID DESCRIPTOR (9 bytes)
            0x09,                                 // bLength of HID descriptor
            0x21,                                 // HID Descriptor Type: 0x21
            0x01,0x01,                            // HID Revision number 1.01
            0x00,                                // Target country, nothing specified (00h)
            0x01,                                // Number of HID classes to follow
            0x22,                                // Report descriptor type
            (report_desc_size_HID0 & 0x0ff),  // Total length of report descriptor
            (report_desc_size_HID0  >> 8),

            SIZEOF_ENDPOINT_DESCRIPTOR,         // bLength
            DESC_TYPE_ENDPOINT,                 // bDescriptorType
            HID0_INEP_ADDR,                     // bEndpointAddress; bit7=1 for IN, bits 3-0=1 for ep1
            EP_DESC_ATTR_TYPE_INT,              // bmAttributes, interrupt transfers
            0x40, 0x00,                         // wMaxPacketSize, 64 bytes
            25,                                  // bInterval, ms

            SIZEOF_ENDPOINT_DESCRIPTOR,         // bLength
            DESC_TYPE_ENDPOINT,                 // bDescriptorType
            HID0_OUTEP_ADDR,                    // bEndpointAddress; bit7=1 for IN, bits 3-0=1 for ep1
            EP_DESC_ATTR_TYPE_INT,              // bmAttributes, interrupt transfers
            0x40, 0x00,                         // wMaxPacketSize, 64 bytes
            25,                                  // bInterval, ms
            /* end of HID[0]*/
        }

    }    /******************************************************* end of HID**************************************/

    
        
            
};

/*-----------------------------------------------------------------------------+
| String Descriptor                                                            |
|-----------------------------------------------------------------------------*/
uint8_t const abromStringDescriptor[] = {
    // String index0, language support

    4,        // Length of language descriptor ID
    3,        // LANGID tag
    0x09, 0x04,    // 0x0409 for English


    // String index1, Manufacturer

    36,        // Length of this string descriptor
    3,        // bDescriptorType
    'T',0x00,'e',0x00,'x',0x00,'a',0x00,'s',0x00,' ',0x00,
    'I',0x00,'n',0x00,'s',0x00,'t',0x00,'r',0x00,'u',0x00,
    'm',0x00,'e',0x00,'n',0x00,'t',0x00,'s',0x00,

    // String index2, Product

    38,        // Length of this string descriptor
    3,        // bDescriptorType
    'M',0x00,'S',0x00,'P',0x00,'4',0x00,'3',0x00,'0',0x00,
    '-',0x00,'U',0x00,'S',0x00,'B',0x00,' ',0x00,'E',0x00,
    'x',0x00,'a',0x00,'m',0x00,'p',0x00,'l',0x00,'e',0x00,

    // String index3, Serial Number

    4,        // Length of this string descriptor
    3,        // bDescriptorType
    '0',0x00,

    // String index4, Configuration String

    22,        // Length of this string descriptor
    3,        // bDescriptorType
    'M',0x00,'S',0x00,'P',0x00,'4',0x00,'3',0x00,'0',0x00,
    ' ',0x00,'U',0x00,'S',0x00,'B',0x00,


    // String index5, Interface String
    28,        // Length of this string descriptor
    3,        // bDescriptorType
    'H',0x00,'I',0x00,'D',0x00,' ',0x00,'I',0x00,'n',0x00,
    't',0x00,'e',0x00,'r',0x00,'f',0x00,'a',0x00,'c',0x00,
    'e',0x00
};

uint8_t const report_desc_HID0[]=
{
0x05, 0x01, //		USAGE_PAGE (Generic Desktop)
0x09, 0x05, //		USAGE (Game Pad)
0xA1, 0x01, //		COLLECTION (Application)
0xA1, 0x00, //			COLLECTION (Physical)
0x05, 0x09, //				USAGE_PAGE (Button)
0x19, 0x01, //				USAGE_MINIMUM (Button 1)
0x29, 0x10, //				USAGE_MAXIMUM (Button 16)
0x15, 0x00, //				LOGICAL_MINIMUM (0)
0x25, 0x01, //				LOGICAL_MAXIMUM (1)
0x95, 0x10, //				REPORT_COUNT (16)
0x75, 0x01, //				REPORT_SIZE (1)
0x81, 0x02, //				INPUT (Data,Var,Abs)
0x05, 0x01, //				USAGE_PAGE (Generic Desktop)
0x09, 0x30, //				USAGE (X)
0x09, 0x31, //				USAGE (Y)
0x09, 0x32, //				USAGE (Z)
0x09, 0x33, //				USAGE (Rx)
0x15, 0x81, //				LOGICAL_MINIMUM (-127)
0x25, 0x7F, //				LOGICAL_MAXIMUM (127)
0x75, 0x08, //				REPORT_SIZE (8)
0x95, 0x04, //				REPORT_COUNT (4)
0x81, 0x02, //				INPUT (Data,Var,Abs)
0xC0, //			END COLLECTION
0xC0 //		END COLLECTION
};

const uint8_t* report_desc[HID_NUM_INTERFACES] =
{
    (uint8_t*)&report_desc_HID0
};

/**** Populating the endpoint information handle here ****/
const struct tUsbHandle stUsbHandle[]=
{
    {
        HID0_INEP_ADDR,
        HID0_OUTEP_ADDR,
        0,
        HID_CLASS,
        0,
        0,
        OEP1_X_BUFFER_ADDRESS,
        OEP1_Y_BUFFER_ADDRESS,
        IEP1_X_BUFFER_ADDRESS,
        IEP1_Y_BUFFER_ADDRESS
    }

    
        
            
};

//-------------DEVICE REQUEST LIST---------------------------------------------

const tDEVICE_REQUEST_COMPARE tUsbRequestList[] = 
{

    {
        //---- HID 0 Class Requests -----//
            USB_REQ_TYPE_INPUT | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,

            USB_REQ_GET_REPORT,
            0xff,0xff,
            HID0_REPORT_INTERFACE,0x00,
            0xff,0xff,
            0xcc,&usbGetReport,
    },
    {
            // SET REPORT
            USB_REQ_TYPE_OUTPUT | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
            USB_REQ_SET_REPORT,
            0xff,0xFF,                          // bValueL is index and bValueH is type
            HID0_REPORT_INTERFACE,0x00,
            0xff,0xff,
            0xcc,&usbSetReport,
    },
    {
            // GET REPORT DESCRIPTOR
            USB_REQ_TYPE_INPUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE,
            USB_REQ_GET_DESCRIPTOR,
            0xff,DESC_TYPE_REPORT,              // bValueL is index and bValueH is type
            HID0_REPORT_INTERFACE,0x00,
            0xff,0xff,
            0xdc,&usbGetReportDescriptor,
    },
    {
            // GET HID DESCRIPTOR
            USB_REQ_TYPE_INPUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE,
            USB_REQ_GET_DESCRIPTOR,
            0xff,DESC_TYPE_HID,                 // bValueL is index and bValueH is type
            HID0_REPORT_INTERFACE,0x00,
            0xff,0xff,
            0xdc,&usbGetHidDescriptor,
    },

    {
        //---- USB Standard Requests -----//
            // clear device feature
            USB_REQ_TYPE_OUTPUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE,
            USB_REQ_CLEAR_FEATURE,
            FEATURE_REMOTE_WAKEUP,0x00,         // feature selector
            0x00,0x00,
            0x00,0x00,
            0xff,&usbClearDeviceFeature,
    },
    {

            // clear endpoint feature
            USB_REQ_TYPE_OUTPUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_ENDPOINT,
            USB_REQ_CLEAR_FEATURE,
            FEATURE_ENDPOINT_STALL,0x00,
            0xff,0x00,
            0x00,0x00,
            0xf7,&usbClearEndpointFeature,
    },
    {
            // get configuration
            USB_REQ_TYPE_INPUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE,
            USB_REQ_GET_CONFIGURATION,
            0x00,0x00, 
            0x00,0x00, 
            0x01,0x00,
            0xff,&usbGetConfiguration,
    },
    {
            // get device descriptor
            USB_REQ_TYPE_INPUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE,
            USB_REQ_GET_DESCRIPTOR,
            0xff,DESC_TYPE_DEVICE,              // bValueL is index and bValueH is type
            0xff,0xff,
            0xff,0xff,
            0xd0,&usbGetDeviceDescriptor,
    },
    {
            // get configuration descriptor
            USB_REQ_TYPE_INPUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE,
            USB_REQ_GET_DESCRIPTOR,
            0xff,DESC_TYPE_CONFIG,              // bValueL is index and bValueH is type
            0xff,0xff,
            0xff,0xff,
            0xd0,&usbGetConfigurationDescriptor,
    },
    {
            // get string descriptor
            USB_REQ_TYPE_INPUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE,
            USB_REQ_GET_DESCRIPTOR,
            0xff,DESC_TYPE_STRING,              // bValueL is index and bValueH is type
            0xff,0xff,
            0xff,0xff,
            0xd0,&usbGetStringDescriptor,
    },
    {
           // get interface
            USB_REQ_TYPE_INPUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE,
            USB_REQ_GET_INTERFACE,
            0x00,0x00,
            0xff,0xff,
            0x01,0x00,
            0xf3,&usbGetInterface,
    },
    {
            // get device status
            USB_REQ_TYPE_INPUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE,
            USB_REQ_GET_STATUS,
            0x00,0x00,
            0x00,0x00,
            0x02,0x00,
            0xff,&usbGetDeviceStatus, 
    },
    {
            // get interface status
            USB_REQ_TYPE_INPUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE,
            USB_REQ_GET_STATUS,
            0x00,0x00,
            0xff,0x00,
            0x02,0x00,
            0xf7,&usbGetInterfaceStatus,
    },
    {
            // get endpoint status
            USB_REQ_TYPE_INPUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_ENDPOINT,
            USB_REQ_GET_STATUS,
            0x00,0x00,
            0xff,0x00,
            0x02,0x00,
            0xf7,&usbGetEndpointStatus,
    },
    {
            // set address
            USB_REQ_TYPE_OUTPUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE,
            USB_REQ_SET_ADDRESS,
            0xff,0x00,
            0x00,0x00,
            0x00,0x00,
            0xdf,&usbSetAddress,
    },
    {
            // set configuration
            USB_REQ_TYPE_OUTPUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE,
            USB_REQ_SET_CONFIGURATION,
            0xff,0x00,
            0x00,0x00,
            0x00,0x00,
            0xdf,&usbSetConfiguration,
    },
    {
           // set device feature
            USB_REQ_TYPE_OUTPUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE,
            USB_REQ_SET_FEATURE,
            0xff,0x00,                      // feature selector
            0x00,0x00,
            0x00,0x00,
            0xdf,&usbSetDeviceFeature,
    },
    {
            // set endpoint feature
            USB_REQ_TYPE_OUTPUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_ENDPOINT,
            USB_REQ_SET_FEATURE,
            0xff,0x00,                      // feature selector
            0xff,0x00,                      // endpoint number <= 127
            0x00,0x00,
            0xd7,&usbSetEndpointFeature,
    },
    {
            // set interface
            USB_REQ_TYPE_OUTPUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE,
            USB_REQ_SET_INTERFACE,
            0xff,0x00,                      // feature selector
            0xff,0x00,                      // interface number
            0x00,0x00,
            0xd7,&usbSetInterface,
    },
    {

            // end of usb descriptor -- this one will be matched to any USB request
            // since bCompareMask is 0x00.
            0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 
            0x00,&usbInvalidRequest     // end of list
    }
	
};


/*-----------------------------------------------------------------------------+
| END OF Descriptor.c FILE
|-----------------------------------------------------------------------------*/


//Released_Version_5_20_06_03

- Usblsr.c

/* --COPYRIGHT--,BSD
 * Copyright (c) 2015, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * --/COPYRIGHT--*/


// Generated by MSP USB Descriptor Tool: Fri Jul 09 10:27:06 BST 2021

/*-----------------------------------------------------------------------------+
| Include files                                                                |
|-----------------------------------------------------------------------------*/
#include <USB_API/USB_Common/device.h>        // Basic Type declarations
#include <USB_API/USB_Common/defMSP430USB.h>
#include "descriptors.h"
#include <USB_API/USB_Common/usb.h>           //USB-specific Data Structures
#include <USB_API/USB_Common/UsbIsr.h>
#include <string.h>
#include <USB_API/USB_HID_API/UsbHid.h>
#include <USB_API/USB_HID_API/UsbHidReq.h>

/*----------------------------------------------------------------------------+
| External Variables                                                          |
+----------------------------------------------------------------------------*/
extern uint8_t  bFunctionSuspended;
extern __no_init tEDB0 __data16 tEndPoint0DescriptorBlock;
extern __no_init tEDB __data16 tInputEndPointDescriptorBlock[];
extern __no_init tEDB __data16 tOutputEndPointDescriptorBlock[];
extern volatile uint8_t bHostAsksUSBData;
extern volatile uint8_t bTransferInProgress;
extern volatile uint8_t bSecondUartTxDataCounter[];
extern volatile uint8_t* pbSecondUartTxData;
extern uint8_t bStatusAction;
extern uint16_t wUsbEventMask;
int16_t CdcToHostFromBuffer(uint8_t);
int16_t CdcToBufferFromHost(uint8_t);
int16_t CdcIsReceiveInProgress(uint8_t);
int16_t HidToHostFromBuffer(uint8_t);
int16_t HidToBufferFromHost(uint8_t);
int16_t HidIsReceiveInProgress(uint8_t);
extern uint16_t wUsbHidEventMask;
int16_t PHDCToHostFromBuffer(uint8_t);
int16_t PHDCToBufferFromHost(uint8_t);
int16_t PHDCIsReceiveInProgress(uint8_t);
uint16_t USB_determineFreq(void);
/*----------------------------------------------------------------------------+
| General Subroutines                                                         |
+----------------------------------------------------------------------------*/
#if defined(__TI_COMPILER_VERSION__) || (__IAR_SYSTEMS_ICC__) 
#pragma vector=USB_UBM_VECTOR
__interrupt void iUsbInterruptHandler(void)
#elif defined(__GNUC__) && (__MSP430__)
void __attribute__ ((interrupt(USB_UBM_VECTOR))) iUsbInterruptHandler(void)
#endif
{
    uint8_t bWakeUp = FALSE;
//Check if the setup interrupt is pending.
    //We need to check it before other interrupts,
    //to work around that the Setup Int has lower priority then Input Endpoint 0
    if (USBIFG & SETUPIFG)
    {
        bWakeUp = SetupPacketInterruptHandler();  
#ifdef USB10_WORKAROUND
        tEndPoint0DescriptorBlock.bIEPCNFG &= ~EPCNF_UBME; // Clear ME to gate off SETUPIFG clear event
        tEndPoint0DescriptorBlock.bOEPCNFG &= ~EPCNF_UBME; // Clear ME to gate off SETUPIFG clear event
#endif
        USBIFG &= ~SETUPIFG;    // clear the interrupt bit
#ifdef USB10_WORKAROUND
        tEndPoint0DescriptorBlock.bIEPCNFG |= EPCNF_UBME; // Set ME to continue with normal operation
        tEndPoint0DescriptorBlock.bOEPCNFG |= EPCNF_UBME; // Set ME to continue with normal operation
#endif
    }   
    switch (__even_in_range(USBVECINT & 0x3f, USBVECINT_OUTPUT_ENDPOINT7))
    {
    case USBVECINT_NONE:
        break;
    case USBVECINT_PWR_DROP:
      __no_operation();
        break;
    case USBVECINT_PLL_LOCK:
        break;
    case USBVECINT_PLL_SIGNAL:
        break;
    case USBVECINT_PLL_RANGE:
        if (wUsbEventMask & USB_CLOCK_FAULT_EVENT)
        {
            bWakeUp = USB_handleClockEvent();
        }
        break;
    case USBVECINT_PWR_VBUSOn:
        PWRVBUSonHandler();
        if (wUsbEventMask & USB_VBUS_ON_EVENT)
        {
            bWakeUp = USB_handleVbusOnEvent();
        }
        break;
    case USBVECINT_PWR_VBUSOff:
        PWRVBUSoffHandler();
        if (wUsbEventMask & USB_VBUS_OFF_EVENT)
        {
            bWakeUp = USB_handleVbusOffEvent();
        }
        break;
    case USBVECINT_USB_TIMESTAMP:
        break;
    case USBVECINT_INPUT_ENDPOINT0:
        IEP0InterruptHandler();
        break;
    case USBVECINT_OUTPUT_ENDPOINT0:
        OEP0InterruptHandler();
        break;
    case USBVECINT_RSTR:
        USB_reset();
        if (wUsbEventMask & USB_RESET_EVENT)
        {
            bWakeUp = USB_handleResetEvent();
        }
        break;
    case USBVECINT_SUSR:
        USB_suspend();
        if (wUsbEventMask & USB_SUSPENDED_EVENT)
        {
            bWakeUp = USB_handleSuspendEvent();
        }
        break;
    case USBVECINT_RESR:
        USB_resume();
        if (wUsbEventMask & USB_RESUME_EVENT)
        {
            bWakeUp = USB_handleResumeEvent();
        }
        //-- after resume we will wake up! Independ what event handler says.
        bWakeUp = TRUE;
        break;
    case USBVECINT_SETUP_PACKET_RECEIVED:
        // NAK both IEP and OEP enpoints
        tEndPoint0DescriptorBlock.bIEPBCNT = EPBCNT_NAK;
        tEndPoint0DescriptorBlock.bOEPBCNT = EPBCNT_NAK;
        SetupPacketInterruptHandler();
        break;
    case USBVECINT_STPOW_PACKET_RECEIVED:
        break;
	case USBVECINT_INPUT_ENDPOINT1:
        //send saved bytes from buffer...
        bWakeUp = HidToHostFromBuffer(HID0_INTFNUM);
        break;
    case USBVECINT_INPUT_ENDPOINT2:
         break;
    case USBVECINT_INPUT_ENDPOINT3:
        break;
    case USBVECINT_INPUT_ENDPOINT4:
		break;
    case USBVECINT_INPUT_ENDPOINT5:
		break;
    case USBVECINT_INPUT_ENDPOINT6:
		break;
    case USBVECINT_INPUT_ENDPOINT7:
		break;
    case USBVECINT_OUTPUT_ENDPOINT1:
        //call callback function if no receive operation is underway
        if (!HidIsReceiveInProgress(HID0_INTFNUM))
        {
            if (wUsbEventMask & USB_DATA_RECEIVED_EVENT)
            {
                bWakeUp = USBHID_handleDataReceived(HID0_INTFNUM); 
            }
        }
        else
        {
                //complete receive opereation - copy data to user buffer
                bWakeUp = HidToBufferFromHost(HID0_INTFNUM);
        }
	    break;
    case USBVECINT_OUTPUT_ENDPOINT2:
        break;
    case USBVECINT_OUTPUT_ENDPOINT3:
        break;
    case USBVECINT_OUTPUT_ENDPOINT4:
        break;
    case USBVECINT_OUTPUT_ENDPOINT5:
        break;
    case USBVECINT_OUTPUT_ENDPOINT6:
        break;
    case USBVECINT_OUTPUT_ENDPOINT7:
        break;
    default:
        break;
    }

    if (bWakeUp)
    {
        __bic_SR_register_on_exit(LPM3_bits);   // Exit LPM0-3
        __no_operation();  // Required for debugger
    }
}
	


/*----------------------------------------------------------------------------+
| Interrupt Sub-routines                                                      |
+----------------------------------------------------------------------------*/
uint8_t SetupPacketInterruptHandler(void)
{
    uint8_t bTemp;
    uint8_t bWakeUp = FALSE;
    USBCTL |= FRSTE;      // Function Reset Connection Enable - set enable after first setup packet was received
    usbProcessNewSetupPacket:
    // copy the MSB of bmRequestType to DIR bit of USBCTL
    if((tSetupPacket.bmRequestType & USB_REQ_TYPE_INPUT) == USB_REQ_TYPE_INPUT)
    {
        USBCTL |= DIR;
    }
    else
    {
        USBCTL &= ~DIR;
    }
    bStatusAction = STATUS_ACTION_NOTHING;
    // clear out return data buffer
    for(bTemp=0; bTemp<USB_RETURN_DATA_LENGTH; bTemp++)
    {
        abUsbRequestReturnData[bTemp] = 0x00;
    }
    // decode and process the request
    bWakeUp = usbDecodeAndProcessUsbRequest();
    // check if there is another setup packet pending
    // if it is, abandon current one by NAKing both data endpoint 0
    if((USBIFG & STPOWIFG) != 0x00)
    {
        USBIFG &= ~(STPOWIFG | SETUPIFG);
        goto usbProcessNewSetupPacket;
    }
    return bWakeUp;
}

//----------------------------------------------------------------------------
void PWRVBUSoffHandler(void)
{
   uint16_t MCLKFreq = USB_determineFreq();
   uint16_t DelayConstant_250us = ((MCLKFreq >> 6) + (MCLKFreq >> 7) + (MCLKFreq >> 9));
   volatile uint16_t i, j;

    //wait 1 ms till enable USB 
    for(j = 0; j < 4; j++)
    {
        for (i = 0; i < (DelayConstant_250us); i++){
            _NOP();
        }
   }
    if (!(USBPWRCTL & USBBGVBV))
    {
        USBKEYPID   =    0x9628;        // set KEY and PID to 0x9628 -> access to configuration registers enabled
        bEnumerationStatus = 0x00;      // device is not enumerated
        bFunctionSuspended = FALSE;     // device is not suspended
        USBCNF     =    0;              // disable USB module
        USBPLLCTL  &=  ~UPLLEN;         // disable PLL
        USBPWRCTL &= ~(VBOFFIE + VBOFFIFG + SLDOEN);          // disable interrupt VBUSoff
        USBKEYPID   =    0x9600;        // access to configuration registers disabled
    }
}

//----------------------------------------------------------------------------
void PWRVBUSonHandler(void)
{
   uint16_t MCLKFreq = USB_determineFreq();
   uint16_t DelayConstant_250us = ((MCLKFreq >> 6) + (MCLKFreq >> 7) + (MCLKFreq >> 9));
   volatile uint16_t i, j;

    //wait 1 ms till enable USB 
    for(j = 0; j < 4; j++)
    {
        for (i = 0; i < (DelayConstant_250us); i++){
            _NOP();
        }
   }
    if (USBPWRCTL & USBBGVBV)                //Checking for USB Bandgap and VBUS valid before modifying USBPWRCTL
    {
        USBKEYPID =  0x9628;                // set KEY and PID to 0x9628 -> access to configuration registers enabled
        USBPWRCTL |= VBOFFIE;               // enable interrupt VBUSoff
        USBPWRCTL &= ~ (VBONIFG + VBOFFIFG);             // clean int flag (bouncing)
        USBKEYPID =  0x9600;                // access to configuration registers disabled
    }
}

//----------------------------------------------------------------------------
void IEP0InterruptHandler(void)
{
    USBCTL |= FRSTE;                              // Function Reset Connection Enable
    tEndPoint0DescriptorBlock.bOEPBCNT = 0x00;     
    if(bStatusAction == STATUS_ACTION_DATA_IN)
    {
        usbSendNextPacketOnIEP0();
    }
    else
    {
        tEndPoint0DescriptorBlock.bIEPCNFG |= EPCNF_STALL; // no more data
    }
}

//----------------------------------------------------------------------------
uint8_t OEP0InterruptHandler(void)
{
    uint8_t bWakeUp = FALSE;
    USBCTL |= FRSTE;                              // Function Reset Connection Enable
    tEndPoint0DescriptorBlock.bIEPBCNT = 0x00;    
    if(bStatusAction == STATUS_ACTION_DATA_OUT)
    {
        usbReceiveNextPacketOnOEP0();
        if(bStatusAction == STATUS_ACTION_NOTHING)
        {
#           ifdef _CDC_
                if(tSetupPacket.bRequest == USB_CDC_SET_LINE_CODING)
                {
                    bWakeUp = Handler_SetLineCoding();
                }
#          endif
#ifdef _HID_
                if (tSetupPacket.bRequest == USB_REQ_SET_REPORT) {
                    bWakeUp = USBHID_handleEP0SetReportDataAvailable(tSetupPacket.wIndex);
                }
#endif
          }
    }
    else
    {
        tEndPoint0DescriptorBlock.bOEPCNFG |= EPCNF_STALL; // no more data
    }
    return (bWakeUp);
}



/*----------------------------------------------------------------------------+
| End of source file                                                          |
+----------------------------------------------------------------------------*/
/*------------------------ Nothing Below This Line --------------------------*/	
	//Released_Version_5_20_06_03

  • Hi Hishan,

    Let me see if I can find someone who might be able to help.

  • Hello Hishan,

    I'm not having any luck on this one, so let me see if I can set something up to emulate what you are attempting.

  • Part Number: MSP430F5529

    Hi experts,

    A few weeks ago, I was trying to emulate a USB-HID gamepad using the MSP430 with 7-14 analog inputs. I had trouble getting the descriptors right for my custom USB-HID device. I posted my code but nobody was able to help me.

    Fortunately, I came across this code online: GitHub - TI-FIRST/MSP430-Gamepad: MSP430F5529 Gamepad Code for FRC which helped me get the MSP430 up and running as a gamepad with 8 analog inputs.

    The main.c file contains instructions to change the report structure: 

    * This example functions as a gamepad on the host. The gamepad has a HID report as described in
    * report_desc_HID0 variable in descriptors.c. Please note that if this report structure is
    * changed then the following lengths need to be updated -
    * 1. #define report_desc_size_HID0 in descriptors.h needs to be updated with descriptor size
    * 2. report_desc_size and report_len_input need t be updated in descriptors.c
    * As is this demo will enumerate with 18 bytes of input report and 2 bytes of output report
    * The input and output report structures for the gamepad as described in USB_gamepad.h
    * The input reports are used to report ADC values and status of buttons (GPIO)
    * The output report is used to set/reset indicators (GPIO)

    The descriptors currently in the descriptors.c file are:

    UsagePage(USB_HID_GENERIC_DESKTOP),
    Usage(USB_HID_JOYSTICK),
    Collection(USB_HID_APPLICATION),
        //
        // The axis for the controller.
        //
        UsagePage(USB_HID_GENERIC_DESKTOP),
        Usage (USB_HID_POINTER),
        Collection (USB_HID_PHYSICAL),
    
            //
            // The X, Y and Z values which are specified as 8-bit absolute
            // position values.
            //
            Usage (USB_HID_X),
            Usage (USB_HID_Y),
            Usage (USB_HID_Z),
            Usage (USB_HID_RX),
            Usage (USB_HID_RY),
            Usage (USB_HID_RZ),
            Usage (USB_HID_SLIDER),
            Usage (USB_HID_DIAL),
            //
            // 8 16-bit absolute values.
            //
            ReportSize(16),
            ReportCount(8),
            Input(USB_HID_INPUT_DATA | USB_HID_INPUT_VARIABLE |
                  USB_HID_INPUT_ABS),
    
            //
            // Max 32 buttons.
            //
            UsagePage(USB_HID_BUTTONS),
            UsageMinimum(1),
            UsageMaximum(NUM_BUTTONS),
            LogicalMinimum(0),
            LogicalMaximum(1),
            PhysicalMinimum(0),
            PhysicalMaximum(1),
    
            //
            // 8 - 1 bit values for the buttons.
            //
            ReportSize(1),
            ReportCount(32),
            Input(USB_HID_INPUT_DATA | USB_HID_INPUT_VARIABLE |
                  USB_HID_INPUT_ABS),
    
             //
             // Max 16 indicator bits
             //
             UsagePage(USB_HID_BUTTONS),
             UsageMinimum(1),
             UsageMaximum(NUM_INDICATORS),
             LogicalMinimum(0),
             LogicalMaximum(1),
             PhysicalMinimum(0),
             PhysicalMaximum(1),
    
             //
             // 8 - 1 bit values for the leds.
             //
             ReportSize(1),
             ReportCount(16),
             Output(USB_HID_INPUT_DATA | USB_HID_INPUT_VARIABLE |
                   USB_HID_INPUT_ABS),
    
        EndCollection,
    EndCollection

    I would like to change it to 14 16-bit analog inputs like this:

    UsagePage(USB_HID_GENERIC_DESKTOP),
    Usage(USB_HID_JOYSTICK),
    Collection(USB_HID_APPLICATION),
        //
        // The axis for the controller.
        //
        UsagePage(USB_HID_GENERIC_DESKTOP),
        Usage (USB_HID_POINTER),
        Collection (USB_HID_PHYSICAL),
    
            //
            // The X, Y and Z values which are specified as 8-bit absolute
            // position values.
            //
            Usage (USB_HID_X),
            Usage (USB_HID_Y),
            Usage (USB_HID_Z),
            Usage (USB_HID_RX),
            Usage (USB_HID_RY),
            Usage (USB_HID_RZ),
            Usage (USB_HID_SLIDER),
            Usage (USB_HID_DIAL),
            Usage (USB_HID_VX),
            Usage (USB_HID_VY),
            Usage (USB_HID_VZ),
            Usage (USB_HID_VRX),
            Usage (USB_HID_VRY),
            Usage (USB_HID_VRZ),
            //
            // 8 16-bit absolute values.
            //
            ReportSize(16),
            ReportCount(14),
            Input(USB_HID_INPUT_DATA | USB_HID_INPUT_VARIABLE |
                  USB_HID_INPUT_ABS),
    
            //
            // Max 32 buttons.
            //
            UsagePage(USB_HID_BUTTONS),
            UsageMinimum(1),
            UsageMaximum(6),
            LogicalMinimum(0),
            LogicalMaximum(1),
            PhysicalMinimum(0),
            PhysicalMaximum(1),
    
            //
            // 8 - 1 bit values for the buttons.
            //
            ReportSize(1),
            ReportCount(32),
            Input(USB_HID_INPUT_DATA | USB_HID_INPUT_VARIABLE |
                  USB_HID_INPUT_ABS),
    
             //
             // Max 16 indicator bits
             //
             UsagePage(USB_HID_BUTTONS),
             UsageMinimum(1),
             UsageMaximum(6),
             LogicalMinimum(0),
             LogicalMaximum(1),
             PhysicalMinimum(0),
             PhysicalMaximum(1),
    
             //
             // 8 - 1 bit values for the leds.
             //
             ReportSize(1),
             ReportCount(16),
             Output(USB_HID_INPUT_DATA | USB_HID_INPUT_VARIABLE |
                   USB_HID_INPUT_ABS),
    
        EndCollection,
    EndCollection

    However, I cannot figure out how to calculate the length/size/bytes of the descriptor. I tried going through the USB-HID spec (Device Class Definition for HID 1.11 | USB-IF) which states that items have a byte prefix, but I can't really figure out which items to count and how they add up. Apologies but I am very inexperienced in USB.

    I think the size of the descriptor would be 32 bytes? But the computer does not detect the gamepad when plugged in because I think I got the value in report_len_input wrong.

    Would someone be able look at the code, and let me know what values I need in report_desc_size, report_len_input in the descriptor files plus anything else I need to change to expand the functionality of this code for 14 16-bit analog inputs.

    P.S. to replicate and see the working gamepad, just upload the code to a dev kit and search 'Set up USB Game Controllers' on Windows, which should recognize it as a gamepad if everything is running correctly and the reports are being accepted.



    Thanks!

  • Hello Hishan,

    I joined your posts together as they are really about the same topic. 

    For HID, our USB Developer's Package and our Descriptor tool only really supports a few HID types natively, namely, keyboard, mouse, and datapipe. Any other "traditional" HID types need be done via the "Custom" functionality within the Descriptor Tool where you will need to enter the raw report descriptor. We are unable to support you in creating this custom descriptor at this time to fit your need. I would suggest looking into third party resources or guides on what the descriptor report looks like for your chosen HID type. 

  • Hi All,

    I'm joining in on this conversation as we're having very similar problems to this. 

    As this USB descriptor tool is TI specific, I'm struggling to understand how we can get support if you can't help us? Can you point me towards relevant third party resources, recommended reading or guides on how we can get extra support on the issue?

    thanks

    Mat 

  • Hello All,

    The USB Descriptor tool is TI made and is used to help get supported HID types correctly on the PC you are using. We allow for a Custom category to expand to HID class types we don't natively support. Joystick/Gamepads fall into this category. You can find the correct descriptor fields for this class via the USB HID spec, or other online forums. stackexchange is a good forum to check out for general knowledge and 430h.com is an independent MSP430 specific forum that may have what your looking for. 

**Attention** This is a public forum