I'm trying to get two identical joystics (Saitek cyborg 3D) running with the USB-Host-Shield on a Mega 2560 and an USB-Hub.
I already get the event-messages of both of them:
#include <usbhid.h>
#include <hiduniversal.h>
#include <usbhub.h>
// Satisfy IDE, which only needs to see the include statment in the ino.
#ifdef dobogusinclude
#include <spi4teensy3.h>
#endif
#include <SPI.h>
#include "hidjoystickrptparser.h"
USB Usb;
USBHub Hub(&Usb);
HIDUniversal Hid1(&Usb); // first Joystick
HIDUniversal Hid2(&Usb); // second Joystick
JoystickEvents Joy1Events;
JoystickEvents Joy2Events;
JoystickReportParser Joy1(&Joy1Events);
JoystickReportParser Joy2(&Joy2Events);
void setup() {
Serial.begin(115200);
#if !defined(__MIPSEL__)
while (!Serial); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection
#endif
Serial.println("Start");
if (Usb.Init() == -1)
Serial.println("OSC did not start.");
delay(200);
if (!Hid1.SetReportParser(0, &Joy1))
ErrorMessage<uint8_t > (PSTR("SetReportParser1"), 1);
if (!Hid2.SetReportParser(0, &Joy2))
ErrorMessage<uint8_t > (PSTR("SetReportParser2"), 1);
}
void loop() {
Usb.Task();
Serial.print("\tX1: ");
PrintHex<uint8_t > (JoystickEvents::mostRecentEvent.X, 0x80);
Serial.print("\tY1: ");
PrintHex<uint8_t > (JoystickEvents::mostRecentEvent.Y, 0x80);
Serial.print("\tX2: ");
PrintHex<uint8_t > (JoystickEvents::mostRecentEvent.Z1, 0x80);
Serial.print("\tY2: ");
PrintHex<uint8_t > (JoystickEvents::mostRecentEvent.Z2, 0x80);
Serial.print("\tRz: ");
PrintHex<uint8_t > (JoystickEvents::mostRecentEvent.Rz, 0x80);
Serial.println("");
}
My question is: How can I distinguish the events from the different joysticks.
I'm trying to get some kind of port-information from the USB-Hub. Unfortunately something like
!hid->GetAddress()
within the JoystickReportParser doesn't do the job as it always returns 0.
Any ideas?
-
look at the hub demojsotola– jsotola2018年01月29日 08:54:39 +00:00Commented Jan 29, 2018 at 8:54
-
That's what I'm doing since several days but I don't get the clue. I get message-events but how do I recognize from which port they do come? In the hub demo there is this function: PrintAllAddresses() which takes a pointer to the device. But it's called within this statement: Usb.ForEachUsbDevice(&PrintAllAddresses);Palmstroem– Palmstroem2018年01月29日 09:02:33 +00:00Commented Jan 29, 2018 at 9:02
-
In the hub demo there is this function: PrintAllAddresses() which takes a pointer to the device. But it's called within this statement: Usb.ForEachUsbDevice(&PrintAllAddresses); So how would I call something like this from within the JoytickReportParser or the eventhandler OnGamepadChanged ?Palmstroem– Palmstroem2018年01月29日 09:08:24 +00:00Commented Jan 29, 2018 at 9:08
-
Or how do I get a pointer to the device from which a message-event comes in?Palmstroem– Palmstroem2018年01月29日 09:09:42 +00:00Commented Jan 29, 2018 at 9:09
-
To be honest. I'm not so familiar with all this pointer arithmetic. All these -> :: ! * . Is still a little bit wired to me.Palmstroem– Palmstroem2018年01月29日 09:13:03 +00:00Commented Jan 29, 2018 at 9:13
2 Answers 2
Not quite the question that was asked but part of the problem.
This is a simple introduction to pointers.
int variable = 42; // Create a variable
int* pointer = &variable; // Create a pointer to the variable (by getting its address)
*pointer = 99; // Set the address to a new value
printf ("variable has the value %d", variable); // Print 99.
&x
get the address of x
*y
dereferences
the pointer y, which means it 'turns it back to a variable' (this is simplistic view which isn't really true, but will do for now).
So you could, if you wanted (which you wouldn't) do this *&z
which would be the same as doing z
.
Basically think of &
and *
as a pair of complimentary operators like - and + or * and /. (They aren't operators, but to start with it might help).
The next problem is when you do this
SomeFunction(&variable);
All function parameters in C/C++ are passed by value by default. This means the function gets a copy of them not the actual value. So if you had:
void FunctionOne (int val)
{
val = 99;
}
int val = 4;
FunctionOne(val);
printf("val = %d", val); // You will see 4 printed.
If you pass by reference then you will see 99 printed, to pass by reference you can do it one of two ways.
void FunctionTwo (int& valByRef);
void FunctionThree (int* valPointer);
FunctionTwo
only works with C++ (It will work with an Arduino).
FunctionThree
might cause a segmentation error if NULL is passed in and the function writes to it.
If it helps in my opinion pointers was one of the hardest concepts to grasp in classic C/C++ so don't worry if you don't understand it just have a play with it and see what you can do.
Calling Methods
object.method()
- Call the function method on the instance called object which is of typeX
.object->method()
- Call the function method on the instance called object which is a pointer of typeX
.object::method()
- call the function method which is a static member of class object (static means it doesn't change any data within an instance of a class)- *object->method() - Avoid this like the plague. It either means
*(object->method())
or(*object)->method()
to know you would need to look at the type of object and the return type of the function. Its easier just to bracket it to remove ambiguity.
As for *object.&method()
I've never come across that one, but that doesn't mean it doesn't exist. :)
-
Those who don't understand pointers are doomed to program in Javascript the rest of their lives.user31481– user314812018年01月29日 19:39:50 +00:00Commented Jan 29, 2018 at 19:39
-
Thank you very much for this explanation. Good explanation! What confuses me is: Sometimes you can access a property by object.method or by object.object.method then by object::method and object->method or object.&method or *object.&object::method and object.@->/!%&wtf$method and so on. These things were not made for human brains to be understood.Palmstroem– Palmstroem2018年01月29日 20:00:40 +00:00Commented Jan 29, 2018 at 20:00
-
Are you saying I'm not human? :) (See edit) Its learning a new language, and you just have to remember certain rules, the more you use them the more they become ingrained, there is no short cut :(Code Gorilla– Code Gorilla2018年01月31日 01:07:23 +00:00Commented Jan 31, 2018 at 1:07
-
Thank you very much. Superhuman! Any ideas for the original question? I'm inside a signal-handler-function and want to access an attribute of a parent or grand-parent class, but don't know how to find the right method. The documentation at felis.github.io/USB_Host_Shield_2.0/… seems to be quite comprehensive. But I don't get the clue.Palmstroem– Palmstroem2018年02月01日 18:11:28 +00:00Commented Feb 1, 2018 at 18:11
-
!Hid->GetAddress() always returns 0. Maybe I need to do something like *evt.HIDDevice.Hid->GetAddress() but all trials like that lead to compile errors.Palmstroem– Palmstroem2018年02月01日 18:20:34 +00:00Commented Feb 1, 2018 at 18:20
this could be a possible answer, in Arduino Code, the USB Host Shield 2.0 library is necessary:
#include <usbhid.h>
#include <hiduniversal.h>
#include <usbhub.h>
// Logitech Attack 3 HID report
struct GamePadEventData {
uint8_t X, Y, Z1, Z2, Rz;
} __attribute__((packed));
class JoystickEvents {
public: virtual void OnGamePadChanged(const GamePadEventData *evt, int joystick);
};
class JoystickReportParser : public HIDReportParser {
JoystickEvents *joyEvents;
uint8_t joyId;
uint8_t oldPad[sizeof(GamePadEventData)];
public: JoystickReportParser(JoystickEvents *evt, uint8_t id) : joyEvents(evt), joyId(id) {}
virtual void Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
};
void JoystickReportParser::Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
if (!is_rpt_id && len == sizeof(GamePadEventData)) {
// Checking if there are changes in report since the method was last called
bool match = (sizeof(oldPad) == len) && (memcmp(oldPad, buf, len) == 0);
if (!match && joyEvents) {
joyEvents->OnGamePadChanged((const GamePadEventData*)buf, joyId);
memcpy(oldPad, buf, len);
}
}
}
void JoystickEvents::OnGamePadChanged(const GamePadEventData *evt, int joystick) {
Serial.print("Joystick ");
Serial.print(joystick);
Serial.print(": X: "); PrintHex<uint16_t>(evt->X, 0x80);
Serial.print(" Y: "); PrintHex<uint16_t>(evt->Y, 0x80);
Serial.print(" Z1: "); PrintHex<uint8_t>(evt->Z1, 0x80);
Serial.print(" Z2: "); PrintHex<uint8_t>(evt->Z2, 0x80);
Serial.print(" Rz: "); PrintHex<uint8_t>(evt->Rz, 0x80);
Serial.println();
}
USB Usb;
USBHub Hub(&Usb);
HIDUniversal Hid1(&Usb); // first Joystick
HIDUniversal Hid2(&Usb); // second Joystick
JoystickEvents JoyEvents;
JoystickReportParser Joy1(&JoyEvents, 1);
JoystickReportParser Joy2(&JoyEvents, 2);
void setup() {
Serial.begin(115200);
Serial.println("Start");
if (Usb.Init() == -1) {
Serial.println("OSC did not start.");
}
delay(200);
if (!Hid1.SetReportParser(0, &Joy1) || !Hid2.SetReportParser(1, &Joy2)) {
ErrorMessage<uint8_t>(PSTR("SetReportParser"), 1);
}
}
void loop() {
Usb.Task();
}