Home > database >  How to send data to HID device in Unity Input System
How to send data to HID device in Unity Input System

Time:02-04

I managed to implement the HID device in Unity Input System and I can read from it easily. But how to send data back to the HID device?

This is the IInputDeviceCommandInfo implementation I have:

    [StructLayout(LayoutKind.Explicit)]
    internal struct MyControlCommand : IInputDeviceCommandInfo
    {
        public static FourCC Type { get { return new FourCC("HIDO"); } }
  
        [FieldOffset(0)]
        public byte res;

        [FieldOffset(1)]
        public byte magic; 

        [FieldOffset(2)]
        public byte DataType;

        [FieldOffset(3)]
        public short Data;
 
        public FourCC typeStatic
        {
            get { return Type; }
        }

        public static MyControlCommand Create(byte dataType, short data)
        {
            return new MyControlCommand
            { 
                magic = 0x7e,
                DataType = dataType,
                Data = data
            };
        }
    }

I wanted to send these bytes:

0
0x7e
0x04
0xfff

So I used:

var c = MyControlCommand.Create(0x04, 0xfff);
var res = current.ExecuteCommand(ref c);

The res variable gets -1, so It's unsuccessful.

I managed to communicate with the device (above bytes worked fine) using HidSharp library and my own HID implementation, but Unity is stubborn...

Thanks for help!

CodePudding user response:

Ok, that was not an easy problem to solve:

The problem was that IInputDeviceCommandInfo does not force user to implement Field(0) to be an InputDeviceCommand. InputDeviceCommand must be added at Field(0) offset and other fields must be shifted respectively.

The second problem was that my device required different size of the output data. Probably OS checks if the sizes matches (the one reported by the descriptor in capabilities.outputReportSize and the one actually to be sent).

So I have added missing fields in the struct and it works:

[StructLayout(LayoutKind.Explicit, Size = kSize)]
    internal struct Command2 : IInputDeviceCommandInfo
    {
        public static FourCC Type => new FourCC('H', 'I', 'D', 'O');
        public FourCC typeStatic => Type;

        internal const int kSize = InputDeviceCommand.BaseCommandSize   31; //<---- calculate manually
          
        [FieldOffset(0)] public InputDeviceCommand baseCommand; // <--- required, overlaps the rest, that's the trick to avoid Marshalling struct to byte array, that I use 
        [FieldOffset(InputDeviceCommand.BaseCommandSize   0)] public byte zero; // <--- don't know why
        [FieldOffset(InputDeviceCommand.BaseCommandSize   1)] public byte magic;
        [FieldOffset(InputDeviceCommand.BaseCommandSize   2)] public byte reportId;
        [FieldOffset(InputDeviceCommand.BaseCommandSize   3)] public short payload;
      
         
        public static Command2 Create(byte id, short payload)
        {
            return new Command2
            {
                baseCommand = new InputDeviceCommand(Type, kSize),
                magic = 0x7e,
                reportId = id,
                payload = payload
            };
        }
    }

I hope someone will benefit from this.

  •  Tags:  
  • Related