File indexing completed on 2024-05-12 17:07:10
0001 /* 0002 This file is part of the KDE Control Center Module for Joysticks 0003 0004 SPDX-FileCopyrightText: 2003 Martin Koller <kollix@aon.at> 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "joydevice.h" 0009 0010 #include <KLocalizedString> 0011 #include <QDebug> 0012 0013 #include <errno.h> 0014 #include <fcntl.h> 0015 #include <math.h> 0016 #include <sys/ioctl.h> 0017 #include <sys/select.h> 0018 #include <sys/stat.h> 0019 #include <sys/time.h> 0020 #include <unistd.h> 0021 0022 JoyDevice::JoyDevice(const QString &devicefile) 0023 : devName(devicefile) 0024 , joyFd(-1) 0025 , buttons(0) 0026 , axes(0) 0027 , amin(nullptr) 0028 , amax(nullptr) 0029 , corr(nullptr) 0030 , origCorr(nullptr) 0031 { 0032 } 0033 0034 QString JoyDevice::errText(ErrorCode code) const 0035 { 0036 switch (code) { 0037 case SUCCESS: 0038 return QString(); 0039 0040 case OPEN_FAILED: { 0041 return i18n("The given device %1 could not be opened: %2", devName, strerror(errno)); 0042 } 0043 0044 case NO_JOYSTICK: { 0045 return i18n("The given device %1 is not a joystick.", devName); 0046 } 0047 0048 case ERR_GET_VERSION: { 0049 return i18n("Could not get kernel driver version for joystick device %1: %2", devName, strerror(errno)); 0050 } 0051 0052 case WRONG_VERSION: { 0053 int version = 0; 0054 int fd = ::open(devName.toLatin1(), O_RDONLY); 0055 if (fd != -1) { 0056 ::ioctl(fd, JSIOCGVERSION, &version); 0057 ::close(fd); 0058 } 0059 0060 KLocalizedString loc = ki18n("The current running kernel driver version (%1.%2.%3) is not the one this module was compiled for (%4.%5.%6)."); 0061 loc = loc.subs(version >> 16); 0062 loc = loc.subs((version >> 8) & 0xFF); 0063 loc = loc.subs(version & 0xFF); 0064 loc = loc.subs(JS_VERSION >> 16); 0065 loc = loc.subs((JS_VERSION >> 8) & 0xFF); 0066 loc = loc.subs(JS_VERSION & 0xFF); 0067 return loc.toString(); 0068 } 0069 0070 case ERR_GET_BUTTONS: { 0071 return i18n("Could not get number of buttons for joystick device %1: %2", devName, strerror(errno)); 0072 } 0073 0074 case ERR_GET_AXES: { 0075 return i18n("Could not get number of axes for joystick device %1: %2", devName, strerror(errno)); 0076 } 0077 0078 case ERR_GET_CORR: { 0079 return i18n("Could not get calibration values for joystick device %1: %2", devName, strerror(errno)); 0080 } 0081 0082 case ERR_RESTORE_CORR: { 0083 return i18n("Could not restore calibration values for joystick device %1: %2", devName, strerror(errno)); 0084 } 0085 0086 case ERR_INIT_CAL: { 0087 return i18n("Could not initialize calibration values for joystick device %1: %2", devName, strerror(errno)); 0088 } 0089 0090 case ERR_APPLY_CAL: { 0091 return i18n("Could not apply calibration values for joystick device %1: %2", devName, strerror(errno)); 0092 } 0093 0094 default: 0095 return i18n("internal error - code %1 unknown", int(code)); 0096 } 0097 } 0098 0099 JoyDevice::ErrorCode JoyDevice::open() 0100 { 0101 if (joyFd != -1) 0102 return JoyDevice::SUCCESS; // already open 0103 0104 int fd = ::open(devName.toLatin1(), O_RDONLY); 0105 0106 if (fd == -1) 0107 return JoyDevice::OPEN_FAILED; 0108 0109 // we could open the devicefile, now check if a joystick is attached 0110 char name[128]; 0111 0112 if (::ioctl(fd, JSIOCGNAME(sizeof(name)), &name) == -1) { 0113 ::close(fd); 0114 return JoyDevice::NO_JOYSTICK; 0115 } 0116 0117 // check the kernel driver version 0118 int version; 0119 if (::ioctl(fd, JSIOCGVERSION, &version) == -1) { 0120 ::close(fd); 0121 return JoyDevice::ERR_GET_VERSION; 0122 } 0123 0124 if (version != JS_VERSION) { 0125 ::close(fd); 0126 return JoyDevice::WRONG_VERSION; 0127 } 0128 0129 char bt = 0, ax = 0; 0130 if (::ioctl(fd, JSIOCGBUTTONS, &bt) == -1) { 0131 ::close(fd); 0132 return JoyDevice::ERR_GET_BUTTONS; 0133 } 0134 0135 if (::ioctl(fd, JSIOCGAXES, &ax) == -1) { 0136 ::close(fd); 0137 return JoyDevice::ERR_GET_AXES; 0138 } 0139 0140 struct js_corr *oldCorr = new struct js_corr[ax]; 0141 0142 if (::ioctl(fd, JSIOCGCORR, oldCorr) == -1) { 0143 ::close(fd); 0144 delete[] oldCorr; 0145 return JoyDevice::ERR_GET_CORR; 0146 } 0147 0148 if (bt < 0) { 0149 ::close(fd); 0150 delete[] oldCorr; 0151 return JoyDevice::ERR_GET_BUTTONS; 0152 } 0153 0154 descr = name; 0155 joyFd = fd; 0156 axes = ax; 0157 buttons = bt; 0158 origCorr = oldCorr; 0159 corr = new struct js_corr[axes]; 0160 0161 amin = new int[axes]; 0162 amax = new int[axes]; 0163 0164 int i; 0165 0166 for (i = 0; i < axes; i++) 0167 resetMinMax(i); 0168 0169 return JoyDevice::SUCCESS; 0170 } 0171 0172 void JoyDevice::close() 0173 { 0174 if (joyFd == -1) 0175 return; 0176 0177 ::close(joyFd); 0178 0179 joyFd = -1; 0180 descr = QString(); 0181 0182 delete[] amin; 0183 delete[] amax; 0184 amin = nullptr; 0185 amax = nullptr; 0186 0187 delete[] corr; 0188 corr = nullptr; 0189 delete[] origCorr; 0190 origCorr = nullptr; 0191 } 0192 0193 int JoyDevice::axisMin(int axis) const 0194 { 0195 if ((axis < 0) || (axis >= axes)) 0196 return 0; 0197 0198 return amin[axis]; 0199 } 0200 0201 int JoyDevice::axisMax(int axis) const 0202 { 0203 if ((axis < 0) || (axis >= axes)) 0204 return 0; 0205 0206 return amax[axis]; 0207 } 0208 0209 JoyDevice::ErrorCode JoyDevice::initCalibration() 0210 { 0211 if (joyFd == -1) 0212 return JoyDevice::ERR_INIT_CAL; 0213 0214 int i; 0215 0216 // Reset all current correction values 0217 for (i = 0; i < axes; i++) { 0218 corr[i].type = JS_CORR_NONE; 0219 corr[i].prec = 0; 0220 } 0221 0222 if (::ioctl(joyFd, JSIOCSCORR, corr) == -1) 0223 return JoyDevice::ERR_INIT_CAL; 0224 0225 for (i = 0; i < axes; i++) 0226 corr[i].type = JS_CORR_BROKEN; 0227 0228 return JoyDevice::SUCCESS; 0229 } 0230 0231 JoyDevice::ErrorCode JoyDevice::applyCalibration() 0232 { 0233 if (joyFd == -1) 0234 return JoyDevice::ERR_APPLY_CAL; 0235 0236 if (::ioctl(joyFd, JSIOCSCORR, corr) == -1) 0237 return JoyDevice::ERR_APPLY_CAL; 0238 0239 return JoyDevice::SUCCESS; 0240 } 0241 0242 void JoyDevice::resetMinMax(int axis, int value) 0243 { 0244 amin[axis] = value; 0245 amax[axis] = value; 0246 } 0247 0248 void JoyDevice::calcPrecision() 0249 { 0250 if (!corr) 0251 return; 0252 0253 int i; 0254 0255 for (i = 0; i < axes; i++) { 0256 corr[i].prec = amax[i] - amin[i]; 0257 qDebug() << "Precision for axis: " << i << ": " << corr[i].prec; 0258 } 0259 } 0260 0261 JoyDevice::ErrorCode JoyDevice::restoreCorr() 0262 { 0263 if (joyFd == -1) 0264 return JoyDevice::SUCCESS; 0265 0266 if (::ioctl(joyFd, JSIOCSCORR, origCorr) == -1) 0267 return JoyDevice::ERR_RESTORE_CORR; 0268 else 0269 return JoyDevice::SUCCESS; 0270 } 0271 0272 JoyDevice::~JoyDevice() 0273 { 0274 close(); 0275 } 0276 0277 bool JoyDevice::getEvent(JoyDevice::EventType &type, int &number, int &value, bool wait) 0278 { 0279 number = value = 0; 0280 0281 int ret; 0282 0283 fd_set readSet; 0284 0285 FD_ZERO(&readSet); 0286 FD_SET(joyFd, &readSet); 0287 0288 struct timeval timeout; 0289 timeout.tv_sec = 0; 0290 timeout.tv_usec = wait ? 10000 : 0; 0291 0292 ret = ::select(joyFd + 1, &readSet, nullptr, nullptr, &timeout); 0293 0294 if (ret == 1) // got an event from the joystick 0295 { 0296 struct js_event e; 0297 0298 if (::read(joyFd, &e, sizeof(struct js_event)) == sizeof(struct js_event)) { 0299 if (e.type & JS_EVENT_BUTTON) { 0300 type = JoyDevice::BUTTON; 0301 value = e.value; 0302 number = e.number; 0303 0304 return true; 0305 } 0306 0307 if (e.type & JS_EVENT_AXIS) { 0308 type = JoyDevice::AXIS; 0309 value = e.value; 0310 number = e.number; 0311 0312 // store min, max values 0313 if (e.value < amin[number]) 0314 amin[number] = e.value; 0315 if (e.value > amax[number]) 0316 amax[number] = e.value; 0317 0318 return true; 0319 } 0320 } 0321 } 0322 0323 return false; // no event 0324 } 0325 0326 void JoyDevice::calcCorrection(int axis, int *min, int *center, int *max) 0327 { 0328 const int MIN = 0; 0329 const int MAX = 1; 0330 0331 double a, b, c, d; 0332 0333 a = center[MIN]; // inputs.cmin[1]; 0334 b = center[MAX]; // inputs.cmax[1]; 0335 c = 32767.0 / (center[MIN] - min[MAX]); // (inputs.cmin[1] - inputs.cmax[0]); 0336 d = 32767.0 / (max[MIN] - center[MAX]); // (inputs.cmin[2] - inputs.cmax[1]); 0337 0338 corr[axis].coef[0] = (int)rint(a); 0339 corr[axis].coef[1] = (int)rint(b); 0340 corr[axis].coef[2] = (int)rint(c * 16384.0); 0341 corr[axis].coef[3] = (int)rint(d * 16384.0); 0342 0343 qDebug() << "min min: " << min[0] << " max: " << min[1]; 0344 qDebug() << "max min: " << max[0] << " max: " << max[1]; 0345 qDebug() << "Correction values for axis: " << axis << ": " << corr[axis].coef[0] << ", " << corr[axis].coef[1] << ", " << corr[axis].coef[2] << ", " 0346 << corr[axis].coef[3] << Qt::endl; 0347 }