|
|
|
/***************************************************************************
|
|
|
|
* Copyright (C) 2003 by Martin Koller *
|
|
|
|
* m.koller@surfeu.at *
|
|
|
|
* This file is part of the Trinity Control Center Module for Joysticks *
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
* This program is distributed in the hope that it will be useful, *
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
|
|
* GNU General Public License for more details. *
|
|
|
|
* *
|
|
|
|
* You should have received a copy of the GNU General Public License *
|
|
|
|
* along with this program; if not, write to the *
|
|
|
|
* Free Software Foundation, Inc., *
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#include "joydevice.h"
|
|
|
|
|
|
|
|
#include <tdelocale.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/select.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
|
|
|
|
|
|
JoyDevice::JoyDevice(const TQString &devicefile)
|
|
|
|
: devName(devicefile), joyFd(-1), buttons(0), axes(0),
|
|
|
|
amin(0), amax(0), corr(0), origCorr(0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
|
|
|
|
|
|
TQString JoyDevice::errText(ErrorCode code) const
|
|
|
|
{
|
|
|
|
switch ( code )
|
|
|
|
{
|
|
|
|
case SUCCESS: return "";
|
|
|
|
|
|
|
|
case OPEN_FAILED:
|
|
|
|
{
|
|
|
|
return i18n("The given device %1 could not be opened: %2")
|
|
|
|
.arg(devName).arg(strerror(errno));
|
|
|
|
}
|
|
|
|
|
|
|
|
case NO_JOYSTICK:
|
|
|
|
{
|
|
|
|
return i18n("The given device %1 is not a joystick.").arg(devName);
|
|
|
|
}
|
|
|
|
|
|
|
|
case ERR_GET_VERSION:
|
|
|
|
{
|
|
|
|
return i18n("Could not get kernel driver version for joystick device %1: %2")
|
|
|
|
.arg(devName).arg(strerror(errno));
|
|
|
|
}
|
|
|
|
|
|
|
|
case WRONG_VERSION:
|
|
|
|
{
|
|
|
|
int version = 0;
|
|
|
|
int fd = ::open(devName.latin1(), O_RDONLY);
|
|
|
|
if ( fd != -1 )
|
|
|
|
{
|
|
|
|
::ioctl(fd, JSIOCGVERSION, &version);
|
|
|
|
::close(fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
return i18n("The current running kernel driver version (%1.%2.%3) is not the one this module was compiled for (%4.%5.%6).")
|
|
|
|
.arg(version >> 16).arg((version >> 8) & 0xFF).arg(version & 0xFF)
|
|
|
|
.arg(JS_VERSION >> 16).arg((JS_VERSION >> 8) & 0xFF).arg(JS_VERSION & 0xFF);
|
|
|
|
}
|
|
|
|
|
|
|
|
case ERR_GET_BUTTONS:
|
|
|
|
{
|
|
|
|
return i18n("Could not get number of buttons for joystick device %1: %2")
|
|
|
|
.arg(devName).arg(strerror(errno));
|
|
|
|
}
|
|
|
|
|
|
|
|
case ERR_GET_AXES:
|
|
|
|
{
|
|
|
|
return i18n("Could not get number of axes for joystick device %1: %2")
|
|
|
|
.arg(devName).arg(strerror(errno));
|
|
|
|
}
|
|
|
|
|
|
|
|
case ERR_GET_CORR:
|
|
|
|
{
|
|
|
|
return i18n("Could not get calibration values for joystick device %1: %2")
|
|
|
|
.arg(devName).arg(strerror(errno));
|
|
|
|
}
|
|
|
|
|
|
|
|
case ERR_RESTORE_CORR:
|
|
|
|
{
|
|
|
|
return i18n("Could not restore calibration values for joystick device %1: %2")
|
|
|
|
.arg(devName).arg(strerror(errno));
|
|
|
|
}
|
|
|
|
|
|
|
|
case ERR_INIT_CAL:
|
|
|
|
{
|
|
|
|
return i18n("Could not initialize calibration values for joystick device %1: %2")
|
|
|
|
.arg(devName).arg(strerror(errno));
|
|
|
|
}
|
|
|
|
|
|
|
|
case ERR_APPLY_CAL:
|
|
|
|
{
|
|
|
|
return i18n("Could not apply calibration values for joystick device %1: %2")
|
|
|
|
.arg(devName).arg(strerror(errno));
|
|
|
|
}
|
|
|
|
|
|
|
|
default: return i18n("internal error - code %1 unknown").arg(int(code));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
|
|
|
|
|
|
JoyDevice::ErrorCode JoyDevice::open()
|
|
|
|
{
|
|
|
|
if ( joyFd != -1 ) return JoyDevice::SUCCESS; // already open
|
|
|
|
|
|
|
|
int fd = ::open(devName.latin1(), O_RDONLY);
|
|
|
|
|
|
|
|
if ( fd == -1 )
|
|
|
|
return JoyDevice::OPEN_FAILED;
|
|
|
|
|
|
|
|
// we could open the devicefile, now check if a joystick is attached
|
|
|
|
char name[128];
|
|
|
|
|
|
|
|
if ( ::ioctl(fd, JSIOCGNAME(sizeof(name)), &name) == -1 )
|
|
|
|
{
|
|
|
|
::close(fd);
|
|
|
|
return JoyDevice::NO_JOYSTICK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check the kernel driver version
|
|
|
|
int version;
|
|
|
|
if ( ::ioctl(fd, JSIOCGVERSION, &version) == -1 )
|
|
|
|
{
|
|
|
|
::close(fd);
|
|
|
|
return JoyDevice::ERR_GET_VERSION;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( version != JS_VERSION )
|
|
|
|
{
|
|
|
|
::close(fd);
|
|
|
|
return JoyDevice::WRONG_VERSION;
|
|
|
|
}
|
|
|
|
|
|
|
|
char bt = 0, ax = 0;
|
|
|
|
if ( ::ioctl(fd, JSIOCGBUTTONS, &bt) == -1 )
|
|
|
|
{
|
|
|
|
::close(fd);
|
|
|
|
return JoyDevice::ERR_GET_BUTTONS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ::ioctl(fd, JSIOCGAXES, &ax) == -1 )
|
|
|
|
{
|
|
|
|
::close(fd);
|
|
|
|
return JoyDevice::ERR_GET_AXES;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct js_corr *oldCorr = new struct js_corr[ax];
|
|
|
|
|
|
|
|
if ( ::ioctl(fd, JSIOCGCORR, oldCorr) == -1 )
|
|
|
|
{
|
|
|
|
::close(fd);
|
|
|
|
delete [] oldCorr;
|
|
|
|
return JoyDevice::ERR_GET_CORR;
|
|
|
|
}
|
|
|
|
|
|
|
|
descr = name;
|
|
|
|
joyFd = fd;
|
|
|
|
axes = ax;
|
|
|
|
buttons = bt;
|
|
|
|
origCorr = oldCorr;
|
|
|
|
corr = new struct js_corr[axes];
|
|
|
|
|
|
|
|
amin = new int[axes];
|
|
|
|
amax = new int[axes];
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < axes; i++)
|
|
|
|
resetMinMax(i);
|
|
|
|
|
|
|
|
return JoyDevice::SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
|
|
|
|
|
|
void JoyDevice::close()
|
|
|
|
{
|
|
|
|
if ( joyFd == -1 ) return;
|
|
|
|
|
|
|
|
::close(joyFd);
|
|
|
|
|
|
|
|
joyFd = -1;
|
|
|
|
descr = "";
|
|
|
|
|
|
|
|
delete [] amin;
|
|
|
|
delete [] amax;
|
|
|
|
amin = 0;
|
|
|
|
amax = 0;
|
|
|
|
|
|
|
|
delete [] corr;
|
|
|
|
corr = 0;
|
|
|
|
delete [] origCorr;
|
|
|
|
origCorr = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
|
|
|
|
|
|
int JoyDevice::axisMin(int axis) const
|
|
|
|
{
|
|
|
|
if ( (axis < 0) || (axis >= axes) ) return 0;
|
|
|
|
|
|
|
|
return amin[axis];
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
|
|
|
|
|
|
int JoyDevice::axisMax(int axis) const
|
|
|
|
{
|
|
|
|
if ( (axis < 0) || (axis >= axes) ) return 0;
|
|
|
|
|
|
|
|
return amax[axis];
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
|
|
|
|
|
|
JoyDevice::ErrorCode JoyDevice::initCalibration()
|
|
|
|
{
|
|
|
|
if ( joyFd == -1 ) return JoyDevice::ERR_INIT_CAL;
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
// Reset all current correction values
|
|
|
|
for (i = 0; i < axes; i++)
|
|
|
|
{
|
|
|
|
corr[i].type = JS_CORR_NONE;
|
|
|
|
corr[i].prec = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ::ioctl(joyFd, JSIOCSCORR, corr) == -1 )
|
|
|
|
return JoyDevice::ERR_INIT_CAL;
|
|
|
|
|
|
|
|
for (i = 0; i < axes; i++)
|
|
|
|
corr[i].type = JS_CORR_BROKEN;
|
|
|
|
|
|
|
|
return JoyDevice::SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
|
|
|
|
|
|
JoyDevice::ErrorCode JoyDevice::applyCalibration()
|
|
|
|
{
|
|
|
|
if ( joyFd == -1 ) return JoyDevice::ERR_APPLY_CAL;
|
|
|
|
|
|
|
|
if ( ::ioctl(joyFd, JSIOCSCORR, corr) == -1 )
|
|
|
|
return JoyDevice::ERR_APPLY_CAL;
|
|
|
|
|
|
|
|
return JoyDevice::SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
|
|
|
|
|
|
void JoyDevice::resetMinMax(int axis, int value)
|
|
|
|
{
|
|
|
|
amin[axis] = value;
|
|
|
|
amax[axis] = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
|
|
|
|
|
|
void JoyDevice::calcPrecision()
|
|
|
|
{
|
|
|
|
if ( !corr ) return;
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < axes; i++)
|
|
|
|
{
|
|
|
|
corr[i].prec = amax[i] - amin[i];
|
|
|
|
kdDebug() << "Precision for axis: " << i << ": " << corr[i].prec << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
|
|
|
|
|
|
JoyDevice::ErrorCode JoyDevice::restoreCorr()
|
|
|
|
{
|
|
|
|
if ( joyFd == -1 ) return JoyDevice::SUCCESS;
|
|
|
|
|
|
|
|
if ( ::ioctl(joyFd, JSIOCSCORR, origCorr) == -1 )
|
|
|
|
return JoyDevice::ERR_RESTORE_CORR;
|
|
|
|
else
|
|
|
|
return JoyDevice::SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
|
|
|
|
|
|
JoyDevice::~JoyDevice()
|
|
|
|
{
|
|
|
|
close();
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
|
|
|
|
|
|
bool JoyDevice::getEvent(JoyDevice::EventType &type, int &number, int &value)
|
|
|
|
{
|
|
|
|
number = value = 0;
|
|
|
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
fd_set readSet;
|
|
|
|
|
|
|
|
FD_ZERO(&readSet);
|
|
|
|
FD_SET(joyFd, &readSet);
|
|
|
|
|
|
|
|
struct timeval timeout;
|
|
|
|
timeout.tv_sec = 0;
|
|
|
|
timeout.tv_usec = 100000;
|
|
|
|
|
|
|
|
ret = ::select(joyFd + 1, &readSet, 0, 0, &timeout);
|
|
|
|
|
|
|
|
if ( ret == 1 ) // got an event from the joystick
|
|
|
|
{
|
|
|
|
struct js_event e;
|
|
|
|
|
|
|
|
if ( ::read(joyFd, &e, sizeof(struct js_event)) == sizeof(struct js_event) )
|
|
|
|
{
|
|
|
|
if ( e.type & JS_EVENT_BUTTON )
|
|
|
|
{
|
|
|
|
type = JoyDevice::BUTTON;
|
|
|
|
value = e.value;
|
|
|
|
number = e.number;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( e.type & JS_EVENT_AXIS )
|
|
|
|
{
|
|
|
|
type = JoyDevice::AXIS;
|
|
|
|
value = e.value;
|
|
|
|
number = e.number;
|
|
|
|
|
|
|
|
// store min, max values
|
|
|
|
if ( e.value < amin[number] ) amin[number] = e.value;
|
|
|
|
if ( e.value > amax[number] ) amax[number] = e.value;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false; // no event
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
|
|
|
|
|
|
void JoyDevice::calcCorrection(int axis, int *min, int *center, int *max)
|
|
|
|
{
|
|
|
|
const int MIN = 0;
|
|
|
|
const int MAX = 1;
|
|
|
|
|
|
|
|
double a, b, c, d;
|
|
|
|
|
|
|
|
a = center[MIN]; // inputs.cmin[1];
|
|
|
|
b = center[MAX]; // inputs.cmax[1];
|
|
|
|
c = 32767.0 / (center[MIN] - min[MAX]); // (inputs.cmin[1] - inputs.cmax[0]);
|
|
|
|
d = 32767.0 / (max[MIN] - center[MAX]); // (inputs.cmin[2] - inputs.cmax[1]);
|
|
|
|
|
|
|
|
corr[axis].coef[0] = (int)rint(a);
|
|
|
|
corr[axis].coef[1] = (int)rint(b);
|
|
|
|
corr[axis].coef[2] = (int)rint(c*16384.0);
|
|
|
|
corr[axis].coef[3] = (int)rint(d*16384.0);
|
|
|
|
|
|
|
|
kdDebug() << "min min: " << min[0] << " max: " << min[1] << endl;
|
|
|
|
kdDebug() << "max min: " << max[0] << " max: " << max[1] << endl;
|
|
|
|
kdDebug() << "Correction values for axis: " << axis << ": "
|
|
|
|
<< corr[axis].coef[0] << ", "
|
|
|
|
<< corr[axis].coef[1] << ", "
|
|
|
|
<< corr[axis].coef[2] << ", "
|
|
|
|
<< corr[axis].coef[3] << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------
|