Paparazzi UAS  v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
nps_main_common.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2009 Antoine Drouin <poinix@gmail.com>
3  * Copyright (C) 2012 The Paparazzi Team
4  * Copyright (C) 2016 Michal Podhradsky <http://github.com/podhrmic>
5  *
6  * This file is part of paparazzi.
7  *
8  * paparazzi is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2, or (at your option)
11  * any later version.
12  *
13  * paparazzi is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with paparazzi; see the file COPYING. If not, write to
20  * the Free Software Foundation, 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23 
24 #include "nps_main.h"
25 #include <signal.h>
26 #include <stdio.h>
27 #include <getopt.h>
28 
29 #include "nps_flightgear.h"
30 
31 #include "nps_ivy.h"
32 
33 pthread_t th_flight_gear;
34 pthread_t th_display_ivy;
35 pthread_t th_main_loop;
36 pthread_mutex_t fdm_mutex;
38 struct NpsMain nps_main;
39 
40 #ifdef __MACH__
41 pthread_mutex_t clock_mutex; // mutex for clock
42 void clock_get_current_time(struct timespec *ts)
43 {
44  pthread_mutex_lock(&clock_mutex);
45  clock_serv_t cclock;
46  mach_timespec_t mts;
47  host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
48  clock_get_time(cclock, &mts);
49  mach_port_deallocate(mach_task_self(), cclock);
50  ts->tv_sec = mts.tv_sec;
51  ts->tv_nsec = mts.tv_nsec;
52  pthread_mutex_unlock(&clock_mutex);
53 }
54 #endif
55 
56 void tstp_hdl(int n __attribute__((unused)))
57 {
58  if (pauseSignal) {
59  pauseSignal = 0;
60  signal(SIGTSTP, SIG_DFL);
61  raise(SIGTSTP);
62  } else {
63  pauseSignal = 1;
64  }
65 }
66 
67 
68 void cont_hdl(int n __attribute__((unused)))
69 {
70  signal(SIGCONT, cont_hdl);
71  signal(SIGTSTP, tstp_hdl);
72  printf("Press <enter> to continue.\n");
73 }
74 
75 
76 double time_to_double(struct timeval *t)
77 {
78  return ((double)t->tv_sec + (double)(t->tv_usec * 1e-6));
79 }
80 
81 double ntime_to_double(struct timespec *t)
82 {
83  return ((double)t->tv_sec + (double)(t->tv_nsec * 1e-9));
84 }
85 
86 int nps_main_init(int argc, char **argv)
87 {
88  pauseSignal = 0;
89 
90  if (!nps_main_parse_options(argc, argv)) { return 1; }
91 
92  /* disable buffering for stdout,
93  * so it properly works in paparazzi center
94  * where it is not detected as interactive
95  * and hence fully buffered instead of line buffered
96  */
97  setbuf(stdout, NULL);
98 
99 
100  nps_main.sim_time = 0.;
101  nps_main.display_time = 0.;
102  struct timeval t;
103  gettimeofday(&t, NULL);
106 
110  printf("Simulating with dt of %f\n", SIM_DT);
111 
113 
114 #if DEBUG_NPS_TIME
115  printf("host_time_factor,host_time_elapsed,host_time_now,scaled_initial_time,sim_time_before,display_time_before,sim_time_after,display_time_after\n");
116 #endif
117 
118  signal(SIGCONT, cont_hdl);
119  signal(SIGTSTP, tstp_hdl);
120  printf("Time factor is %f. (Press Ctrl-Z to change)\n", nps_main.host_time_factor);
121 
122  return 0;
123 }
124 
125 
126 void nps_set_time_factor(float time_factor)
127 {
128  if (time_factor < 0.0 || time_factor > 100.0) {
129  return;
130  }
131  if (fabs(nps_main.host_time_factor - time_factor) < 0.01) {
132  return;
133  }
134 
135  struct timeval tv_now;
136  double t_now, t_elapsed;
137 
138  gettimeofday(&tv_now, NULL);
139  t_now = time_to_double(&tv_now);
140 
141  /* "virtual" elapsed time with old time factor */
142  t_elapsed = (t_now - nps_main.scaled_initial_time) * nps_main.host_time_factor;
143 
144  /* set new time factor */
145  nps_main.host_time_factor = time_factor;
146  printf("Time factor is %f\n", nps_main.host_time_factor);
147  fflush(stdout);
148 
149  /* set new "virtual" scaled initial time using new time factor*/
151 }
152 
153 
154 bool nps_main_parse_options(int argc, char **argv)
155 {
156 
157  nps_main.fg_host = NULL;
158  nps_main.fg_port = 5501;
159  nps_main.fg_port_in = 5502;
161  nps_main.js_dev = NULL;
162  nps_main.spektrum_dev = NULL;
163  nps_main.rc_script = 0;
164  nps_main.norc = false;
165  nps_main.ivy_bus = NULL;
167  nps_main.fg_fdm = 0;
168  nps_main.nodisplay = false;
169 
170  static const char *usage =
171  "Usage: %s [options]\n"
172  " Options :\n"
173  " -h Display this help\n"
174  " --fg_host <flight gear host> e.g. 127.0.0.1\n"
175  " --fg_port <flight gear port> e.g. 5501\n"
176  " --fg_port_in <flight gear in port> e.g. 5502\n"
177  " --fg_time_offset <offset in seconds> e.g. 21600 for 6h\n"
178  " -j --js_dev <optional joystick index> e.g. 1 (default 0)\n"
179  " --spektrum_dev <spektrum device> e.g. /dev/ttyUSB0\n"
180  " --rc_script <number> e.g. 0\n"
181  " --norc e.g. disable RC\n"
182  " --ivy_bus <ivy bus> e.g. 127.255.255.255\n"
183  " --time_factor <factor> e.g. 2.5\n"
184  " --nodisplay e.g. disable NPS ivy messages\n"
185  " --fg_fdm";
186 
187 
188  while (1) {
189 
190  static struct option long_options[] = {
191  {"fg_host", 1, NULL, 0},
192  {"fg_port", 1, NULL, 0},
193  {"fg_time_offset", 1, NULL, 0},
194  {"js_dev", 2, NULL, 0},
195  {"spektrum_dev", 1, NULL, 0},
196  {"rc_script", 1, NULL, 0},
197  {"norc", 0, NULL, 0},
198  {"ivy_bus", 1, NULL, 0},
199  {"time_factor", 1, NULL, 0},
200  {"fg_fdm", 0, NULL, 0},
201  {"fg_port_in", 1, NULL, 0},
202  {"nodisplay", 0, NULL, 0},
203  {0, 0, 0, 0}
204  };
205  int option_index = 0;
206  int c = getopt_long(argc, argv, "jh",
207  long_options, &option_index);
208  if (c == -1) {
209  break;
210  }
211 
212  switch (c) {
213  case 0:
214  switch (option_index) {
215  case 0:
216  nps_main.fg_host = strdup(optarg); break;
217  case 1:
218  nps_main.fg_port = atoi(optarg); break;
219  case 2:
220  nps_main.fg_time_offset = atoi(optarg); break;
221  case 3:
222  if (optarg == NULL) {nps_main.js_dev = strdup("0");}
223  else {nps_main.js_dev = strdup(optarg);}
224  break;
225  case 4:
226  nps_main.spektrum_dev = strdup(optarg); break;
227  case 5:
228  nps_main.rc_script = atoi(optarg); break;
229  case 6:
230  nps_main.norc = true; break;
231  case 7:
232  nps_main.ivy_bus = strdup(optarg); break;
233  case 8:
234  nps_main.host_time_factor = atof(optarg); break;
235  case 9:
236  nps_main.fg_fdm = 1; break;
237  case 10:
238  nps_main.fg_port_in = atoi(optarg); break;
239  case 11:
240  nps_main.nodisplay = true; break;
241  default:
242  break;
243  }
244  break;
245 
246  case 'j':
247  if (optarg == NULL) {nps_main.js_dev = strdup("0");}
248  else {nps_main.js_dev = strdup(optarg);}
249  break;
250 
251  case 'h':
252  fprintf(stderr, usage, argv[0]);
253  exit(0);
254 
255  default:
256  printf("?? getopt returned character code 0%o ??\n", c);
257  fprintf(stderr, usage, argv[0]);
258  exit(EXIT_FAILURE);
259  }
260  }
261  return TRUE;
262 }
263 
264 
265 void *nps_flight_gear_loop(void *data __attribute__((unused)))
266 {
267  struct timespec requestStart;
268  struct timespec requestEnd;
269  struct timespec waitFor;
270  long int period_ns = DISPLAY_DT * 1000000000L; // thread period in nanoseconds
271  long int task_ns = 0; // time it took to finish the task in nanoseconds
272 
273 
275 
276  while (TRUE) {
277  clock_get_current_time(&requestStart);
278 
279  pthread_mutex_lock(&fdm_mutex);
280  if (nps_main.fg_host) {
281  if (nps_main.fg_fdm) {
283  } else {
285  }
286  }
287  pthread_mutex_unlock(&fdm_mutex);
288 
289  clock_get_current_time(&requestEnd);
290 
291  // Calculate time it took
292  task_ns = (requestEnd.tv_sec - requestStart.tv_sec) * 1000000000L + (requestEnd.tv_nsec - requestStart.tv_nsec);
293 
294  // task took less than one period, sleep for the rest of time
295  if (task_ns < period_ns) {
296  waitFor.tv_sec = 0;
297  waitFor.tv_nsec = period_ns - task_ns;
298  nanosleep(&waitFor, NULL);
299  } else {
300  // task took longer than the period
301 #ifdef PRINT_TIME
302  printf("FG THREAD: task took longer than one period, exactly %f [ms], but the period is %f [ms]\n",
303  (double)task_ns / 1E6, (double)period_ns / 1E6);
304 #endif
305  }
306  }
307 
308  return(NULL);
309 }
310 
311 
312 
313 void *nps_main_display(void *data __attribute__((unused)))
314 {
315  struct timespec requestStart;
316  struct timespec requestEnd;
317  struct timespec waitFor;
318  long int period_ns = 3 * DISPLAY_DT * 1000000000L; // thread period in nanoseconds
319  long int task_ns = 0; // time it took to finish the task in nanoseconds
320 
322 
323  // start the loop only if no_display is false
324  if (!nps_main.nodisplay) {
325  while (TRUE) {
326  clock_get_current_time(&requestStart);
327 
329 
330  clock_get_current_time(&requestEnd);
331 
332  // Calculate time it took
333  task_ns = (requestEnd.tv_sec - requestStart.tv_sec) * 1000000000L + (requestEnd.tv_nsec - requestStart.tv_nsec);
334 
335  // task took less than one period, sleep for the rest of time
336  if (task_ns < period_ns) {
337  waitFor.tv_sec = 0;
338  waitFor.tv_nsec = period_ns - task_ns;
339  nanosleep(&waitFor, NULL);
340  } else {
341  // task took longer than the period
342  #ifdef PRINT_TIME
343  printf("IVY DISPLAY THREAD: task took longer than one period, exactly %f [ms], but the period is %f [ms]\n",
344  (double)task_ns / 1E6, (double)period_ns / 1E6);
345  #endif
346  }
347  }
348  }
349  return(NULL);
350 }
#define sensors(...)
Definition: cc2500_compat.h:68
static void usage(BaseSequentialStream *lchp, char *p)
Definition: microrlShell.c:137
void nps_atmosphere_init(void)
void nps_fdm_init(double dt)
NPS FDM rover init.
struct NpsFdm fdm
Holds all necessary NPS FDM state information.
void nps_flightgear_send(void)
Send FlightGear GUI packet For visualization of airplane position and attitude only start fgfs with –...
void nps_flightgear_init(const char *host, unsigned int port, unsigned int port_in, unsigned int time_offset)
void nps_flightgear_send_fdm(void)
Send FlightGear FDM packet For visualization with moving surfaces (elevator, propeller etc).
void nps_ivy_display(struct NpsFdm *fdm_data, struct NpsSensors *sensors_data)
Definition: nps_ivy.c:221
void nps_ivy_init(char *ivy_bus)
Definition: nps_ivy.c:58
char * spektrum_dev
Definition: nps_main.h:65
char * js_dev
Definition: nps_main.h:64
#define DISPLAY_DT
Definition: nps_main.h:21
double display_time
Definition: nps_main.h:58
int rc_script
Definition: nps_main.h:66
unsigned int fg_port_in
Definition: nps_main.h:61
#define clock_get_current_time(_x)
Definition: nps_main.h:17
bool norc
Definition: nps_main.h:67
bool nodisplay
Definition: nps_main.h:69
double host_time_factor
Definition: nps_main.h:56
void nps_radio_and_autopilot_init(void)
Definition: nps_main_hitl.c:58
int fg_fdm
Definition: nps_main.h:63
double sim_time
Definition: nps_main.h:57
char * fg_host
Definition: nps_main.h:59
char * ivy_bus
Definition: nps_main.h:68
#define SIM_DT
Definition: nps_main.h:20
double scaled_initial_time
Definition: nps_main.h:55
double real_initial_time
Definition: nps_main.h:54
unsigned int fg_time_offset
Definition: nps_main.h:62
unsigned int fg_port
Definition: nps_main.h:60
void * nps_flight_gear_loop(void *data)
void tstp_hdl(int n)
pthread_t th_display_ivy
void cont_hdl(int n)
struct NpsMain nps_main
int nps_main_init(int argc, char **argv)
void * nps_main_display(void *data)
bool nps_main_parse_options(int argc, char **argv)
int pauseSignal
void nps_set_time_factor(float time_factor)
double time_to_double(struct timeval *t)
pthread_mutex_t fdm_mutex
pthread_t th_main_loop
pthread_t th_flight_gear
double ntime_to_double(struct timespec *t)
void nps_sensors_init(double time)
Definition: nps_sensors.c:5
#define TRUE
Definition: std.h:4