USB Host Shield плюс 2 одинаковых джойстика
Я пытаюсь запустить два одинаковых джойстика (Saitek cyborg 3D) с USB-Host-Shield на Mega 2560 и USB-концентратор.
Я уже получаю сообщения о событиях от обоих:
#include <usbhid.h>
#include <hiduniversal.h>
#include <usbhub.h>
// Удовлетворить IDE, которой нужно только увидеть статус включения в файле ino.
#ifdef dobogusinclude
#include <spi4teensy3.h>
#endif
#include <SPI.h>
#include "hidjoystickrptparser.h"
USB Usb;
USBHub Hub(&Usb);
HIDUniversal Hid1(&Usb); // первый джойстик
HIDUniversal Hid2(&Usb); // второй джойстик
JoystickEvents Joy1Events;
JoystickEvents Joy2Events;
JoystickReportParser Joy1(&Joy1Events);
JoystickReportParser Joy2(&Joy2Events);
void setup() {
Serial.begin(115200);
#if !defined(__MIPSEL__)
while (!Serial); // Дождитесь подключения последовательного порта — используется на платах Leonardo, Teensy и других со встроенным последовательным соединением USB CDC
#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("");
}
Мой вопрос: как я могу отличить события от разных джойстиков.
Я пытаюсь получить информацию о порте от USB-концентратора. К сожалению, что-то вроде
!hid->GetAddress()
внутри JoystickReportParser не выполняет свою работу, поскольку всегда возвращает 0.
Есть идеи?
@Palmstroem, 👍0
Обсуждение2 ответа
Не совсем тот вопрос, который был задан, но часть проблемы.
Это простое введение в указатели.
int variable = 42; // Создаем переменную
int* pointer = &variable; // Создаем указатель на переменную (получая ее адрес)
*pointer = 99; // Установить адрес в новое значение
printf ("variable has the value %d", variable); // Напечатать 99.
&x
получить адрес x
*y
разыменовывает
указатель y, что означает, что он «превращает его обратно в переменную» (это упрощенное представление, которое на самом деле не верно, но подойдет на данный момент).
Таким образом, вы могли бы, если бы захотели (чего бы вы не сделали), сделать это *&z
, что было бы таким же, как выполнение z
.
Представьте, что &
и *
— это пара дополняющих друг друга операторов, таких как - и + или * и /. (Они не операторы, но для начала может помочь).
Следующая проблема заключается в том, когда вы это делаете
SomeFunction(&variable);
Все параметры функций в C/C++ по умолчанию передаются по значению. Это означает, что функция получает их копию, а не фактическое значение. Итак, если бы у вас было:
void FunctionOne (int val)
{
val = 99;
}
int val = 4;
FunctionOne(val);
printf("val = %d", val); // Вы увидите 4 напечатанных.
Если вы передаете по ссылке, то вы увидите напечатанное 99, чтобы передать по ссылке, вы можете сделать это одним из двух способов.
void FunctionTwo (int& valByRef);
void FunctionThree (int* valPointer);
FunctionTwo
работает только с C++ (подойдет и для Arduino).
FunctionThree
может вызвать ошибку сегментации, если передается значение NULL и функция выполняет запись в него.
Если это поможет, на мой взгляд, указатели были одной из самых сложных концепций для понимания в классическом C/C++, поэтому не беспокойтесь, если вы не понимаете этого, просто поиграйте с ними и посмотрите, что вы можете сделать.< / р>
Методы вызова
object.method()
— вызывает метод функции в вызываемом экземпляре объект типаX
.object->method()
— вызывает метод функции в вызываемом экземпляре объект, который является указателем типаX
.object::method()
- вызов метода функции который является статическим членом объекта класса (статический означает, что он не изменить любые данные в экземпляре класса)- *object->method() — избегайте этого как чумы. Это означает либо
*(object->method())
, либо(*object)->method()
, чтобы узнать, что вам нужно посмотреть на тип объекта и возвращаемый тип функции. Его проще просто заключить в квадратные скобки, чтобы устранить двусмысленность.
Что касается *object.&method()
, я никогда не сталкивался с таким, но это не значит, что его не существует. :)
Большое спасибо за это объяснение. Хорошее объяснение! Что меня смущает: иногда вы можете получить доступ к свойству с помощью object.method или object.object.method, затем с помощью object::method и object->method или object.&method или *object.&object::method и object.@- >/!%&wtf$метод и так далее. Эти вещи не были созданы для понимания человеческим мозгом., @Palmstroem
Ты хочешь сказать, что я не человек? :) (См. редактирование) Это изучение нового языка, и вам просто нужно помнить определенные правила, чем больше вы их используете, тем больше они укореняются, нет короткого пути :(, @Code Gorilla
Большое спасибо. Сверхчеловек! Любые идеи для исходного вопроса? Я нахожусь внутри функции обработчика сигналов и хочу получить доступ к атрибуту родительского или прародительского класса, но не знаю, как найти правильный метод. Документация на http://felis.github.io/USB_Host_Shield_2.0/class_u_s_b_device_config.html кажется достаточно исчерпывающей. Но я не понимаю., @Palmstroem
!Hid->GetAddress() всегда возвращает 0. Возможно, мне нужно сделать что-то вроде *evt.HIDDevice.Hid->GetAddress(), но все подобные попытки приводят к ошибкам компиляции., @Palmstroem
это может быть возможным ответом, в коде Arduino необходима библиотека USB Host Shield 2.0:
#include <usbhid.h>
#include <hiduniversal.h>
#include <usbhub.h>
// Отчет Logitech Attack 3 HID
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)) {
// Проверяем, есть ли изменения в отчете с момента последнего вызова метода
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); // первый джойстик
HIDUniversal Hid2(&Usb); // второй джойстик
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();
}
- Вибрационный геймпад Arduino с силовой обратной связью
- Экспонируйте два устройства HID Joystick с одной платой RP2040 (Waveshare Pi Pico Zero)
- Можно ли использовать Arduino UNO для эмуляции джойстика PS4?
- Библиотека джойстиков Arduino не распознается играми (Steam)
- Как использовать защитный экран USB-хост с различными джойстиками HID
- Подключение джойстика Logitech к Arduino и прерывание цикла while
- Можно ли заставить Arduino Uno Rev3 притворяться джойстиком?
- Первая настройка - отказ в доступе к usb-порту - ubuntu 14.04
посмотрите демонстрацию хаба, @jsotola
Это то, что я делаю уже несколько дней, но я не понимаю. Я получаю сообщения-события, но как узнать, с какого порта они приходят? В демонстрационной версии хаба есть функция: PrintAllAddresses(), которая принимает указатель на устройство. Но он вызывается в этом операторе: Usb.ForEachUsbDevice(&PrintAllAddresses);, @Palmstroem
В демонстрационной версии хаба есть функция: PrintAllAddresses(), которая принимает указатель на устройство. Но он вызывается в этом операторе: Usb.ForEachUsbDevice(&PrintAllAddresses); Итак, как мне вызвать что-то подобное из JoytickReportParser или обработчика событий OnGamepadChanged?, @Palmstroem
Или как мне получить указатель на устройство, с которого приходит сообщение-событие?, @Palmstroem
Если быть честным. Я не так хорошо знаком со всей этой арифметикой указателей. Все это -> :: ! * . Все еще немного проводной для меня., @Palmstroem
я говорю об этой демонстрации... https://github.com/felis/USB_Host_Shield_2.0/blob/master/examples/hub_demo/hub_demo.ino.... похоже, что она печатает целую кучу информации о каждом подключенное USB-устройство ..... начните с этого, @jsotola
!
- это логическое выражениене
... когдадождливо
, то!солнечно
, @jsotola@jstola Боюсь, ваше утверждение неверно, иногда бывает солнечно и дождливо одновременно., @Code Gorilla
логически это верно, но это был грубый пример оператора not (также мой комментарий неверен, потому что
not
на самом деле является унарным оператором, а не утверждением), @jsotolaБольшое спасибо за Вашу помощь. @jsotola Я уже запускал эту хаб-демонстрацию. Итак, я знаю, что два джойстика подключены к двум USP-портам на концентраторе, которые имеют такие адреса, как A и B. Вывод функции PrintAdress() выглядит примерно так (0,1,A) и (0,1, B) для двух джойстиков. Чего я не знаю. Как я могу получить доступ к этой информации из функции обработчика событий, называемой void JoystickEvents::OnGamePadChanged(const GamePadEventData *evt) {} из Joystick-Demo., @Palmstroem
Документацию по библиотеке USB-HUB-2.0 можно найти здесь: http://felis.github.io/USB_Host_Shield_2.0/inherits.html. (В нижней части сайта есть хорошая иерархия классов). Глядя туда, мне кажется, что класс USBHID, который может отвечать за показания джойстика, похоже, наследуется от класса USBDeviceConfig (или наоборот, что для меня не имеет смысла, но кто знает. Указывает ли направление стрелок направление наследование на этой диаграмме?), @Palmstroem
Итак, мой вопрос: какую строку кода мне нужно добавить в функцию-обработчик событий void JoystickEvents:: OnGamePadChanged(const GamePadEventData *evt) {} в hidjoystickrptparser.cpp из USBHIDJoystick.ino-Demo, чтобы получить эти A и B USB-адреса из моего предыдущего комментария? Поэтому, когда приходит сообщение-событие, я знаю, с какого джойстика оно приходит., @Palmstroem
Или позвольте мне поставить вопрос другими словами. Пустота JoystickEvents::OnGamePadChanged(const GamePadEventData *evt) { }-Функция получает указатель на объект-событие *evt. Этот объект *evt должен быть каким-то образом связан с объектом USBdevice, откуда он исходит. Но как я могу получить к этому доступ и как я могу выяснить, какой метод вызывать, проходя через иерархию наследования, чтобы получить адрес USB-устройства?, @Palmstroem
Или, может быть, так: В хабе-демо я нахожу функцию: пустота PrintAllAddresses (UsbDevice * pdev) { адрес UsbDeviceAddress; adr.devAddress = pdev->address.devAddress; Serial.print(adr.bmAddress, HEX); Серийный.println(")"); } Поэтому, если бы я мог каким-то образом получить этот дескриптор *pdev из функции-обработчика событий из демонстрации джойстика, я мог бы получить этот адрес. Но, к сожалению, я не знаю, как это получить., @Palmstroem
Я пытаюсь решить ту же проблему. Я уже работал в основном цикле void: Serial.print(Hid1.GetAddress()); А отличить 2 одинаковых джойстика в цикле событий уже удалось -> Palmstroem?, @Bart
это может быть возможный ответ: https://github.com/Bratski/Arduino-2-Джойстики-to-PPM, @Bart