]> git.mxchange.org Git - flightgear.git/blob - Main/fg_serial.cxx
Added a "Garman" mode.
[flightgear.git] / Main / fg_serial.cxx
1 // fg_serial.cxx -- higher level serial port management routines
2 //
3 // Written by Curtis Olson, started November 1998.
4 //
5 // Copyright (C) 1998  Curtis L. Olson - curt@flightgear.org
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 //
21 // $Id$
22 // (Log is kept at end of this file)
23
24
25 #include <stdlib.h>   // atoi()
26 #include <string>
27
28 #include <Aircraft/aircraft.hxx>
29 #include <Debug/logstream.hxx>
30 #include <Include/fg_constants.h>
31 #include <Serial/serial.hxx>
32 #include <Time/fg_time.hxx>
33
34 #include "options.hxx"
35
36 #include "fg_serial.hxx"
37
38
39 // support up to four serial channels.  Each channel can be assigned
40 // to an arbitrary port.  Bi-directional communication is supported by
41 // the underlying layer.
42
43 // define the four channels
44 fgSERIAL port_a;
45 fgSERIAL port_b;
46 fgSERIAL port_c;
47 fgSERIAL port_d;
48
49 // the type of each channel
50 fgSerialPortKind port_a_kind = FG_SERIAL_DISABLED;
51 fgSerialPortKind port_b_kind = FG_SERIAL_DISABLED;
52 fgSerialPortKind port_c_kind = FG_SERIAL_DISABLED;
53 fgSerialPortKind port_d_kind = FG_SERIAL_DISABLED;
54
55
56 // configure a port based on the config string
57 static bool config_port(fgSERIAL& s, fgSerialPortKind& kind,
58                                     const string& config)
59 {
60     string::size_type begin, end;
61
62     string device;
63     string format;
64     string baud;
65     string direction;
66
67     begin = 0;;
68
69     // device name
70     end = config.find(",", begin);
71     if ( end == string::npos ) {
72         return false;
73     }
74     
75     device = config.substr(begin, end - begin);
76     begin = end + 1;
77     cout << "  device = " << device << endl;
78
79     // format
80     end = config.find(",", begin);
81     if ( end == string::npos ) {
82         return false;
83     }
84     
85     format = config.substr(begin, end - begin);
86     begin = end + 1;
87     cout << "  format = " << format << endl;
88
89     // baud
90     end = config.find(",", begin);
91     if ( end == string::npos ) {
92         return false;
93     }
94     
95     baud = config.substr(begin, end - begin);
96     begin = end + 1;
97     cout << "  baud = " << baud << endl;
98
99     // direction
100     direction = config.substr(begin);
101     cout << "  direction = " << direction << endl;
102
103     if ( s.is_enabled() ) {
104         FG_LOG( FG_SERIAL, FG_ALERT, "This shouldn't happen, but the port " 
105                 << "is already in use, ignoring" );
106         return false;
107     }
108
109     if ( ! s.open_port( device ) ) {
110         FG_LOG( FG_SERIAL, FG_ALERT, "Error opening device: " << device );
111     }
112
113     if ( ! s.set_baud( atoi( baud.c_str() ) ) ) {
114         FG_LOG( FG_SERIAL, FG_ALERT, "Error setting baud: " << baud );
115     }
116
117     if ( format == "nmea" ) {
118         if ( direction == "out" ) {
119             kind = FG_SERIAL_NMEA_OUT;
120         } else if ( direction == "in" ) {
121             kind = FG_SERIAL_NMEA_IN;
122         } else {
123             FG_LOG( FG_SERIAL, FG_ALERT, "Unknown direction" );
124             return false;
125         }
126     } else if ( format == "garman" ) {
127         if ( direction == "out" ) {
128             kind = FG_SERIAL_GARMAN_OUT;
129         } else if ( direction == "in" ) {
130             kind = FG_SERIAL_GARMAN_IN;
131         } else {
132             FG_LOG( FG_SERIAL, FG_ALERT, "Unknown direction" );
133             return false;
134         }
135     } else if ( format == "fgfs" ) {
136         if ( direction == "out" ) {
137             kind = FG_SERIAL_FGFS_OUT;
138         } else if ( direction == "in" ) {
139             kind = FG_SERIAL_FGFS_IN;
140         } else {
141             FG_LOG( FG_SERIAL, FG_ALERT, "Unknown direction" );
142             return false;
143         }
144     } else {
145         FG_LOG( FG_SERIAL, FG_ALERT, "Unknown format" );
146         return false;
147     }
148
149     return true;
150 }
151
152
153 // initialize serial ports based on command line options (if any)
154 void fgSerialInit() {
155     if ( current_options.get_port_a_config() != "" ) {
156         config_port(port_a, port_a_kind, current_options.get_port_a_config() );
157     }
158
159     if ( current_options.get_port_b_config() != "" ) {
160         config_port(port_b, port_b_kind, current_options.get_port_b_config() );
161     }
162
163     if ( current_options.get_port_c_config() != "" ) {
164         config_port(port_c, port_c_kind, current_options.get_port_c_config() );
165     }
166
167     if ( current_options.get_port_d_config() != "" ) {
168         config_port(port_d, port_d_kind, current_options.get_port_d_config() );
169     }
170 }
171
172
173 static void send_nmea_out( fgSERIAL& s ) {
174     char rmc[256], gga[256], rmz[256];
175     char dir;
176     int deg;
177     double min;
178     fgFLIGHT *f;
179     fgTIME *t;
180
181     f = current_aircraft.flight;
182     t = &cur_time_params;
183
184     char utc[10];
185     sprintf( utc, "%02d%02d%02d", 
186              t->gmt->tm_hour, t->gmt->tm_min, t->gmt->tm_sec );
187
188     char lat[20];
189     double latd = FG_Latitude * RAD_TO_DEG;
190     if ( latd < 0.0 ) {
191         latd *= -1.0;
192         dir = 'S';
193     } else {
194         dir = 'N';
195     }
196     deg = (int)(latd);
197     min = (latd - (double)deg) * 60.0;
198     sprintf( lat, "%02d%06.3f,%c", abs(deg), min, dir);
199
200     char lon[20];
201     double lond = FG_Longitude * RAD_TO_DEG;
202     if ( lond < 0.0 ) {
203         lond *= -1.0;
204         dir = 'W';
205     } else {
206         dir = 'E';
207     }
208     deg = (int)(lond);
209     min = (lond - (double)deg) * 60.0;
210     sprintf( lon, "%02d%06.3f,%c", abs(deg), min, dir);
211
212     char speed[10];
213     sprintf( speed, "%05.1f", FG_V_equiv_kts );
214
215     char heading[10];
216     sprintf( heading, "%05.1f", FG_Psi * RAD_TO_DEG );
217
218     char altitude_m[10];
219     sprintf( altitude_m, "%02d", (int)(FG_Altitude * FEET_TO_METER) );
220
221     char altitude_ft[10];
222     sprintf( altitude_ft, "%02d", (int)FG_Altitude );
223
224     char date[10];
225     sprintf( date, "%02d%02d%02d", 
226              t->gmt->tm_mday, t->gmt->tm_mon+1, t->gmt->tm_year );
227
228     // $GPRMC,HHMMSS,A,DDMM.MMM,N,DDDMM.MMM,W,XXX.X,XXX.X,DDMMYY,XXX.X,E*XX
229     sprintf( rmc, "$GPRMC,%s,A,%s,%s,%s,%s,%s,000.0,E*00\r\n",
230              utc, lat, lon, speed, heading, date );
231
232     sprintf( gga, "$GPGGA,%s,%s,%s,1,04,0.0,%s,M,00.0,M,,*00\r\n",
233              utc, lat, lon, altitude_m );
234
235     // sprintf( rmz, "$PGRMZ,%s,f,3*00\r\n", altitude_ft );
236
237     FG_LOG( FG_SERIAL, FG_DEBUG, rmc );
238     FG_LOG( FG_SERIAL, FG_DEBUG, gga );
239     // FG_LOG( FG_SERIAL, FG_DEBUG, rmz );
240
241
242     // one full frame every 2 seconds according to the standard
243     if ( cur_time_params.cur_time % 2 == 0 ) {
244         // rmc on even seconds
245         s.write_port(rmc);
246     } else {
247         // gga on odd seconds
248         s.write_port(gga);
249     }
250     // s.write_port(rmz);
251 }
252
253 static void read_nmea_in( fgSERIAL& s ) {
254 }
255
256 static void send_garman_out( fgSERIAL& s ) {
257     char rmc[256], rmz[256];
258     char dir;
259     int deg;
260     double min;
261     fgFLIGHT *f;
262     fgTIME *t;
263
264     f = current_aircraft.flight;
265     t = &cur_time_params;
266
267     char utc[10];
268     sprintf( utc, "%02d%02d%02d", 
269              t->gmt->tm_hour, t->gmt->tm_min, t->gmt->tm_sec );
270
271     char lat[20];
272     double latd = FG_Latitude * RAD_TO_DEG;
273     if ( latd < 0.0 ) {
274         latd *= -1.0;
275         dir = 'S';
276     } else {
277         dir = 'N';
278     }
279     deg = (int)(latd);
280     min = (latd - (double)deg) * 60.0;
281     sprintf( lat, "%02d%06.3f,%c", abs(deg), min, dir);
282
283     char lon[20];
284     double lond = FG_Longitude * RAD_TO_DEG;
285     if ( lond < 0.0 ) {
286         lond *= -1.0;
287         dir = 'W';
288     } else {
289         dir = 'E';
290     }
291     deg = (int)(lond);
292     min = (lond - (double)deg) * 60.0;
293     sprintf( lon, "%02d%06.3f,%c", abs(deg), min, dir);
294
295     char speed[10];
296     sprintf( speed, "%05.1f", FG_V_equiv_kts );
297
298     char heading[10];
299     sprintf( heading, "%05.1f", FG_Psi * RAD_TO_DEG );
300
301     char altitude_m[10];
302     sprintf( altitude_m, "%02d", (int)(FG_Altitude * FEET_TO_METER) );
303
304     char altitude_ft[10];
305     sprintf( altitude_ft, "%02d", (int)FG_Altitude );
306
307     char date[10];
308     sprintf( date, "%02d%02d%02d", 
309              t->gmt->tm_mday, t->gmt->tm_mon+1, t->gmt->tm_year );
310
311     // $GPRMC,HHMMSS,A,DDMM.MMM,N,DDDMM.MMM,W,XXX.X,XXX.X,DDMMYY,XXX.X,E*XX
312     sprintf( rmc, "$GPRMC,%s,A,%s,%s,%s,%s,%s,000.0,E*00\r\n",
313              utc, lat, lon, speed, heading, date );
314
315     // sprintf( gga, "$GPGGA,%s,%s,%s,1,04,0.0,%s,M,00.0,M,,*00\r\n",
316     //          utc, lat, lon, altitude_m );
317
318     sprintf( rmz, "$PGRMZ,%s,f,3*00\r\n", altitude_ft );
319
320     FG_LOG( FG_SERIAL, FG_DEBUG, rmc );
321     FG_LOG( FG_SERIAL, FG_DEBUG, rmz );
322
323
324     // one full frame every 2 seconds according to the standard
325     if ( cur_time_params.cur_time % 2 == 0 ) {
326         // rmc on even seconds
327         s.write_port(rmc);
328     } else {
329         // gga on odd seconds
330         s.write_port(rmz);
331     }
332 }
333
334 static void read_garman_in( fgSERIAL& s ) {
335 }
336
337 static void send_fgfs_out( fgSERIAL& s ) {
338 }
339
340 static void read_fgfs_in( fgSERIAL& s ) {
341 }
342
343
344 // one more level of indirection ...
345 static void process_port( fgSERIAL& s, const fgSerialPortKind kind ) {
346     static long last_time;
347     if ( kind == FG_SERIAL_NMEA_OUT ) {
348         if (cur_time_params.cur_time > last_time ) {
349             send_nmea_out(s);
350         } 
351         last_time = cur_time_params.cur_time;
352     } else if ( kind == FG_SERIAL_NMEA_IN ) {
353         read_nmea_in(s);
354     } else if ( kind == FG_SERIAL_GARMAN_OUT ) {
355         if (cur_time_params.cur_time > last_time ) {
356             send_garman_out(s);
357         } 
358         last_time = cur_time_params.cur_time;
359     } else if ( kind == FG_SERIAL_GARMAN_IN ) {
360         read_garman_in(s);
361     } else if ( kind == FG_SERIAL_FGFS_OUT ) {
362         send_fgfs_out(s);
363     } else if ( kind == FG_SERIAL_FGFS_IN ) {
364         read_fgfs_in(s);
365     }
366 }
367
368
369 // process any serial port work
370 void fgSerialProcess() {
371     if ( port_a_kind != FG_SERIAL_DISABLED ) {
372         process_port(port_a, port_a_kind);
373     }
374
375     if ( port_b_kind != FG_SERIAL_DISABLED ) {
376         process_port(port_b, port_b_kind);
377     }
378
379     if ( port_c_kind != FG_SERIAL_DISABLED ) {
380         process_port(port_c, port_c_kind);
381     }
382
383     if ( port_d_kind != FG_SERIAL_DISABLED ) {
384         process_port(port_d, port_d_kind);
385     }
386 }
387
388
389 // $Log$
390 // Revision 1.2  1998/11/19 13:53:25  curt
391 // Added a "Garman" mode.
392 //
393 // Revision 1.1  1998/11/16 13:57:42  curt
394 // Initial revision.
395 //