2 * (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
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.
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.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
35 #include <osmocom/core/utils.h>
37 #include <osmocom/bb/common/osmocom_data.h>
38 #include <osmocom/bb/common/logging.h>
39 #include <osmocom/bb/common/gps.h>
55 static struct bsc_fd gps_bfd;
59 static struct gps_data_t* gdata;
61 int osmo_gpsd_cb(struct bsc_fd *bfd, unsigned int what)
73 if (gps_waiting(gdata))
76 /* polling returned an error */
81 if (gdata->set & LATLON_SET) {
83 g.gmt = gdata->fix.time;
84 tm = localtime(&g.gmt);
85 diff = time(NULL) - g.gmt;
86 g.latitude = gdata->fix.latitude;
87 g.longitude = gdata->fix.longitude;
89 LOGP(DGPS, LOGL_INFO, " time=%02d:%02d:%02d %04d-%02d-%02d, "
90 "diff-to-host=%d, latitude=%do%.4f, longitude=%do%.4f\n",
91 tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_year + 1900,
92 tm->tm_mday, tm->tm_mon + 1, diff,
94 (g.latitude - ((int)g.latitude)) * 60.0,
96 (g.longitude - ((int)g.longitude)) * 60.0);
102 LOGP(DGPS, LOGL_DEBUG, "gps is offline");
106 int osmo_gpsd_open(void)
108 LOGP(DGPS, LOGL_INFO, "Connecting to gpsd at '%s:%s'\n", g.gpsd_host, g.gpsd_port);
111 gps_bfd.when = BSC_FD_READ;
112 gps_bfd.cb = osmo_gpsd_cb;
114 gdata = gps_open(g.gpsd_host, g.gpsd_port);
116 LOGP(DGPS, LOGL_ERROR, "Can't connect to gpsd\n");
119 gps_bfd.fd = gdata->gps_fd;
123 if (gps_stream(gdata, WATCH_ENABLE, NULL) == -1) {
124 LOGP(DGPS, LOGL_ERROR, "Error in gps_stream()\n");
128 bsc_register_fd(&gps_bfd);
133 void osmo_gpsd_close(void)
138 LOGP(DGPS, LOGL_INFO, "Disconnecting from gpsd\n");
140 bsc_unregister_fd(&gps_bfd);
143 gps_bfd.fd = -1; /* -1 or 0 indicates: 'close' */
148 static struct termios gps_termios, gps_old_termios;
150 static int osmo_serialgps_line(char *line)
152 time_t gps_now, host_now;
155 double latitude, longitude;
157 if (!!strncmp(line, "$GPGLL", 6))
160 if (strlen(line) < 37)
163 /* ddmm.mmmm,N,dddmm.mmmm,E,hhmmss.mmm,A */
166 if (line[36] != 'A') {
167 LOGP(DGPS, LOGL_INFO, "%s (invalid)\n", line);
174 gps_now = line[30] - '0';
175 gps_now += (line[29] - '0') * 10;
176 gps_now += (line[28] - '0') * 60;
177 gps_now += (line[27] - '0') * 600;
178 gps_now += (line[26] - '0') * 3600;
179 gps_now += (line[25] - '0') * 36000;
181 /* calculate the number of seconds the host differs from GPS */
182 diff = host_now % 86400 - gps_now;
187 /* apply the "date" part to the GPS time */
188 gps_now = host_now - diff;
190 tm = localtime(&gps_now);
193 latitude = (double)(line[0] - '0') * 10.0;
194 latitude += (double)(line[1] - '0');
195 latitude += (double)(line[2] - '0') / 6.0;
196 latitude += (double)(line[3] - '0') / 60.0;
197 latitude += (double)(line[5] - '0') / 600.0;
198 latitude += (double)(line[6] - '0') / 6000.0;
199 latitude += (double)(line[7] - '0') / 60000.0;
200 latitude += (double)(line[8] - '0') / 600000.0;
202 latitude = 0.0 - latitude;
203 g.latitude = latitude;
204 longitude = (double)(line[12] - '0') * 100.0;
205 longitude += (double)(line[13] - '0') * 10.0;
206 longitude += (double)(line[14] - '0');
207 longitude += (double)(line[15] - '0') / 6.0;
208 longitude += (double)(line[16] - '0') / 60.0;
209 longitude += (double)(line[18] - '0') / 600.0;
210 longitude += (double)(line[19] - '0') / 6000.0;
211 longitude += (double)(line[20] - '0') / 60000.0;
212 longitude += (double)(line[21] - '0') / 600000.0;
214 longitude = 360.0 - longitude;
215 g.longitude = longitude;
217 LOGP(DGPS, LOGL_DEBUG, "%s\n", line);
218 LOGP(DGPS, LOGL_INFO, " time=%02d:%02d:%02d %04d-%02d-%02d, "
219 "diff-to-host=%d, latitude=%do%.4f, longitude=%do%.4f\n",
220 tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_year + 1900,
221 tm->tm_mday, tm->tm_mon + 1, diff,
223 (g.latitude - ((int)g.latitude)) * 60.0,
225 (g.longitude - ((int)g.longitude)) * 60.0);
229 static int nmea_checksum(char *line)
231 uint8_t checksum = 0;
242 return (strtoul(line+1, NULL, 16) == checksum);
245 int osmo_serialgps_cb(struct bsc_fd *bfd, unsigned int what)
248 static char line[128];
252 len = read(bfd->fd, buff, sizeof(buff));
254 fprintf(stderr, "error reading GPS device (errno=%d)\n", errno);
266 if (!nmea_checksum(line))
267 fprintf(stderr, "NMEA checksum error\n");
269 osmo_serialgps_line(line);
272 line[lpos++] = buff[i++];
273 if (lpos == sizeof(line))
280 int osmo_serialgps_open(void)
287 LOGP(DGPS, LOGL_INFO, "Open GPS device '%s'\n", g.device);
290 gps_bfd.when = BSC_FD_READ;
291 gps_bfd.cb = osmo_serialgps_cb;
292 gps_bfd.fd = open(g.device, O_RDONLY);
302 baud = B19200; break;
304 baud = B38400; break;
306 baud = B57600; break;
308 baud = B115200; break;
311 if (isatty(gps_bfd.fd))
314 tcgetattr(gps_bfd.fd, &gps_old_termios);
315 tcgetattr(gps_bfd.fd, &gps_termios);
318 gps_termios.c_cflag |= baud;
319 cfsetispeed(&gps_termios, baud);
320 cfsetospeed(&gps_termios, baud);
322 if (tcsetattr(gps_bfd.fd, TCSANOW, &gps_termios))
323 printf("Failed to set termios for GPS\n");
326 bsc_register_fd(&gps_bfd);
331 void osmo_serialgps_close(void)
336 LOGP(DGPS, LOGL_INFO, "Close GPS device\n");
338 bsc_unregister_fd(&gps_bfd);
340 if (isatty(gps_bfd.fd))
341 tcsetattr(gps_bfd.fd, TCSANOW, &gps_old_termios);
344 gps_bfd.fd = -1; /* -1 or 0 indicates: 'close' */
347 void osmo_gps_init(void)
349 memset(&gps_bfd, 0, sizeof(gps_bfd));
352 int osmo_gps_open(void)
354 switch (g.gps_type) {
357 return osmo_gpsd_open();
359 case GPS_TYPE_SERIAL:
360 return osmo_serialgps_open();
367 void osmo_gps_close(void)
369 switch (g.gps_type) {
372 return osmo_gpsd_close();
374 case GPS_TYPE_SERIAL:
375 return osmo_serialgps_close();