2 * This file is part of INAV Project.
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
6 * You can obtain one at http://mozilla.org/MPL/2.0/.
8 * Alternatively, the contents of this file may be used under the terms
9 * of the GNU General Public License Version 3, as described below:
11 * This file is free software: you may copy, redistribute and/or modify
12 * it under the terms of the GNU General Public License as published by the
13 * Free Software Foundation, either version 3 of the License, or (at your
14 * option) any later version.
16 * This file is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
19 * Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see http://www.gnu.org/licenses/.
30 #include <sys/socket.h>
31 #include <arpa/inet.h>
33 #include <sys/types.h>
34 #include <netinet/in.h>
42 #include "target/SITL/sim/xplane.h"
43 #include "target/SITL/sim/simHelper.h"
44 #include "fc/runtime_config.h"
45 #include "drivers/time.h"
46 #include "drivers/accgyro/accgyro_fake.h"
47 #include "drivers/barometer/barometer_fake.h"
48 #include "sensors/battery_sensor_fake.h"
49 #include "sensors/acceleration.h"
50 #include "drivers/pitotmeter/pitotmeter_fake.h"
51 #include "drivers/compass/compass_fake.h"
52 #include "drivers/rangefinder/rangefinder_virtual.h"
53 #include "io/rangefinder.h"
54 #include "common/utils.h"
55 #include "common/maths.h"
56 #include "flight/mixer.h"
57 #include "flight/servos.h"
58 #include "flight/imu.h"
63 #define XPLANE_JOYSTICK_AXIS_COUNT 8
66 static uint8_t pwmMapping
[XP_MAX_PWM_OUTS
];
67 static uint8_t mappingCount
;
69 static struct sockaddr_storage serverAddr
;
70 static socklen_t serverAddrLen
;
72 static pthread_t listenThread
;
73 static bool initalized
= false;
74 static bool useImu
= false;
76 static float lattitude
= 0;
77 static float longitude
= 0;
78 static float elevation
= 0;
80 static float local_vx
= 0;
81 static float local_vy
= 0;
82 static float local_vz
= 0;
83 static float groundspeed
= 0;
84 static float airspeed
= 0;
85 static float roll
= 0;
86 static float pitch
= 0;
88 static float hpath
= 0;
89 static float accel_x
= 0;
90 static float accel_y
= 0;
91 static float accel_z
= 0;
92 static float gyro_x
= 0;
93 static float gyro_y
= 0;
94 static float gyro_z
= 0;
95 static float barometer
= 0;
96 static bool hasJoystick
= false;
97 static float joystickRaw
[XPLANE_JOYSTICK_AXIS_COUNT
];
120 DREF_POS_BARO_CURRENT_INHG
,
123 DREF_JOYSTICK_VALUES_ROll
,
124 DREF_JOYSTICK_VALUES_PITCH
,
125 DREF_JOYSTICK_VALUES_THROTTLE
,
126 DREF_JOYSTICK_VALUES_YAW
,
127 DREF_JOYSTICK_VALUES_CH5
,
128 DREF_JOYSTICK_VALUES_CH6
,
129 DREF_JOYSTICK_VALUES_CH7
,
130 DREF_JOYSTICK_VALUES_CH8
,
133 uint32_t xint2uint32 (uint8_t * buf
)
135 return buf
[3] << 24 | buf
[2] << 16 | buf
[1] << 8 | buf
[0];
138 float xflt2float (uint8_t * buf
)
145 v
.i
= xint2uint32 (buf
);
149 static void registerDref(dref_t id
, char* dref
, uint32_t freq
)
152 memset(buf
, 0, sizeof(buf
));
155 memcpy(buf
+ 5, &freq
, 4);
156 memcpy(buf
+ 9, &id
, 4);
157 memcpy(buf
+ 13, dref
, strlen(dref
) + 1);
159 sendto(sockFd
, (void*)buf
, sizeof(buf
), 0, (struct sockaddr
*)&serverAddr
, serverAddrLen
);
162 static void sendDref(char* dref
, float value
)
166 memcpy(buf
+ 5, &value
, 4);
167 memset(buf
+ 9, ' ', sizeof(buf
) - 9);
168 strcpy(buf
+ 9, dref
);
170 sendto(sockFd
, (void*)buf
, sizeof(buf
), 0, (struct sockaddr
*)&serverAddr
, serverAddrLen
);
173 static void* listenWorker(void* arg
)
178 struct sockaddr_storage remoteAddr
;
179 socklen_t slen
= sizeof(remoteAddr
);
185 float motorValue
= 0;
186 float yokeValues
[3] = { 0 };
188 for (int i
= 0; i
< mappingCount
; i
++) {
192 if (pwmMapping
[i
] & 0x80) { // Motor
193 motorValue
= PWM_TO_FLOAT_0_1(motor
[pwmMapping
[i
] & 0x7f]);
195 yokeValues
[y
] = PWM_TO_FLOAT_MINUS_1_1(servo
[pwmMapping
[i
]]);
200 sendDref("sim/operation/override/override_joystick", 1);
201 sendDref("sim/cockpit2/engine/actuators/throttle_ratio_all", motorValue
);
202 sendDref("sim/joystick/yoke_roll_ratio", yokeValues
[0]);
203 sendDref("sim/joystick/yoke_pitch_ratio", yokeValues
[1]);
204 sendDref("sim/joystick/yoke_heading_ratio", yokeValues
[2]);
205 sendDref("sim/cockpit2/engine/actuators/cowl_flap_ratio[0]", 0);
206 sendDref("sim/cockpit2/engine/actuators/cowl_flap_ratio[1]", 0);
207 sendDref("sim/cockpit2/engine/actuators/cowl_flap_ratio[2]", 0);
208 sendDref("sim/cockpit2/engine/actuators/cowl_flap_ratio[3]", 0);
209 sendDref("sim/cockpit2/engine/actuators/cowl_flap_ratio[4]", 0);
211 recvLen
= recvfrom(sockFd
, buf
, sizeof(buf
), 0, (struct sockaddr
*)&remoteAddr
, &slen
);
212 if (recvLen
< 0 && errno
!= EWOULDBLOCK
) {
216 if (strncmp((char*)buf
, "RREF", 4) != 0) {
220 for (int i
= 5; i
< recvLen
; i
+= 8) {
221 dref_t dref
= (dref_t
)xint2uint32(&buf
[i
]);
222 float value
= xflt2float(&(buf
[i
+ 4]));
254 case DREF_GROUNDSPEED
:
258 case DREF_TRUE_AIRSPEED
:
278 case DREF_FORCE_G_AXI1
:
282 case DREF_FORCE_G_SIDE
:
286 case DREF_FORCE_G_NRML
:
302 case DREF_POS_BARO_CURRENT_INHG
:
306 case DREF_HAS_JOYSTICK
:
307 hasJoystick
= value
>= 1 ? true : false;
310 case DREF_JOYSTICK_VALUES_ROll
:
311 joystickRaw
[0] = value
;
314 case DREF_JOYSTICK_VALUES_PITCH
:
315 joystickRaw
[1] = value
;
318 case DREF_JOYSTICK_VALUES_THROTTLE
:
319 joystickRaw
[2] = value
;
322 case DREF_JOYSTICK_VALUES_YAW
:
323 joystickRaw
[3] = value
;
326 case DREF_JOYSTICK_VALUES_CH5
:
327 joystickRaw
[4] = value
;
330 case DREF_JOYSTICK_VALUES_CH6
:
331 joystickRaw
[5] = value
;
334 case DREF_JOYSTICK_VALUES_CH7
:
335 joystickRaw
[6] = value
;
338 case DREF_JOYSTICK_VALUES_CH8
:
339 joystickRaw
[7] = value
;
356 uint16_t channelValues
[XPLANE_JOYSTICK_AXIS_COUNT
];
357 channelValues
[0] = FLOAT_MINUS_1_1_TO_PWM(joystickRaw
[0]);
358 channelValues
[1] = FLOAT_MINUS_1_1_TO_PWM(joystickRaw
[1]);
359 channelValues
[2] = FLOAT_0_1_TO_PWM(joystickRaw
[2]);
360 channelValues
[3] = FLOAT_MINUS_1_1_TO_PWM(joystickRaw
[3]);
361 channelValues
[4] = FLOAT_0_1_TO_PWM(joystickRaw
[4]);
362 channelValues
[5] = FLOAT_0_1_TO_PWM(joystickRaw
[5]);
363 channelValues
[6] = FLOAT_0_1_TO_PWM(joystickRaw
[6]);
364 channelValues
[7] = FLOAT_0_1_TO_PWM(joystickRaw
[7]);
366 rxSimSetChannelValue(channelValues
, XPLANE_JOYSTICK_AXIS_COUNT
);
372 (int32_t)roundf(lattitude
* 10000000),
373 (int32_t)roundf(longitude
* 10000000),
374 (int32_t)roundf(elevation
* 100),
375 (int16_t)roundf(groundspeed
* 100),
376 (int16_t)roundf(hpath
* 10),
377 0, //(int16_t)roundf(-local_vz * 100),
378 0, //(int16_t)roundf(local_vx * 100),
379 0, //(int16_t)roundf(-local_vy * 100),
383 const int32_t altitideOverGround
= (int32_t)roundf(agl
* 100);
384 if (altitideOverGround
> 0 && altitideOverGround
<= RANGEFINDER_VIRTUAL_MAX_RANGE_CM
) {
385 fakeRangefindersSetData(altitideOverGround
);
387 fakeRangefindersSetData(-1);
390 const int16_t roll_inav
= roll
* 10;
391 const int16_t pitch_inav
= -pitch
* 10;
392 const int16_t yaw_inav
= yaw
* 10;
395 imuSetAttitudeRPY(roll_inav
, pitch_inav
, yaw_inav
);
396 imuUpdateAttitude(micros());
400 constrainToInt16(-accel_x
* GRAVITY_MSS
* 1000.0f
),
401 constrainToInt16(accel_y
* GRAVITY_MSS
* 1000.0f
),
402 constrainToInt16(accel_z
* GRAVITY_MSS
* 1000.0f
)
406 constrainToInt16(gyro_x
* 16.0f
),
407 constrainToInt16(-gyro_y
* 16.0f
),
408 constrainToInt16(-gyro_z
* 16.0f
)
411 fakeBaroSet((int32_t)roundf(barometer
* 3386.39f
), DEGREES_TO_CENTIDEGREES(21));
412 fakePitotSetAirspeed(airspeed
* 100.0f
);
414 fakeBattSensorSetVbat(16.8f
* 100);
421 computeQuaternionFromRPY(&quat
, roll_inav
, pitch_inav
, yaw_inav
);
422 transformVectorEarthToBody(&north
, &quat
);
424 constrainToInt16(north
.x
* 1024.0f
),
425 constrainToInt16(north
.y
* 1024.0f
),
426 constrainToInt16(north
.z
* 1024.0f
)
430 ENABLE_ARMING_FLAG(SIMULATOR_MODE_SITL
);
431 // Aircraft can wobble on the runway and prevents calibration of the accelerometer
432 ENABLE_STATE(ACCELEROMETER_CALIBRATED
);
443 bool simXPlaneInit(char* ip
, int port
, uint8_t* mapping
, uint8_t mapCount
, bool imu
)
445 memcpy(pwmMapping
, mapping
, mapCount
);
446 mappingCount
= mapCount
;
450 port
= XP_PORT
; // use default port
453 if(lookupAddress(ip
, port
, SOCK_DGRAM
, (struct sockaddr
*)&serverAddr
, &serverAddrLen
) != 0) {
457 sockFd
= socket(((struct sockaddr
*)&serverAddr
)->sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
461 char addrbuf
[IPADDRESS_PRINT_BUFLEN
];
462 char *nptr
= prettyPrintAddress((struct sockaddr
*)&serverAddr
, addrbuf
, IPADDRESS_PRINT_BUFLEN
);
464 fprintf(stderr
, "[SOCKET] xplane address = %s, fd=%d\n", nptr
, sockFd
);
471 if (setsockopt(sockFd
, SOL_SOCKET
, SO_RCVTIMEO
, (struct timeval
*) &tv
,sizeof(struct timeval
))) {
475 if (setsockopt(sockFd
, SOL_SOCKET
, SO_SNDTIMEO
, (struct timeval
*) &tv
,sizeof(struct timeval
))) {
479 if (pthread_create(&listenThread
, NULL
, listenWorker
, NULL
) < 0) {
483 while (!initalized
) {
484 registerDref(DREF_LATITUDE
, "sim/flightmodel/position/latitude", 100);
485 registerDref(DREF_LONGITUDE
, "sim/flightmodel/position/longitude", 100);
486 registerDref(DREF_ELEVATION
, "sim/flightmodel/position/elevation", 100);
487 registerDref(DREF_AGL
, "sim/flightmodel/position/y_agl", 100);
488 registerDref(DREF_LOCAL_VX
, "sim/flightmodel/position/local_vx", 100);
489 registerDref(DREF_LOCAL_VY
, "sim/flightmodel/position/local_vy", 100);
490 registerDref(DREF_LOCAL_VZ
, "sim/flightmodel/position/local_vz", 100);
491 registerDref(DREF_GROUNDSPEED
, "sim/flightmodel/position/groundspeed", 100);
492 registerDref(DREF_TRUE_AIRSPEED
, "sim/flightmodel/position/true_airspeed", 100);
493 registerDref(DREF_POS_PHI
, "sim/flightmodel/position/phi", 100);
494 registerDref(DREF_POS_THETA
, "sim/flightmodel/position/theta", 100);
495 registerDref(DREF_POS_PSI
, "sim/flightmodel/position/psi", 100);
496 registerDref(DREF_POS_HPATH
, "sim/flightmodel/position/hpath", 100);
497 registerDref(DREF_FORCE_G_AXI1
, "sim/flightmodel/forces/g_axil", 100);
498 registerDref(DREF_FORCE_G_SIDE
, "sim/flightmodel/forces/g_side", 100);
499 registerDref(DREF_FORCE_G_NRML
, "sim/flightmodel/forces/g_nrml", 100);
500 registerDref(DREF_POS_P
, "sim/flightmodel/position/P", 100);
501 registerDref(DREF_POS_Q
, "sim/flightmodel/position/Q", 100);
502 registerDref(DREF_POS_R
, "sim/flightmodel/position/R", 100);
503 registerDref(DREF_POS_BARO_CURRENT_INHG
, "sim/weather/barometer_current_inhg", 100);
504 registerDref(DREF_HAS_JOYSTICK
, "sim/joystick/has_joystick", 100);
505 registerDref(DREF_JOYSTICK_VALUES_PITCH
, "sim/joystick/joy_mapped_axis_value[1]", 100);
506 registerDref(DREF_JOYSTICK_VALUES_ROll
, "sim/joystick/joy_mapped_axis_value[2]", 100);
507 registerDref(DREF_JOYSTICK_VALUES_YAW
, "sim/joystick/joy_mapped_axis_value[3]", 100);
508 // Abusing cowl flaps for other channels
509 registerDref(DREF_JOYSTICK_VALUES_THROTTLE
, "sim/joystick/joy_mapped_axis_value[57]", 100);
510 registerDref(DREF_JOYSTICK_VALUES_CH5
, "sim/joystick/joy_mapped_axis_value[58]", 100);
511 registerDref(DREF_JOYSTICK_VALUES_CH6
, "sim/joystick/joy_mapped_axis_value[59]", 100);
512 registerDref(DREF_JOYSTICK_VALUES_CH7
, "sim/joystick/joy_mapped_axis_value[60]", 100);
513 registerDref(DREF_JOYSTICK_VALUES_CH8
, "sim/joystick/joy_mapped_axis_value[61]", 100);