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.
34 #include <osmocore/utils.h>
36 #include <osmocom/bb/common/osmocom_data.h>
37 #include <osmocom/bb/common/logging.h>
38 #include <osmocom/bb/common/gps.h>
40 struct osmo_gps gps = {
54 static struct bsc_fd gps_bfd;
58 static struct gps_data_t* gdata;
60 int osmo_gps_cb(struct bsc_fd *bfd, unsigned int what)
72 if (gps_waiting(gdata))
75 /* polling returned an error */
80 if (gdata->set & LATLON_SET) {
82 gps.gmt = gdata->fix.time;
83 tm = localtime(&gps.gmt);
84 diff = time(NULL) - gps.gmt;
85 gps.latitude = gdata->fix.latitude;
86 gps.longitude = gdata->fix.longitude;
88 LOGP(DGPS, LOGL_INFO, " time=%02d:%02d:%02d %04d-%02d-%02d, "
89 "diff-to-host=%d, latitude=%do%.4f, longitude=%do%.4f\n",
90 tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_year + 1900,
91 tm->tm_mday, tm->tm_mon + 1, diff,
93 (gps.latitude - ((int)gps.latitude)) * 60.0,
95 (gps.longitude - ((int)gps.longitude)) * 60.0);
101 LOGP(DGPS, LOGL_DEBUG, "gps is offline");
105 int osmo_gps_open(void)
107 LOGP(DGPS, LOGL_INFO, "Connecting to gpsd at '%s:%s'\n", gps.gpsd_host, gps.gpsd_port);
110 gps_bfd.when = BSC_FD_READ;
111 gps_bfd.cb = osmo_gps_cb;
113 gdata = gps_open(gps.gpsd_host, gps.gpsd_port);
115 LOGP(DGPS, LOGL_ERROR, "Can't connect to gpsd\n");
118 gps_bfd.fd = gdata->gps_fd;
122 if (gps_stream(gdata, WATCH_ENABLE, NULL) == -1) {
123 LOGP(DGPS, LOGL_ERROR, "Error in gps_stream()\n");
127 bsc_register_fd(&gps_bfd);
132 void osmo_gps_close(void)
137 LOGP(DGPS, LOGL_INFO, "Disconnecting from gpsd\n");
139 bsc_unregister_fd(&gps_bfd);
142 gps_bfd.fd = -1; /* -1 or 0 indicates: 'close' */
147 static struct termios gps_termios, gps_old_termios;
149 static int osmo_gps_line(char *line)
151 time_t gps_now, host_now;
154 double latitude, longitude;
156 if (!!strncmp(line, "$GPGLL", 6))
159 if (strlen(line) < 37)
162 /* ddmm.mmmm,N,dddmm.mmmm,E,hhmmss.mmm,A */
165 if (line[36] != 'A') {
166 LOGP(DGPS, LOGL_INFO, "%s (invalid)\n", line);
173 gps_now = line[30] - '0';
174 gps_now += (line[29] - '0') * 10;
175 gps_now += (line[28] - '0') * 60;
176 gps_now += (line[27] - '0') * 600;
177 gps_now += (line[26] - '0') * 3600;
178 gps_now += (line[25] - '0') * 36000;
180 /* calculate the number of seconds the host differs from GPS */
181 diff = host_now % 86400 - gps_now;
186 /* apply the "date" part to the GPS time */
187 gps_now = host_now - diff;
189 tm = localtime(&gps_now);
192 latitude = (double)(line[0] - '0') * 10.0;
193 latitude += (double)(line[1] - '0');
194 latitude += (double)(line[2] - '0') / 6.0;
195 latitude += (double)(line[3] - '0') / 60.0;
196 latitude += (double)(line[5] - '0') / 600.0;
197 latitude += (double)(line[6] - '0') / 6000.0;
198 latitude += (double)(line[7] - '0') / 60000.0;
199 latitude += (double)(line[8] - '0') / 600000.0;
201 latitude = 0.0 - latitude;
202 gps.latitude = latitude;
203 longitude = (double)(line[12] - '0') * 100.0;
204 longitude += (double)(line[13] - '0') * 10.0;
205 longitude += (double)(line[14] - '0');
206 longitude += (double)(line[15] - '0') / 6.0;
207 longitude += (double)(line[16] - '0') / 60.0;
208 longitude += (double)(line[18] - '0') / 600.0;
209 longitude += (double)(line[19] - '0') / 6000.0;
210 longitude += (double)(line[20] - '0') / 60000.0;
211 longitude += (double)(line[21] - '0') / 600000.0;
213 longitude = 360.0 - longitude;
214 gps.longitude = longitude;
216 LOGP(DGPS, LOGL_DEBUG, "%s\n", line);
217 LOGP(DGPS, LOGL_INFO, " time=%02d:%02d:%02d %04d-%02d-%02d, "
218 "diff-to-host=%d, latitude=%do%.4f, longitude=%do%.4f\n",
219 tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_year + 1900,
220 tm->tm_mday, tm->tm_mon + 1, diff,
222 (gps.latitude - ((int)gps.latitude)) * 60.0,
224 (gps.longitude - ((int)gps.longitude)) * 60.0);
228 static int nmea_checksum(char *line)
230 uint8_t checksum = 0;
241 return (strtoul(line+1, NULL, 16) == checksum);
244 int osmo_gps_cb(struct bsc_fd *bfd, unsigned int what)
247 static char line[128];
251 len = read(bfd->fd, buff, sizeof(buff));
253 fprintf(stderr, "error reading GPS device (errno=%d)\n", errno);
265 if (!nmea_checksum(line))
266 fprintf(stderr, "NMEA checksum error\n");
271 line[lpos++] = buff[i++];
272 if (lpos == sizeof(line))
279 int osmo_gps_open(void)
286 LOGP(DGPS, LOGL_INFO, "Open GPS device '%s'\n", gps.device);
289 gps_bfd.when = BSC_FD_READ;
290 gps_bfd.cb = osmo_gps_cb;
291 gps_bfd.fd = open(gps.device, O_RDONLY);
301 baud = B19200; break;
303 baud = B38400; break;
305 baud = B57600; break;
307 baud = B115200; break;
310 if (isatty(gps_bfd.fd))
313 tcgetattr(gps_bfd.fd, &gps_old_termios);
314 tcgetattr(gps_bfd.fd, &gps_termios);
317 gps_termios.c_cflag |= baud;
318 cfsetispeed(&gps_termios, baud);
319 cfsetospeed(&gps_termios, baud);
321 if (tcsetattr(gps_bfd.fd, TCSANOW, &gps_termios))
322 printf("Failed to set termios for GPS\n");
325 bsc_register_fd(&gps_bfd);
330 void osmo_gps_close(void)
335 LOGP(DGPS, LOGL_INFO, "Close GPS device\n");
337 bsc_unregister_fd(&gps_bfd);
339 if (isatty(gps_bfd.fd))
340 tcsetattr(gps_bfd.fd, TCSANOW, &gps_old_termios);
343 gps_bfd.fd = -1; /* -1 or 0 indicates: 'close' */
348 void osmo_gps_init(void)
350 memset(&gps_bfd, 0, sizeof(gps_bfd));