PDA

View Full Version : Thread Implementation



bruceariggs
16th October 2011, 22:27
In a nutshell... my question is: How do you set up the signals and slots of objects that go on different threads?

I have a function that has to run over and over seperate from my main GUI application (A joystick polling function).

When it comes to connecting the signals and slots of my joystick reader to my main GUI, would I do something like this?


class JoystickPoller : public QThread
{
/* implement all QThread functions here,
set up some custom signals as well */
}


And then in my main GUI do something like this?



JoystickPoller* poller = new JoystickPoller();
connect( poller, SIGNAL( NewJoystickInfo( JoystickData ) ),
this, SLOT( HandleNewJoyStickInfo( JoystickData ) ) );


Would that be how you set up 2 threads to safely signal and slot with each other?

Thanks in advance to anyone who answers.

And I know Mr. Wysota's always on it! Thank you Wysota. You've answered like 80 of my questions now!

helloworld
16th October 2011, 23:57
Do you really need to use threads for this? What does the JoystickPoller class look like?

bruceariggs
17th October 2011, 15:30
Well,

It's not really a JoystickPoller, it's actually event based, and it does a blocking GET for input, which just sits there until it gets input. That's why I put it in a seperate thread.

wysota
17th October 2011, 15:37
Where does it read its data from?

bruceariggs
17th October 2011, 17:38
Okay, here's the code for my reader

The file being read is /dev/input/js0, it's a file that is created by Linux and joystick drivers when a joystick is plugged in. If you have multiple joysticks, there'd be js1, js2, js3... etc. etc. We're only ever going to have 1 joystick plugged in.

First thing to know, it's always set to a Logitech joystick right now, because we only have that joystick at the moment. So it will always get into readLogitechJoystick.

This code is working fine at the moment. I actually did figure out the thread safe signal/slot stuff.

But I always love advice. I know C++ really well, but I don't know linux hardware stuff hardly at all.

I don't like the way I'm doing an infinite loop for this event based device, and I don't like that I'm using ifstream, because I don't think read() is a blocking call?

Here's the .h



#ifndef JOYSTICKREADER_H
#define JOYSTICKREADER_H

#include <iostream>
#include <fstream>
#include <QThread>

#include "JoystickData.h"
#include "Joystick.h"

using std::ifstream;
using DataStore::JoystickData;

class JoystickReader : public QThread
{
Q_OBJECT

public:

enum JoystickModel
{
LOGITECH = 0,
OFFICIAL
};

JoystickReader(QObject *parent = 0, JoystickModel joyType=LOGITECH );

~JoystickReader();

void run();

signals:

void sendJoystick( const Joystick newJoystick );

private:

enum LogitechJoystickCommandType
{
LOGITECH_BUTTON = 1,
LOGITECH_JOYSTICK = 2
};

enum LogitechJoystickDirection
{
LOGITECH_AXIS_X = 0,
LOGITECH_AXIS_Y = 1
};

enum LogitechJoystickPress
{
LOGITECH_RELEASE = 0,
LOGITECH_PRESS = 1
};

enum LogitechButtonValue
{
LOGITECH_DEADMAN = 0,
LOGITECH_DOWN = 1,
LOGITECH_UP = 2,
LOGITECH_LEFT = 3,
LOGITECH_RIGHT = 4
};

// The file reader
ifstream fd;

// Which joystick we're using
JoystickModel joystickType;

// the temp Joystick we'll be constantly writing into
Joystick joystick;

// Whether a button is pressed or released
char buttonPress;

// The magnitude of the joystick press
char magnitude;

// Whether it's a button press or a joystick movement
char commandType;

// More details on a command type
char messageClarify;

void readLogitechJoystick();

void readOfficialJoystick();

void handleLogitechButtonRelease();

void handleLogitechButtonPress();

void handleLogitechJoystickMovement();
};

#endif // JOYSTICKREADER_H




And here's the .cpp



#include "JoystickReader.h"

JoystickReader::JoystickReader(QObject *parent, JoystickModel joyType ) :
QThread(parent)
{
fd.open( "/dev/input/js0", ifstream::in | ifstream::binary );
joystickType = joyType;
}

JoystickReader::~JoystickReader()
{
fd.close();
}

void JoystickReader::run()
{
if( joystickType == LOGITECH )
{
readLogitechJoystick();
}
else
{
readOfficialJoystick();
}
}

void JoystickReader::readLogitechJoystick()
{
// These variables aren't used in our program, THEY DON'T HAVE SOULS!
char unknown, timeChar, timeChar2, timeChar3;
unknown = timeChar = timeChar2 = timeChar3 = 0;
int myTime = 0;

// Initialize the important variables (the ones with souls)
buttonPress = magnitude = commandType = messageClarify = 0;
joystick.setXPosition( 0 );
joystick.setYPosition( 0 );

// FOR- -EH- -VER
while( 1 )
{
if( fd.is_open() )
{
// Read in the data
fd.read(&unknown, sizeof(char));
fd.read(&timeChar, sizeof(char));
fd.read(&timeChar2, sizeof(char));
fd.read(&timeChar3, sizeof(char));
fd.read(&buttonPress, sizeof(char));
fd.read(&magnitude, sizeof(char));
fd.read(&commandType, sizeof(char));
fd.read(&messageClarify, sizeof(char));

// With their powers combined, they are the current time!
myTime = (((timeChar3<<16)&0x00FF0000)
+ ((timeChar2<<8)&0x0000FF00))
+ (timeChar & 0x000000FF);

// Joystick is obviously connected
joystick.setConnectionState( true );

// Is this a button press update?
if( commandType == LOGITECH_BUTTON )
{
// Is this button released or pressed?
if( buttonPress == LOGITECH_RELEASE )
{
handleLogitechButtonRelease();
}
else if( buttonPress == LOGITECH_PRESS )
{
handleLogitechButtonPress();
}
}
// Else this is a joystick movement update
else if( commandType == LOGITECH_JOYSTICK )
{
handleLogitechJoystickMovement();
}
}
}
}

void JoystickReader::handleLogitechButtonRelease()
{
// Which button?
switch( messageClarify )
{
case LOGITECH_DEADMAN:
{
// deadman released
joystick.setDeadmanState( false );
break;
}
case LOGITECH_DOWN:// down released
case LOGITECH_UP:// up released
case LOGITECH_LEFT:// left released
case LOGITECH_RIGHT:// right released
{
joystick.setButtonPressed( Joystick::NONE );
break;
}
default:
{
// It was one of the buttons we don't care about, do nothing
break;
}
};
}

void JoystickReader::handleLogitechButtonPress()
{
// Which button?
switch( messageClarify )
{
case LOGITECH_DEADMAN:
{
// deadman pressed
joystick.setDeadmanState( true );
break;
}
case LOGITECH_DOWN:// down pressed
{
joystick.setButtonPressed( Joystick::DOWN );
break;
}
case LOGITECH_UP:// up pressed
{
joystick.setButtonPressed( Joystick::UP );
break;
}
case LOGITECH_LEFT:// left pressed
{
joystick.setButtonPressed( Joystick::LEFT );
break;
}
case LOGITECH_RIGHT:// right pressed
{
joystick.setButtonPressed( Joystick::RIGHT );
break;
}
default:
{
// Do nothing
break;
}
};
}

void JoystickReader::handleLogitechJoystickMovement()
{
// Which axis?
switch( messageClarify )
{
case LOGITECH_AXIS_X: // X Axis
{
joystick.setXPosition( magnitude );
break;
}
case LOGITECH_AXIS_Y: // Y Axis
{
joystick.setYPosition( magnitude );
break;
}
default:
{
break;
}
}
}

void JoystickReader::readOfficialJoystick()
{
// Currently does nothing!
}

wysota
17th October 2011, 17:50
You don't need threads then. Just use QSocketNotifier or QLocalSocket on /dev/input/js0 and use signals and slots.

33333
19th October 2011, 13:39
I actually did figure out the thread safe signal/slot stuff.

And?


But I always love advice.

So do I!:)

bruceariggs
21st October 2011, 16:06
Yeap! This worked out just fine for me.



// Create the JoystickReader thread
JoystickReader *myReader = new JoystickReader(
0, DisplaySettingsData::getInstance()->getMiscSettings()
.getJoystickModel() );

// Connect the thread signal to the DataStore slot
QObject::connect( myReader,
SIGNAL( setNewJoystick(const Joystick&) ),
JoystickControl::getInstance(),
SLOT(setJoystick(const Joystick&)) );

// Start the thread
myReader->start();