From c8a011440601329618b027cfd3c7de8a3e9b0e59 Mon Sep 17 00:00:00 2001 From: curt Date: Thu, 15 Jun 2000 18:49:42 +0000 Subject: [PATCH] Start of a ascii-file configurable joystick module. --- src/Joystick/joystick.cxx | 241 ++++++++++++++++++++++++++++---------- src/Joystick/js_demo.cxx | 53 +++++---- 2 files changed, 209 insertions(+), 85 deletions(-) diff --git a/src/Joystick/joystick.cxx b/src/Joystick/joystick.cxx index 28810d97c..77f41320e 100644 --- a/src/Joystick/joystick.cxx +++ b/src/Joystick/joystick.cxx @@ -1,6 +1,7 @@ // joystick.cxx -- joystick support // // Written by Curtis Olson, started October 1998. +// Amended by Alexander Perry, started May 2000, for lots of game controllers. // // Copyright (C) 1998 - 1999 Curtis L. Olson - curt@flightgear.org // @@ -33,6 +34,7 @@ #include #include
+#include
#if defined( ENABLE_PLIB_JOYSTICK ) # include // plib include @@ -47,15 +49,61 @@ #if defined( ENABLE_PLIB_JOYSTICK ) +// Maximum number of joystick devices +#define jsN 8 + // joystick classes -static jsJoystick *js0; -static jsJoystick *js1; +static jsJoystick *( js[jsN] ); // these will hold the values of the axes -static float *js_ax0, *js_ax1; +// the first points to all the axes, the second by device +static int js_axes; +static float *js_ax_all, *( js_ax[jsN] ); +static int js_buttons[jsN]; + +// these will point to elements of that float array +static float *to_elevator, *to_aileron, *to_rudder, *to_throttle; +static float *to_viewhat, *to_brakeL, *to_brakeR; + +// these will point to elements of that digital button array +static int *to_gearmove, *to_flapup, *to_flapdn, *to_eltrimup, *to_eltrimdn; +static int msk_gearmove, msk_flapup, msk_flapdn, msk_eltrimup, msk_eltrimdn; + +// this finds the first unused occasion of a specific channel number +// on a controller with a known number of channels. Remember, when +// you use USB devices, they appear in a semi-random order. Sigh. +void to_find_A ( int firstcall, float **ptr, int axes, int axis ) +{ int a; + if (firstcall) (*ptr) = NULL; + for ( a = 0; a < jsN; a++ ) + if ( ( NULL != js[a] ) + && ( NULL == *ptr ) + && ( axes == js[a]->getNumAxes() ) + && ( (js_ax[a])[axis] > 0.5 ) + ) { ( *ptr) = (js_ax[a]) + axis; + (**ptr) = 0; + } +} -static bool sync_throttle=false; +// this finds a specific button on a given controller device +static int to_find_D_zero; +void to_find_D ( int butnum, float *ana, int **butptr, int *mask ) +{ int a; + to_find_D_zero = 0; + (*butptr) = & to_find_D_zero; + (*mask) = ( (int) 1 ) << butnum; + if ( NULL != ana ) + for ( a=0; a < jsN; a++ ) + if ( ( NULL != js[a] ) + && ( ana >= js_ax[a] ) + && ( ana - js_ax[a] <= js[a]->getNumAxes() ) + ){ (*butptr) = & ( js_buttons[a] ); +// printf ( "Button %i uses mask %i\n", butnum, *mask ); + } +} +// this decides whether we believe the throttle is safe to use +static bool sync_throttle=false; static float throttle_tmp=0; #define SYNC_TOLERANCE 0.02 @@ -127,58 +175,90 @@ void joystick(unsigned int buttonMask, int js_x, int js_y, int js_z) // Initialize the joystick(s) int fgJoystickInit( void ) { + int i, j; + FG_LOG( FG_INPUT, FG_INFO, "Initializing joystick" ); #if defined( ENABLE_PLIB_JOYSTICK ) - js0 = new jsJoystick ( 0 ); - js1 = new jsJoystick ( 1 ); - - if ( js0->notWorking () ) { - // not working - } else { - // allocate storage for axes values - js_ax0 = new float [ js0->getNumAxes() ]; + js_axes = 0; + for ( i = 0; i < jsN; i ++ ) + { js[i] = new jsJoystick ( i ); + if ( js[i]->notWorking () ) + { // not working +//BUG free ( js[i] ); + js[i] = NULL; + } else { + j = js[i]->getNumAxes(); + FG_LOG ( FG_INPUT, FG_INFO, + " Joystick " << i << " detected with " << j << " axes" ); + // Count axes and set all the deadbands + js_axes += j; + while ( j>0 ) + js[i]->setDeadBand( --j, 0.1 ); + } + } - // configure - js0->setDeadBand( 0, 0.1 ); - js0->setDeadBand( 1, 0.1 ); + // allocate storage for axes values + js_ax_all = new float [ js_axes + 1 ]; + j = 0; + for ( i = 0; i < jsN; i ++ ) + if ( js[i] != NULL ) + { // Point to the memory + js_ax [i] = js_ax_all + j; + j += js[i]->getNumAxes(); + } + + // Warn user if we didn't find anything in the end + if ( js_axes == 0 ) { + FG_LOG ( FG_INPUT, FG_INFO, " No joysticks detected" ); + } - FG_LOG ( FG_INPUT, FG_INFO, - " Joystick 0 detected with " << js0->getNumAxes() - << " axes" ); + // Guess channel assignments; do this once and save nightmares later + for ( i = 0; i < js_axes; i++ ) + { js_ax_all[i] = 1.0; + js_buttons[i] = 0; } - if ( js1->notWorking () ) { - // not working - } else { - // allocate storage for axes values - js_ax1 = new float [ js1->getNumAxes() ]; + to_find_A ( 1, &to_aileron , 6, 0 ); // Yoke + to_find_A ( 0, &to_aileron , 2, 0 ); // Analog JS + to_find_A ( 1, &to_elevator , 6, 1 ); // Yoke + to_find_A ( 0, &to_elevator , 2, 1 ); // Analog JS - // configure - js1->setDeadBand( 0, 0.1 ); - js1->setDeadBand( 1, 0.1 ); + to_find_A ( 1, &to_throttle , 6, 3 ); // Yoke + to_find_A ( 0, &to_throttle , 2, 0 ); // Analog JS, presume second + to_find_A ( 0, &to_throttle , 4, 2 ); // gaming joystick - FG_LOG ( FG_INPUT, FG_INFO, - " Joystick 1 detected with " << js1->getNumAxes() - << " axes" ); - } + to_find_A ( 1, &to_rudder , 4, 3 ); // Pedals or gaming joystick + to_find_A ( 0, &to_rudder , 2, 1 ); // Analog JS, maybe second - if ( js0->notWorking() && js1->notWorking() ) { - FG_LOG ( FG_INPUT, FG_INFO, " No joysticks detected" ); - return 0; - } + to_find_A ( 1, &to_viewhat , 6, 4 ); // Yoke + + to_find_A ( 1, &to_brakeL , 4, 0 ); // Pedals + to_find_A ( 1, &to_brakeR , 4, 1 ); // Pedals + + // Derive some of the interesting buttons from the channels + // 0 is the push-to-talk, 1 is gear switch + to_find_D ( 1, to_viewhat , &to_gearmove, &msk_gearmove ); + // 2,3 are rudder trim + // 4,5 are spare buttons + // 8,9 are flaps + to_find_D ( 9, to_viewhat , &to_flapup, &msk_flapup ); + to_find_D ( 8, to_viewhat , &to_flapdn, &msk_flapdn ); + to_find_D ( 6, to_viewhat , &to_eltrimup, &msk_eltrimup ); + to_find_D ( 7, to_viewhat , &to_eltrimdn, &msk_eltrimdn ); // I hate doing this sort of thing, but it's overridable from the // command line/config file. If the user hasn't specified an - // autocoordination preference, and if they have a single 2 axis + // autocoordination preference, and if they only have two axes of // joystick, then automatical enable auto_coordination. - if ( (current_options.get_auto_coordination() == - fgOPTIONS::FG_AUTO_COORD_NOT_SPECIFIED) && - (!js0->notWorking() && js1->notWorking() && (js0->getNumAxes() < 3) - ) - ) + if ( ( current_options.get_auto_coordination() == + fgOPTIONS::FG_AUTO_COORD_NOT_SPECIFIED + ) + && ( js_axes > 0 ) + && ( js_axes < 3 ) + ) { current_options.set_auto_coordination(fgOPTIONS::FG_AUTO_COORD_ENABLED); } @@ -208,17 +288,36 @@ int fgJoystickInit( void ) { // update the control parameters based on joystick intput int fgJoystickRead( void ) { - int b; - - if ( ! js0->notWorking() ) { - js0->read( &b, js_ax0 ) ; - controls.set_aileron( js_ax0[0] ); - controls.set_elevator( -js_ax0[1] ); + int i; + + // Go and fetch all the readings in one pass + for ( i = 0; i < jsN; i++ ) + if ( NULL != js[i] ) + js[i]->read( & ( js_buttons[i] ), js_ax[i] ) ; + + // These are the easy ones for now + if ( NULL != to_aileron ) controls.set_aileron ( * to_aileron ); + if ( NULL != to_elevator ) controls.set_elevator( - * to_elevator ); + if ( NULL != to_brakeL ) controls.set_brake ( 0, * to_brakeL ); + if ( NULL != to_brakeR ) controls.set_brake ( 1, * to_brakeR ); + // Good! Brakes need half travel to act. + +// No gear implemented yet! +// if ( msk_gearmove & *to_gearmove ) controls.set_gear +// ( 1 - controls.get_gear()); + + if ( msk_flapup & *to_flapup ) controls.move_flaps ( 0.02 ); + if ( msk_flapdn & *to_flapdn ) controls.move_flaps ( - 0.02 ); + if ( msk_eltrimup & *to_eltrimup ) + controls.move_elevator_trim ( 0.005 ); + if ( msk_eltrimdn & *to_eltrimdn ) + controls.move_elevator_trim ( - 0.005 ); + + // Added by William Riley -- riley@technologist.com + // Modified by Alex Perry + if ( NULL != to_throttle ) { + throttle_tmp=(- * to_throttle + 1) / 2; - // Added by William Riley -- riley@technologist.com - if ( js0->getNumAxes() >= 3 ) { - throttle_tmp=(-js_ax0[3] + 1) / 2; - if(sync_throttle == true) { if (fabs(controls.get_throttle(0)-throttle_tmp) < SYNC_TOLERANCE) @@ -231,25 +330,39 @@ int fgJoystickRead( void ) { controls.set_throttle( FGControls::ALL_ENGINES,throttle_tmp ); } } - if ( js0->getNumAxes() > 3 ) { + + if ( NULL != to_rudder ) + { if ( current_options.get_auto_coordination() != fgOPTIONS::FG_AUTO_COORD_ENABLED ) { - controls.set_rudder( js_ax0[2] ); + double dead_zone = 0.0; // 0.4; + double value = * to_rudder; + if (value < -dead_zone) { + value += dead_zone; + value *= 1.0 / (1.0 - dead_zone); + } else if (value > dead_zone) { + value -= dead_zone; + value *= 1.0 / (1.0 - dead_zone); + } else { + value = 0.0; + } + controls.set_rudder(value); } } - // End of William's code - - } - - if ( ! js1->notWorking() ) { - js1->read( &b, js_ax1 ) ; - if ( current_options.get_auto_coordination() != - fgOPTIONS::FG_AUTO_COORD_ENABLED ) - { - controls.set_rudder( js_ax1[0] ); - } - controls.set_throttle( FGControls::ALL_ENGINES, -js_ax1[1] * 1.05 ); + // End of William's code + + // Use hat to set view direction + // Alex Perry 2000-05-31, based on concept by dpm + if ( NULL != to_viewhat ) + { double n = * ( to_viewhat + 1 ); + double e = * ( to_viewhat ); + double d; + if ( fabs(n) + fabs(e) > 0.1 ) + { d = atan2 ( -e, -n ); + if ( d < 0 ) d += 2 * FG_PI; + current_view.set_goal_view_offset ( d ); + } } return 1; diff --git a/src/Joystick/js_demo.cxx b/src/Joystick/js_demo.cxx index aeee4dbec..594616072 100644 --- a/src/Joystick/js_demo.cxx +++ b/src/Joystick/js_demo.cxx @@ -1,33 +1,42 @@ #include +#define Z 8 + int main ( int, char ** ) { - jsJoystick *js[2] ; - float *ax[2] ; + jsJoystick *js[Z] ; + float *ax[Z] ; + int i, j, t, useful[Z]; - js[0] = new jsJoystick ( 0 ) ; - js[1] = new jsJoystick ( 1 ) ; + for ( i = 0; i < Z; i++ ) + js[i] = new jsJoystick ( i ) ; printf ( "Joystick test program.\n" ) ; printf ( "~~~~~~~~~~~~~~~~~~~~~~\n" ) ; - if ( js[0]->notWorking () ) printf ( "Joystick 0 not detected\n" ) ; - if ( js[1]->notWorking () ) printf ( "Joystick 1 not detected\n" ) ; - if ( js[0]->notWorking () && js[1]->notWorking () ) exit ( 1 ) ; - - ax[0] = new float [ js[0]->getNumAxes () ] ; - ax[1] = new float [ js[1]->getNumAxes () ] ; + t = 0; + for ( i = 0; i < Z; i++ ) + { useful[i] = ! ( js[i]->notWorking () ); + if ( useful[i] ) + t++; + else printf ( "Joystick %i not detected\n", i ) ; + } + if ( t == 0 ) exit ( 1 ) ; - int i, j ; + for ( i = 0; i < Z; i++ ) + if ( useful[i] ) + ax[i] = new float [ js[i]->getNumAxes () ] ; - for ( i = 0 ; i < 2 ; i++ ) - printf ( "+---------------JS.%d-----------------", i ) ; + for ( i = 0 ; i < Z ; i++ ) + if ( useful[i] ) + printf ( "+---------------JS.%d-----------------", i ) ; printf ( "+\n" ) ; - for ( i = 0 ; i < 2 ; i++ ) - { + for ( i = 0 ; i < Z ; i++ ) + if ( useful[i] ) + { if ( js[i]->notWorking () ) printf ( "| ~~~ Not Detected ~~~ " ) ; else @@ -40,19 +49,21 @@ int main ( int, char ** ) for ( ; j < 6 ; j++ ) printf ( " " ) ; } - } + } printf ( "|\n" ) ; - for ( i = 0 ; i < 2 ; i++ ) - printf ( "+------------------------------------" ) ; + for ( i = 0 ; i < Z ; i++ ) + if ( useful[i] ) + printf ( "+------------------------------------" ) ; printf ( "+\n" ) ; while (1) { - for ( i = 0 ; i < 2 ; i++ ) - { + for ( i = 0 ; i < Z ; i++ ) + if ( useful[i] ) + { if ( js[i]->notWorking () ) printf ( "| . . . . . . . . . " ) ; else @@ -69,7 +80,7 @@ int main ( int, char ** ) for ( ; j < 6 ; j++ ) printf ( " . " ) ; } - } + } printf ( "|\r" ) ; fflush ( stdout ) ; -- 2.39.5