How to use USB HID Feature report? - usb

I'm having another issue, I'm building a HID device (Joystick) that uses Rx, Ry, Rz and in some point I need to do a calibration on the device side. I need to send data from PC(Host) to the device and back for this calibration purpose using custom PC client software and I'm willing to use FEATURE report, which I think is suitable for this purpose.
My INPUT report handling the Rx, Ry, Rz axes works with no problem. I'm sending 3 16-bit (total of 6 bytes) values into the device and it works perfectly.
But I'm having trouble with the FEATURE report, I searched like half the internet already but couldn't manage to get the FEATURE reports to work. I'm using HIDAPITESTER command line tool for the testing purposes. I need to send data from-to host when I need to. As to my information, FEATURE reports are right for this purpose, they are controlled from the host side and are bidirectional. The data contained will be always the same - 64-bytes of data (I actually need only 38 bytes).
I really think that the only problem is with my report descriptor, could you advise on what I'm doing wrong?
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x04, // Usage (Joystick)
0xA1, 0x01, // Collection (Application)
0x09, 0x33, // Usage (Rx)
0x09, 0x34, // Usage (Ry)
0x09, 0x35, // Usage (Rz)
0x15, 0x00, // Logical Minimum (0)
0x26, 0x00, 0x10, // Logical Maximum (4096)
0x75, 0x10, // Report Size (16)
0x95, 0x03, // Report Count (3)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x00, // Usage (Undefined)
0x15, 0x00, // Logical Minimum (0)
0x26, 0x00, 0x10, // Logical Maximum (4096)
0x75, 0x10, // Report Size (16)
0x95, 0x20, // Report Count (32)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, // End Collection
I have tried another report descriptors, but they always resulted in not being able to enumerate.
The USB stack I'm using is M-Stack.
I'm using endpoints 0x81 for IN and 0x01 for OUT packets.
The device is PIC18F2458 but I don't think this has any thing to do with this issue really.
Thank you for any valuable help, I'm really desperate for past two days already.

Related

USB HID report descriptor, multiple reports

I am trying to emulate USB Multimedia keyboard, but stuck at HID report descriptor. I am manage to define "single report" descriptor, but then stuck when I am trying to add additional report id. Below example was minimized, in final application I am trying to put more data in single report, also MUTE function is choosen to make it testing simple.
0x09, 0x01, // Usage (Consumer Control)
0xA1, 0x01, // Collection (Application)
0x85, 0x01, // Report ID (1)
0x05, 0x0C, // Usage Page (Consumer)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x01, // Report Count (1)
0x09, 0xE2, // Usage (Mute)
0x81, 0x62, // Input (Data,Var,Abs,No Wrap,Linear,No Preferred State,Null State)
0x85, 0x02, // Report ID (2)
0x05, 0x0C, // Usage Page (Consumer)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x01, // Report Count (1)
0x09, 0xE2, // Usage (Mute)
0x81, 0x62, // Input (Data,Var,Abs,No Wrap,Linear,No Preferred State,Null State)
0xC0, // End Collection
The result is, when I sent 0x01 0x01 (request 1, bit 1) computer (Windows) mute sounds, but when the USB device sent 0x02 0x01 (request 2, bit 2) over same endpoint, computer ignore it. I tried to group reports into Logical Collection, but it does not chane anything.
How this descriptor should look like?
PS there was obvious mistake in descriptor (missing Input entity for report #2) on the first post, but it was done when I simplified the descriptor for purpose of this question.
Accidently I solved the problem. More, the minimal example shown above is not working, but the issue was same as in my full implementation.
For some reason for Windows each report must be aligned to 8 bits, otherway the last byte which is "not complete" does not trigger expected action. The solution is to add byte alignment bits to the report.

Teensy 3.2 outgoing packet payload limit 8 bytes

I would like to emulate 3M USB touchscreen controller. I found exact protocol and slightly changed the source code in teensy3 library. I changed VendorID and ProductID. Also I added my USB isr handler and send protocol specific report having size 11 bytes. I use Wireshark to sniff usb and I see that I can only send 8 bytes. If I try even 9 byte there is no payload at all.
I changed wMaxPacketSize in endpoint descriptor. Then I changed size of 'pressure' report size from 8 to 11, but it also didn't help. I found out that low speed devices allow only 8bytes per packet. But here author of teensy tells that it operates on 12Mbit/s and therefore should support 64bytes.
Could anyone tell me where am I wrong? How to make it send more than 8 bytes at once?
I'm hanging out with that about 2 days with no success.
-- Update --
Why do you want to change the amount of bytes?
As I said I need to make an emulator of 3M touchscreen. So, it has it's own protocol you can see the spec here. Page 18 describes touch report sent to host when touch occurs. It's size is 11 bytes.
I changed void usb_touchscreen_update_callback(void) that is defined in usb_touch.c to make it to send necessary structure (ref to spec page 18).
Here I found out that I can't send more then 8 bytes. If I try to send the payload voids at all.
What descriptor are you using?
I use endpoint descriptor that regards to an interface with bInterfaceClass field assigned 3 (HID). In this endpoint descriptor that is originally used for Touchscreen emulator by teensy lib I set wMaxPacketSize to 11. Originally it was set to 8. These interface, HID interface, endpoint descriptors are defined if MULTITOUCH_INTERFACE macro available.
#ifdef MULTITOUCH_INTERFACE
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
MULTITOUCH_INTERFACE, // bInterfaceNumber
0, // bAlternateSetting
1, // bNumEndpoints
0x03, // bInterfaceClass (0x03 = HID)
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0, // iInterface
// HID interface descriptor, HID 1.11 spec, section 6.2.1
9, // bLength
0x21, // bDescriptorType
0x11, 0x01, // bcdHID
0, // bCountryCode
1, // bNumDescriptors
0x22, // bDescriptorType
LSB(sizeof(multitouch_report_desc)), // wDescriptorLength
MSB(sizeof(multitouch_report_desc)),
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
MULTITOUCH_ENDPOINT | 0x80, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
MULTITOUCH_SIZE, 0, // wMaxPacketSize
1, // bInterval
#endif // KEYMEDIA_INTERFACE
There is MULTITOUCH_SIZE macro is set by header to 11.
Farther investigation cause I found out that joystick has 12 bytes packet length and it really sends them while having the same interface, HID interface and endpoint descriptors as touchscreen has. So looks like they only different in HID report descriptors
This HID report descriptor regards to touchscreen
static uint8_t multitouch_report_desc[] = {
0x05, 0x0D, // Usage Page (Digitizer)
0x09, 0x04, // Usage (Touch Screen)
0xa1, 0x01, // Collection (Application)
0x09, 0x22, // Usage (Finger)
0xA1, 0x02, // Collection (Logical)
0x09, 0x42, // Usage (Tip Switch)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x01, // Report Count (1)
0x81, 0x02, // Input (variable,absolute)
0x09, 0x51, // Usage (Contact Identifier)
0x25, 0x7F, // Logical Maximum (127)
0x75, 0x07, // Report Size (7)
0x95, 0x01, // Report Count (1)
0x81, 0x02, // Input (variable,absolute)
0x09, 0x30, // Usage (Pressure)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x0b, // Report Size (11)
// 0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1)
0x81, 0x02, // Input (variable,absolute)
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x26, 0xFF, 0x7F, // Logical Maximum (32767)
0x65, 0x00, // Unit (None) <-- probably needs real units?
0x75, 0x10, // Report Size (16)
0x95, 0x02, // Report Count (2)
0x81, 0x02, // Input (variable,absolute)
0xC0, // End Collection
0x05, 0x0D, // Usage Page (Digitizer)
0x27, 0xFF, 0xFF, 0, 0, // Logical Maximum (65535)
0x75, 0x10, // Report Size (16)
0x95, 0x01, // Report Count (1)
0x09, 0x56, // Usage (Scan Time)
0x81, 0x02, // Input (variable,absolute)
0x05, 0x0D, // Usage Page (Digitizers)
0x09, 0x55, // Usage (Contact Count Maximum)
0x25, MULTITOUCH_FINGERS, // Logical Maximum (10)
0x75, 0x0b, // Report Size (11)
// 0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1)
0xB1, 0x02, // Feature (variable,absolute)
0xC0 // End Collection
};
And this one to joystick
static uint8_t joystick_report_desc[] = {
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x04, // Usage (Joystick)
0xA1, 0x01, // Collection (Application)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x20, // Report Count (32)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (Button #1)
0x29, 0x20, // Usage Maximum (Button #32)
0x81, 0x02, // Input (variable,absolute)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x07, // Logical Maximum (7)
0x35, 0x00, // Physical Minimum (0)
0x46, 0x3B, 0x01, // Physical Maximum (315)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
0x65, 0x14, // Unit (20)
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x39, // Usage (Hat switch)
0x81, 0x42, // Input (variable,absolute,null_state)
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x01, // Usage (Pointer)
0xA1, 0x00, // Collection ()
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x03, // Logical Maximum (1023)
0x75, 0x0A, // Report Size (10)
0x95, 0x04, // Report Count (4)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x09, 0x32, // Usage (Z)
0x09, 0x35, // Usage (Rz)
0x81, 0x02, // Input (variable,absolute)
0xC0, // End Collection
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x03, // Logical Maximum (1023)
0x75, 0x0A, // Report Size (10)
0x95, 0x02, // Report Count (2)
0x09, 0x36, // Usage (Slider)
0x09, 0x36, // Usage (Slider)
0x81, 0x02, // Input (variable,absolute)
0xC0 // End Collection
};
Then I replaced the first one with the second one and after that I have complete 11 bytes sent via this endpoint. Then I changed first byte 0x01 (Generic Desktop) to 0x0d (Digitizer) and now I have my cursor on Linux moves. On Windows driver is failed to install unfortunately.
Also it was necessary to change touchscreen interface to 0 and endpoint to 1 due to original device has only one interface and one endpoint.
But anyway I still don't know the reason why first HID report descriptor prevents from sending more than 8 bytes. So I ended up on reading this article https://eleccelerator.com/tutorial-about-usb-hid-report-descriptors/.
Also I need no to know everything about USB. I just need the level of understanding to make this emulator work properly.
-- Update --
I'm on Linux, so I use Wireshark. But the issue is that this 3M original device is not HID device, so it has no HID report descriptor. The device populate only one interface that marked as Vendor specific. The field bInterfaceClass has 0xff value.
On the picture below are original device's descriptors
And here descriptors of teensy
As you can see the only difference is in bInterfaceClass value that is for teensy 0x03 (also bInterval in endpoint descriptor is slightly different, but I suppose it's value doesn't matter for this issue).
If I try to get rid of HID report descriptor and make interface equal to 0xff the device doesn't work. Also if I try to get rid of unnecessary extra interfaces (that comes from teensy) having 1, 2, 3 indexes it doesn't work.
Following picture shows the result where there is only one interface and endpoint as original device provides see the first pic (dark one). And the field bInterfaceClass is set to 0xff Vendor specific. The communication to host looks normally except there is no response to USB_INTERRUPT in from endpoint. While the original device has the response.
Is there any subtle things regarding to non HID devices? How to make the device to be non HID device?
Do you notice that nobody answers your question here? Not even a comment! There are very very few USB experts in the world. I worked over one year with USB at the lowest level (bits and bytes) and I learned a lot. And for the difficult parts I had to buy an expensive USB analyzer from Beagle. It is a very hard work because you simply don't get help from nobody with your USB problems. And Paul Stoffregen (who knows) will not have time to help you with this. He is busy with his own stuff. He hardly answers questions in his forum.
1:
You are correct that Low speed devices allow a maximum of 8 bytes while Full speed allows 64 bytes.
2:
If I understand you correctly you use the touchscreen descriptor of Teensyduino to emulate a 3M touchscreen? This is wrong. If you want to emulate a 3M touchscreen you MUST use the exactly same descriptors as the real 3M touchscreen does. This is the only guarantee that your emulator will work the same on all operating systems using the same drivers as the real 3M touchscreen. If you have this touchscreen available use the software USBLyzer to extract the descriptors from the real 3M touchscreen.
3:
You can also use USBLyzer to verify your own descriptors. BUT there is a very big catch: Windows remembers USB devices in the registry. When you make changes in the descriptor you must always assign a new ProductID in your Teensy so Windows will detect it as a new device. Otherwise your changes on the descriptors will have no effect or will not work.
4:
Your main problem seems to be the same problem which I had when I worked on this project: https://www.codeproject.com/Articles/1001891/A-USB-HID-Keyboard-Mouse-Touchscreen-emulator-with
The code in TeensyDuino (written by Paul Stoffregen) is hard to understand. He optimized the code for only one purpose: To use as less as possible RAM and store all the descriptor stuff in the non volatile memory of the Teensy. For that reason all his definitions are hard coded. It is a very hard work to understand his code and even harder to modify it without breaking it.
5:
I set wMaxPacketSize to 11.
This is wrong. Use the original 3M descriptor! Apart from that this does not solve your problem. This value is only an information for the driver. It does not affect the amount of bytes sent in Teensy code.
6.
Also I added my USB isr handler...
I don't know why should do this? This is not necessary.
7.
Here I found out that I can't send more then 8 bytes. If I try to send the payload voids at all.
Where do you see that? You are missing information here. Where do you see that the payload is void? As you already discovered there IS no limitation because the joystick sends more than 8 bytes.
Did you analyze the packets with USBLyzer? Without this information it is difficult to answer. Did you adapt the values in the section
// **************************************************************
// USB Descriptor Sizes
// **************************************************************
Use USBlyzer to capture the packets sent from the real 3M touch screen and compare them with the packets of your Teensy. Obviously ALL the descriptors must be identical before doing this.
I'm hanging out with that about 2 days with no success.
You will need far more time to learn USB. You need a lot programming experience, reverse engineering experience and a lot of patience and intelligence.
The most important thing is that you first study the code of Paul Stoffregen until you understood it 100%. Otherwise changing a value here and there without understanding what you are doing, you will just waste your time.

MSP430: Trying to learn interrupts using button and LED blinking

I'm learning the MSP430 for the first time, and trying to teach myself interrupts.
I'm trying to follow these examples 1 2 3 4.
I'm using an MSP430FR6989 eval board and writing the code in Code Composer Studio.
I'm trying to have the REDLED on the board toggle when I push the P1.1 button (ie, using an interrupt).
I'm able to blink the LEDs using separate code, so I know the board works.
This is the code that i'm trying to get to work.
#include <msp430.h>
#include "driverlib.h"
int main(void) //Main program
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
P1DIR |= BIT0; // Set P1.0 to output and P1.3 to input direction
P1OUT &= ~BIT0; // set P1.0 to Off
P1IE |= BIT3; // P1.3 interrupt enabled
P1IFG &= ~BIT3; // P1.3 interrupt flag cleared
__bis_SR_register(GIE); // Enable all interrupts
while(1) //Loop forever, we'll do our job in the interrupt routine...
{}
}
#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void)
{
P1OUT ^= BIT0; // Toggle P1.0
P1IFG &= ~BIT3; // P1.3 interrupt flag cleared
}
When I press the button, the LED doesn't turn on and I'm not sure why.
I'd appreciate any help!
To show a working LED Blink program as requested by user #CL
#include <msp430.h>
#include "driverlib.h"
int main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Disables the watchdog
PM5CTL0 &= ~LOCKLPM5; // allows output pins to be set... turning off pullups
P1DIR = BIT0; // Make a pin an output... RED LED
long x = 0; // Will be used to slow down blinking
while(1) // Continuously repeat everything below
{
for(x=0 ; x < 30000 ; x=x+1); // Count from 0 to 30,000 for a delay
P1OUT = BIT0; // Turn red LED light on
for(x=0 ; x < 30000 ; x=x+1); // Count from 0 to 30,000 for a delay
P1OUT ^= BIT0; // Turn off the red LED light
}
}
On the MSP430FR6989 LaunchPad, P1.3 is not connected to a button. Use P1.1 instead.
The button requires a pull-up resistor, so you have to configure it in P1REN and P1OUT.
It might be a good idea to configure the signal edge for the interrupt in P1IES.
You have to clear LOCKLPM5 to activate the port settings.
All this can be seen in the msp430fr69xx_p1_03.c example program.

Why does Metal slow down when the number of fragment shader arguments increases?

I have a very basic fragment shader that accepts an array of array textures defined like so:
fragment float4 shader(RasterizerData in [[ stage_in ]],
sampler sampler2d [[ sampler(0) ]],
const array<texture2d_array<half>, 5> textures [[ texture(0) ]]) {
return float4(textures[in.textureIndex].sample(sampler2d, in.textureCoordinate, in.textureSlice));
}
I'd like to pass a variable number of textures to this shader. Each texture is an array texture and each array texture is a different size. (Hence why I can't just pass in a single array texture.)
In the code above, I've arbitrarily defined the array size to be 5 because I normally have only 1 texture. If I have less than 5 textures, then the fragment indexes are not set in my application code.
My app code is similar to this:
for (int i = 0; i < textures.size(); ++i) {
[renderEncoder setFragmentTexture:textures[i] atIndex:i];
}
With an array size of 5, performance is fine. However, if the only change I make is to redefine the size of the array to 64 in the shader, then overall rendering performance plummets. No other changes are made, which means that most of the fragment texture indexes are not set.
Why does this change impact performance so much?
The GPU debugger shows that most of the time is spent in my render encoder's drawIndexedPrimitives. (24.04 ms) When I declare a much smaller array size, then I can easily achieve 60fps.
On macOS 10.14, MacBook Pro 13" TB 2016.

Glut Solid Shape Renders as Wire when calling GLClear in JOGL

I am trying to render some simple solid shapes in JOGL (and Eclipse) and then step through them 'layer' by 'layer'; but when I add the glClear method all I get are wire frames, not the filled shape!? If I comment that line out (as below) displays the solid shape but 'fills' to the largest the shape will be and then does not shrink down again. e.g with a sphere the front half is fine but the back half comes out as a solid cylinder if that makes sense.
public void render(GLAutoDrawable gLDrawable)
{
GL2 gl = gLDrawable.getGL().getGL2();
**//gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);**
gl.glColor3b((byte) 0, (byte) 127, (byte) 0);
gl.glLoadIdentity();
gl.glTranslatef(500, 350, -300);
glut.glutSolidSphere(300.0, 20, 16);
gl.glTranslatef(-500, -350, 300);
gl.glEnd();
gl.glFlush();
}
Any help would be much appreciated, Ic an post more of the code if needed.
Thanks
Tim
EDITED To make more sense
insert this before you create your sphere... It will tell Opengl to fill the next polygons that are drawn...
gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL);
if you want the wireframe again, just call:
gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_LINE);
:)