1

I bought a Logitech Attack3 joystick at a garage sale for a couple of bucks and now I want to use it for something useful, like controlling a car or my small robotic arm. This joystick has 11 buttons and three sliders. I plugged it into a Sparkfun USB shield on top of an Arduino UNO and found some code online to get it up and running. It outputs hex values that tell me the slider values and the states of all the buttons. Where I am having difficulty is that I don't know C++ at all and the event handler and serial output commands are coming from the cpp file. I think that if I can get the output from the cpp file into the main loop in the ino file, I'll be able to do what I want with the data more easily. I plan to use a radio like XBee or Bluetooth to send commands based on the joystick output.

I cut down the code as much as I thought I could get away with. I'm hoping that someone can show me how to organize the code to allow me to do all my logic in the ino file.

Here is the INO file.

#include <usbhid.h>
#include <hiduniversal.h>
#include <usbhub.h>
#include <SPI.h>
#include "hidjoystickrptparser.h"

USB Usb;
USBHub Hub(&Usb);
HIDUniversal Hid(&Usb);
JoystickEvents JoyEvents;
JoystickReportParser Joy(&JoyEvents);

void setup() {
  Serial.begin(115200);
  pinMode(7, OUTPUT);
  digitalWrite(7, HIGH);
  if (Usb.Init() == -1)
    Serial.println("OSC did not start.");
  delay(200);
  if (!Hid.SetReportParser(0, &Joy))
    ErrorMessage<uint8_t > (PSTR("SetReportParser"), 1);
}

void loop() {
  Usb.Task();
  delay(10);
}

and the cpp file

#include "hidjoystickrptparser.h"

JoystickReportParser::JoystickReportParser(JoystickEvents *evt) :
joyEvents(evt),
oldButtons(0) {
        for (uint8_t i = 0; i < RPT_GEMEPAD_LEN; i++)
                oldPad[i] = 0xD;
}

void JoystickReportParser::Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
        bool match = true;

        // Checking if there are changes in report since the method was last called  
        for (uint8_t i = 0; i < RPT_GEMEPAD_LEN; i++)
                if (buf[i] != oldPad[i]) {
                        match = false;
                        break;
                }

        // Calling Game Pad event handler
        if (!match && joyEvents) {
                joyEvents->OnGamePadChanged((const GamePadEventData*)buf);
                for (uint8_t i = 0; i < RPT_GEMEPAD_LEN; i++) oldPad[i] = buf[i];
        }

        uint16_t buttons = (0x0000 | buf[6]);
        buttons <<= 4;
        buttons |= (buf[5] >> 4);
        uint16_t changes = (buttons ^ oldButtons);

}

void JoystickEvents::OnGamePadChanged(const GamePadEventData *evt) {
        Serial.print("Joystick X: ");
        PrintHex<uint8_t > (evt->X, 0x80);
        Serial.print("\tJoystick Y: ");
        PrintHex<uint8_t > (evt->Y, 0x80);
        Serial.print("\tTrim: ");
        PrintHex<uint8_t > (evt->Z1, 0x80);
        Serial.print("\tSW1-8: ");
        PrintHex<uint8_t > (evt->Z2, 0x80);
        Serial.print("  SW9-11: ");
        PrintHex<uint8_t > (evt->Rz, 0x80);
        Serial.println("\t");

and the header file

#if !defined(__HIDJOYSTICKRPTPARSER_H__)
#define __HIDJOYSTICKRPTPARSER_H__

#include <usbhid.h>

struct GamePadEventData {
        uint8_t X, Y, Z1, Z2, Rz;
};

class JoystickEvents {
public:
        virtual void OnGamePadChanged(const GamePadEventData *evt);
};

#define RPT_GEMEPAD_LEN     5

class JoystickReportParser : public HIDReportParser {
        JoystickEvents *joyEvents;

        uint8_t oldPad[RPT_GEMEPAD_LEN];
        uint8_t oldHat;
        uint16_t oldButtons;

public:
        JoystickReportParser(JoystickEvents *evt);

        virtual void Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
};

#endif 

Here is what the output looks like in the serial monitor

Joystick X: 80  Joystick Y: 82  Trim: 7A    SW1-8: 00  SW9-11: 00   
Joystick X: 7B  Joystick Y: 80  Trim: 7A    SW1-8: 00  SW9-11: 00   
Joystick X: 7B  Joystick Y: 7F  Trim: 7A    SW1-8: 00  SW9-11: 00   
Joystick X: 7B  Joystick Y: 7F  Trim: 7A    SW1-8: 00  SW9-11: 01   
Joystick X: 7B  Joystick Y: 7F  Trim: 7A    SW1-8: 00  SW9-11: 00   

enter image description here

  • An Arduino Sketch's .ino is C++ code. It just doesn't define or use any C++ classes by default. It's vanilla C, which is a subset of C++. It isn't clear to me what your Usb.Task(); line does, or how that invokes code in the joystick C++ file you posted. Is there documentation on the joystick library you're using? – Duncan C Apr 12 at 23:23
  • The sample I'm showing is exactly as I found online, except that I took out unneeded some code and tweaked the Serial.print lines in the cpp file. I also don't know exactly what routine Usb.Task() does. I'll get back to you with more information. – Scott M Apr 15 at 18:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.