Hello dear FreeBSD community.
I'm trying to access a joystick (or better said two) through usbhid(3)
However, when using hid_start_parse (desc, 1, 2) I can't only receive the item with the 2nd report ID (I also get the data from the Item with the Report ID 1). So I wanted to ask if I'm doing something wrong or if it's usbhid(3) which doesn't allow me access. The joysticks are located at /dev/uhid1, (they share one node) that's why it's hardcoded.
My descriptor goes as following:
Here is my code which is partially based on the BSD driver for SDL (which isn't working properly either):
It would always output both reports. Even when printing report_ID (from the item) together with the axis value. report_ID would remain constant while it outputs the value from two different items (which should also have different report_IDs). I am quite inexperienced in matters of developing so please forgive me my non-professionalism.
EDIT:
I have a workaround for this, after having parsed one report, I simply toggle the joystick number. But maybe there is a better solution out there.
I'm trying to access a joystick (or better said two) through usbhid(3)
However, when using hid_start_parse (desc, 1, 2) I can't only receive the item with the 2nd report ID (I also get the data from the Item with the Report ID 1). So I wanted to ask if I'm doing something wrong or if it's usbhid(3) which doesn't allow me access. The joysticks are located at /dev/uhid1, (they share one node) that's why it's hardcoded.
My descriptor goes as following:
Code:
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x04, // Usage (Joystick)
0xA1, 0x01, // Collection (Application)
0x85, 0x01, // Report ID (1)
0xA1, 0x02, // Collection (Logical)
0x75, 0x08, // Report Size (8)
0x95, 0x04, // Report Count (4)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x35, 0x00, // Physical Minimum (0)
0x46, 0xFF, 0x00, // Physical Maximum (255)
0x09, 0x32, // Usage (Z)
0x09, 0x35, // Usage (Rz)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
0x25, 0x07, // Logical Maximum (7)
0x46, 0x3B, 0x01, // Physical Maximum (315)
0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter)
0x09, 0x39, // Usage (Hat switch)
0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
0x65, 0x00, // Unit (None)
0x75, 0x01, // Report Size (1)
0x95, 0x0C, // Report Count (12)
0x25, 0x01, // Logical Maximum (1)
0x45, 0x01, // Physical Maximum (1)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x0C, // Usage Maximum (0x0C)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
0x75, 0x01, // Report Size (1)
0x95, 0x08, // Report Count (8)
0x25, 0x01, // Logical Maximum (1)
0x45, 0x01, // Physical Maximum (1)
0x09, 0x01, // Usage (0x01)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
0xA1, 0x02, // Collection (Logical)
0x75, 0x08, // Report Size (8)
0x95, 0x04, // Report Count (4)
0x46, 0xFF, 0x00, // Physical Maximum (255)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x09, 0x02, // Usage (0x02)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, // End Collection
0xC0, // End Collection
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x04, // Usage (Joystick)
0xA1, 0x01, // Collection (Application)
0x85, 0x02, // Report ID (2)
0xA1, 0x02, // Collection (Logical)
0x75, 0x08, // Report Size (8)
0x95, 0x04, // Report Count (4)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x35, 0x00, // Physical Minimum (0)
0x46, 0xFF, 0x00, // Physical Maximum (255)
0x09, 0x32, // Usage (Z)
0x09, 0x35, // Usage (Rz)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
0x25, 0x07, // Logical Maximum (7)
0x46, 0x3B, 0x01, // Physical Maximum (315)
0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter)
0x09, 0x39, // Usage (Hat switch)
0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
0x65, 0x00, // Unit (None)
0x75, 0x01, // Report Size (1)
0x95, 0x0C, // Report Count (12)
0x25, 0x01, // Logical Maximum (1)
0x45, 0x01, // Physical Maximum (1)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x0C, // Usage Maximum (0x0C)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
0x75, 0x01, // Report Size (1)
0x95, 0x08, // Report Count (8)
0x25, 0x01, // Logical Maximum (1)
0x45, 0x01, // Physical Maximum (1)
0x09, 0x01, // Usage (0x01)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
0xA1, 0x02, // Collection (Logical)
0x75, 0x08, // Report Size (8)
0x95, 0x04, // Report Count (4)
0x46, 0xFF, 0x00, // Physical Maximum (255)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x09, 0x02, // Usage (0x02)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, // End Collection
0xC0, // End Collection
// 202 bytes, generated by http://eleccelerator.com/usbdescreqparser/
Here is my code which is partially based on the BSD driver for SDL (which isn't working properly either):
Code:
#include <iostream>
#include <usbhid.h>
#include <dev/usb/usbhid.h>
#include <fcntl.h>
using namespace std;
/*
#define HUP_GENERIC_DESKTOP 0x0001
#define HUG_JOYSTICK 0x0004
#define HUG_GAME_PAD 0x0005
#define HUP_BUTTON 0x0009
*/
enum
{
JOYAXE_X,
JOYAXE_Y,
JOYAXE_Z,
JOYAXE_SLIDER,
JOYAXE_WHEEL,
JOYAXE_RX,
JOYAXE_RY,
JOYAXE_RZ,
JOYAXE_count
};
static int
usage_to_joyaxe(unsigned usage)
{
int joyaxe;
switch (usage) {
case HUG_X:
joyaxe = JOYAXE_X;
break;
case HUG_Y:
joyaxe = JOYAXE_Y;
break;
case HUG_Z:
joyaxe = JOYAXE_Z;
break;
case HUG_SLIDER:
joyaxe = JOYAXE_SLIDER;
break;
case HUG_WHEEL:
joyaxe = JOYAXE_WHEEL;
break;
case HUG_RX:
joyaxe = JOYAXE_RX;
break;
case HUG_RY:
joyaxe = JOYAXE_RY;
break;
case HUG_RZ:
joyaxe = JOYAXE_RZ;
break;
default:
joyaxe = -1;
}
return joyaxe;
}
void* buffer;
int main()
{
int id = 0;
/* Read the default USB HID usage table. */
//buffer = new void;
hid_init(NULL);
int fd;
report_desc_t desc;
hid_data_t hdata;
hid_item_t hitem;
int v;
//struct joystick gameport;
char *path = {"/dev/uhid1"};
fd = open(path, O_RDONLY);
if (fd == -1)
{
cout << "Failed to open device, check permission\n";
}
//cout << hid_get_report_id (fd);
id = hid_get_report_id (fd);
desc = hid_get_report_desc(fd);
int report_size = hid_report_size(desc,hid_input, id);
buffer = malloc(report_size);
hdata = hid_start_parse(desc, 1, id ); // 0 Input 1 Output 2 Feature
int troll = hid_collection;
while (hid_get_item(hdata, &hitem) > 0)
{
char *sp;
const char *s;
int test = HID_PAGE(hitem.usage);
// cout << hitem.kind << endl;
switch (hitem.kind) {
case hid_collection:
switch (HID_PAGE(hitem.usage))
{
case HUG_JOYSTICK:
case HUG_GAME_PAD:
s = hid_usage_in_page(hitem.usage);
cout << "s is:" << s;
}
break;
case hid_input:
switch (HID_PAGE(hitem.usage))
{
case HUP_GENERIC_DESKTOP:
{
unsigned usage = HID_USAGE(hitem.usage);
cout << "Usage found: " << usage << endl;
}
break;
case HUP_BUTTON:
{
cout << "Button found" << endl;
}
break;
default:
break;
}
break;
default: break;
}
}
hid_end_parse(hdata);
while (read(fd, buffer, report_size) == report_size)//Read the block device into buffer, If a new complete report is available
{
hdata = hid_start_parse(desc, 1, 2 ); // 0 Input 1 Output 2 Feature, Start parsing the descriptor
//id = hid_get_report_id (fd);
//cout << "ID is:" << id << endl;
// int joyNum = 0;
if (hdata == NULL) {
/*fprintf(stderr, "%s: Cannot start HID parser\n", joy->hwdata->path);*/
continue;
}
while (hid_get_item(hdata, &hitem) > 0) {//As soon as there are any items left
int nbutton = 0;
switch (hitem.kind) {//Get the kind of the item
case hid_input://If it is an Input device
switch (HID_PAGE(hitem.usage)) {//Check what it' good for
case HUP_GENERIC_DESKTOP://If it is meant for use at the desktop / If the page is Desktop
{
unsigned usage = HID_USAGE(hitem.usage);
int joyaxe = usage_to_joyaxe(usage); //Map it's usage towards the struct defined in joyaxe
if (joyaxe >= 0) {//If it matches any axe
// naxe = joy->hwdata->axis_map[joyaxe];//Set naxe to the current axis
/* scaleaxe */
v = hid_get_data(buffer, &hitem); //Get the data
v -= (hitem.logical_maximum + //Get the maximum and minimum reported by the descriptor
hitem.logical_minimum + 1) / 2; // And match the scale for use in SDL
v *= 32768 /((hitem.logical_maximum - hitem.logical_minimum + 1) / 2);
cout << "Joy: " << hitem.report_ID << " Axis: " << joyaxe << " Value: " << v << endl;
// if (v != joy->axes[naxe]) {
// SDL_PrivateJoystickAxis(joy, naxe, v);
// }
} else if (usage == HUG_HAT_SWITCH) { // If it is a HAT_SWITCH
// v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem); // Get the data
// SDL_PrivateJoystickHat(joy, 0, // Match the HAT value reported to SDL
// hatval_to_sdl(v) -
// hitem.logical_minimum);
}
break;
}
case HUP_BUTTON://If it's a Button
v = hid_get_data(buffer, &hitem);//Get the data from it
//if (joy->buttons[nbutton] != v) {//If state changed
// SDL_PrivateJoystickButton(joy, nbutton, v);
//}
// cout << "Button: " << nbutton << " pressed:" << v << endl; //and print it out
nbutton++;//Iterate through nbutton
break;
default:
continue;
}
break;
default:
break;
}
}
hid_end_parse(hdata);
}
cout << "Ending" << endl;
cin.ignore();
return 0;
}
It would always output both reports. Even when printing report_ID (from the item) together with the axis value. report_ID would remain constant while it outputs the value from two different items (which should also have different report_IDs). I am quite inexperienced in matters of developing so please forgive me my non-professionalism.
EDIT:
I have a workaround for this, after having parsed one report, I simply toggle the joystick number. But maybe there is a better solution out there.