Rev 1655 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1655 | giacomo | 1 | #include <kernel/kern.h> |
2 | #include <math.h> |
||
3 | #include <stdio.h> |
||
4 | #include <string.h> |
||
5 | #include "nmea.h" |
||
6 | |||
7 | extern struct OUTDATA gNMEAdata; |
||
8 | static void do_lat_lon(char *sentence, int begin); |
||
9 | static void do_grid(void); |
||
10 | static char *field(char *sentence, short n); |
||
11 | static void update_field_i(char *sentence, int fld, int *dest, int mask); |
||
12 | |||
13 | void processGPRMC(char *sentence) |
||
14 | { |
||
15 | char s[20], d[10]; |
||
16 | int tmp; |
||
17 | |||
18 | sscanf(field(sentence, 9), "%s", d); /* Date: ddmmyy */ |
||
19 | |||
20 | strncpy(s, d + 2, 2); /* copy month */ |
||
21 | |||
22 | strncpy(s + 3, d, 2); /* copy date */ |
||
23 | |||
24 | sscanf((d+4), "%2d", &tmp); |
||
25 | |||
26 | /* Tf.: Window the year from 1970 to 2069. This buys us some time. */ |
||
27 | if (tmp < 70) |
||
28 | strncpy(s + 6, "20", 2); /* 21th century */ |
||
29 | else |
||
30 | strncpy(s + 6, "19", 2); /* 20th century */ |
||
31 | |||
32 | strncpy(s + 8, d + 4, 2); /* copy year */ |
||
33 | |||
34 | sscanf(field(sentence, 1), "%s", d); /* Time: hhmmss */ |
||
35 | |||
36 | strncpy(s + 11, d, 2); /* copy hours */ |
||
37 | |||
38 | strncpy(s + 14, d + 2, 2); /* copy minutes */ |
||
39 | |||
40 | strncpy(s + 17, d + 4, 2); /* copy seconds */ |
||
41 | |||
42 | s[2] = s[5] = '/'; /* add the '/'s, ':'s, ' ' and string terminator */ |
||
43 | |||
44 | s[10] = ' '; |
||
45 | s[13] = s[16] = ':'; |
||
46 | s[19] = '\0'; |
||
47 | |||
48 | strcpy(gNMEAdata.utc, s); |
||
49 | |||
50 | /* A = valid, V = invalid */ |
||
51 | if (strcmp(field(sentence, 2), "V") == 0) |
||
52 | gNMEAdata.status = 0; |
||
53 | #if 0 /* Let the GGA sentence do the update so we catch diff fixes */ |
||
54 | else |
||
55 | gNMEAdata.status = 0; |
||
56 | #endif |
||
57 | |||
58 | sscanf(field(sentence, 7), "%lf", &gNMEAdata.speed); |
||
59 | sscanf(field(sentence, 8), "%lf", &gNMEAdata.track); |
||
60 | |||
61 | do_lat_lon(sentence, 3); |
||
62 | do_grid(); |
||
63 | |||
64 | } |
||
65 | |||
66 | /* ----------------------------------------------------------------------- */ |
||
67 | |||
68 | void processGPVTG(char *sentence) |
||
69 | { |
||
70 | sscanf(field(sentence, 3), "%lf", &gNMEAdata.speed); |
||
71 | sscanf(field(sentence, 1), "%lf", &gNMEAdata.track); |
||
72 | } |
||
73 | |||
74 | /* ----------------------------------------------------------------------- */ |
||
75 | |||
76 | void processGPGGA(char *sentence) |
||
77 | { |
||
78 | do_lat_lon(sentence, 2); |
||
79 | do_grid(); |
||
80 | /* 0 = none, 1 = normal, 2 = diff */ |
||
81 | sscanf(field(sentence, 6), "%d", &gNMEAdata.status); |
||
82 | if ((gNMEAdata.status > 0) && (gNMEAdata.mode < 2)) |
||
83 | gNMEAdata.mode = 2; |
||
84 | if ((gNMEAdata.status < 1) && (gNMEAdata.mode > 1)) |
||
85 | gNMEAdata.mode = 1; |
||
86 | sscanf(field(sentence, 7), "%d", &gNMEAdata.satellites); |
||
87 | sscanf(field(sentence, 9), "%lf", &gNMEAdata.altitude); |
||
88 | } |
||
89 | |||
90 | /* ----------------------------------------------------------------------- */ |
||
91 | |||
92 | void processGPGSA(char *sentence) |
||
93 | { |
||
94 | |||
95 | /* 1 = none, 2 = 2d, 3 = 3d */ |
||
96 | sscanf(field(sentence, 2), "%d", &gNMEAdata.mode); |
||
97 | if ((gNMEAdata.mode > 1) && (gNMEAdata.status < 1)) |
||
98 | gNMEAdata.status = 1; |
||
99 | if ((gNMEAdata.mode < 2) && (gNMEAdata.status > 0)) |
||
100 | gNMEAdata.status = 0; |
||
101 | sscanf(field(sentence, 15), "%lf", &gNMEAdata.pdop); |
||
102 | sscanf(field(sentence, 16), "%lf", &gNMEAdata.hdop); |
||
103 | sscanf(field(sentence, 17), "%lf", &gNMEAdata.vdop); |
||
104 | } |
||
105 | |||
106 | /* ----------------------------------------------------------------------- */ |
||
107 | |||
108 | void processGPGSV(char *sentence) |
||
109 | { |
||
110 | int n, m, f = 4; |
||
111 | |||
112 | |||
113 | if (sscanf(field(sentence, 2), "%d", &n) < 1) |
||
114 | return; |
||
115 | update_field_i(sentence, 3, &gNMEAdata.in_view, C_SAT); |
||
116 | |||
117 | n = (n - 1) * 4; |
||
118 | m = n + 4; |
||
119 | |||
120 | while (n < gNMEAdata.in_view && n < m) { |
||
121 | update_field_i(sentence, f++, &gNMEAdata.PRN[n], C_SAT); |
||
122 | update_field_i(sentence, f++, &gNMEAdata.elevation[n], C_SAT); |
||
123 | update_field_i(sentence, f++, &gNMEAdata.azimuth[n], C_SAT); |
||
124 | if (*(field(sentence, f))) |
||
125 | update_field_i(sentence, f, &gNMEAdata.ss[n], C_SAT); |
||
126 | f++; |
||
127 | n++; |
||
128 | } |
||
129 | } |
||
130 | |||
131 | /* ----------------------------------------------------------------------- */ |
||
132 | |||
133 | void processPRWIZCH(char *sentence) |
||
134 | { |
||
135 | int i; |
||
136 | |||
137 | for (i = 0; i < 12; i++) { |
||
138 | update_field_i(sentence, 2 * i + 1, &gNMEAdata.Zs[i], C_ZCH); |
||
139 | update_field_i(sentence, 2 * i + 2, &gNMEAdata.Zv[i], C_ZCH); |
||
140 | } |
||
141 | gNMEAdata.ZCHseen = 1; |
||
142 | } |
||
143 | |||
144 | /* ----------------------------------------------------------------------- */ |
||
145 | |||
146 | static void do_lat_lon(char *sentence, int begin) |
||
147 | { |
||
148 | double lat, lon, d, m; |
||
149 | char str[20], *p; |
||
150 | int updated = 0; |
||
151 | |||
152 | |||
153 | if (*(p = field(sentence, begin + 0)) != '\0') { |
||
154 | strncpy(str, p, 20); |
||
155 | sscanf(p, "%lf", &lat); |
||
156 | m = 100.0 * modf(lat / 100.0, &d); |
||
157 | lat = d + m / 60.0; |
||
158 | p = field(sentence, begin + 1); |
||
159 | if (*p == 'S') |
||
160 | lat = -lat; |
||
161 | if (gNMEAdata.latitude != lat) { |
||
162 | gNMEAdata.latitude = lat; |
||
163 | gNMEAdata.cmask |= C_LATLON; |
||
164 | } |
||
165 | updated++; |
||
166 | } |
||
167 | if (*(p = field(sentence, begin + 2)) != '\0') { |
||
168 | strncpy(str, p, 20); |
||
169 | sscanf(p, "%lf", &lon); |
||
170 | m = 100.0 * modf(lon / 100.0, &d); |
||
171 | lon = d + m / 60.0; |
||
172 | |||
173 | p = field(sentence, begin + 3); |
||
174 | if (*p == 'W') |
||
175 | lon = -lon; |
||
176 | if (gNMEAdata.longitude != lon) { |
||
177 | gNMEAdata.longitude = lon; |
||
178 | gNMEAdata.cmask |= C_LATLON; |
||
179 | } |
||
180 | updated++; |
||
181 | } |
||
182 | if (updated == 2) |
||
183 | gNMEAdata.last_update = sys_gettime(NULL); |
||
184 | } |
||
185 | |||
186 | /* ----------------------------------------------------------------------- */ |
||
187 | |||
188 | static void do_grid() { |
||
189 | double lat, lon; |
||
190 | |||
191 | lat = gNMEAdata.latitude; |
||
192 | lon = gNMEAdata.longitude; |
||
193 | |||
194 | gNMEAdata.grid[0] = 65 + (int)((180.0 + lon) / 20.0); |
||
195 | gNMEAdata.grid[1] = 65 + (int)((90.0 + lat) / 10.0); |
||
196 | gNMEAdata.grid[2] = 48 + (int)((180.0 + lon) / 2) % 10; |
||
197 | gNMEAdata.grid[3] = 48 + (int)(90.0 + lat) % 10; |
||
198 | gNMEAdata.grid[4] = 97 + ((int)(180.0 + lon) % 2) * 12 + (int)(((180.0 + lon) - (int)(180.0 + lon)) * 12); |
||
199 | gNMEAdata.grid[5] = 97 + (int)(((90.0 + lat) - (int)(90.0 + lat)) * 24); |
||
200 | gNMEAdata.grid[6] = '\0'; |
||
201 | } |
||
202 | |||
203 | /* ----------------------------------------------------------------------- */ |
||
204 | |||
205 | static void update_field_i(char *sentence, int fld, int *dest, int mask) |
||
206 | { |
||
207 | int tmp; |
||
208 | |||
209 | sscanf(field(sentence, fld), "%d", &tmp); |
||
210 | |||
211 | if (tmp != *dest) { |
||
212 | *dest = tmp; |
||
213 | gNMEAdata.cmask |= mask; |
||
214 | } |
||
215 | } |
||
216 | |||
217 | void process_message(char *sentence) |
||
218 | { |
||
219 | if (checksum(sentence)) { |
||
220 | if (strncmp(GPRMC, sentence, 5) == 0) { |
||
221 | processGPRMC(sentence); |
||
222 | } else if (strncmp(GPGGA, sentence, 5) == 0) { |
||
223 | processGPGGA(sentence); |
||
224 | } else if (strncmp(GPVTG, sentence, 5) == 0) { |
||
225 | processGPVTG(sentence); |
||
226 | } else if (strncmp(GPGSA, sentence, 5) == 0) { |
||
227 | processGPGSA(sentence); |
||
228 | } else if (strncmp(GPGSV, sentence, 5) == 0) { |
||
229 | processGPGSV(sentence); |
||
230 | } else if (strncmp(PRWIZCH, sentence, 7) == 0) { |
||
231 | processPRWIZCH(sentence); |
||
232 | } else { |
||
233 | cprintf("Unknown sentence: \"%s\"\n",sentence); |
||
234 | } |
||
235 | } else { |
||
236 | cprintf("Bad Checksum !\n"); |
||
237 | } |
||
238 | } |
||
239 | |||
240 | /* ----------------------------------------------------------------------- */ |
||
241 | |||
242 | short checksum(char *sentence) |
||
243 | { |
||
244 | unsigned char sum = '\0'; |
||
245 | char c, *p = sentence, csum[3]; |
||
246 | |||
247 | while ((c = *p++) != '*' && c != '\0') |
||
248 | sum ^= c; |
||
249 | |||
250 | sprintf(csum, "%02x", sum); |
||
251 | return (strncmp(csum, p, 2) == 0); |
||
252 | } |
||
253 | |||
254 | void add_checksum(char *sentence) |
||
255 | { |
||
256 | unsigned char sum = '\0'; |
||
257 | char c, *p = sentence; |
||
258 | |||
259 | while ((c = *p++) != '*') |
||
260 | sum ^= c; |
||
261 | |||
262 | sprintf(p, "%02x\r\n", sum); |
||
263 | } |
||
264 | |||
265 | static char *field(char *sentence, short n) |
||
266 | { |
||
267 | static char result[100]; |
||
268 | char *p = sentence; |
||
269 | |||
270 | while (n-- > 0) |
||
271 | while (*p++ != ','); |
||
272 | strcpy(result, p); |
||
273 | p = result; |
||
274 | while (*p && *p != ',' && *p != '*' && *p != '\r') |
||
275 | p++; |
||
276 | |||
277 | *p = '\0'; |
||
278 | return result; |
||
279 | } |