1 //
2 // This file is part of Dire Wolf, an amateur radio packet TNC.
3 //
4 // Copyright (C) 2015 John Langner, WB2OSZ
5 //
6 // This program is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation, either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 //
19
20
21 /*------------------------------------------------------------------
22 *
23 * Module: dwgps.c
24 *
25 * Purpose: Interface for obtaining location from GPS.
26 *
27 * Description: This is a wrapper for two different implementations:
28 *
29 * (1) Read NMEA sentences from a serial port (or USB
30 * that looks line one). Available for all platforms.
31 *
32 * (2) Read from gpsd. Not available for Windows.
33 * Including this is optional because it depends
34 * on another external software component.
35 *
36 *
37 * API: dwgps_init Connect to data stream at start up time.
38 *
39 * dwgps_read Return most recent location to application.
40 *
41 * dwgps_print Print contents of structure for debugging.
42 *
43 * dwgps_term Shutdown on exit.
44 *
45 *
46 * from below: dwgps_set_data Called from other two implementations to
47 * save data until it is needed.
48 *
49 *---------------------------------------------------------------*/
50
51 #include "direwolf.h"
52
53 #include <stdio.h>
54 #include <unistd.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <time.h>
58
59 #include "textcolor.h"
60 #include "dwgps.h"
61 #include "dwgpsnmea.h"
62 #include "dwgpsd.h"
63
64
65 static int s_dwgps_debug = 0; /* Enable debug output. */
66 /* >= 2 show updates from GPS. */
67 /* >= 1 show results from dwgps_read. */
68
69 /*
70 * The GPS reader threads deposit current data here when it becomes available.
71 * dwgps_read returns it to the requesting application.
72 *
73 * A critical region to avoid inconsistency between fields.
74 */
75
76 static dwgps_info_t s_dwgps_info = {
77 .timestamp = 0,
78 .fix = DWFIX_NOT_INIT, /* to detect read without init. */
79 .dlat = G_UNKNOWN,
80 .dlon = G_UNKNOWN,
81 .speed_knots = G_UNKNOWN,
82 .track = G_UNKNOWN,
83 .altitude = G_UNKNOWN
84 };
85
86 static dw_mutex_t s_gps_mutex;
87
88
89 /*-------------------------------------------------------------------
90 *
91 * Name: dwgps_init
92 *
93 * Purpose: Intialize the GPS interface.
94 *
95 * Inputs: pconfig Configuration settings. This might include
96 * serial port name for direct connect and host
97 * name or address for network connection.
98 *
99 * debug - If >= 1, print results when dwgps_read is called.
100 * (In this file.)
101 *
102 * If >= 2, location updates are also printed.
103 * (In other two related files.)
104 *
105 * Returns: none
106 *
107 * Description: Call corresponding functions for implementations.
108 * Normally we would expect someone to use either GPSNMEA or
109 * GPSD but there is nothing to prevent use of both at the
110 * same time.
111 *
112 *--------------------------------------------------------------------*/
113
114
dwgps_init(struct misc_config_s * pconfig,int debug)115 void dwgps_init (struct misc_config_s *pconfig, int debug)
116 {
117
118 s_dwgps_debug = debug;
119
120 dw_mutex_init (&s_gps_mutex);
121
122 dwgpsnmea_init (pconfig, debug);
123
124 #if ENABLE_GPSD
125
126 dwgpsd_init (pconfig, debug);
127
128 #endif
129
130 SLEEP_MS(500); /* So receive thread(s) can clear the */
131 /* not init status before it gets checked. */
132
133 } /* end dwgps_init */
134
135
136 /*-------------------------------------------------------------------
137 *
138 * Name: dwgps_clear
139 *
140 * Purpose: Clear the gps info structure.
141 *
142 *--------------------------------------------------------------------*/
143
dwgps_clear(dwgps_info_t * gpsinfo)144 void dwgps_clear (dwgps_info_t *gpsinfo)
145 {
146 gpsinfo->timestamp = 0;
147 gpsinfo->fix = DWFIX_NOT_SEEN;
148 gpsinfo->dlat = G_UNKNOWN;
149 gpsinfo->dlon = G_UNKNOWN;
150 gpsinfo->speed_knots = G_UNKNOWN;
151 gpsinfo->track = G_UNKNOWN;
152 gpsinfo->altitude = G_UNKNOWN;
153 }
154
155
156 /*-------------------------------------------------------------------
157 *
158 * Name: dwgps_read
159 *
160 * Purpose: Return most recent location data available.
161 *
162 * Outputs: gpsinfo - Structure with latitude, longitude, etc.
163 *
164 * Returns: Position fix quality. Same as in structure.
165 *
166 *
167 *--------------------------------------------------------------------*/
168
dwgps_read(dwgps_info_t * gpsinfo)169 dwfix_t dwgps_read (dwgps_info_t *gpsinfo)
170 {
171
172 dw_mutex_lock (&s_gps_mutex);
173
174 memcpy (gpsinfo, &s_dwgps_info, sizeof(*gpsinfo));
175
176 dw_mutex_unlock (&s_gps_mutex);
177
178 if (s_dwgps_debug >= 1) {
179 text_color_set (DW_COLOR_DEBUG);
180 dwgps_print ("gps_read: ", gpsinfo);
181 }
182
183 // TODO: Should we check timestamp and complain if very stale?
184 // or should we leave that up to the caller?
185
186 return (s_dwgps_info.fix);
187 }
188
189
190 /*-------------------------------------------------------------------
191 *
192 * Name: dwgps_print
193 *
194 * Purpose: Print gps information for debugging.
195 *
196 * Inputs: msg - Message for prefix on line.
197 * gpsinfo - Structure with latitude, longitude, etc.
198 *
199 * Description: Caller is responsible for setting text color.
200 *
201 *--------------------------------------------------------------------*/
202
dwgps_print(char * msg,dwgps_info_t * gpsinfo)203 void dwgps_print (char *msg, dwgps_info_t *gpsinfo)
204 {
205
206 dw_printf ("%stime=%d fix=%d lat=%.6f lon=%.6f trk=%.0f spd=%.1f alt=%.0f\n",
207 msg,
208 (int)gpsinfo->timestamp, (int)gpsinfo->fix,
209 gpsinfo->dlat, gpsinfo->dlon,
210 gpsinfo->track, gpsinfo->speed_knots,
211 gpsinfo->altitude);
212
213 } /* end dwgps_set_data */
214
215
216 /*-------------------------------------------------------------------
217 *
218 * Name: dwgps_term
219 *
220 * Purpose: Shut down GPS interface before exiting from application.
221 *
222 * Inputs: none.
223 *
224 * Returns: none.
225 *
226 *--------------------------------------------------------------------*/
227
dwgps_term(void)228 void dwgps_term (void) {
229
230 dwgpsnmea_term ();
231
232 #if ENABLE_GPSD
233 dwgpsd_term ();
234 #endif
235
236 } /* end dwgps_term */
237
238
239
240
241 /*-------------------------------------------------------------------
242 *
243 * Name: dwgps_set_data
244 *
245 * Purpose: Called by the GPS interfaces when new data is available.
246 *
247 * Inputs: gpsinfo - Structure with latitude, longitude, etc.
248 *
249 *--------------------------------------------------------------------*/
250
dwgps_set_data(dwgps_info_t * gpsinfo)251 void dwgps_set_data (dwgps_info_t *gpsinfo)
252 {
253
254 /* Debug print is handled by the two callers so */
255 /* we can distinguish the source. */
256
257 dw_mutex_lock (&s_gps_mutex);
258
259 memcpy (&s_dwgps_info, gpsinfo, sizeof(s_dwgps_info));
260
261 dw_mutex_unlock (&s_gps_mutex);
262
263 } /* end dwgps_set_data */
264
265
266 /* end dwgps.c */
267
268
269
270