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