Added support for NMEA GPS receiver
[osmocom-bb.git] / src / host / layer23 / src / mobile / gps.c
1 /*
2  * (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
3  *
4  * All Rights Reserved
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 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.
19  *
20  */
21
22 #include <stdio.h>
23 #include <sys/file.h>
24 #include <termios.h>
25 #include <unistd.h>
26 #include <stdlib.h>
27 #include <errno.h>
28
29 #include <osmocore/utils.h>
30
31 #include <osmocom/bb/common/osmocom_data.h>
32 #include <osmocom/bb/mobile/gps.h>
33
34 struct gps gps = {
35         0,
36         "/dev/ttyACM0",
37         0
38 };
39
40 static struct bsc_fd gps_bfd;
41 static struct termios gps_termios, gps_old_termios;
42
43 static int gps_line(char *line)
44 {
45         if (!!strncmp(line, "$GPGLL", 6))
46                 return 0;
47         line += 7;
48         if (strlen(line) < 37)
49                 return 0;
50         line[37] = '\0';
51         /* ddmm.mmmm,N,dddmm.mmmm,E,hhmmss.mmm,A */
52
53         printf("'%s'\n", line);
54
55         return 0;
56 }
57
58 static int nmea_checksum(char *line)
59 {
60         uint8_t checksum = 0;
61
62         while (*line) {
63                 if (*line == '$') {
64                         line++;
65                         continue;
66                 }
67                 if (*line == '*')
68                         break;
69                 checksum ^= *line++;
70         }
71         return (strtoul(line+1, NULL, 16) == checksum);
72 }
73
74 int gps_cb(struct bsc_fd *bfd, unsigned int what)
75 {
76         char buff[128];
77         static char line[128];
78         static int lpos = 0;
79         int i = 0, len;
80
81         len = read(bfd->fd, buff, sizeof(buff));
82         if (len <= 0) {
83                 fprintf(stderr, "error reading GPS device (errno=%d)\n", errno);
84                 return len;
85         }
86         while(i < len) {
87                 if (buff[i] == 13) {
88                         i++;
89                         continue;
90                 }
91                 if (buff[i] == 10) {
92                         line[lpos] = '\0';
93                         lpos = 0;
94                         i++;
95                         if (!nmea_checksum(line))
96                                 fprintf(stderr, "NMEA checksum error\n");
97                         else
98                                 gps_line(line);
99                         continue;
100                 }
101                 line[lpos++] = buff[i++];
102                 if (lpos == sizeof(line))
103                         lpos--;
104         }
105
106         return 0;
107 }
108
109 int gps_open(void)
110 {
111         int baud = 0;
112
113         if (gps_bfd.fd > 0)
114                 return 0;
115         gps_bfd.data = NULL;
116         gps_bfd.when = BSC_FD_READ;
117         gps_bfd.cb = gps_cb;
118         gps_bfd.fd = open(gps.device, O_RDONLY);
119         if (gps_bfd.fd < 0)
120                 return gps_bfd.fd;
121
122         switch (gps.baud) {
123         case   4800:
124                 baud = B4800;      break;
125         case   9600:
126                 baud = B9600;      break;
127         case  19200:
128                 baud = B19200;     break;
129         case  38400:
130                 baud = B38400;     break;
131         case  57600:
132                 baud = B57600;     break;       
133         case 115200: 
134                 baud = B115200;    break;
135         }
136
137         if (isatty(gps_bfd.fd))
138         {
139                 /* get termios */
140                 tcgetattr(gps_bfd.fd, &gps_old_termios);
141                 tcgetattr(gps_bfd.fd, &gps_termios);
142                 /* set baud */
143                 if (baud) {
144                         gps_termios.c_cflag |= baud;
145                         cfsetispeed(&gps_termios, baud);
146                         cfsetospeed(&gps_termios, baud);
147                 }
148                 if (tcsetattr(gps_bfd.fd, TCSANOW, &gps_termios))
149                         printf("Failed to set termios for GPS\n");
150         }
151
152         bsc_register_fd(&gps_bfd);
153
154         return 0;
155 }
156
157 void gps_close(void)
158 {
159         if (gps_bfd.fd <= 0)
160                 return;
161
162         bsc_unregister_fd(&gps_bfd);
163
164         if (isatty(gps_bfd.fd))
165                 tcsetattr(gps_bfd.fd, TCSANOW, &gps_old_termios);
166
167         close(gps_bfd.fd);
168         gps_bfd.fd = -1; /* -1 or 0 indicates: 'close' */
169 }
170
171