/*************************************************************************** * Copyright (C) 2003 by Martin Koller * * m.koller@surfeu.at * * This file is part of the TDE 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 <klocale.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; } //--------------------------------------------------------------