0

I have recently restarted to play around with micro controllers and finally got kinda stuck. So what I am building is a custom game pad. I can simulate data correctly for buttons but nothing works when I bring in the hat switch. I assume I am sending wrong data packet but cannot figure out the correct structure. In the test code I am just trying to send some "button press" and also trying to press down a key from hat switch, but it looks like that pc cannot recognise my data packet. I did go through the hid documentation (especially page 64, 65) and still have no idea why this is not working.

My HID descriptor:

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, 0x0e,                    //     USAGE_MAXIMUM (Button 14)
0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
0x25, 0x01,                    //     LOGICAL_MAXIMUM (1)
0x95, 0x0e,                    //     REPORT_COUNT (14)
0x75, 0x01,                    //     REPORT_SIZE (1)
0x81, 0x02,                    //   INPUT (Data,Var,Abs)
0x95, 0x01,                    //   REPORT_COUNT (1)
0x75, 0x02,                    //   REPORT_SIZE (2)
0x81, 0x03,                    //   INPUT (Cnst,Var,Abs)
0x05, 0x01,                    //   USAGE_PAGE (Generic Desktop)
0x09, 0x39,                    //   USAGE (Hat switch)
0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
0x25, 0x03,                    //   LOGICAL_MAXIMUM (3)
0x35, 0x00,                    //   PHYSICAL_MINIMUM (0)
0x46, 0x0e, 0x01,              //   PHYSICAL_MAXIMUM (270)
0x95, 0x01,                    //   REPORT_COUNT (1)
0x75, 0x04,                    //   REPORT_SIZE (4)
0x81, 0x42,                    //   INPUT (Data,Var,Abs,Null)
0x95, 0x01,                    //   REPORT_COUNT (1)
0x75, 0x04,                    //   REPORT_SIZE (4)
0x81, 0x03,                    //   INPUT (Cnst,Var,Abs)
0xc0,                          //   END_COLLECTION
0xc0                           // END_COLLECTION

Basic test code:

struct gamepad_report_t
{
    uint16_t buttons;
    uint8_t hs0 : 1;
    uint8_t hs1 : 1;
    uint8_t hs2 : 1;
    uint8_t hs3 : 1;
};

struct gamepad_report_t gamepad_report;

gamepad_report.buttons = 0x0001;
gamepad_report.hs0 = 1;
gamepad_report.hs1 = 0;
gamepad_report.hs2 = 0;
gamepad_report.hs3 = 0;

int main()
{
    while (1)
    {
      gamepad_report.buttons = 0x0010;
      HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_4);
      USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS, &gamepad_report, sizeof(struct gamepad_report_t));
      HAL_Delay(500);
    }
}

Data packet structure I have imaganed

What I see in the device properties when the uC is connected

rololo
  • 1
  • 1
  • Your report descriptor look OK to me, however other ones I have seen with hat switches have the physical unit (in this case, degrees) specified too: 0x65,0x14, /* (GLOBAL) UNIT 0x14 Rotation in degrees [1° units] (4=System=English Rotation, 1=Rotation=Degrees) */ ...that may be worth adding. – aja Feb 09 '20 at 05:09
  • Thanks for your input, just tried your suggestion, still the same result. I suspect that my struct variable _gamepad_report_t_ is somehow wrong but still it is a black picture for me why... – rololo Feb 09 '20 at 08:33
  • If you capture a Wireshark trace you will be able to confirm that the packets are being sent to the host. If the host still fails to respond (or respond negatively) then it may be a host driver issue. Another avenue is to post your question on Jan Axelson's USB forum http://janaxelson.com/forum/index.php ...she writes books about USB and is very helpful. – aja Feb 09 '20 at 11:44
  • Thank you for the direction, I am new to USB so your input is much appreciated. I will definitely take a look at Wireshark and read the forum mentioned above. Thumbs up for you. – rololo Feb 09 '20 at 13:01

2 Answers2

0

The problem I struggled here was the struct variable I wanted to send to the PC. If I am sending an array, everything works as expected... so the conclusion is that sizeof(struct) is not returning correct value, I should read through data structure alignment ... typically simple issue what can drive people crazy.

rololo
  • 1
  • 1
0

First thing I see wrong is that you are trying to use the hat switch like buttons. The hat switch has a value for each direction. For example Up-Left has its own value, it is not a combination of Up and Left being pressed. You will have to read your buttons, and then encode them as a value. It can be a little finicky to set up for the first time.

Here are the values for each button, which should clear up any confusion. (Won't work with every report descriptor!)

#define HATSWITCH_UP            0x00
#define HATSWITCH_UPRIGHT       0x01
#define HATSWITCH_RIGHT         0x02
#define HATSWITCH_DOWNRIGHT     0x03
#define HATSWITCH_DOWN          0x04
#define HATSWITCH_DOWNLEFT      0x05
#define HATSWITCH_LEFT          0x06
#define HATSWITCH_UPLEFT        0x07
#define HATSWITCH_NONE          0x0F

And here is part of a descriptor that will work with those values. Just define a uint8_t for the hat switch in the report descriptor and you should be good to go.

    0x05, 0x01,         //Usage Page        : Generic Desktop
    0x09, 0x39,         //Usage             : Hat Switch,
    0x15, 0x00,         //Logical Min       : 0
    0x25, 0x07,         //Logical Max       : 7
    0x46, 0x3B, 0x01,   //Physical Maximum  : 315 degrees (Optional)
    0x75, 0x08,         //Report Size       : 8
    0x95, 0x01,         //Report Count      : 1
    0x65, 0x14,         //Unit              : English Rotation/Angular Position 1 degree (Optional)
    0x81, 0x42,         //Input             : Data, Var, Abs, Null State

I know this is an old topic, and you most likely figured it out, but it will help people in the future.

Addio
  • 89
  • 1
  • 6