Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

HID Output

Discussion in 'Input System' started by tgaldi, Oct 24, 2019.

  1. tgaldi

    tgaldi

    Joined:
    Oct 28, 2015
    Posts:
    102
    I'm trying to send a message to our custom hid device and not getting a response. The message requests the device's current state, which causes the device to output the state of all its knobs, buttons, etc.

    Code (CSharp):
    1.  
    2.     [StructLayout( LayoutKind.Explicit, Size = size )]
    3.     public unsafe struct GetDeviceStateMessage : IInputDeviceCommandInfo
    4.     {
    5.         public static FourCC type => new FourCC( 'H', 'I', 'D', 'O' );
    6.  
    7.         internal const int size = InputDeviceCommand.BaseCommandSize + 3;
    8.         internal const int id = 63;
    9.         internal const int length = 7;
    10.         internal const int message = 255;
    11.  
    12.         [FieldOffset(0)]
    13.         public InputDeviceCommand baseCommand;
    14.  
    15.         [FieldOffset(InputDeviceCommand.BaseCommandSize + 0)]
    16.         public byte reportId;
    17.         [FieldOffset(InputDeviceCommand.BaseCommandSize + 2)]
    18.         public byte reportLength;
    19.         [FieldOffset(InputDeviceCommand.BaseCommandSize + 3)]
    20.         public byte getDeviceStateMessage;
    21.  
    22.         public FourCC typeStatic => type;
    23.  
    24.         public static GetDeviceStateMessage Create()
    25.         {
    26.             return new GetDeviceStateMessage
    27.             {
    28.                 baseCommand = new InputDeviceCommand( type, size ),
    29.                 reportId = id,
    30.                 reportLength = length,
    31.                 getDeviceStateMessage = message
    32.             };
    33.         }
    34.     }
    35.  
    Its called when a device is reconnected:
    Code (CSharp):
    1.  
    2. InputSystem.onDeviceChange +=
    3.     ( device, change ) =>
    4.         {
    5.             if( device.GetType() != typeof( My_HID_Device ) )
    6.                 return;
    7.  
    8.             switch( change )
    9.             {
    10.                 case InputDeviceChange.Reconnected:
    11.                     My_HID_Device.current.RequestDeviceState();
    12.                     break;
    13.             }
    14.         };
    15.  

    which calls:
    Code (CSharp):
    1.         public void RequestDeviceState()
    2.         {
    3.             Debug.Log( "REQUEST" );
    4.             var command = GetDeviceStateMessage.Create();
    5.             ExecuteCommand( ref command );
    6.         }
    7.  

    On a previous platform I had packed the message into a 64 byte packet and sent it out by hand like this:

    Code (CSharp):
    1. bool HandHeldInput::MessageDevice( BYTE msgIn[], int msgLength ) {
    2.  
    3.     bool SUCCESS = true;
    4.     BYTE buff[USB_OUTPUT_SIZE];
    5.     memset( buff, 0x0, USB_OUTPUT_SIZE );
    6.     for( int i = 0; i < msgLength; ++i )
    7.         buff[i] = msgIn[i];
    8.     if( m_hDeviceHandle == NULL ||
    9.         hid_write( m_hDeviceHandle, buff, USB_OUTPUT_SIZE ) == -1 )
    10.     {
    11.         std::cout << "Device message not sent! Is message format correct?" << std::endl;
    12.         SUCCESS = false;
    13.     }
    14.      
    15.     return SUCCESS;
    16. }
    I'm not sure if something different is going on under the hood for Unity and the base command?

    I also notice that if I set a break point and connect the debugger and run (the game) - I stop receiving device input, though I still see them coming across in the Input Debug editor.
     
    Last edited: Oct 24, 2019
  2. Rene-Damm

    Rene-Damm

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    My suspicion would be that it's the buffer size not matching. Probably because of the reportLength field. From the MessageDevice function you posted, it appears that the message length shouldn't be part of the message.

    In the Windows backend HID code, there's a check that the buffer size matches the output buffer size reported by the device. If that is not the case, the device command fails. (wondering whether that check should actually be there)

    So the payload size of your device command (i.e. total struct size minus sizeof(InputDeviceCommand)) has to correspond to the output report size expected by the device. Everything in the command's payload is copied over verbatim and sent to the device via WriteFile.

    Unfortunately, we don't yet have any kind of nuanced error reporting for this kind of stuff. If it fails, there's usually no indication why.
     
    Last edited: Oct 24, 2019
    tgaldi likes this.
  3. tgaldi

    tgaldi

    Joined:
    Oct 28, 2015
    Posts:
    102
    On the previous platform it was sent like so:


    Code (CSharp):
    1.     m_DEVICE_OUTPUT_MESSAGE[OUTPUT_BYTE_0] = OUTPUT_REPORT_ID;
    2.     m_DEVICE_OUTPUT_MESSAGE[OUTPUT_BYTE_1] = OUTPUT_REPORT_LENGTH;
    3.     m_DEVICE_OUTPUT_MESSAGE[OUTPUT_BYTE_2] = OUTPUT_MESSAGE_GETSTATE;
    4.     m_inputDevice.MessageDevice( m_DEVICE_OUTPUT_MESSAGE, MAX_OUTPUT_SIZE );
    where:

    Code (CSharp):
    1.     enum DEVICE_OUTPUT
    2.     {
    3.         OUTPUT_BYTE_0                       = 0,
    4.             OUTPUT_REPORT_ID                =   0x3F,
    5.        
    6.         OUTPUT_BYTE_1                       = 1,
    7.             OUTPUT_REPORT_LENGTH            =   0x7,
    8.        
    9.         OUTPUT_BYTE_2                       = 2,
    10.             OUTPUT_MESSAGE_GETSTATE         =   0xFF,
    11.    
    12.         MAX_OUTPUT_SIZE                     = 3
    13.     };
    14.     BYTE    m_DEVICE_OUTPUT_MESSAGE[MAX_OUTPUT_SIZE];

    I tried changing the size in Unity to

           internal const int size = InputDeviceCommand.BaseCommandSize + 64;


    64 because we
    #define USB_OUTPUT_SIZE 64



    but still no response =(
     
  4. tgaldi

    tgaldi

    Joined:
    Oct 28, 2015
    Posts:
    102
    Never mind, it looks like changing the size did fix it.