]> git.mxchange.org Git - flightgear.git/blob - utils/GPSsmooth/MIDG_main.cxx
333877866d632e15078130ee187fb8b84722c421
[flightgear.git] / utils / GPSsmooth / MIDG_main.cxx
1 #ifdef HAVE_CONFIG_H
2 #  include <config.h>
3 #endif
4
5 #include <iostream>
6 #include <string>
7
8 #include <plib/net.h>
9 #include <plib/sg.h>
10
11 #include <simgear/constants.h>
12 #include <simgear/io/lowlevel.hxx> // endian tests
13 #include <simgear/math/sg_geodesy.hxx>
14 #include <simgear/timing/timestamp.hxx>
15
16 #include <Network/net_ctrls.hxx>
17 #include <Network/net_fdm.hxx>
18
19 #include "MIDG-II.hxx"
20
21
22 SG_USING_STD(cout);
23 SG_USING_STD(endl);
24 SG_USING_STD(string);
25
26
27 // Network channels
28 static netSocket fdm_sock, ctrls_sock;
29
30 // midg data
31 MIDGTrack track;
32
33 // Default ports
34 static int fdm_port = 5505;
35 static int ctrls_port = 5506;
36
37 // Default path
38 static string file = "";
39
40 // Master time counter
41 float sim_time = 0.0f;
42 double frame_us = 0.0f;
43
44 // sim control
45 SGTimeStamp last_time_stamp;
46 SGTimeStamp current_time_stamp;
47
48 // altitude offset
49 double alt_offset = 0.0;
50
51 // for speed estimate
52 // double last_lat = 0.0, last_lon = 0.0;
53 // double kts_filter = 0.0;
54
55 bool inited = false;
56
57
58 // The function htond is defined this way due to the way some
59 // processors and OSes treat floating point values.  Some will raise
60 // an exception whenever a "bad" floating point value is loaded into a
61 // floating point register.  Solaris is notorious for this, but then
62 // so is LynxOS on the PowerPC.  By translating the data in place,
63 // there is no need to load a FP register with the "corruped" floating
64 // point value.  By doing the BIG_ENDIAN test, I can optimize the
65 // routine for big-endian processors so it can be as efficient as
66 // possible
67 static void htond (double &x)   
68 {
69     if ( sgIsLittleEndian() ) {
70         int    *Double_Overlay;
71         int     Holding_Buffer;
72     
73         Double_Overlay = (int *) &x;
74         Holding_Buffer = Double_Overlay [0];
75     
76         Double_Overlay [0] = htonl (Double_Overlay [1]);
77         Double_Overlay [1] = htonl (Holding_Buffer);
78     } else {
79         return;
80     }
81 }
82
83 // Float version
84 static void htonf (float &x)    
85 {
86     if ( sgIsLittleEndian() ) {
87         int    *Float_Overlay;
88         int     Holding_Buffer;
89     
90         Float_Overlay = (int *) &x;
91         Holding_Buffer = Float_Overlay [0];
92     
93         Float_Overlay [0] = htonl (Holding_Buffer);
94     } else {
95         return;
96     }
97 }
98
99
100 static void midg2fg( const MIDGpos pos, const MIDGatt att,
101                      FGNetFDM *fdm, FGNetCtrls *ctrls )
102 {
103     unsigned int i;
104
105     // Version sanity checking
106     fdm->version = FG_NET_FDM_VERSION;
107
108     // Aero parameters
109     fdm->longitude = pos.lon_deg * SGD_DEGREES_TO_RADIANS;
110     fdm->latitude = pos.lat_deg * SGD_DEGREES_TO_RADIANS;
111     fdm->altitude = pos.altitude_msl + alt_offset;
112     fdm->agl = -9999.0;
113     fdm->psi = att.yaw_rad; // heading
114     fdm->phi = att.roll_rad; // roll
115     fdm->theta = att.pitch_rad; // pitch;
116
117     fdm->phidot = 0.0;
118     fdm->thetadot = 0.0;
119     fdm->psidot = 0.0;
120
121     // estimate speed
122     // double az1, az2, dist;
123     // geo_inverse_wgs_84( pos.altitude_msl, last_lat, last_lon,
124     //                     pos.lat_deg, pos.lon_deg, &az1, &az2, &dist );
125     // double v_ms = dist / (frame_us / 1000000);
126     // double v_kts = v_ms * SG_METER_TO_NM * 3600;
127     // kts_filter = (0.99 * kts_filter) + (0.01 * v_kts);
128     fdm->vcas = pos.speed_kts;
129     // last_lat = pos.lat_deg;
130     // last_lon = pos.lon_deg;
131     // cout << "kts_filter = " << kts_filter << " vel = " << pos.speed_kts << endl;
132
133     fdm->climb_rate = 0; // fps
134     // cout << "climb rate = " << aero->hdota << endl;
135     fdm->v_north = 0.0;
136     fdm->v_east = 0.0;
137     fdm->v_down = 0.0;
138     fdm->v_wind_body_north = 0.0;
139     fdm->v_wind_body_east = 0.0;
140     fdm->v_wind_body_down = 0.0;
141     fdm->stall_warning = 0.0;
142
143     fdm->A_X_pilot = 0.0;
144     fdm->A_Y_pilot = 0.0;
145     fdm->A_Z_pilot = 0.0 /* (should be -G) */;
146
147     // Engine parameters
148     fdm->num_engines = 1;
149     fdm->eng_state[0] = 2;
150     // cout << "state = " << fdm->eng_state[0] << endl;
151     double rpm = ((pos.speed_kts - 15.0) / 65.0) * 2000.0 + 500.0;
152     if ( rpm < 0.0 ) { rpm = 0.0; }
153     if ( rpm > 3000.0 ) { rpm = 3000.0; }
154     fdm->rpm[0] = rpm;
155
156     fdm->fuel_flow[0] = 0.0;
157     fdm->egt[0] = 0.0;
158     // cout << "egt = " << aero->EGT << endl;
159     fdm->oil_temp[0] = 0.0;
160     fdm->oil_px[0] = 0.0;
161
162     // Consumables
163     fdm->num_tanks = 2;
164     fdm->fuel_quantity[0] = 0.0;
165     fdm->fuel_quantity[1] = 0.0;
166
167     // Gear and flaps
168     fdm->num_wheels = 3;
169     fdm->wow[0] = 0;
170     fdm->wow[1] = 0;
171     fdm->wow[2] = 0;
172
173     // the following really aren't used in this context
174     fdm->cur_time = 0;
175     fdm->warp = 0;
176     fdm->visibility = 0;
177
178     // cout << "Flap deflection = " << aero->dflap << endl;
179     fdm->left_flap = 0.0;
180     fdm->right_flap = 0.0;
181
182     fdm->elevator = -fdm->theta * 1.0;
183     fdm->elevator_trim_tab = 0.0;
184     fdm->left_flap = 0.0;
185     fdm->right_flap = 0.0;
186     fdm->left_aileron = fdm->phi * 1.0;
187     fdm->right_aileron = -fdm->phi * 1.0;
188     fdm->rudder = 0.0;
189     fdm->nose_wheel = 0.0;
190     fdm->speedbrake = 0.0;
191     fdm->spoilers = 0.0;
192
193     // Convert the net buffer to network format
194     fdm->version = htonl(fdm->version);
195
196     htond(fdm->longitude);
197     htond(fdm->latitude);
198     htond(fdm->altitude);
199     htonf(fdm->agl);
200     htonf(fdm->phi);
201     htonf(fdm->theta);
202     htonf(fdm->psi);
203     htonf(fdm->alpha);
204     htonf(fdm->beta);
205
206     htonf(fdm->phidot);
207     htonf(fdm->thetadot);
208     htonf(fdm->psidot);
209     htonf(fdm->vcas);
210     htonf(fdm->climb_rate);
211     htonf(fdm->v_north);
212     htonf(fdm->v_east);
213     htonf(fdm->v_down);
214     htonf(fdm->v_wind_body_north);
215     htonf(fdm->v_wind_body_east);
216     htonf(fdm->v_wind_body_down);
217
218     htonf(fdm->A_X_pilot);
219     htonf(fdm->A_Y_pilot);
220     htonf(fdm->A_Z_pilot);
221
222     htonf(fdm->stall_warning);
223     htonf(fdm->slip_deg);
224
225     for ( i = 0; i < fdm->num_engines; ++i ) {
226         fdm->eng_state[i] = htonl(fdm->eng_state[i]);
227         htonf(fdm->rpm[i]);
228         htonf(fdm->fuel_flow[i]);
229         htonf(fdm->egt[i]);
230         htonf(fdm->cht[i]);
231         htonf(fdm->mp_osi[i]);
232         htonf(fdm->tit[i]);
233         htonf(fdm->oil_temp[i]);
234         htonf(fdm->oil_px[i]);
235     }
236     fdm->num_engines = htonl(fdm->num_engines);
237
238     for ( i = 0; i < fdm->num_tanks; ++i ) {
239         htonf(fdm->fuel_quantity[i]);
240     }
241     fdm->num_tanks = htonl(fdm->num_tanks);
242
243     for ( i = 0; i < fdm->num_wheels; ++i ) {
244         fdm->wow[i] = htonl(fdm->wow[i]);
245         htonf(fdm->gear_pos[i]);
246         htonf(fdm->gear_steer[i]);
247         htonf(fdm->gear_compression[i]);
248     }
249     fdm->num_wheels = htonl(fdm->num_wheels);
250
251     fdm->cur_time = htonl( fdm->cur_time );
252     fdm->warp = htonl( fdm->warp );
253     htonf(fdm->visibility);
254
255     htonf(fdm->elevator);
256     htonf(fdm->elevator_trim_tab);
257     htonf(fdm->left_flap);
258     htonf(fdm->right_flap);
259     htonf(fdm->left_aileron);
260     htonf(fdm->right_aileron);
261     htonf(fdm->rudder);
262     htonf(fdm->nose_wheel);
263     htonf(fdm->speedbrake);
264     htonf(fdm->spoilers);
265 }
266
267
268 static void send_data( const MIDGpos pos, const MIDGatt att ) {
269     int len;
270     int ctrlsize = sizeof( FGNetCtrls );
271     int fdmsize = sizeof( FGNetFDM );
272
273     // cout << "Running main loop" << endl;
274
275     FGNetFDM fgfdm;
276     FGNetCtrls fgctrls;
277
278     midg2fg( pos, att, &fgfdm, &fgctrls );
279     len = fdm_sock.send(&fgfdm, fdmsize, 0);
280 }
281
282
283 void usage( const string &argv0 ) {
284     cout << "Usage: " << argv0 << endl;
285     cout << "\t[ --help ]" << endl;
286     cout << "\t[ --file <file_name>" << endl;
287     cout << "\t[ --hertz <hertz> ]" << endl;
288     cout << "\t[ --host <hostname> ]" << endl;
289     cout << "\t[ --broadcast ]" << endl;
290     cout << "\t[ --fdm-port <fdm output port #> ]" << endl;
291     cout << "\t[ --ctrls-port <ctrls output port #> ]" << endl;
292     cout << "\t[ --altitude-offset <meters> ]" << endl;
293 }
294
295
296 int main( int argc, char **argv ) {
297     double hertz = 60.0;
298     string out_host = "localhost";
299     bool do_broadcast = false;
300
301     // process command line arguments
302     for ( int i = 1; i < argc; ++i ) {
303         if ( strcmp( argv[i], "--help" ) == 0 ) {
304             usage( argv[0] );
305             exit( 0 );
306         } else if ( strcmp( argv[i], "--hertz" ) == 0 ) {
307             ++i;
308             if ( i < argc ) {
309                 hertz = atof( argv[i] );
310             } else {
311                 usage( argv[0] );
312                 exit( -1 );
313             }
314         } else if ( strcmp( argv[i], "--file" ) == 0 ) {
315             ++i;
316             if ( i < argc ) {
317                 file = argv[i];
318             } else {
319                 usage( argv[0] );
320                 exit( -1 );
321             }
322         } else if ( strcmp( argv[i], "--host" ) == 0 ) {
323             ++i;
324             if ( i < argc ) {
325                 out_host = argv[i];
326             } else {
327                 usage( argv[0] );
328                 exit( -1 );
329             }
330         } else if ( strcmp( argv[i], "--broadcast" ) == 0 ) {
331           do_broadcast = true;
332         } else if ( strcmp( argv[i], "--fdm-port" ) == 0 ) {
333             ++i;
334             if ( i < argc ) {
335                 fdm_port = atoi( argv[i] );
336             } else {
337                 usage( argv[0] );
338                 exit( -1 );
339             }
340         } else if ( strcmp( argv[i], "--ctrls-port" ) == 0 ) {
341             ++i;
342             if ( i < argc ) {
343                 ctrls_port = atoi( argv[i] );
344             } else {
345                 usage( argv[0] );
346                 exit( -1 );
347             }
348         } else if ( strcmp( argv[i], "--altitude-offset" ) == 0 ) {
349             ++i;
350             if ( i < argc ) {
351                 alt_offset = atof( argv[i] );
352             } else {
353                 usage( argv[0] );
354                 exit( -1 );
355             }
356         } else {
357             usage( argv[0] );
358             exit( -1 );
359         }
360     }
361
362     // Load the track data
363     if ( file == "" ) {
364         cout << "No track file specified" << endl;
365         exit(-1);
366     }
367     track.load( file );
368     cout << "Loaded " << track.possize() << " position records." << endl;
369     cout << "Loaded " << track.attsize() << " attitude records." << endl;
370
371     // Setup up outgoing network connections
372
373     netInit( &argc,argv ); // We must call this before any other net stuff
374
375     if ( ! fdm_sock.open( false ) ) {  // open a UDP socket
376         cout << "error opening fdm output socket" << endl;
377         return -1;
378     }
379     if ( ! ctrls_sock.open( false ) ) {  // open a UDP socket
380         cout << "error opening ctrls output socket" << endl;
381         return -1;
382     }
383     cout << "open net channels" << endl;
384
385     fdm_sock.setBlocking( false );
386     ctrls_sock.setBlocking( false );
387     cout << "blocking false" << endl;
388
389     if ( do_broadcast ) {
390         fdm_sock.setBroadcast( true );
391         ctrls_sock.setBroadcast( true );
392     }
393
394     if ( fdm_sock.connect( out_host.c_str(), fdm_port ) == -1 ) {
395         perror("connect");
396         cout << "error connecting to outgoing fdm port: " << out_host
397              << ":" << fdm_port << endl;
398         return -1;
399     }
400     cout << "connected outgoing fdm socket" << endl;
401
402     if ( ctrls_sock.connect( out_host.c_str(), ctrls_port ) == -1 ) {
403         perror("connect");
404         cout << "error connecting to outgoing ctrls port: " << out_host
405              << ":" << ctrls_port << endl;
406         return -1;
407     }
408     cout << "connected outgoing ctrls socket" << endl;
409
410     int size = track.possize();
411
412     double current_time = track.get_pospt(0).get_seconds();
413     cout << "Track begin time is " << current_time << endl;
414     double end_time = track.get_pospt(size-1).get_seconds();
415     cout << "Track end time is " << end_time << endl;
416     cout << "Duration = " << end_time - current_time << endl;
417
418     frame_us = 1000000.0 / hertz;
419     if ( frame_us < 0.0 ) {
420         frame_us = 0.0;
421     }
422
423     SGTimeStamp start_time;
424     start_time.stamp();
425     int pos_count = 0;
426     int att_count = 0;
427
428     MIDGpos pos0, pos1;
429     pos0 = pos1 = track.get_pospt( 0 );
430     
431     MIDGatt att0, att1;
432     att0 = att1 = track.get_attpt( 0 );
433     
434     while ( current_time < end_time ) {
435         // cout << "current_time = " << current_time << " end_time = "
436         //      << end_time << endl;
437
438         // Advance position pointer
439         if ( current_time > pos1.get_seconds() ) {
440             pos0 = pos1;
441             ++pos_count;
442             // cout << "count = " << count << endl;
443             pos1 = track.get_pospt( pos_count );
444         }
445         // cout << "p0 = " << p0.get_time() << " p1 = " << p1.get_time()
446         //      << endl;
447
448         // Advance attitude pointer
449         if ( current_time > att1.get_seconds() ) {
450             att0 = att1;
451             ++att_count;
452             // cout << "count = " << count << endl;
453             att1 = track.get_attpt( att_count );
454         }
455         // cout << "p0 = " << p0.get_time() << " p1 = " << p1.get_time()
456         //      << endl;
457
458         double pos_percent;
459         if ( fabs(pos1.get_seconds() - pos0.get_seconds()) < 0.00001 ) {
460             pos_percent = 0.0;
461         } else {
462             pos_percent =
463                 (current_time - pos0.get_seconds()) /
464                 (pos1.get_seconds() - pos0.get_seconds());
465         }
466         // cout << "Percent = " << percent << endl;
467         double att_percent;
468         if ( fabs(att1.get_seconds() - att0.get_seconds()) < 0.00001 ) {
469             att_percent = 0.0;
470         } else {
471             att_percent =
472                 (current_time - att0.get_seconds()) /
473                 (att1.get_seconds() - att0.get_seconds());
474         }
475         // cout << "Percent = " << percent << endl;
476
477         MIDGpos pos = MIDGInterpPos( pos0, pos1, pos_percent );
478         MIDGatt att = MIDGInterpAtt( att0, att1, att_percent );
479         // cout << current_time << " " << p0.lat_deg << ", " << p0.lon_deg
480         //      << endl;
481         // cout << current_time << " " << p1.lat_deg << ", " << p1.lon_deg
482         //      << endl;
483         // cout << (double)current_time << " " << pos.lat_deg << ", "
484         //      << pos.lon_deg << " " << att.yaw_deg << endl;
485         printf( "%.3f  %.4f %.4f %.1f  %.2f %.2f %.2f\n",
486                 current_time,
487                 pos.lat_deg, pos.lon_deg, pos.altitude_msl,
488                 att.yaw_rad * 180.0 / SG_PI,
489                 att.pitch_rad * 180.0 / SG_PI,
490                 att.roll_rad * 180.0 / SG_PI );
491
492         send_data( pos, att );
493
494         // Update the elapsed time.
495         static bool first_time = true;
496         if ( first_time ) {
497             last_time_stamp.stamp();
498             first_time = false;
499         }
500
501         current_time_stamp.stamp();
502         /* Convert to ms */
503         double elapsed_us = current_time_stamp - last_time_stamp;
504         if ( elapsed_us < (frame_us - 2000) ) {
505             double requested_us = (frame_us - elapsed_us) - 2000 ;
506             ulMilliSecondSleep ( (int)(requested_us / 1000.0) ) ;
507         }
508         current_time_stamp.stamp();
509         while ( current_time_stamp - last_time_stamp < frame_us ) {
510             current_time_stamp.stamp();
511         }
512
513         current_time += (frame_us / 1000000.0);
514         last_time_stamp = current_time_stamp;
515     }
516
517     cout << "Processed " << pos_count << " entries in "
518          << (current_time_stamp - start_time) / 1000000 << " seconds." << endl;
519
520     return 0;
521 }