]> git.mxchange.org Git - flightgear.git/blob - Main/fg_serial.cxx
Tweaking serial stuff.
[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 char calc_nmea_cksum(char *sentence) {
174     unsigned char sum = 0;
175     int i, len;
176
177     // printf("%s\n", sentence);
178
179     len = strlen(sentence);
180     sum = sentence[0];
181     for ( i = 1; i < len; i++ ) {
182         // printf("%c", sentence[i]);
183         sum ^= sentence[i];
184     }
185     // printf("\n");
186
187     // printf("sum = %02x\n", sum);
188     return sum;
189 }
190
191
192 static void send_nmea_out( fgSERIAL& s ) {
193     char rmc[256], gga[256];
194     char rmc_sum[10], gga_sum[10];
195     char dir;
196     int deg;
197     double min;
198     fgFLIGHT *f;
199     fgTIME *t;
200
201     f = current_aircraft.flight;
202     t = &cur_time_params;
203
204     char utc[10];
205     sprintf( utc, "%02d%02d%02d", 
206              t->gmt->tm_hour, t->gmt->tm_min, t->gmt->tm_sec );
207
208     char lat[20];
209     double latd = FG_Latitude * RAD_TO_DEG;
210     if ( latd < 0.0 ) {
211         latd *= -1.0;
212         dir = 'S';
213     } else {
214         dir = 'N';
215     }
216     deg = (int)(latd);
217     min = (latd - (double)deg) * 60.0;
218     sprintf( lat, "%02d%06.3f,%c", abs(deg), min, dir);
219
220     char lon[20];
221     double lond = FG_Longitude * RAD_TO_DEG;
222     if ( lond < 0.0 ) {
223         lond *= -1.0;
224         dir = 'W';
225     } else {
226         dir = 'E';
227     }
228     deg = (int)(lond);
229     min = (lond - (double)deg) * 60.0;
230     sprintf( lon, "%02d%06.3f,%c", abs(deg), min, dir);
231
232     char speed[10];
233     sprintf( speed, "%05.1f", FG_V_equiv_kts );
234
235     char heading[10];
236     sprintf( heading, "%05.1f", FG_Psi * RAD_TO_DEG );
237
238     char altitude_m[10];
239     sprintf( altitude_m, "%02d", (int)(FG_Altitude * FEET_TO_METER) );
240
241     char altitude_ft[10];
242     sprintf( altitude_ft, "%02d", (int)FG_Altitude );
243
244     char date[10];
245     sprintf( date, "%02d%02d%02d", 
246              t->gmt->tm_mday, t->gmt->tm_mon+1, t->gmt->tm_year );
247
248     // $GPRMC,HHMMSS,A,DDMM.MMM,N,DDDMM.MMM,W,XXX.X,XXX.X,DDMMYY,XXX.X,E*XX
249     sprintf( rmc, "GPRMC,%s,A,%s,%s,%s,%s,%s,0.000,E",
250              utc, lat, lon, speed, heading, date );
251     sprintf( rmc_sum, "%02X", 0 /*calc_nmea_cksum(rmc)*/ );
252
253     sprintf( gga, "GPGGA,%s,%s,%s,1,,,%s,M,,,,",
254              utc, lat, lon, altitude_m );
255     sprintf( gga_sum, "%02X", 0 /*calc_nmea_cksum(gga)*/ );
256
257
258     FG_LOG( FG_SERIAL, FG_DEBUG, rmc );
259     FG_LOG( FG_SERIAL, FG_DEBUG, gga );
260
261     // one full frame every 2 seconds according to the standard
262     if ( cur_time_params.cur_time % 2 == 0 ) {
263         // rmc on even seconds
264         string rmc_sentence = "$";
265         rmc_sentence += rmc;
266         rmc_sentence += "*";
267         rmc_sentence += rmc_sum;
268         rmc_sentence += "\r\n";
269         s.write_port(rmc_sentence);
270     } else {
271         // gga on odd seconds
272         string gga_sentence = "$";
273         gga_sentence += gga;
274         gga_sentence += "*";
275         gga_sentence += gga_sum;
276         gga_sentence += "\n";
277         // s.write_port(gga_sentence);
278     }
279 }
280
281 static void read_nmea_in( fgSERIAL& s ) {
282 }
283
284 static void send_garman_out( fgSERIAL& s ) {
285     char rmc[256], rmz[256];
286     char dir;
287     int deg;
288     double min;
289     fgFLIGHT *f;
290     fgTIME *t;
291
292     f = current_aircraft.flight;
293     t = &cur_time_params;
294
295     char utc[10];
296     sprintf( utc, "%02d%02d%02d", 
297              t->gmt->tm_hour, t->gmt->tm_min, t->gmt->tm_sec );
298
299     char lat[20];
300     double latd = FG_Latitude * RAD_TO_DEG;
301     if ( latd < 0.0 ) {
302         latd *= -1.0;
303         dir = 'S';
304     } else {
305         dir = 'N';
306     }
307     deg = (int)(latd);
308     min = (latd - (double)deg) * 60.0;
309     sprintf( lat, "%02d%06.3f,%c", abs(deg), min, dir);
310
311     char lon[20];
312     double lond = FG_Longitude * RAD_TO_DEG;
313     if ( lond < 0.0 ) {
314         lond *= -1.0;
315         dir = 'W';
316     } else {
317         dir = 'E';
318     }
319     deg = (int)(lond);
320     min = (lond - (double)deg) * 60.0;
321     sprintf( lon, "%02d%06.3f,%c", abs(deg), min, dir);
322
323     char speed[10];
324     sprintf( speed, "%05.1f", FG_V_equiv_kts );
325
326     char heading[10];
327     sprintf( heading, "%05.1f", FG_Psi * RAD_TO_DEG );
328
329     char altitude_m[10];
330     sprintf( altitude_m, "%02d", (int)(FG_Altitude * FEET_TO_METER) );
331
332     char altitude_ft[10];
333     sprintf( altitude_ft, "%02d", (int)FG_Altitude );
334
335     char date[10];
336     sprintf( date, "%02d%02d%02d", 
337              t->gmt->tm_mday, t->gmt->tm_mon+1, t->gmt->tm_year );
338
339     // $GPRMC,HHMMSS,A,DDMM.MMM,N,DDDMM.MMM,W,XXX.X,XXX.X,DDMMYY,XXX.X,E*XX
340     sprintf( rmc, "$GPRMC,%s,A,%s,%s,%s,%s,%s,000.0,E*00\r\n",
341              utc, lat, lon, speed, heading, date );
342
343     // sprintf( gga, "$GPGGA,%s,%s,%s,1,04,0.0,%s,M,00.0,M,,*00\r\n",
344     //          utc, lat, lon, altitude_m );
345
346     sprintf( rmz, "$PGRMZ,%s,f,3*00\r\n", altitude_ft );
347
348     FG_LOG( FG_SERIAL, FG_DEBUG, rmc );
349     FG_LOG( FG_SERIAL, FG_DEBUG, rmz );
350
351
352     // one full frame every 2 seconds according to the standard
353     if ( cur_time_params.cur_time % 2 == 0 ) {
354         // rmc on even seconds
355         s.write_port(rmc);
356     } else {
357         // gga on odd seconds
358         s.write_port(rmz);
359     }
360 }
361
362 static void read_garman_in( fgSERIAL& s ) {
363 }
364
365 static void send_fgfs_out( fgSERIAL& s ) {
366 }
367
368 static void read_fgfs_in( fgSERIAL& s ) {
369 }
370
371
372 // one more level of indirection ...
373 static void process_port( fgSERIAL& s, const fgSerialPortKind kind ) {
374     static long last_time;
375     if ( kind == FG_SERIAL_NMEA_OUT ) {
376         if (cur_time_params.cur_time > last_time ) {
377             send_nmea_out(s);
378         } 
379         last_time = cur_time_params.cur_time;
380     } else if ( kind == FG_SERIAL_NMEA_IN ) {
381         read_nmea_in(s);
382     } else if ( kind == FG_SERIAL_GARMAN_OUT ) {
383         if (cur_time_params.cur_time > last_time ) {
384             send_garman_out(s);
385         } 
386         last_time = cur_time_params.cur_time;
387     } else if ( kind == FG_SERIAL_GARMAN_IN ) {
388         read_garman_in(s);
389     } else if ( kind == FG_SERIAL_FGFS_OUT ) {
390         send_fgfs_out(s);
391     } else if ( kind == FG_SERIAL_FGFS_IN ) {
392         read_fgfs_in(s);
393     }
394 }
395
396
397 // process any serial port work
398 void fgSerialProcess() {
399     if ( port_a_kind != FG_SERIAL_DISABLED ) {
400         process_port(port_a, port_a_kind);
401     }
402
403     if ( port_b_kind != FG_SERIAL_DISABLED ) {
404         process_port(port_b, port_b_kind);
405     }
406
407     if ( port_c_kind != FG_SERIAL_DISABLED ) {
408         process_port(port_c, port_c_kind);
409     }
410
411     if ( port_d_kind != FG_SERIAL_DISABLED ) {
412         process_port(port_d, port_d_kind);
413     }
414 }
415
416
417 // $Log$
418 // Revision 1.3  1998/11/23 20:51:51  curt
419 // Tweaking serial stuff.
420 //
421 // Revision 1.2  1998/11/19 13:53:25  curt
422 // Added a "Garman" mode.
423 //
424 // Revision 1.1  1998/11/16 13:57:42  curt
425 // Initial revision.
426 //