USB Host Shield плюс 2 одинаковых джойстика

usb joystick

Я пытаюсь запустить два одинаковых джойстика (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.

Есть идеи?

, 👍0

Обсуждение

посмотрите демонстрацию хаба, @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


2 ответа


1

Не совсем тот вопрос, который был задан, но часть проблемы.

Это простое введение в указатели.

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


0

это может быть возможным ответом, в коде 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(); 
} 
,