1 /*
2  * CRRCsim - the Charles River Radio Control Club Flight Simulator Project
3  *   Copyright (C) 2005, 2008 - Jens Wilhelm Wulf (original author)
4  *   Copyright (C) 2005, 2008, 2009, 2010 - Jan Reucker
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  */
21 #include "inputdev_software.h"
22 #include <SDL.h>
23 #include "../../defines.h"
24 
25 #include "../../mod_misc/lib_conversions.h"
26 
T_TX_InterfaceSoftware(int method,int axesnum)27 T_TX_InterfaceSoftware::T_TX_InterfaceSoftware(int method, int axesnum)
28   :     input_method(method),
29     numberOfAxes(axesnum)
30 {
31 #if DEBUG_TX_INTERFACE > 0
32   printf("T_TX_InterfaceSoftware::T_TX_InterfaceSoftware(int method)\n");
33 #endif
34 
35   mixer = new T_TX_Mixer(this);
36 
37   switch (input_method)
38   {
39     case eIM_joystick:
40       map = new T_AxisMapper(this);
41       calib = new T_Calibration(this);
42       break;
43 
44     case eIM_mouse:
45       map = new T_AxisMapper(this);
46       break;
47 
48     default:
49       break;
50   }
51 
52   for (int i = 0; i < TX_MAXAXIS; i++)
53   {
54     input_raw_data[i] = 0.0;
55   }
56 }
57 
~T_TX_InterfaceSoftware()58 T_TX_InterfaceSoftware::~T_TX_InterfaceSoftware()
59 {
60 #if DEBUG_TX_INTERFACE > 0
61   printf("T_TX_InterfaceSoftware::~T_TX_InterfaceSoftware()\n");
62 #endif
63   delete map;
64   delete calib;
65   delete mixer;
66 }
67 
init(SimpleXMLTransfer * config)68 int T_TX_InterfaceSoftware::init(SimpleXMLTransfer* config)
69 {
70 #if DEBUG_TX_INTERFACE > 0
71   printf("int T_TX_InterfaceSoftware::init(SimpleXMLTransfer* config)\n");
72 #endif
73 
74   int ret = 0;
75 
76   // initialize generic stuff
77   T_TX_Interface::init(config);
78 
79   // initialize mixer
80   switch (input_method)
81   {
82     case eIM_mouse:
83       ret = mixer->init(config, "inputMethod.mouse");
84       map->init(config, "inputMethod.mouse");
85       break;
86 
87     case eIM_joystick:
88       ret = mixer->init(config, "inputMethod.joystick");
89       map->init(config, "inputMethod.joystick");
90       calib->init(config, "inputMethod.joystick");
91       break;
92 
93     case eIM_keyboard:
94     default:
95       ret = mixer->init(config, "inputMethod.keyboard");
96       break;
97   }
98 
99   return ret;
100 }
101 
putBackIntoCfg(SimpleXMLTransfer * config)102 void T_TX_InterfaceSoftware::putBackIntoCfg(SimpleXMLTransfer* config)
103 {
104 #if DEBUG_TX_INTERFACE > 0
105   printf("int T_TX_InterfaceSoftware::putBackIntoCfg(SimpleXMLTransfer* config)\n");
106 #endif
107   T_TX_Interface::putBackIntoCfg(config);
108 
109   if (usesMixer())
110   {
111     mixer->putBackIntoCfg(config);
112   }
113   if (usesMapper())
114   {
115     map->putBackIntoCfg(config);
116   }
117   if (usesCalibration())
118   {
119     calib->putBackIntoCfg(config);
120   }
121 }
122 
getInputData(TSimInputs * inputs)123 void T_TX_InterfaceSoftware::getInputData(TSimInputs* inputs)
124 {
125 #if DEBUG_TX_INTERFACE > 1
126   printf("void T_TX_InterfaceSoftware::getInputData(TSimInputs* inputs)\n");
127 #endif
128 
129   float calibrated[T_AxisMapper::NUM_AXISFUNCS];
130   int   axisnum;
131 
132   // pre-initialize all axes with the values from the keyboard interface
133   preInitFromKeyboard(inputs);
134 
135   calibrated[T_AxisMapper::NOTHING] = 0.0;
136   calibrated[T_AxisMapper::ELEVATOR] = inputs->elevator;
137   calibrated[T_AxisMapper::AILERON] = inputs->aileron;
138   calibrated[T_AxisMapper::RUDDER] = inputs->rudder;
139   calibrated[T_AxisMapper::THROTTLE] = inputs->throttle;
140   calibrated[T_AxisMapper::FLAP] = inputs->flap;
141   calibrated[T_AxisMapper::SPOILER] = inputs->spoiler;
142   calibrated[T_AxisMapper::RETRACT] = inputs->retract;
143   calibrated[T_AxisMapper::PITCH] = inputs->pitch;
144 
145   // now override all axes that are mapped to a "real" controller
146 
147   // evaluate calibrated input for all axis
148 
149   if (input_method != eIM_keyboard)
150   {
151     if (usesCalibration())
152     {
153       axisnum    = map->func[T_AxisMapper::ELEVATOR];
154       if (axisnum >= 0)
155         calibrated[T_AxisMapper::ELEVATOR] =
156           calib->calibrate(axisnum, input_raw_data[axisnum]) * map->inv[T_AxisMapper::ELEVATOR];
157 
158       axisnum    = map->func[T_AxisMapper::AILERON];
159       if (axisnum >= 0)
160         calibrated[T_AxisMapper::AILERON] =
161           calib->calibrate(axisnum, input_raw_data[axisnum]) * map->inv[T_AxisMapper::AILERON];
162 
163       axisnum    = map->func[T_AxisMapper::RUDDER];
164       if (axisnum >= 0)
165         calibrated[T_AxisMapper::RUDDER] =
166           calib->calibrate(axisnum, input_raw_data[axisnum]) * map->inv[T_AxisMapper::RUDDER];
167 
168       axisnum    = map->func[T_AxisMapper::THROTTLE];
169       if (axisnum >= 0)
170         calibrated[T_AxisMapper::THROTTLE] =
171           calib->calibrate(axisnum, input_raw_data[axisnum]) * map->inv[T_AxisMapper::THROTTLE];
172 
173       axisnum    = map->func[T_AxisMapper::FLAP];
174       if (axisnum >= 0)
175         calibrated[T_AxisMapper::FLAP] =
176           calib->calibrate(axisnum, input_raw_data[axisnum]) * map->inv[T_AxisMapper::FLAP];
177 
178       axisnum    = map->func[T_AxisMapper::SPOILER];
179       if (axisnum >= 0)
180         calibrated[T_AxisMapper::SPOILER] =
181           calib->calibrate(axisnum, input_raw_data[axisnum]) * map->inv[T_AxisMapper::SPOILER];
182 
183       axisnum    = map->func[T_AxisMapper::RETRACT];
184       if (axisnum >= 0)
185         calibrated[T_AxisMapper::RETRACT] =
186           calib->calibrate(axisnum, input_raw_data[axisnum]) * map->inv[T_AxisMapper::RETRACT];
187 
188       axisnum    = map->func[T_AxisMapper::PITCH];
189       if (axisnum >= 0)
190         calibrated[T_AxisMapper::PITCH] =
191           calib->calibrate(axisnum, input_raw_data[axisnum]) * map->inv[T_AxisMapper::PITCH];
192     }
193     else  // doesn't use calibration
194     {
195       axisnum    = map->func[T_AxisMapper::ELEVATOR];
196       if (axisnum >= 0)
197         calibrated[T_AxisMapper::ELEVATOR] =
198           input_raw_data[axisnum] * map->inv[T_AxisMapper::ELEVATOR];
199 
200       axisnum    = map->func[T_AxisMapper::AILERON];
201       if (axisnum >= 0)
202         calibrated[T_AxisMapper::AILERON] =
203           input_raw_data[axisnum] * map->inv[T_AxisMapper::AILERON];
204 
205       axisnum    = map->func[T_AxisMapper::RUDDER];
206       if (axisnum >= 0)
207         calibrated[T_AxisMapper::RUDDER] =
208           input_raw_data[axisnum] * map->inv[T_AxisMapper::RUDDER];
209 
210       axisnum    = map->func[T_AxisMapper::THROTTLE];
211       if (axisnum >= 0)
212         calibrated[T_AxisMapper::THROTTLE] =
213           input_raw_data[axisnum] * map->inv[T_AxisMapper::THROTTLE];
214 
215       axisnum    = map->func[T_AxisMapper::FLAP];
216       if (axisnum >= 0)
217         calibrated[T_AxisMapper::FLAP] =
218           input_raw_data[axisnum] * map->inv[T_AxisMapper::FLAP];
219 
220       axisnum    = map->func[T_AxisMapper::SPOILER];
221       if (axisnum >= 0)
222         calibrated[T_AxisMapper::SPOILER] =
223           input_raw_data[axisnum] * map->inv[T_AxisMapper::SPOILER];
224 
225       axisnum    = map->func[T_AxisMapper::RETRACT];
226       if (axisnum >= 0)
227         calibrated[T_AxisMapper::RETRACT] =
228           input_raw_data[axisnum] * map->inv[T_AxisMapper::RETRACT];
229 
230       axisnum    = map->func[T_AxisMapper::PITCH];
231       if (axisnum >= 0)
232         calibrated[T_AxisMapper::PITCH] =
233           input_raw_data[axisnum] * map->inv[T_AxisMapper::PITCH];
234     }
235   }
236 
237   // apply expo, scaling and trim
238   calibrated[T_AxisMapper::ELEVATOR] = limit(mixer->mix_signed(
239     calibrated[T_AxisMapper::ELEVATOR], T_AxisMapper::ELEVATOR));
240   calibrated[T_AxisMapper::AILERON]  = limit(mixer->mix_signed(
241     calibrated[T_AxisMapper::AILERON],  T_AxisMapper::AILERON));
242   calibrated[T_AxisMapper::RUDDER]   = limit(mixer->mix_signed(
243     calibrated[T_AxisMapper::RUDDER],   T_AxisMapper::RUDDER));
244   calibrated[T_AxisMapper::THROTTLE] = limit_unsigned(mixer->mix_unsigned(
245     calibrated[T_AxisMapper::THROTTLE], T_AxisMapper::THROTTLE));
246   calibrated[T_AxisMapper::FLAP]     = limit(mixer->mix_signed(
247     calibrated[T_AxisMapper::FLAP],     T_AxisMapper::FLAP));
248   calibrated[T_AxisMapper::SPOILER]  = limit_unsigned(mixer->mix_unsigned(
249     calibrated[T_AxisMapper::SPOILER],  T_AxisMapper::SPOILER));
250   calibrated[T_AxisMapper::RETRACT]  = limit_unsigned(mixer->mix_unsigned(
251     calibrated[T_AxisMapper::RETRACT],  T_AxisMapper::RETRACT));
252   calibrated[T_AxisMapper::PITCH]    = limit(mixer->mix_signed(
253     calibrated[T_AxisMapper::PITCH],    T_AxisMapper::PITCH));
254 
255   // further apply mixers
256   inputs->elevator = limit(mixer->mix_mixer(calibrated, T_AxisMapper::ELEVATOR));
257   inputs->aileron  = limit(mixer->mix_mixer(calibrated, T_AxisMapper::AILERON));
258   inputs->rudder   = limit(mixer->mix_mixer(calibrated, T_AxisMapper::RUDDER));
259   inputs->throttle = limit_unsigned(mixer->mix_mixer(calibrated, T_AxisMapper::THROTTLE));
260   inputs->flap     = limit(mixer->mix_mixer(calibrated, T_AxisMapper::FLAP));
261   inputs->spoiler  = limit_unsigned(mixer->mix_mixer(calibrated, T_AxisMapper::SPOILER));
262   inputs->retract  = limit_unsigned(mixer->mix_mixer(calibrated, T_AxisMapper::RETRACT));
263   inputs->pitch    = limit(mixer->mix_mixer(calibrated, T_AxisMapper::PITCH));
264 }
265 
266 
getRawData(float * dest)267 void T_TX_InterfaceSoftware::getRawData(float *dest)
268 {
269   int axes = getNumAxes();
270 
271   if (axes > TX_MAXAXIS)
272   {
273     axes = TX_MAXAXIS;
274   }
275   for (int i = 0; i < axes; i++)
276   {
277     *(dest + i) = input_raw_data[i];
278   }
279 }
280 
setAxis(int axis,const float x)281 void T_TX_InterfaceSoftware::setAxis(int axis, const float x)
282 {
283   input_raw_data[axis] = limit(x);
284 }
285 
286 
getDeviceList(std::vector<std::string> & Devices)287 int T_TX_InterfaceSoftware::getDeviceList(std::vector<std::string>& Devices)
288 {
289   Devices.erase(Devices.begin(), Devices.end());
290 
291   #if TEST_WITHOUT_JOYSTICK > 0
292   for (int i = 0; i < TEST_WITHOUT_JOYSTICK; i++)
293   {
294     char number[7];
295     std::string name;
296 
297     snprintf(number, 6, "%2d - ", i);
298     name = number;
299     name += "fake joystick";
300     Devices.push_back(name);
301   }
302   #else
303   for (int i = 0; i < SDL_NumJoysticks(); i++)
304   {
305     std::string name;
306 
307     if (SDL_JoystickName(i) != NULL)
308     {
309       name = SDL_JoystickName(i);
310     }
311     else
312     {
313       name = "not available (removed?)";
314       std::cerr << "CGUICtrlGeneralDialog::rebuildJoystickComboBox(): error:" << std::endl;
315       std::cerr << "  Joystick " << i << " is no longer available (removed after starting CRRCsim?)." << std::endl;
316     }
317     Devices.push_back(name);
318   }
319   #endif
320 
321   return Devices.size();
322 }
323 
324