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.

TM4C123G USB Raw HID

Hi all, hope things are going well.

I'm trying to get my Tiva C (123G) board to interact with a PC as a Raw HID Device. I've searched through the forum and have found a few relevant posts. Mostly just advice on trying to get CDC to work, using bulk transfer, or reworking the keyboard example. CDC and bulk transfer are not an option, unfortunately, and I need some help converting the keyboard example.

The Raw HID Descriptor looks like this:

// RAW 16-BYTE I/O

    0x06, 0xAB, 0xFF,   // Usage Page (Vendor-Defined 172)
    0x0A, 0x00, 0x02,   // Usage (Vendor-Defined 512)
    0xA1, 0x01,         // Collection (Application)
    0x85, 0x04,         /* REPORT_ID (4) */
    0x75, 0x08,         // Report Size (8)
    0x15, 0x00,         // Logical Minimum (0)
    0x26, 0xFF, 0x00,   // Logical Maximum (255)
    0x95, 0x10,         // Report Count (16)
    0x09, 0x01,         // Usage (Vendor-Defined 1)
    0x81, 0x02,         // Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit)
    0x95, 0x10,         // Report Count (16)
    0x09, 0x02,         // Usage (Vendor-Defined 2)
    0x91, 0x02,         // Output (Data,Var,Abs,NWrp,Lin,Pref,NNul,NVol,Bit)
    0xc0,               // End Collection

Which I got from this link

My plan is to convert the keyboard example with the above descriptor, but the part I'm stuck on (I don't know where to begin, maybe the CDC example?) is how to receive data back from the PC. If anyone has any Raw HID pointers, I'll definitely take them! 

Thanks,

Duane Bester

  • Duane Bester said:
    My plan is to convert the keyboard example with the above descriptor,



    It's a good plan, because the HID keyboard example implements both of IN/OUT interrupt endpoints.

    In the HID keyboard example, the size of input/output reports are defined in usbdhidkeyb.h

    \TivaWare_C_Series-2.1.0.12573\usblib\device\usbdhidkeyb.h

    #define KEYB_IN_REPORT_SIZE 8
    #define KEYB_OUT_REPORT_SIZE 1

    Copy this file to your project folder, and modify above macros.
    Also copy usbdhidkeyb.c to your project folder.

    The interface descriptor should be modified, as follows.
    The original one declares boot keyboard, and yours is "RAW" (vendor-specific) HID

    \TivaWare_C_Series-2.1.0.12573\usblib\device\usbdhidkeyb.c

    static uint8_t g_pui8HIDInterface[HIDINTERFACE_SIZE] =
    {
        //
        // HID Device Class Interface Descriptor.
        //
        9,                          // Size of the interface descriptor.
        USB_DTYPE_INTERFACE,        // Type of this descriptor.
        0,                          // The index for this interface.
        0,                          // The alternate setting for this interface.
        1,                          // The number of endpoints used by this
                                    // interface.
        USB_CLASS_HID,              // The interface class
        USB_HID_SCLASS_BOOT,     <--- USB_HID_SCLASS_NONE
                                    // The interface sub-class.
        USB_HID_PROTOCOL_KEYB,   <--- USB_HID_PROTOCOL_NONE
                                    // The interface protocol for the sub-class
                                    // specified above.
        4,                          // The string index for this interface.
    };

    There are a couple ways to declare the report descriptor, this is the simplest one.

    \TivaWare_C_Series-2.1.0.12573\usblib\device\usbdhidkeyb.c

    static const uint8_t g_pui8KeybReportDescriptor[] =
    {
        0x06, 0x00, 0xff,              // USAGE_PAGE (Vendor Defined Page 1)
        0x09, 0x01,                    // USAGE (Vendor Usage 1)
        0xa1, 0x01,                    // COLLECTION (Application)
                                       // --- common globals ---
        0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
        0x26, 0xff, 0x00,              //   LOGICAL_MAXIMUM (255)
        0x75, 0x08,                    //   REPORT_SIZE (8)
                                       // --- input report ---
        0x09, 0x01,                    //   USAGE (Vendor Usage 1)
        0x95, KEYB_IN_REPORT_SIZE,     //   REPORT_COUNT (KEYB_IN_REPORT_SIZE)
        0x81, 0x02,                    //   INPUT (Data,Var,Abs)
                                       // --- output report ---
        0x09, 0x01,                    //   USAGE (Vendor Usage 1)
        0x95, KEYB_OUT_REPORT_SIZE,    //   REPORT_COUNT (KEYB_OUT_REPORT_SIZE)
        0x91, 0x02,                    //   OUTPUT (Data,Var,Abs)
        0xc0                           // END_COLLECTION
    };


    To send an input report to host, the example calls USBDHIDKeyboardKeyStateChange()

    \TivaWare_C_Series-2.1.0.12573\examples\boards\dk-tm4c123g\usb_dev_keyboard\usb_dev_keyboard.c
            //
            // Send the key press message.
            //
            g_eKeyboardState = STATE_SENDING;
            if(USBDHIDKeyboardKeyStateChange((void *)&g_sKeyboardDevice,
                                             g_ppi8KeyUsageCodes[ui32Char][0],
                                             g_ppi8KeyUsageCodes[ui32Char][1],
                                             true) != KEYB_SUCCESS)
            {
                return;
            }

    As of the input report,
    You have to modify USBDHIDKeyboardKeyStateChange() (in usbdhidkeyb.c), because this routine makes up an input report specific to keyboard format on psInst->pui8Report[] buffer. You'll fill this buffer with your own input report, before it is sent using USBDHIDReportWrite()

    When an output report comes from host,
    HIDKeyboardRxHandler() is called by the stack with ui32Event == USBD_HID_EVENT_SET_REPORT
    psInst->pui8DataBuffer[] holds the output report.

    [EDIT] refer to my post below


    Tsuneo

  • Thank you! Got it all to work

  • HI  Bester

    great to get this. Now, i need some application like this. would you like to share your code?

  • Hello Wellin,

    Please see the following thread.

    http://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/t/359326.aspx

    Regards

    Amit

  • Hi Amit

    I am referring this post. and have done the modify. but the host can only get one input endpoint instend of one input and one output endpoint.

    //*****************************************************************************
    //
    // HID device configuration descriptor.
    //
    // It is vital that the configuration descriptor bConfigurationValue field
    // (byte 6) is 1 for the first configuration and increments by 1 for each
    // additional configuration defined here.  This relationship is assumed in the
    // device stack for simplicity even though the USB 2.0 specification imposes
    // no such restriction on the bConfigurationValue values.
    //
    // Note that this structure is deliberately located in RAM since we need to
    // be able to patch some values in it based on client requirements.
    //
    //*****************************************************************************
    static uint8_t g_pui8KeybDescriptor[] =
    {
        //
        // Configuration descriptor header.
        //
        9,                          // Size of the configuration descriptor.
        USB_DTYPE_CONFIGURATION,    // Type of this descriptor.
        USBShort(34),               // The total size of this full structure.
        1,                          // The number of interfaces in this
                                    // configuration.
        1,                          // The unique value for this configuration.
        4,                          // The string identifier that describes this
                                    // configuration.
        USB_CONF_ATTR_SELF_PWR,     // Bus Powered, Self Powered, remote wake up.
        250,                        // The maximum power in 2mA increments.
    };
    
    //*****************************************************************************
    //
    // The remainder of the configuration descriptor is stored in flash since we
    // don't need to modify anything in it at runtime.
    //
    //*****************************************************************************
    static uint8_t g_pui8HIDInterface[HIDINTERFACE_SIZE] =
    {
        //
        // HID Device Class Interface Descriptor.
        //
        9,                          // Size of the interface descriptor.
        USB_DTYPE_INTERFACE,        // Type of this descriptor.
        0,                          // The index for this interface.
        0,                          // The alternate setting for this interface.
        2,                          //M 1>2 The number of endpoints used by this
                                    // interface.
        USB_CLASS_HID,              // The interface class
        USB_HID_SCLASS_NONE,        //M The interface sub-class.
        USB_HID_PROTOCOL_NONE,      //M The interface protocol for the sub-class
                                    // specified above.
        5,                          // The string index for this interface.
    };
    
    static const uint8_t g_pui8HIDInEndpoint[HIDINENDPOINT_SIZE] =
    {
        //
        // Interrupt IN endpoint descriptor
        //
        7,                          // The size of the endpoint descriptor.
        USB_DTYPE_ENDPOINT,         // Descriptor type is an endpoint.
        0x81,
        USB_EP_ATTR_INT,            // Endpoint is an interrupt endpoint.
        USBShort(USBFIFOSizeToBytes(USB_FIFO_SZ_64)),
                                    // The maximum packet size.
        16,                         // The polling interval for this endpoint.
    };
    
    static const uint8_t g_pui8HIDOutEndpoint[HIDOUTENDPOINT_SIZE] =
    {
        //
        // Interrupt OUT endpoint descriptor
        //
        7,                          // The size of the endpoint descriptor.
        USB_DTYPE_ENDPOINT,         // Descriptor type is an endpoint.
        0x01,
        USB_EP_ATTR_INT,            // Endpoint is an interrupt endpoint.
        USBShort(USBFIFOSizeToBytes(USB_FIFO_SZ_64)),
                                    // The maximum packet size.
        16,                         // The polling interval for this endpoint.
    };
    
    //*****************************************************************************
    //
    // The following is the HID report structure definition that is passed back
    // to the host.
    //
    //*****************************************************************************
    static const uint8_t g_pui8KeybReportDescriptor[] =
    {
    
        0x06, 0x00, 0xff,              // USAGE_PAGE (Vendor Defined Page 1)
        0x09, 0x01,                    // USAGE (Vendor Usage 1)
        0xa1, 0x01,                    // COLLECTION (Application)
                                       // --- common globals ---
        0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
        0x26, 0xff, 0x00,              //   LOGICAL_MAXIMUM (255)
        0x75, 0x08,                    //   REPORT_SIZE (8)
                                       // --- input report ---
        0x09, 0x01,                    //   USAGE (Vendor Usage 1)
        0x95, KEYB_IN_REPORT_SIZE,     //   REPORT_COUNT (KEYB_IN_REPORT_SIZE)
        0x81, 0x02,                    //   INPUT (Data,Var,Abs)
                                       // --- output report ---
        0x09, 0x01,                    //   USAGE (Vendor Usage 1)
        0x95, KEYB_OUT_REPORT_SIZE,    //   REPORT_COUNT (KEYB_OUT_REPORT_SIZE)
        0x91, 0x02,                    //   OUTPUT (Data,Var,Abs)
        0xc0                           // END_COLLECTION
    
    };
    
    //*****************************************************************************
    //
    // The HID descriptor for the keyboard device.
    //
    //*****************************************************************************
    static const tHIDDescriptor g_sKeybHIDDescriptor =
    {
        9,                              // bLength
        USB_HID_DTYPE_HID,              // bDescriptorType
        0x111,                          // bcdHID (version 1.11 compliant)
        0,                              // bCountryCode (not localized)
        1,                              // bNumDescriptors
        {
            {
                USB_HID_DTYPE_REPORT,   // Report descriptor
                sizeof(g_pui8KeybReportDescriptor)
                                        // Size of report descriptor
            }
        }
    };

    When debug, We get follow Log

    config 1 interface 0 altsetting 0 has 1 endpoint descriptor, different from the interface descriptor's value: 2 

  • Hi Wellin,

    The wTotalLength field of the config descriptor is wrong.

    It should be
    9 (config)
    + 9 (interface)
    + 9 (HID)
    + 7 (IN endpoint)
    + 7 (OUT endpoint)
    = 41


    \TivaWare_C_Series-2.1.0.12573\usblib\device\usbdhidkeyb.c

    static uint8_t g_pui8KeybDescriptor[] =
    {
        //
        // Configuration descriptor header.
        //
        9,                          // Size of the configuration descriptor.
        USB_DTYPE_CONFIGURATION,    // Type of this descriptor.
        USBShort(34),   // The total size of this full structure.  <--- USBShort(41)

    This bug is seen in the original usbdhidkeyb.c

    To Ti, please fix it.

    [EDIT]

    This isn"t a real solution.

    The stack tunes wTotalLength, automatically.

    Sorry, this comment was too early without enough code analysis


    Tsuneo

  • Hi Tsuneo

    Thank you for your infomation. but it seems not enough to modify these to behavior bi-directional function. Can you provide your email? My case is emergency, so I want to have a more direct discuss. Thank you.

  • Auu, my bad.
    wTotalLength field is tuned by the stack.

    The real solution to enable the interrupt OUT endpoint is,

    1) interface descriptor
    Increase bNumEndpoint field by one

     
    usbdhidkeyb.c

    static uint8_t g_pui8HIDInterface[HIDINTERFACE_SIZE] =
    {
        //
        // HID Device Class Interface Descriptor.
        //
        9,                          // Size of the interface descriptor.
        USB_DTYPE_INTERFACE,        // Type of this descriptor.
        0,                          // The index for this interface.
        0,                          // The alternate setting for this interface.
        1,             // The number of endpoints used by this        // <------ 2
                                    // interface.
        USB_CLASS_HID,              // The interface class
        USB_HID_SCLASS_BOOT,        // The interface sub-class.
        USB_HID_PROTOCOL_KEYB,      // The interface protocol for the sub-class
                                    // specified above.
        4,                          // The string index for this interface.
    };

    2) descriptor sections
    The original code temporally decreases the number of descriptors by one
    And then, the last descriptor (ie. the interrupt OUT endpoint) is not included

    usbdhidkeyb.c
    #define NUM_HID_SECTIONS        ((sizeof(g_psHIDSections) /                   \
                                      sizeof(g_psHIDSections[0])) - 1)   // <------

    Recover the number of descriptors

    #define NUM_HID_SECTIONS        ((sizeof(g_psHIDSections) /                   \
                                      sizeof(g_psHIDSections[0])) )

    3) When an output report comes over the interrupt OUT endpoint, the stack raises USB_EVENT_RX_AVAILABLE
    Add "case USB_EVENT_RX_AVAILABLE:" to the "switch" in HIDKeyboardRxHandler(), as follows

    usbdhidkeyb.c

    static uint32_t
    HIDKeyboardRxHandler(void *pvKeyboardDevice, uint32_t ui32Event,
                         uint32_t ui32MsgData, void *pvMsgData)
    {
        ...
        //
        // Which event were we sent?
        //
        switch (ui32Event)
        {
            //
            // A new packet has been received.
            //
            case USB_EVENT_RX_AVAILABLE:
            {
                //
                // ui32MsgData: the size of recieved data, passed by the stack
                // read out a packet (output report) from the interrupt OUT endpoint
                //
                USBDHIDPacketRead((void *)&(psInst->sHIDDevice), psInst->pui8DataBuffer, ui32MsgData, false);
                
                //
                // process the output report on psInst->pui8DataBuffer, here
                //
                temp = psInst->pui8DataBuffer[0];

                break;
            }



    Tsuneo

  • Tsuneo

    Thank you for your reponse.

    Now I am using http://janaxelson.com/files/SimpleHIDWrite3.zip to test. What is the difference between “write” and “set report” button? I can use set report to send packet to device. But the write option doesn’t work.

    I connect the device to linux host. It can’t received the report from host. I think the Linux host may use the way like “write”  to send report.

    Do you have any suggest?

  • > What is the difference between “write” and “set report” button?

    "Write" button sends the output report to the interrupt OUT endpoint.
    - HIDKeyboardRxHandler() is called by the stack with USB_EVENT_RX_AVAILABLE on the device side.

    "Set report" button sends it to the default endpoint using Set_Report request.
    - HIDKeyboardRxHandler() is called with USBD_HID_EVENT_SET_REPORT

    > I think the Linux host may use the way like “write”  to send report.

    Linux kernel HID driver doesn't support interrupt OUT EP.
    As you said, it sends output report using  Set_Report request.
    If you would like to send data to the interrupt OUT EP, you have to detach the default driver, and attach libusb to the HID device.

    https://github.com/libusb/libusb/wiki/FAQ#Does_libusb_support_HID_devices

    Tsuneo

  • So I modified the keyboard files in usblib/device:

    usbdhidgeneric.c

    usbdhidgeneric.h

  • Tsuneo

     

    Thank you. Your comments is really help. Now, It works.

     

    Wellin

  • Hi Duane, all,

    the files you provided are without the modifications described above, right?

    I did an own implementation but I have no device-read success if I write from host. (No reception of Feature report nor host write). I used as well the HIDWrite tool and I receive data from the device!

     

    Is there anything else you need to take care in addition.

    It would be great if you could look over my files.

    4812.usbdhidgeneric.h

    1205.usbdhidgeneric.c
    //*****************************************************************************
    //
    // usbdhidkeyb.c - USB HID Generic device class driver.
    //
    // Copyright (c) 2008-2014 Texas Instruments Incorporated.  All rights reserved.
    // Software License Agreement
    // 
    // Texas Instruments (TI) is supplying this software for use solely and
    // exclusively on TI's microcontroller products. The software is owned by
    // TI and/or its suppliers, and is protected under applicable copyright
    // laws. You may not combine this software with "viral" open-source
    // software in order to form a larger program.
    // 
    // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
    // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
    // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
    // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
    // DAMAGES, FOR ANY REASON WHATSOEVER.
    // 
    // This is not part of revision 2.1.0.12573 of the Tiva USB Library.
    
    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_types.h"
    #include "driverlib/debug.h"
    #include "driverlib/usb.h"
    #include "usblib/usblib.h"
    #include "usblib/usblibpriv.h"
    #include "usblib/device/usbdevice.h"
    #include "usblib/usbhid.h"
    #include "usblib/device/usbdhid.h"
    #include "usbdhidgeneric.h"
    
    //*****************************************************************************
    //
    //! \addtogroup hid_Generic_device_class_api
    //! @{
    //
    //*****************************************************************************
    
    //*****************************************************************************
    //
    // HID device configuration descriptor.
    //
    // It is vital that the configuration descriptor bConfigurationValue field
    // (byte 6) is 1 for the first configuration and increments by 1 for each
    // additional configuration defined here.  This relationship is assumed in the
    // device stack for simplicity even though the USB 2.0 specification imposes
    // no such restriction on the bConfigurationValue values.
    //
    // Note that this structure is deliberately located in RAM since we need to
    // be able to patch some values in it based on client requirements.
    //
    //*****************************************************************************
    static uint8_t g_pui8GenDescriptor[] =
    {
        //
        // Configuration descriptor header.
        //
        9,                          // Size of the configuration descriptor.
        USB_DTYPE_CONFIGURATION,    // Type of this descriptor.
        USBShort(41),               // The total size of this full structure. //34
        1,                          // The number of interfaces in this
                                    // configuration.
        1,                          // The unique value for this configuration.
        5,                          // The string identifier that describes this
                                    // configuration.
        USB_CONF_ATTR_SELF_PWR,     // Bus Powered, Self Powered, remote wake up.
        250,                        // The maximum power in 2mA increments.
    };
    
    //*****************************************************************************
    //
    // The remainder of the configuration descriptor is stored in flash since we
    // don't need to modify anything in it at runtime.
    //
    //*****************************************************************************
    static uint8_t g_pui8HIDInterface[HIDINTERFACE_SIZE] =
    {
        //
        // HID Device Class Interface Descriptor.
        //
        9,                          // Size of the interface descriptor.
        USB_DTYPE_INTERFACE,        // Type of this descriptor.
        0,                          // The index for this interface.
        0,                          // The alternate setting for this interface.
        2,                          // The number of endpoints used by this
                                    // interface.
        USB_CLASS_HID,              // The interface class
        USB_HID_SCLASS_NONE,        // The interface sub-class.
        USB_HID_PROTOCOL_NONE,      // The interface protocol for the sub-class
                                    // specified above.
        4,                          // The string index for this interface.
    };
    
    static const uint8_t g_pui8HIDInEndpoint[HIDINENDPOINT_SIZE] =
    {
        //
        // Interrupt IN endpoint descriptor
        //
        7,                          // The size of the endpoint descriptor.
        USB_DTYPE_ENDPOINT,         // Descriptor type is an endpoint.
        USB_EP_DESC_IN | USBEPToIndex(USB_EP_1),
        USB_EP_ATTR_INT,            // Endpoint is an interrupt endpoint.
        USBShort(USBFIFOSizeToBytes(USB_FIFO_SZ_64)),
                                    // The maximum packet size.
        1,                         // The polling interval for this endpoint.
    };
    
    static const uint8_t g_pui8HIDOutEndpoint[HIDOUTENDPOINT_SIZE] =
    {
        //
        // Interrupt OUT endpoint descriptor
        //
        7,                          // The size of the endpoint descriptor.
        USB_DTYPE_ENDPOINT,         // Descriptor type is an endpoint.
        USB_EP_DESC_OUT | USBEPToIndex(USB_EP_2),
        USB_EP_ATTR_INT,            // Endpoint is an interrupt endpoint.
        USBShort(USBFIFOSizeToBytes(USB_FIFO_SZ_64)),
                                    // The maximum packet size.
        1,                         // The polling interval for this endpoint.
    };
    
    
    //*****************************************************************************
    //
    // The following is the HID report structure definition that is passed back
    // to the host.
    //
    //*****************************************************************************
    
    //*****************************************************************************
    //
    // The following is the HID report structure definition that is passed back
    // to the host.
    //
    //*****************************************************************************
    static const uint8_t g_pui8GenReportDescriptor[] =
    {
    	    UsagePage(0x00),
    	    Usage(0x01),
    	    Collection(USB_HID_APPLICATION),
    
    				UsageMinimum(0),     // 19 00
    				UsageMaximum(64),    // 29 40
    				LogicalMinimum(0),   // 15 00
    				LogicalMaximum(255), // 26 FF 00
    				ReportSize(8),       // 75 08
    				ReportCount(64),     // 95 40
    				Input(USB_HID_INPUT_DATA | USB_HID_INPUT_VARIABLE | USB_HID_INPUT_ABS), // 81 00
    
    				UsageMinimum(0),     // 19 00
    				UsageMaximum(64),    // 29 40
    				LogicalMinimum(0),   // 15 00
    				LogicalMaximum(255), // 26 FF 00
    				ReportSize(8),       // 75 08
    				ReportCount(64),     // 95 40
    				Output(USB_HID_OUTPUT_DATA | USB_HID_OUTPUT_VARIABLE | USB_HID_OUTPUT_ABS), // 91 00
    
    		    EndCollection, // C0
    };
    
    //*****************************************************************************
    //
    // The HID descriptor for the Generic device.
    //
    //*****************************************************************************
    static const tHIDDescriptor g_sGenHIDDescriptor =
    {
        9,                              // bLength
        USB_HID_DTYPE_HID,              // bDescriptorType
        0x111,                          // bcdHID (version 1.11 compliant)
        0,                              // bCountryCode (not localized)
        1,                              // bNumDescriptors
        {
            {
                USB_HID_DTYPE_REPORT,   // Report descriptor
                sizeof(g_pui8GenReportDescriptor)
                                        // Size of report descriptor
            }
        }
    };
    
    //*****************************************************************************
    //
    // The HID configuration descriptor is defined as four or five sections
    // depending upon the client's configuration choice.  These sections are:
    //
    // 1.  The 9 byte configuration descriptor (RAM).
    // 2.  The interface descriptor (RAM).
    // 3.  The HID report and physical descriptors (provided by the client)
    //     (FLASH).
    // 4.  The mandatory interrupt IN endpoint descriptor (FLASH).
    // 5.  The optional interrupt OUT endpoint descriptor (FLASH).
    //
    //*****************************************************************************
    static const tConfigSection g_sHIDConfigSection =
    {
        sizeof(g_pui8GenDescriptor),
        g_pui8GenDescriptor
    };
    
    static const tConfigSection g_sHIDInterfaceSection =
    {
        sizeof(g_pui8HIDInterface),
        g_pui8HIDInterface
    };
    
    static const tConfigSection g_sHIDInEndpointSection =
    {
        sizeof(g_pui8HIDInEndpoint),
        g_pui8HIDInEndpoint
    };
    
    static const tConfigSection g_sHIDOutEndpointSection =
    {
        sizeof(g_pui8HIDOutEndpoint),
        g_pui8HIDOutEndpoint
    };
    
    //*****************************************************************************
    //
    // Place holder for the user's HID descriptor block.
    //
    //*****************************************************************************
    static tConfigSection g_sHIDDescriptorSection =
    {
       sizeof(g_sGenHIDDescriptor),
       (const uint8_t *)&g_sGenHIDDescriptor
    };
    
    //*****************************************************************************
    //
    // This array lists all the sections that must be concatenated to make a
    // single, complete HID configuration descriptor.
    //
    //*****************************************************************************
    static const tConfigSection *g_psHIDSections[] =
    {
        &g_sHIDConfigSection,
        &g_sHIDInterfaceSection,
        &g_sHIDDescriptorSection,
        &g_sHIDInEndpointSection,
        &g_sHIDOutEndpointSection
    };
    
    
    #define NUM_HID_SECTIONS        ((sizeof(g_psHIDSections) /                   \
                                      sizeof(g_psHIDSections[0]))) // cth++ - 1)
    
    
    //*****************************************************************************
    //
    // The header for the single configuration we support.  This is the root of
    // the data structure that defines all the bits and pieces that are pulled
    // together to generate the configuration descriptor.  Note that this must be
    // in RAM since we need to include or exclude the final section based on
    // client supplied initialization parameters.
    //
    //*****************************************************************************
    static tConfigHeader g_sHIDConfigHeader =
    {
        NUM_HID_SECTIONS,
        g_psHIDSections
    };
    
    //*****************************************************************************
    //
    // Configuration Descriptor.
    //
    //*****************************************************************************
    static const tConfigHeader * const g_ppsHIDConfigDescriptors[] =
    {
        &g_sHIDConfigHeader
    };
    
    //*****************************************************************************
    //
    // The HID class descriptor table.  For the Generic class, we have only a
    // single report descriptor.
    //
    //*****************************************************************************
    static const uint8_t * const g_pui8GenClassDescriptors[] =
    {
        g_pui8GenReportDescriptor
    };
    
    //*****************************************************************************
    //
    // Forward references for Generic device callback functions.
    //
    //*****************************************************************************
    static uint32_t HIDGenRxHandler(void *pvGenDevice, uint32_t ui32Event,
                                         uint32_t ui32MsgData, void *pvMsgData);
    static uint32_t HIDGenTxHandler(void *pvGenDevice, uint32_t ui32Event,
                                         uint32_t ui32MsgData, void *pvMsgData);
    
    //*****************************************************************************
    //
    // Main HID device class event handler function.
    //
    // \param pvGenericDevice is the event callback pointer provided during
    //  USBDHIDInit().This is a pointer to our HID device structure
    // (&g_sHIDKeybDevice).
    // \param ui32Event identifies the event we are being called back for.
    // \param ui32MsgData is an event-specific value.
    // \param pvMsgData is an event-specific pointer.
    //
    // This function is called by the HID device class driver to inform the
    // application of particular asynchronous events related to operation of the
    // Generic HID device.
    //
    // \return Returns a value which is event-specific.
    //
    //*****************************************************************************
    static uint32_t
    HIDGenRxHandler(void *pvGenDevice, uint32_t ui32Event,
                         uint32_t ui32MsgData, void *pvMsgData)
    {
        tHIDGenericInstance *psInst;
        tUSBDHIDGenericDevice *psGenericDevice;
    
        volatile uint8_t uiTemp; //cth++
    
        //
        // Make sure we did not get a NULL pointer.
        //
        ASSERT(pvGenDevice);
    
        //
        // Get a pointer to our instance data
        //
        psGenericDevice = (tUSBDHIDGenericDevice *)pvGenDevice;
        psInst = &psGenericDevice->sPrivateData;
    
        //
        // Which event were we sent?
        //
        switch (ui32Event)
        {
            //
            // The host has connected to us and configured the device.
            //
            case USB_EVENT_CONNECTED:
            {
                psInst->ui8USBConfigured = true;
    
                //
                // Pass the information on to the client.
                //
                psGenericDevice->pfnCallback(psGenericDevice->pvCBData,
                                              USB_EVENT_CONNECTED, 0, (void *)0);
    
                break;
            }
    
            //
            // The host has disconnected from us.
            //
            case USB_EVENT_DISCONNECTED:
            {
                psInst->ui8USBConfigured = false;
    
                //
                // Pass the information on to the client.
                //
                psGenericDevice->pfnCallback(psGenericDevice->pvCBData,
                                              USB_EVENT_DISCONNECTED, 0,
                                              (void *)0);
    
                break;
            }
    
            //
            // The host is polling us for a particular report and the HID driver
            // is asking for the latest version to transmit.
            //
            case USBD_HID_EVENT_IDLE_TIMEOUT:
            case USBD_HID_EVENT_GET_REPORT:
            {
                //
                // We only support a single input report so we don't need to check
                // the ui32MsgValue parameter in this case.  Set the report pointer
                // in *pvMsgData and return the length of the report in bytes.
                //
                *(uint8_t **)pvMsgData = psInst->pui8Report;
                return(GENERIC_IN_REPORT_SIZE);
            }
    
            //
            // The device class driver has completed sending a report to the
            // host in response to a Get_Report request.
            //
            case USBD_HID_EVENT_REPORT_SENT:
            {
                //
                // We have nothing to do here.
                //
                break;
            }
    
            //
            // This event is sent in response to a host Set_Report request.  We
            // must return a pointer to a buffer large enough to receive the
            // report into.
            //
            case USBD_HID_EVENT_GET_REPORT_BUFFER:
            {
                //
                // Are we being asked for a report that is shorter than the storage
                // we have set aside for this?  The only output report we define is
                // 8 bits long so we really expect to see a length of 1 passed.
                //
                if((uint32_t)pvMsgData == GENERIC_OUT_REPORT_SIZE )
                {
                    //
                    // Yes - return our pointer.
                    //
                    return((uint32_t)psInst->pui8DataBuffer);
                }
                else
                {
                    //
                    // We are being passed a report that is longer than the
                    // only report we expect so return NULL.  This causes the
                    // device class driver to stall the request.
                    //
                    return(0);
                }
            }
    
            //
            // This event indicates that the host has sent us an Output or
            // Feature report and that the report is now in the buffer we provided
            // on the previous USBD_HID_EVENT_GET_REPORT_BUFFER callback.
            //
            case USBD_HID_EVENT_SET_REPORT:
            {
    
                    //
                    // Pass the information on to the client.
                    //
                    psGenericDevice->pfnCallback(
                                                psGenericDevice->pvCBData,
                                                USBD_HID_KEYB_EVENT_SET_LEDS,
                                                psInst->pui8DataBuffer[0],
                                                (void *) &psInst->pui8DataBuffer[0]);
    
                break;
            }
    
            //
            // The host is asking us to set either boot or report protocol (not
            // that it makes any difference to this particular mouse).
            //
            case USBD_HID_EVENT_SET_PROTOCOL:
            {
                psInst->ui8Protocol = ui32MsgData;
                break;
            }
    
            //###############cth++
            case USB_EVENT_RX_AVAILABLE:
            {
                //
                // ui32MsgData: the size of recieved data, passed by the stack
                // read out a packet (output report) from the interrupt OUT endpoint
                //
                USBDHIDPacketRead((void *)&(psInst->sHIDDevice), psInst->pui8DataBuffer, ui32MsgData, false);
    
    
                //
                      // Pass the information on to the client.
                      //
                      psGenericDevice->pfnCallback(
                                                  psGenericDevice->pvCBData,
                                                  USB_EVENT_RX_AVAILABLE,
                                                  psInst->pui8DataBuffer[0],
                                                  (void *) &psInst->pui8DataBuffer[0]);
    
    
    
    
                //
                // process the output report on psInst->pui8DataBuffer, here
                //
                uiTemp = psInst->pui8DataBuffer[0];
    
                break;
            }
    
            //###############cth++
    
    
            //
            // The host is asking us to tell it which protocol we are currently
            // using, boot or request.
            //
            case USBD_HID_EVENT_GET_PROTOCOL:
            {
                return(psInst->ui8Protocol);
            }
    
            //
            // Pass ERROR, SUSPEND and RESUME to the client unchanged.
            //
            case USB_EVENT_ERROR:
            case USB_EVENT_SUSPEND:
            case USB_EVENT_RESUME:
            case USB_EVENT_LPM_RESUME:
            case USB_EVENT_LPM_SLEEP:
            case USB_EVENT_LPM_ERROR:
            {
                return(psGenericDevice->pfnCallback(
                                             psGenericDevice->pvCBData,
                                             ui32Event, ui32MsgData, pvMsgData));
            }
    
            //
            // We ignore all other events.
            //
            default:
            {
                break;
            }
        }
        return(0);
    }
    
    //*****************************************************************************
    //
    // HID device class transmit channel event handler function.
    //
    // \param pvGenericDevice is the event callback pointer provided during
    // USBDHIDInit().  This is a pointer to our HID device structure
    // (&g_sHIDKeybDevice).
    // \param ui32Event identifies the event we are being called back for.
    // \param ui32MsgData is an event-specific value.
    // \param pvMsgData is an event-specific pointer.
    //
    // This function is called by the HID device class driver to inform the
    // application of particular asynchronous events related to report
    // transmissions made using the interrupt IN endpoint.
    //
    // \return Returns a value which is event-specific.
    //
    //*****************************************************************************
    static uint32_t
    HIDGenTxHandler(void *pvGenericDevice, uint32_t ui32Event,
                         uint32_t ui32MsgData, void *pvMsgData)
    {
        tHIDGenericInstance *psInst;
        tUSBDHIDGenericDevice *psHIDGenDevice;
        tUSBDHIDDevice *psHIDDevice;
    
    
        //
        // Make sure we did not get a NULL pointer.
        //
        ASSERT(pvGenericDevice);
    
        //
        // Get a pointer to our instance data
        //
        psHIDGenDevice = (tUSBDHIDGenericDevice *)pvGenericDevice;
        psInst = &psHIDGenDevice->sPrivateData;
        psHIDDevice = &psInst->sHIDDevice;
    
        //
        // Which event were we sent?
        //
        switch (ui32Event)
        {
            //
            // A report transmitted via the interrupt IN endpoint was acknowledged
            // by the host.
            //
            case USB_EVENT_TX_COMPLETE:
            {
                 //
                    // Yes - go ahead and send another report immediately.
                    //
                    USBDHIDReportWrite((void *)psHIDDevice,
                                                 psInst->pui8Report,
                                                 GENERIC_IN_REPORT_SIZE, true);
    
    
    
                //
                // Pass the event on to the client.
                //
                psHIDGenDevice->pfnCallback(psHIDGenDevice->pvCBData,
                                           USB_EVENT_TX_COMPLETE, ui32MsgData,
                                           (void *)0);
    
                break;
            }
    
            //
            // We ignore all other events related to transmission of reports via
            // the interrupt IN endpoint.
            //
            default:
            {
                break;
            }
        }
    
        return(0);
    }
    
    
    //*****************************************************************************
    //
    //! Initializes HID Generic device operation for a given USB controller.
    //!
    //! \param ui32Index is the index of the USB controller which is to be
    //! initialized for HID Generic device operation.
    //! \param psHIDKbDevice points to a structure containing parameters
    //! customizing the operation of the HID Generic device.
    //!
    //! An application wishing to offer a USB HID Generic interface to a USB host
    //! must call this function to initialize the USB controller and attach the
    //! Generic device to the USB bus.  This function performs all required USB
    //! initialization.
    //!
    //! On successful completion, this function returns the \e psHIDKbDevice
    //! pointer passed to it.  This must be passed on all future calls to the HID
    //! Generic device driver.
    //!
    //! When a host connects and configures the device, the application callback
    //! receives \b USB_EVENT_CONNECTED after which calls can be made to
    //! USBDHIDGenericKeyStateChange() to report key presses and releases to the
    //! USB host.
    //!
    //! \note The application must not make any calls to the lower level USB device
    //! interfaces if interacting with USB via the USB HID Generic device class
    //! API.  Doing so causes unpredictable (though almost certainly
    //! unpleasant) behavior.
    //!
    //! \return Returns NULL on failure or the \e psHIDKbDevice pointer on success.
    //
    //*****************************************************************************
    
    tUSBDHIDGenericDevice *
    USBDHIDGenericInit(uint32_t ui32Index, tUSBDHIDGenericDevice *psHIDGenDevice)
    {
        void *pvRetcode;
        tUSBDHIDDevice *psHIDDevice;
        tConfigDescriptor *pConfigDesc;
    
        //
        // Check parameter validity.
        //
        ASSERT(psHIDGenDevice);
        ASSERT(psHIDGenDevice->ppui8StringDescriptors);
        ASSERT(psHIDGenDevice->pfnCallback);
    
        //
        // Get a pointer to the HID device data.
        //
        psHIDDevice = &psHIDGenDevice->sPrivateData.sHIDDevice;
    
        //
        // Call the common initialization routine.
        //
        pvRetcode = USBDHIDGenericCompositeInit(ui32Index, psHIDGenDevice, 0);
    
        pConfigDesc = (tConfigDescriptor *)g_pui8GenDescriptor;
        pConfigDesc->bmAttributes = psHIDGenDevice->ui8PwrAttributes;
        pConfigDesc->bMaxPower =  (uint8_t)(psHIDGenDevice->ui16MaxPowermA / 2);
    
        //
        // If we initialized the HID layer successfully, pass our device pointer
        // back as the return code, otherwise return NULL to indicate an error.
        //
        if(pvRetcode)
        {
            //
            // Initialize the lower layer HID driver and pass it the various
            // structures and descriptors necessary to declare that we are a
            // Generic.
            //
            pvRetcode = USBDHIDInit(ui32Index, psHIDDevice);
    
            return((void *)psHIDGenDevice);
        }
        else
        {
            return((void *)0);
        }
    }
    
    
    
    //*****************************************************************************
    //
    //! Initializes HID Generic device operation for a given USB controller.
    //!
    //! \param ui32Index is the index of the USB controller which is to be
    //! initialized for HID Generic device operation.
    //! \param psHIDKbDevice points to a structure containing parameters
    //! customizing the operation of the HID Generic device.
    //! \param psCompEntry is the composite device entry to initialize when
    //! creating a composite device.
    //!
    //! This call is very similar to USBDHIDGenericInit() except that it is used
    //! for initializing an instance of the HID Generic device for use in a
    //! composite device.  If this HID Generic is part of a composite device, then
    //! the \e psCompEntry should point to the composite device entry to
    //! initialize. This is part of the array that is passed to the
    //! USBDCompositeInit() function.
    //!
    //! \return Returns zero on failure or a non-zero instance value that should be
    //! used with the remaining USB HID Generic APIs.
    //
    //*****************************************************************************
    
    tUSBDHIDGenericDevice *
    USBDHIDGenericCompositeInit(uint32_t ui32Index,
                                 tUSBDHIDGenericDevice *psHIDGenDevice,
                                 tCompositeEntry *psCompEntry)
    {
        tHIDGenericInstance *psInst;
    
        tUSBDHIDDevice *psHIDDevice;
    
        //
        // Check parameter validity.
        //
        ASSERT(psHIDGenDevice);
        ASSERT(psHIDGenDevice->ppui8StringDescriptors);
        ASSERT(psHIDGenDevice->pfnCallback);
    
        //
        // Get a pointer to our instance data
        //
        psInst = &psHIDGenDevice->sPrivateData;
    
        //
        // Initialize the various fields in our instance structure.
        //
        psInst->ui8USBConfigured = 0;
        psInst->ui8Protocol = USB_HID_PROTOCOL_REPORT;
        psInst->sReportIdle.ui8Duration4mS = 125;
        psInst->sReportIdle.ui8ReportID = 0;
        psInst->sReportIdle.ui32TimeSinceReportmS = 0;
        psInst->sReportIdle.ui16TimeTillNextmS = 0;
        psInst->eGenericState = HID_GENERIC_STATE_UNCONFIGURED;
    
        //
        // Get a pointer to the HID device data.
        //
        psHIDDevice = &psInst->sHIDDevice;
    
        //
        // Initialize the HID device class instance structure based on input from
        // the caller.
        //
        psHIDDevice->ui16PID = psHIDGenDevice->ui16PID;
        psHIDDevice->ui16VID = psHIDGenDevice->ui16VID;
        psHIDDevice->ui16MaxPowermA = psHIDGenDevice->ui16MaxPowermA;
        psHIDDevice->ui8PwrAttributes = psHIDGenDevice->ui8PwrAttributes;
        psHIDDevice->ui8Subclass = USB_HID_SCLASS_NONE;
        psHIDDevice->ui8Protocol = USB_HID_PROTOCOL_NONE;
        psHIDDevice->ui8NumInputReports = 1;
        psHIDDevice->psReportIdle = 0;
        psHIDDevice->pfnRxCallback = HIDGenRxHandler;
        psHIDDevice->pvRxCBData = (void *)psHIDGenDevice;
        psHIDDevice->pfnTxCallback = HIDGenTxHandler;
        psHIDDevice->pvTxCBData = (void *)psHIDGenDevice;
        psHIDDevice->bUseOutEndpoint = false,
    
        psHIDDevice->psHIDDescriptor = &g_sGenHIDDescriptor;
        psHIDDevice->ppui8ClassDescriptors = g_pui8GenClassDescriptors;
        psHIDDevice->ppui8StringDescriptors =
                                            psHIDGenDevice->ppui8StringDescriptors;
        psHIDDevice->ui32NumStringDescriptors =
                                            psHIDGenDevice->ui32NumStringDescriptors;
        psHIDDevice->ppsConfigDescriptor = g_ppsHIDConfigDescriptors;
    
        psHIDDevice->psReportIdle = &psInst->sReportIdle;
    
        //
        // Initialize the lower layer HID driver and pass it the various structures
        // and descriptors necessary to declare that we are a Generic.
        //
        return(USBDHIDCompositeInit(ui32Index, psHIDDevice, psCompEntry));
    }
    
    //*****************************************************************************
    //
    //! Shuts down the HID Generic device.
    //!
    //! \param pvGenericDevice is the pointer to the device instance structure
    //! as returned by USBDHIDGenericInit().
    //!
    //! This function terminates HID Generic operation for the instance supplied
    //! and removes the device from the USB bus.  Following this call, the
    //! \e pvGenericDevice instance may not me used in any other call to the HID
    //! Generic device other than USBDHIDGenericInit().
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBDHIDGenericTerm(void *pvGenericDevice)
    {
        tUSBDHIDGenericDevice *psHIDGenDevice;
        tUSBDHIDDevice *psHIDDevice;
    
        ASSERT(pvGenericDevice);
    
        //
        // Get a pointer to the device.
        //
        psHIDGenDevice = (tUSBDHIDGenericDevice *)pvGenericDevice;
    
        //
        // Get a pointer to the HID device data.
        //
        psHIDDevice = &psHIDGenDevice->sPrivateData.sHIDDevice;
    
        //
        // Mark the device as no longer configured.
        //
        psHIDGenDevice->sPrivateData.ui8USBConfigured = 0;
    
        //
        // Terminate the low level HID driver.
        //
        USBDHIDTerm(psHIDDevice);
    }
    
    //*****************************************************************************
    //
    //! Sets the client-specific pointer parameter for the Generic callback.
    //!
    //! \param pvGenericDevice is the pointer to the device instance structure
    //! as returned by USBDHIDGenericInit().
    //! \param pvCBData is the pointer that client wishes to be provided on each
    //! event sent to the Generic callback function.
    //!
    //! The client uses this function to change the callback pointer passed in
    //! the first parameter on all callbacks to the \e pfnCallback function
    //! passed on USBDHIDGenericInit().
    //!
    //! If a client wants to make runtime changes in the callback pointer, it must
    //! ensure that the \e pvGenericDevice structure passed to
    //! USBDHIDGenericInit() resides in RAM.  If this structure is in flash,
    //! callback data changes is not possible.
    //!
    //! \return Returns the previous callback pointer that was set for this
    //! instance.
    //
    //*****************************************************************************
    void *
    USBDHIDGenericSetCBData(void *pvGenericDevice, void *pvCBData)
    {
        void *pvOldCBData;
        tUSBDHIDGenericDevice *psGeneric;
    
        //
        // Check for a NULL pointer in the device parameter.
        //
        ASSERT(pvGenericDevice);
    
        //
        // Get a pointer to our Generic device.
        //
        psGeneric = (tUSBDHIDGenericDevice *)pvGenericDevice;
    
        //
        // Save the old callback pointer and replace it with the new value.
        //
        pvOldCBData = psGeneric->pvCBData;
        psGeneric->pvCBData = pvCBData;
    
        //
        // Pass the old callback pointer back to the caller.
        //
        return(pvOldCBData);
    }
    
    //*****************************************************************************
    //
    //! Reports a key state change to the USB host.
    //!
    //! \param pvGenericDevice is the pointer to the device instance structure
    //! as returned by USBDHIDGenericInit().
    //! \param ui8Modifiers contains the states of each of the Generic modifiers
    //! (left/right shift, ctrl, alt or GUI keys).  Valid values are logical OR
    //! combinations of the labels \b HID_KEYB_LEFT_CTRL, \b HID_KEYB_LEFT_SHIFT,
    //! \b HID_KEYB_LEFT_ALT, \b HID_KEYB_LEFT_GUI, \b HID_KEYB_RIGHT_CTRL, \b
    //! HID_KEYB_RIGHT_SHIFT, \b HID_KEYB_RIGHT_ALT and \b HID_KEYB_RIGHT_GUI.
    //! Presence of one of these bit flags indicates that the relevant modifier
    //! key is pressed and absence indicates that it is released.
    //! \param ui8UsageCode is the usage code of the key whose state has changed.
    //! If only modifier keys have changed, \b HID_KEYB_USAGE_RESERVED should be
    //! passed in this parameter.
    //! \param bPress is \b true if the key has been pressed or \b false if it has
    //! been released.  If only modifier keys have changed state, this parameter is
    //! ignored.
    //!
    //! This function adds or removes a key usage code from the list of keys
    //! currently pressed and schedules a report transmission to the host to
    //! inform it of the new Generic state.  If the maximum number of simultaneous
    //! key presses are already recorded, the report to the host contains the
    //! rollover error code, \b HID_KEYB_USAGE_ROLLOVER instead of key usage codes
    //! and the caller receives return code \b KEYB_ERR_TOO_MANY_KEYS.
    //!
    //! \return Returns \b KEYB_SUCCESS if the key usage code was added to or
    //! removed from the current list successfully.  \b KEYB_ERR_TOO_MANY_KEYS is
    //! returned if an attempt is made to press a 7th key (the BIOS Generic
    //! protocol can report no more than 6 simultaneously pressed keys).  If called
    //! before the USB host has configured the device, \b KEYB_ERR_NOT_CONFIGURED
    //! is returned and, if an error is reported while attempting to transmit the
    //! report, \b KEYB_ERR_TX_ERROR is returned.  If an attempt is made to remove
    //! a key from the pressed list (by setting parameter \e bPressed to \b false)
    //! but the key usage code is not found, \b KEYB_ERR_NOT_FOUND is returned.
    //
    //*****************************************************************************
    
    uint32_t
    USBDHIDSendData(void *pvGenericDevice, uint8_t * buffer)
    {
        uint32_t ui32Loop, ui32Count;
        tHIDGenericInstance *psInst;
        tUSBDHIDGenericDevice *psHIDGenDevice;
        tUSBDHIDDevice *psHIDDevice;
    
        psHIDGenDevice = (tUSBDHIDGenericDevice *)pvGenericDevice;
    
        //
        // Get a pointer to the HID device data.
        //
        psHIDDevice = &psHIDGenDevice->sPrivateData.sHIDDevice;
    
        //
        // Get a pointer to our instance data
        //
        psInst = &psHIDGenDevice->sPrivateData;
    
        //
    	// Build the report from the current list of keys.  If we added a key
    	// and got a bad return code indicating a roll over error, we need to
    	// send a roll over report
    	//
    	for(ui32Loop = 0; ui32Loop < GENERIC_OUT_REPORT_SIZE; ui32Loop++)
    	{
    		psInst->pui8Report[ui32Loop] = buffer[ui32Loop];
    	}
    
    
        //
        // If we are not configured, return an error here before trying to send
        // anything.
        //
        if(!psInst->ui8USBConfigured)
        {
            return(KEYB_ERR_NOT_CONFIGURED);
        }
    
        //
        // Only send a report if the transmitter is currently free.
        //
        if(USBDHIDTxPacketAvailable((void *)psHIDDevice))
        {
            //
            // Send the report to the host.
            //
            psInst->eGenericState = HID_GENERIC_STATE_SEND;
            ui32Count = USBDHIDReportWrite((void *)psHIDDevice,
                                           psInst->pui8Report, GENERIC_IN_REPORT_SIZE,
                                           true);
    
            //
            // Did we schedule a packet for transmission correctly?
            //
            if(!ui32Count)
            {
                //
                // No - report the error to the caller.
                //
                return(KEYB_ERR_TX_ERROR);
            }
        }
        else
        {
            //
            // We can't send the report immediately so mark the instance so that
            // it is sent next time the transmitter is free.
            //
            //psInst->bChangeMade = true;
        }
    
        //
        // If we get this far, the key information was sent successfully.  Are
        // too many keys currently pressed, though?
        //
        return(KEYB_SUCCESS);
    }
    
    
    #ifndef DEPRECATED
    
    //*****************************************************************************
    //
    //! Reports the device power status (bus or self powered) to the USB library.
    //!
    //! \param pvGenericDevice is the pointer to the Generic device instance
    //! structure.
    //! \param ui8Power indicates the current power status, either
    //! \b USB_STATUS_SELF_PWR or \b USB_STATUS_BUS_PWR.
    //!
    //! Applications which support switching between bus or self powered
    //! operation should call this function whenever the power source changes
    //! to indicate the current power status to the USB library.  This information
    //! is required by the USB library to allow correct responses to be provided
    //! when the host requests status from the device.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBDHIDGenericPowerStatusSet(void *pvGenericDevice, uint8_t ui8Power)
    {
        tUSBDHIDGenericDevice *psHIDKbDevice;
        tUSBDHIDDevice *psHIDDevice;
    
        ASSERT(pvGenericDevice);
    
        //
        // Get the Generic device pointer.
        //
        psHIDKbDevice = (tUSBDHIDGenericDevice *)pvGenericDevice;
    
        //
        // Get a pointer to the HID device data.
    
        psHIDDevice = &psHIDKbDevice->sPrivateData.sHIDDevice;
    
        //
        // Pass the request through to the lower layer.
        //
        USBDHIDPowerStatusSet((void *)psHIDDevice, ui8Power);
    }
    #endif
    
    //*****************************************************************************
    //
    //! Requests a remote wake up to resume communication when in suspended state.
    //!
    //! \param pvGenericDevice is the pointer to the Generic device instance
    //! structure.
    //!
    //! When the bus is suspended, an application which supports remote wake up
    //! (advertised to the host via the configuration descriptor) may call this
    //! function to initiate remote wake up signaling to the host.  If the remote
    //! wake up feature has not been disabled by the host, this causes the bus
    //! to resume operation within 20mS.  If the host has disabled remote wake up,
    //! \b false is returned to indicate that the wake up request was not
    //! successful.
    //!
    //! \return Returns \b true if the remote wake up is not disabled and the
    //! signaling was started or \b false if remote wake up is disabled or if
    //! signaling is currently ongoing following a previous call to this function.
    //
    //*****************************************************************************
    bool
    USBDHIDGenericRemoteWakeupRequest(void *pvGenericDevice)
    {
        tUSBDHIDGenericDevice *psHIDKbDevice;
        tUSBDHIDDevice *psHIDDevice;
    
        ASSERT(pvGenericDevice);
    
        //
        // Get the Generic device pointer.
        //
        psHIDKbDevice = (tUSBDHIDGenericDevice *)pvGenericDevice;
    
        //
        // Get a pointer to the HID device data.
        //
        psHIDDevice = &psHIDKbDevice->sPrivateData.sHIDDevice;
    
        //
        // Pass the request through to the lower layer.
        //
        return(USBDHIDRemoteWakeupRequest((void *)psHIDDevice));
    }
    
    //*****************************************************************************
    //
    // Close the Doxygen group.
    //! @}
    //
    //*****************************************************************************
    

    Please find the log from my c-based host application below.

    The error I retrieved from a function called hid_error(handle)!

    Unable to get a feature report. Error: Unzulõssige Funktion.

    Unable to send a feature report. Error: Unzulõssige Funktion.

    Unable to write Error: Falscher Parameter.

    Any idea.

    Many thanks,

    Best regards,

    Carsten

    Device Found

      type: 1cbe 000b

      serial_number: 12345678

      Manufacturer: Texas Instruments

      Product:      Genericd Example

      Release:      100

      Interface:    -1

    Serial Number String: (49) 12345678

    Indexed String 1: Texas Instruments

    Indexed String 2: Genericd Example

    Indexed String 3: 12345678

    Indexed String 4: HID Genericd Interface

    Indexed String 5: HID Genericd Configuration

    Unable to get a feature report. Error: Unzulõssige Funktion.

    Unable to send a feature report. Error: Unzulõssige Funktion.

    Unable to write Error: Falscher Parameter.

    Read Success!

    Drücken Sie eine beliebige Taste . . .

  • Hey Carsten, the links to the gists of the usbdhidgeneric files in my previous post are modified correctly, they will implement the usb generic device. I'll have a closer look at your code over the weekend.

     

    Duane

  • Hi Duane,
    in the meantime I could also confirm that the code is working. My problem here is more on windows7 side. I found a c# test example and hid_write and hid_send_feature_report working well.

    I still have problems with the win32 console test application. hid_send_feature_report function does still not work with Unknow Function reply from Windows7. I found another thread discussing this and it points out that there is a problem with File Security and Access Rights. But as the hid_write function is working and all priviliges are set in my opinion right I dont know how to look for.
    handle = CreateFileA(path,
    GENERIC_WRITE |GENERIC_READ,
    FILE_SHARE_READ|FILE_SHARE_WRITE, /*share mode*/
    (LPSECURITY_ATTRIBUTES)NULL,
    OPEN_EXISTING,
    FILE_FLAG_OVERLAPPED,//FILE_ATTRIBUTE_NORMAL,
    0);

    I found the problem with hid_write and wrong parameter error. My Buffer Size was 0x40, but the function wanted to have 0x41 buffer size with first entry set to 0x00!

    I`m fine so far as write and read operation is working.
    So my ADC data running to the PC and I could focus on the real world analog challenge.

    Many thanks for the great work.
    Best regards,
    Carsten
  • Also, might be worth looking at hidapi: https://github.com/signal11/hidapi