abratchik / HIDPowerDevice

This project allows to use Arduino Leonardo or Arduino Pro Micro as an intelligent UPS controller.
136 stars 37 forks source link

LIB HID GENERIC ? #5

Open huSenechal opened 1 year ago

huSenechal commented 1 year ago

Hello,

I want to make a communication between an arduino micro pro and a vive tracker in USB HID, do you think I could use your library HID.h/HID.c as a generic library to do that ?

I have to send some particular descriptor to be able to communicate.

image

regards

abratchik commented 1 year ago

Hi Hugo, of course you can do it. Moreover, it was designed exactly for that - to extend the stock HID library in order to support the control pipe for USB HID. You may check this PR: https://github.com/arduino/ArduinoCore-avr/pull/387/commits/87a2b7acb619eb81b4fe51822199c36a899eff26 Regards,, Alex 20.02.2023, 16:56, "Hugo SENECHAL" @.>: Hello,I want to make a communication between an arduino micro pro and a vive tracker in USB HID, do you think I could use your library HID.h/HID.c as a generic library to do that ?I have to send some particular descriptor to be able to communicate.regards—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you are subscribed to this thread.Message ID: @.>  --  Regards, Alex Bratchik 

huSenechal commented 1 year ago

Hi, thanks for your answer, I tried to use your HID library but what I did, didn't work. Here is how I use your library:

In void loop: HID().begin(); uint8_t host_type = 3; // (1=PC, 2=PHONE, 3=ACCESSORY) uint8_t charge_enable = 0; // Reserved uint8_t os_type = 0; // Reserved

FeatureReportB3 report1(host_type, charge_enable, os_type);
HID().SetFeature(0, (uint8_t *) &report1, sizeof(FeatureReportB3));
HID().SendReport(0, (uint8_t *) &report1, sizeof(FeatureReportB3));

And this is what my FeatureReportB3 looks like:

struct attribute((packed)) FeatureReportB3 { uint8_t address = 0xB3; uint8_t payload_size = 3; uint8_t host_type; // (1=PC, 2=PHONE, 3=ACCESSORY) uint8_t charge_enable; // Reserved uint8_t os_type; // Reserved //uint8_t lfp_config; // Reserved

FeatureReportB3(uint8_t host_type = 3, uint8_t charge_enable = 0, uint8_t os_type = 0) : host_type(host_type), charge_enable(charge_enable), os_type(os_type) {} };

I have the impression that my arduino micro pro does not send anything on USB port. Is my library usage good? I just want to send features report like show on the image I posted in my first message.

Thank you in advance for your response and your time.

Regards Hugo,

abratchik commented 1 year ago

Hi Hugo, The SetFeature has 3 parameters. The first one is the feature ID, shoudl be equal to the feature ID in the HID Descriptor, which you are planning to implement. It cannot be zero.The second is the reference to the variable in your sketch, which you want to expose to the host.The third is the size of the variable in bytes. I never tried to expose a structure variable as a feature, not sure if its a good idea. Probably will work since we are converting the the structure to a byte array, but then you will need to interpret this on the host side. Also one more point. Features are different from Reports. When you use Reports, your device is sending a message to the host. This is more like a push scenario. Features do not send anything - it is the host duty to read the feature value and interpret it. When you call HID.SetFeature(), you are exposing your local arduino variable to the host but then it will be up to the host when to read it. This is a pull scenario. You may check the example sketch for the UPS, it should be clear from the code how it works. Usually, you need to call SetFeature only once in your sketch in the setup() and not in the loop for sure. Once you call it, the variable address is stored internally in the HID library, Whenever the host is calling for GetFeature, the HID protocol extracts the value of your variable and returns it to the host. This happens asynchronously outside of your loop. Regards, Alex 08.03.2023, 17:00, "Hugo SENECHAL" @.>: Hi, thanks for your answer, I tried to use your HID library but what I did, didn't work. Here is how I use your library:In void loop:HID().begin();uint8_t host_type = 3; // (1=PC, 2=PHONE, 3=ACCESSORY)uint8_t charge_enable = 0; // Reserveduint8_t os_type = 0; // ReservedFeatureReportB3 report1(host_type, charge_enable, os_type); HID().SetFeature(0, (uint8_t ) &report1, sizeof(FeatureReportB3)); HID().SendReport(0, (uint8_t ) &report1, sizeof(FeatureReportB3)); And this is what my FeatureReportB3 looks like:struct attribute((packed)) FeatureReportB3 {uint8_t address = 0xB3;uint8_t payload_size = 3;uint8_t host_type; // (1=PC, 2=PHONE, 3=ACCESSORY)uint8_t charge_enable; // Reserveduint8_t os_type; // Reserved//uint8_t lfp_config; // ReservedFeatureReportB3(uint8_t host_type = 3, uint8_t charge_enable = 0, uint8_t os_type = 0): host_type(host_type), charge_enable(charge_enable), os_type(os_type) {}};I have the impression that my arduino micro pro does not send anything on USB port. Is my library usage good? I just want to send features report like show on the image I posted in my first message.Thank you in advance for your response and your time.Regards Hugo,—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you commented.Message ID: @.>  --  Regards, Alex Bratchik 

huSenechal commented 1 year ago

Hello, thank you for your answer. Here is a new proposal:

include "HID.h"

uint8_t setFeatureB3[5] = {0xB3, 0x03, 0x03, 0x01, 0x01}; //{address, payloadSize, hostType, charge enable, osType} uint8_t setFeatureB4[8] = {0xB4, 10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; //{address, payloadSize, tagIndex, buttons, padX, padY, trigger, batteryLevel}

void setup() {
HID().begin(); HID().SetFeature(HID_SET_REPORT, setFeatureB3, sizeof(setFeatureB3)); HID().SetFeature(HID_SET_REPORT, setFeatureB4, sizeof(setFeatureB4)); } void loop() {

}

But now that I've done my two setFeature in the setup, how do I communicate with my device to send it information? Can I modify my setFeatureB4 array and send it with the SendReport() function like in your UPS example?

I have absolutely no control over the system (HTC vive tracker) the only thing I have is the image I posted above where I understand that two HID reports must be sent. My goal is to be able to send the position of a joystick.

Thank you in advance for your response.

Regards Hugo,

abratchik commented 1 year ago

Hi, first, your host needs to support the HID device of the type, which you are planning to implement. This is a mandatory requirement. If you plan to make your device HID-compliant, you need to ensure your HID descriptor is following this specification: https://www.usb.org/sites/default/files/hut1_4.pdf. Your example doesn't have any code related to the descriptor declaration and initialization, so I doubt it will work.You may check the example here how the descriptor should look like. You also need to pass your descriptor to the HID library, something like: static const uint8_t _hidReportDescriptor[] PROGMEM = { }; static HIDSubDescriptor node(_hidReportDescriptor, sizeof (_hidReportDescriptor)); HID().AppendDescriptor(&node); Second, the first parameter of the SetFeature is an ID of a Feature, which you are exposing to the host. This ID must be also present in the HID descriptor. You cannot have more than one feature sharing the same ID. If you call SetFeature with the same ID more than once in your sketch it means that only the last call will be in effect. This function doesn't send anything, it just associates the feature ID with the address of a variable (setFeatureB4 in your example). Third, as I explained in my previous email, there are two scenarios how the information is passed between the device  and the host - the "push" and the "pull". SetFeature is for the pull and SendReport is for the push. Which of the two scenarios is to be used is defined in the descriptor. If you plan to make your device HID-compliant, your descriptor should follow the specs for the class of the device you are implementing (Gamepad, as an example). If it does then there is a good chance that your host will understand how to handle your device correctly. Lastly, if you are implementing joystick, you should be able to use the standard HID library, since all the joysticks are typically using the push only. There are plenty of examples in the internet how to implement joystick in Arduino, I'm sure you can find something similar to your case. Hope this helps. Cheers, Alex  09.03.2023, 17:44, "Hugo SENECHAL" @.>: Hello, thank you for your answer. Here is a new proposal:#include "HID.h"uint8_t setFeatureB3[5] = {0xB3, 0x03, 0x03, 0x01, 0x01};//{address, payloadSize, hostType, charge enable, osType}uint8_t setFeatureB4[8] = {0xB4, 10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};//{address, payloadSize, tagIndex, buttons, padX, padY, trigger, batteryLevel}void setup() {HID().begin();HID().SetFeature(HID_SET_REPORT, setFeatureB3, sizeof(setFeatureB3));HID().SetFeature(HID_SET_REPORT, setFeatureB4, sizeof(setFeatureB4));}void loop() {}But now that I've done my two setFeature in the setup, how do I communicate with my device to send it information? Can I modify my setFeatureB4 array and send it with the SendReport() function like in your UPS example?I have absolutely no control over the system (HTC vive tracker) the only thing I have is the image I posted above where I understand that two HID reports must be sent. My goal is to be able to send the position of a joystick.Thank you in advance for your response.Regards Hugo,—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you commented.Message ID: @.>  --  Regards, Alex Bratchik