OSDN Git Service

Disable DEBUG messages by default
[android-x86/hardware-gps.git] / gps_huawei.c
1 /*
2 **
3 ** Copyright 2006, The Android Open Source Project
4 ** Copyright 2009, Michael Trimarchi <michael@panicking.kicks-ass.org>
5 ** Copyright 2011, Eduardo José Tagle <ejtagle@tutopia.com>
6 **
7 ** This program is free software; you can redistribute it and/or modify it under
8 ** the terms of the GNU General Public License as published by the Free
9 ** Software Foundation; either version 2, or (at your option) any later
10 ** version.
11 **
12 ** This program is distributed in the hope that it will be useful, but WITHOUT
13 ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 ** FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15 ** more details.
16 **
17 ** You should have received a copy of the GNU General Public License along with
18 ** this program; if not, write to the Free Software Foundation, Inc., 59
19 ** Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 **/
21
22 #include <errno.h>
23 #include <pthread.h>
24 #include <termios.h>
25 #include <fcntl.h>
26 #include <sys/epoll.h>
27 #include <math.h>
28 #include <time.h>
29 #include <semaphore.h>
30 #include <signal.h>
31 #include <unistd.h>
32 #include <linux/socket.h>
33 #include <sys/socket.h>
34
35 #define  LOG_TAG  "gps_huawei"
36
37 #include <cutils/log.h>
38 #include <cutils/sockets.h>
39 #include <cutils/properties.h>
40 #include <hardware/gps.h>
41
42 #if GPS_DEBUG
43 #  define  D(...)   ALOGD(__VA_ARGS__)
44 #else
45 #  define  D(...)   ((void)0)
46 #endif
47
48 typedef void (*start_t)(void*);
49
50 /* Nmea Parser stuff */
51 #define  NMEA_MAX_SIZE  200
52
53 enum {
54   STATE_QUIT  = 0,
55   STATE_INIT  = 1,
56   STATE_START = 2
57 };
58
59 typedef struct {
60     int     pos;
61     int     overflow;
62     int     utc_year;
63     int     utc_mon;
64     int     utc_day;
65     int     utc_diff;
66     GpsLocation  fix;
67     GpsSvStatus  sv_status;
68     int     sv_status_changed;
69     char    in[ NMEA_MAX_SIZE+1 ];
70 } NmeaReader;
71
72
73 typedef struct {
74     volatile int            init;
75     int                     fd;
76     int                     ctrl_fd;
77     GpsCallbacks            callbacks;
78     AGpsCallbacks           a_callbacks;
79     GpsXtraCallbacks        xtra_callbacks;
80     GpsStatus               gps_status;
81     char                    nmea_buf[512];
82     int                     nmea_len;
83     pthread_t               thread;
84     sem_t                   fix_sem;
85     pthread_t               tmr_thread;
86     int                     control[2];
87     int                     min_interval; // in ms
88     NmeaReader              reader;
89
90 } GpsState;
91
92
93 /* Since NMEA parser requires lcoks */
94 #define GPS_STATE_LOCK_FIX(_s)           \
95 {                                        \
96     int ret;                             \
97     do {                                 \
98         ret = sem_wait(&(_s)->fix_sem);  \
99     } while (ret < 0 && errno == EINTR); \
100 }
101
102 #define GPS_STATE_UNLOCK_FIX(_s)         \
103     sem_post(&(_s)->fix_sem)
104
105 static GpsState  _gps_state[1];
106 static GpsState *gps_state = _gps_state;
107
108 #define GPS_POWER_IF "/sys/bus/platform/devices/shuttle-pm-gps/power_on"
109
110 #define GPS_DEV_SLOW_UPDATE_RATE (10)
111 #define GPS_DEV_HIGH_UPDATE_RATE (1)
112
113 static void dev_start(int fd);
114 static void dev_stop(int fd);
115 static void *gps_timer_thread( void*  arg );
116
117
118 static void serial_write(int fd, char *msg)
119 {
120   int i, n, ret;
121
122   i = strlen(msg);
123
124   n = 0;
125
126   do {
127
128     ret = write(fd, msg + n, i - n);
129
130     if (ret < 0 && errno == EINTR) {
131       continue;
132     }
133
134     n += ret;
135
136   } while (n < i);
137
138   return;
139 }
140
141 static unsigned char calc_nmea_csum(char *msg)
142 {
143   unsigned char csum = 0;
144   int i;
145
146   for (i = 1; msg[i] != '*'; ++i) {
147     csum ^= msg[i];
148   }
149
150   return csum;
151 }
152
153
154 /*****************************************************************/
155 /*****************************************************************/
156 /*****                                                       *****/
157 /*****       D E V I C E                                     *****/
158 /*****                                                       *****/
159 /*****************************************************************/
160 /*****************************************************************/
161
162 static void dev_power(int state)
163 {
164     char   prop[PROPERTY_VALUE_MAX];
165     int fd;
166     char cmd = '0';
167     int ret;
168     return ; //RvdB
169
170     if (property_get("gps.power_on",prop,GPS_POWER_IF) == 0) {
171         ALOGE("no gps power interface name");
172         return;
173     }
174
175     do {
176         fd = open( prop, O_RDWR );
177     } while (fd < 0 && errno == EINTR);
178
179     if (fd < 0) {
180         ALOGE("could not open gps power interface: %s", prop );
181         return;
182     }
183
184     if (state) {
185       cmd = '1';
186     } else {
187       cmd = '0';
188     }
189
190     do {
191         ret = write( fd, &cmd, 1 );
192     } while (ret < 0 && errno == EINTR);
193
194     close(fd);
195
196     D("gps power state = %c", cmd);
197
198     if (state)
199         usleep(500*1000);
200
201     return;
202
203 }
204
205 static void dev_set_nmea_message_rate(int fd,const char *msg, int rate)
206 {
207
208   char buff[50];
209   int i;
210
211   sprintf(buff, "$PUBX,40,%s,%d,%d,%d,0*", msg, rate, rate, rate);
212
213   i = strlen(buff);
214
215   sprintf((buff + i), "%02x\r\n", calc_nmea_csum(buff));
216
217   serial_write(fd, buff);
218
219   D("gps sent to device: %s", buff);
220
221   return;
222
223 }
224
225 static void dev_set_message_rate(int fd, int rate)
226 {
227
228   unsigned int i;
229   static const char *msg[] = {
230                  "GGA", "GLL", "ZDA",
231                  "VTG", "GSA", "GSV",
232                  "RMC"
233                 };
234
235   for (i = 0; i < sizeof(msg)/sizeof(msg[0]); ++i) {
236         dev_set_nmea_message_rate(fd, msg[i], rate);
237   }
238
239   return;
240 }
241
242
243 static void dev_start(int fd)
244 {
245     D("gps dev start initiated");
246     // Set full message rate
247     //RvdB dev_set_message_rate(fd, GPS_DEV_HIGH_UPDATE_RATE);
248 }
249
250 static void dev_stop(int fd)
251 {
252     D("gps dev stop");
253
254     // Set slow message rate
255     //RvdB dev_set_message_rate(fd, GPS_DEV_SLOW_UPDATE_RATE);
256 }
257
258 /*****************************************************************/
259 /*****************************************************************/
260 /*****                                                       *****/
261 /*****       N M E A   T O K E N I Z E R                     *****/
262 /*****                                                       *****/
263 /*****************************************************************/
264 /*****************************************************************/
265
266 typedef struct {
267     const char*  p;
268     const char*  end;
269 } Token;
270
271 #define  MAX_NMEA_TOKENS  32
272
273 typedef struct {
274     int     count;
275     Token   tokens[ MAX_NMEA_TOKENS ];
276 } NmeaTokenizer;
277
278 static int nmea_tokenizer_init( NmeaTokenizer*  t, const char*  p, const char*  end )
279 {
280     int    count = 0;
281     char*  q;
282
283     // the initial '$' is optional
284     if (p < end && p[0] == '$')
285         p += 1;
286
287     // remove trailing newline
288     if (end > p && end[-1] == '\n') {
289         end -= 1;
290         if (end > p && end[-1] == '\r')
291             end -= 1;
292     }
293
294     // get rid of checksum at the end of the sentecne
295     if (end >= p+3 && end[-3] == '*') {
296         end -= 3;
297     }
298
299     while (p < end) {
300         const char*  q = p;
301
302         q = memchr(p, ',', end-p);
303         if (q == NULL)
304             q = end;
305
306         if (count < MAX_NMEA_TOKENS) {
307             t->tokens[count].p   = p;
308             t->tokens[count].end = q;
309             count += 1;
310         }
311
312         if (q < end)
313             q += 1;
314
315         p = q;
316     }
317
318     t->count = count;
319     return count;
320 }
321
322 static Token nmea_tokenizer_get( NmeaTokenizer*  t, int  index )
323 {
324     Token  tok;
325     static const char*  dummy = "";
326
327     if (index < 0 || index >= t->count) {
328         tok.p = tok.end = dummy;
329     } else
330         tok = t->tokens[index];
331
332     return tok;
333 }
334
335
336 static int str2int( const char*  p, const char*  end )
337 {
338     int   result = 0;
339     int   len    = end - p;
340
341     if (len == 0) {
342       return -1;
343     }
344
345     for ( ; len > 0; len--, p++ )
346     {
347         int  c;
348
349         if (p >= end)
350             goto Fail;
351
352         c = *p - '0';
353         if ((unsigned)c >= 10)
354             goto Fail;
355
356         result = result*10 + c;
357     }
358     return  result;
359
360 Fail:
361     return -1;
362 }
363
364 static double str2float( const char*  p, const char*  end )
365 {
366     int   result = 0;
367     int   len    = end - p;
368     char  temp[16];
369
370     if (len == 0) {
371       return -1.0;
372     }
373
374     if (len >= (int)sizeof(temp))
375         return 0.;
376
377     memcpy( temp, p, len );
378     temp[len] = 0;
379     return strtod( temp, NULL );
380 }
381
382 /** @desc Convert struct tm to time_t (time zone neutral).
383  *
384  * The one missing function in libc: It works basically like mktime, with the main difference that
385  * it does no time zone-related processing but interprets the members of the struct tm as UTC.
386  * Unlike mktime, it will not modify any fields of the tm structure; if you need this behavior, call
387  * mktime before this function.
388  *
389  * @param t Pointer to a struct tm containing date and time. Only the tm_year, tm_mon, tm_mday,
390  * tm_hour, tm_min and tm_sec members will be evaluated, all others will be ignored.
391  *
392  * @return The epoch time (seconds since 1970-01-01 00:00:00 UTC) which corresponds to t.
393  *
394  * @author Originally written by Philippe De Muyter <phdm@macqel.be> for Lynx.
395  * http://lynx.isc.org/current/lynx2-8-8/src/mktime.c
396  */
397
398 static time_t mkgmtime(struct tm *t)
399 {
400     short month, year;
401     time_t result;
402     static const int m_to_d[12] =
403         {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
404
405     month = t->tm_mon;
406     year = t->tm_year + month / 12 + 1900;
407     month %= 12;
408     if (month < 0) {
409         year -= 1;
410         month += 12;
411     }
412     result = (year - 1970) * 365 + m_to_d[month];
413     if (month <= 1)
414         year -= 1;
415     result += (year - 1968) / 4;
416     result -= (year - 1900) / 100;
417     result += (year - 1600) / 400;
418     result += t->tm_mday;
419     result -= 1;
420     result *= 24;
421     result += t->tm_hour;
422     result *= 60;
423     result += t->tm_min;
424     result *= 60;
425     result += t->tm_sec;
426     return (result);
427 }
428
429 /*****************************************************************/
430 /*****************************************************************/
431 /*****                                                       *****/
432 /*****       N M E A   P A R S E R                           *****/
433 /*****                                                       *****/
434 /*****************************************************************/
435 /*****************************************************************/
436
437 static void nmea_reader_update_utc_diff( NmeaReader*  r )
438 {
439     time_t         now = time(NULL);
440     struct tm      tm_local;
441     struct tm      tm_utc;
442     long           time_local, time_utc;
443
444     gmtime_r( &now, &tm_utc );
445     localtime_r( &now, &tm_local );
446
447     time_local = mktime(&tm_local);
448     time_utc = mktime(&tm_utc);
449
450     r->utc_diff = time_local - time_utc;
451 }
452
453
454 static void nmea_reader_init( NmeaReader*  r )
455 {
456     int i;
457     memset( r, 0, sizeof(*r) );
458
459     // Initialize the sizes of all the structs we use
460     r->fix.size = sizeof(GpsLocation);
461     r->sv_status.size = sizeof(GpsSvStatus);
462     for (i = 0; i < GPS_MAX_SVS; i++) {
463         r->sv_status.sv_list[i].size = sizeof(GpsSvInfo);
464     }
465
466     r->pos      = 0;
467     r->overflow = 0;
468     r->utc_year = -1;
469     r->utc_mon  = -1;
470     r->utc_day  = -1;
471
472     // not sure if we still need this (this module doesn't use utc_diff)
473     nmea_reader_update_utc_diff( r );
474 }
475
476 static int nmea_reader_update_time( NmeaReader*  r, Token  tok )
477 {
478     int        hour, minute, seconds, milliseconds;
479     struct tm  tm;
480     time_t     fix_time;
481
482     if (tok.p + 6 > tok.end)
483         return -1;
484
485     if (r->utc_year < 0) {
486         // no date, can't return valid timestamp (never ever make up a date, this could wreak havoc)
487         return -1;
488     }
489     else
490     {
491         tm.tm_year = r->utc_year - 1900;
492         tm.tm_mon  = r->utc_mon - 1;
493         tm.tm_mday = r->utc_day;
494     }
495
496     hour    = str2int(tok.p,   tok.p+2);
497     minute  = str2int(tok.p+2, tok.p+4);
498     seconds = str2int(tok.p+4, tok.p+6);
499
500     // parse also milliseconds (if present) for better precision
501     milliseconds = 0;
502     if (tok.end - (tok.p+7) == 2) {
503         milliseconds = str2int(tok.p+7, tok.end) * 10;
504     }
505     else if (tok.end - (tok.p+7) == 1) {
506         milliseconds = str2int(tok.p+7, tok.end) * 100;
507     }
508     else if (tok.end - (tok.p+7) >= 3) {
509         milliseconds = str2int(tok.p+7, tok.p+10);
510     }
511
512     // the following is only guaranteed to work if we have previously set a correct date, so be sure
513     // to always do that before
514
515     tm.tm_hour = hour;
516     tm.tm_min  = minute;
517     tm.tm_sec  = seconds;
518
519     fix_time = mkgmtime( &tm );
520
521     r->fix.timestamp = (long long)fix_time * 1000 + milliseconds;
522     return 0;
523 }
524
525 static int nmea_reader_update_cdate( NmeaReader*  r, Token  tok_d, Token tok_m, Token tok_y )
526 {
527
528     if ( (tok_d.p + 2 > tok_d.end) ||
529          (tok_m.p + 2 > tok_m.end) ||
530          (tok_y.p + 4 > tok_y.end) )
531         return -1;
532
533     r->utc_day = str2int(tok_d.p,   tok_d.p+2);
534     r->utc_mon = str2int(tok_m.p, tok_m.p+2);
535     r->utc_year = str2int(tok_y.p, tok_y.p+4);
536
537     return 0;
538 }
539
540 static int nmea_reader_update_date( NmeaReader*  r, Token  date, Token  time )
541 {
542     Token  tok = date;
543     int    day, mon, year;
544
545     if (tok.p + 6 != tok.end) {
546         D("date not properly formatted: '%.*s'", tok.end-tok.p, tok.p);
547         return -1;
548     }
549     day  = str2int(tok.p, tok.p+2);
550     mon  = str2int(tok.p+2, tok.p+4);
551     year = str2int(tok.p+4, tok.p+6) + 2000;
552
553     if ((day|mon|year) < 0) {
554         D("date not properly formatted: '%.*s'", tok.end-tok.p, tok.p);
555         return -1;
556     }
557
558     r->utc_year  = year;
559     r->utc_mon   = mon;
560     r->utc_day   = day;
561
562     return nmea_reader_update_time( r, time );
563 }
564
565
566 static double convert_from_hhmm( Token  tok )
567 {
568     double  val     = str2float(tok.p, tok.end);
569     int     degrees = (int)(floor(val) / 100);
570     double  minutes = val - degrees*100.;
571     double  dcoord  = degrees + minutes / 60.0;
572     return dcoord;
573 }
574
575
576 static int nmea_reader_update_latlong( NmeaReader*  r,
577                             Token        latitude,
578                             char         latitudeHemi,
579                             Token        longitude,
580                             char         longitudeHemi )
581 {
582     double   lat, lon;
583     Token    tok;
584
585     tok = latitude;
586     if (tok.p + 6 > tok.end) {
587         D("latitude is too short: '%.*s'", tok.end-tok.p, tok.p);
588         return -1;
589     }
590     lat = convert_from_hhmm(tok);
591     if (latitudeHemi == 'S')
592         lat = -lat;
593
594     tok = longitude;
595     if (tok.p + 6 > tok.end) {
596         D("longitude is too short: '%.*s'", tok.end-tok.p, tok.p);
597         return -1;
598     }
599     lon = convert_from_hhmm(tok);
600     if (longitudeHemi == 'W')
601         lon = -lon;
602
603     r->fix.flags    |= GPS_LOCATION_HAS_LAT_LONG;
604     r->fix.latitude  = lat;
605     r->fix.longitude = lon;
606     return 0;
607 }
608
609
610 static int nmea_reader_update_altitude( NmeaReader*  r,
611                              Token        altitude,
612                              Token        units )
613 {
614     double  alt;
615     Token   tok = altitude;
616
617     if (tok.p >= tok.end)
618         return -1;
619
620     r->fix.flags   |= GPS_LOCATION_HAS_ALTITUDE;
621     r->fix.altitude = str2float(tok.p, tok.end);
622     return 0;
623 }
624
625 static int nmea_reader_update_accuracy( NmeaReader*  r,
626                              Token        accuracy )
627 {
628     double  acc;
629     Token   tok = accuracy;
630
631     if (tok.p >= tok.end)
632         return -1;
633
634     r->fix.accuracy = str2float(tok.p, tok.end);
635
636     if (r->fix.accuracy == 99.99){
637       return 0;
638     }
639
640     r->fix.flags   |= GPS_LOCATION_HAS_ACCURACY;
641     return 0;
642 }
643
644 static int nmea_reader_update_bearing( NmeaReader*  r,
645                             Token        bearing )
646 {
647     double  alt;
648     Token   tok = bearing;
649
650     if (tok.p >= tok.end)
651         return -1;
652
653     r->fix.flags   |= GPS_LOCATION_HAS_BEARING;
654     r->fix.bearing  = str2float(tok.p, tok.end);
655     return 0;
656 }
657
658
659 static int nmea_reader_update_speed( NmeaReader*  r,
660                           Token        speed )
661 {
662     double  alt;
663     Token   tok = speed;
664
665     if (tok.p >= tok.end)
666         return -1;
667
668     r->fix.flags   |= GPS_LOCATION_HAS_SPEED;
669     // convert knots into m/sec (1 knot equals 1.852 km/h, 1 km/h equals 3.6 m/s)
670     // since 1.852 / 3.6 is an odd value (periodic), we're calculating the quotient on the fly
671     // to obtain maximum precision (we don't want 1.9999 instead of 2)
672     r->fix.speed    = str2float(tok.p, tok.end) * 1.852 / 3.6;
673     return 0;
674 }
675
676
677 static void nmea_reader_parse( NmeaReader*  r )
678 {
679    /* we received a complete sentence, now parse it to generate
680     * a new GPS fix...
681     */
682     NmeaTokenizer  tzer[1];
683     Token          tok;
684
685     D("Received: '%.*s'", r->pos, r->in);
686
687     if (r->pos < 9) {
688         D("Too short. discarded.");
689         return;
690     }
691
692     nmea_tokenizer_init(tzer, r->in, r->in + r->pos);
693 #if GPS_DEBUG
694     {
695         int  n;
696         D("Found %d tokens", tzer->count);
697         for (n = 0; n < tzer->count; n++) {
698             Token  tok = nmea_tokenizer_get(tzer,n);
699             D("%2d: '%.*s'", n, tok.end-tok.p, tok.p);
700         }
701     }
702 #endif
703
704     tok = nmea_tokenizer_get(tzer, 0);
705
706     if (tok.p + 5 > tok.end) {
707         D("sentence id '%.*s' too short, ignored.", tok.end-tok.p, tok.p);
708         return;
709     }
710
711     // ignore first two characters.
712     tok.p += 2;
713
714     if ( !memcmp(tok.p, "GGA", 3) ) {
715         // GPS fix
716         Token  tok_fixstaus      = nmea_tokenizer_get(tzer,6);
717
718         if ((tok_fixstaus.p[0] > '0') && (r->utc_year >= 0)) {
719           // ignore this until we have a valid timestamp
720
721           Token  tok_time          = nmea_tokenizer_get(tzer,1);
722           Token  tok_latitude      = nmea_tokenizer_get(tzer,2);
723           Token  tok_latitudeHemi  = nmea_tokenizer_get(tzer,3);
724           Token  tok_longitude     = nmea_tokenizer_get(tzer,4);
725           Token  tok_longitudeHemi = nmea_tokenizer_get(tzer,5);
726           Token  tok_altitude      = nmea_tokenizer_get(tzer,9);
727           Token  tok_altitudeUnits = nmea_tokenizer_get(tzer,10);
728
729           // don't use this as we have no fractional seconds and no date; there are better ways to
730           // get a good timestamp from GPS
731           //nmea_reader_update_time(r, tok_time);
732           nmea_reader_update_latlong(r, tok_latitude,
733                                         tok_latitudeHemi.p[0],
734                                         tok_longitude,
735                                         tok_longitudeHemi.p[0]);
736           nmea_reader_update_altitude(r, tok_altitude, tok_altitudeUnits);
737         }
738
739     } else if ( !memcmp(tok.p, "GLL", 3) ) {
740
741         Token  tok_fixstaus      = nmea_tokenizer_get(tzer,6);
742
743         if ((tok_fixstaus.p[0] == 'A') && (r->utc_year >= 0)) {
744           // ignore this until we have a valid timestamp
745
746           Token  tok_latitude      = nmea_tokenizer_get(tzer,1);
747           Token  tok_latitudeHemi  = nmea_tokenizer_get(tzer,2);
748           Token  tok_longitude     = nmea_tokenizer_get(tzer,3);
749           Token  tok_longitudeHemi = nmea_tokenizer_get(tzer,4);
750           Token  tok_time          = nmea_tokenizer_get(tzer,5);
751
752           // don't use this as we have no fractional seconds and no date; there are better ways to
753           // get a good timestamp from GPS
754           //nmea_reader_update_time(r, tok_time);
755           nmea_reader_update_latlong(r, tok_latitude,
756                                         tok_latitudeHemi.p[0],
757                                         tok_longitude,
758                                         tok_longitudeHemi.p[0]);
759         }
760
761     } else if ( !memcmp(tok.p, "GSA", 3) ) {
762
763         Token  tok_fixStatus   = nmea_tokenizer_get(tzer, 2);
764         int i;
765
766         if (tok_fixStatus.p[0] != '\0' && tok_fixStatus.p[0] != '1') {
767
768           Token  tok_accuracy      = nmea_tokenizer_get(tzer, 15);
769
770           nmea_reader_update_accuracy(r, tok_accuracy);
771
772           r->sv_status.used_in_fix_mask = 0ul;
773
774           for (i = 3; i <= 14; ++i){
775
776             Token  tok_prn  = nmea_tokenizer_get(tzer, i);
777             int prn = str2int(tok_prn.p, tok_prn.end);
778
779             if (prn > 0){
780               r->sv_status.used_in_fix_mask |= (1ul << (32 - prn));
781               r->sv_status_changed = 1;
782               D("%s: fix mask is %d", __FUNCTION__, r->sv_status.used_in_fix_mask);
783             }
784
785           }
786
787         }
788
789     } else if ( !memcmp(tok.p, "GSV", 3) ) {
790
791         Token  tok_noSatellites  = nmea_tokenizer_get(tzer, 3);
792         int    noSatellites = str2int(tok_noSatellites.p, tok_noSatellites.end);
793
794         if (noSatellites > 0) {
795
796           Token  tok_noSentences   = nmea_tokenizer_get(tzer, 1);
797           Token  tok_sentence      = nmea_tokenizer_get(tzer, 2);
798
799           int sentence = str2int(tok_sentence.p, tok_sentence.end);
800           int totalSentences = str2int(tok_noSentences.p, tok_noSentences.end);
801           int curr;
802           int i;
803
804           if (sentence == 1) {
805               r->sv_status_changed = 0;
806               r->sv_status.num_svs = 0;
807           }
808
809           curr = r->sv_status.num_svs;
810
811           i = 0;
812
813           while (i < 4 && r->sv_status.num_svs < noSatellites){
814
815                  Token  tok_prn = nmea_tokenizer_get(tzer, i * 4 + 4);
816                  Token  tok_elevation = nmea_tokenizer_get(tzer, i * 4 + 5);
817                  Token  tok_azimuth = nmea_tokenizer_get(tzer, i * 4 + 6);
818                  Token  tok_snr = nmea_tokenizer_get(tzer, i * 4 + 7);
819
820                  r->sv_status.sv_list[curr].prn = str2int(tok_prn.p, tok_prn.end);
821                  r->sv_status.sv_list[curr].elevation = str2float(tok_elevation.p, tok_elevation.end);
822                  r->sv_status.sv_list[curr].azimuth = str2float(tok_azimuth.p, tok_azimuth.end);
823                  r->sv_status.sv_list[curr].snr = str2float(tok_snr.p, tok_snr.end);
824
825                  r->sv_status.num_svs += 1;
826
827                  curr += 1;
828
829                  i += 1;
830           }
831
832           if (sentence == totalSentences) {
833               r->sv_status_changed = 1;
834           }
835
836           D("%s: GSV message with total satellites %d", __FUNCTION__, noSatellites);
837
838         }
839
840     } else if ( !memcmp(tok.p, "RMC", 3) ) {
841
842         Token  tok_fixStatus     = nmea_tokenizer_get(tzer,2);
843
844         if (tok_fixStatus.p[0] == 'A')
845         {
846           Token  tok_time          = nmea_tokenizer_get(tzer,1);
847           Token  tok_latitude      = nmea_tokenizer_get(tzer,3);
848           Token  tok_latitudeHemi  = nmea_tokenizer_get(tzer,4);
849           Token  tok_longitude     = nmea_tokenizer_get(tzer,5);
850           Token  tok_longitudeHemi = nmea_tokenizer_get(tzer,6);
851           Token  tok_speed         = nmea_tokenizer_get(tzer,7);
852           Token  tok_bearing       = nmea_tokenizer_get(tzer,8);
853           Token  tok_date          = nmea_tokenizer_get(tzer,9);
854
855             nmea_reader_update_date( r, tok_date, tok_time );
856
857             nmea_reader_update_latlong( r, tok_latitude,
858                                            tok_latitudeHemi.p[0],
859                                            tok_longitude,
860                                            tok_longitudeHemi.p[0] );
861
862             nmea_reader_update_bearing( r, tok_bearing );
863             nmea_reader_update_speed  ( r, tok_speed );
864         }
865
866     } else if ( !memcmp(tok.p, "VTG", 3) ) {
867
868         Token  tok_fixStatus     = nmea_tokenizer_get(tzer,9);
869
870         if (tok_fixStatus.p[0] != '\0' && tok_fixStatus.p[0] != 'N')
871         {
872             Token  tok_bearing       = nmea_tokenizer_get(tzer,1);
873             Token  tok_speed         = nmea_tokenizer_get(tzer,5);
874
875             nmea_reader_update_bearing( r, tok_bearing );
876             nmea_reader_update_speed  ( r, tok_speed );
877         }
878
879     } else if ( !memcmp(tok.p, "ZDA", 3) ) {
880
881         Token  tok_time;
882         Token  tok_year  = nmea_tokenizer_get(tzer,4);
883         tok_time  = nmea_tokenizer_get(tzer,1);
884
885         if ((tok_year.p[0] != '\0') && (tok_time.p[0] != '\0')) {
886
887           // make sure to always set date and time together, lest bad things happen
888           Token  tok_day   = nmea_tokenizer_get(tzer,2);
889           Token  tok_mon   = nmea_tokenizer_get(tzer,3);
890
891           nmea_reader_update_cdate( r, tok_day, tok_mon, tok_year );
892           nmea_reader_update_time(r, tok_time);
893         }
894
895
896     } else {
897         tok.p -= 2;
898         D("unknown sentence '%.*s", tok.end-tok.p, tok.p);
899     }
900
901 #if GPS_DEBUG
902     if (r->fix.flags != 0) {
903
904         char   temp[256];
905         char*  p   = temp;
906         char*  end = p + sizeof(temp);
907         struct tm   utc;
908
909         p += snprintf( p, end-p, "sending fix" );
910         if (r->fix.flags & GPS_LOCATION_HAS_LAT_LONG) {
911             p += snprintf(p, end-p, " lat=%g lon=%g", r->fix.latitude, r->fix.longitude);
912         }
913         if (r->fix.flags & GPS_LOCATION_HAS_ALTITUDE) {
914             p += snprintf(p, end-p, " altitude=%g", r->fix.altitude);
915         }
916         if (r->fix.flags & GPS_LOCATION_HAS_SPEED) {
917             p += snprintf(p, end-p, " speed=%g", r->fix.speed);
918         }
919         if (r->fix.flags & GPS_LOCATION_HAS_BEARING) {
920             p += snprintf(p, end-p, " bearing=%g", r->fix.bearing);
921         }
922         if (r->fix.flags & GPS_LOCATION_HAS_ACCURACY) {
923             p += snprintf(p,end-p, " accuracy=%g", r->fix.accuracy);
924         }
925         gmtime_r( (time_t*) &r->fix.timestamp, &utc );
926         p += snprintf(p, end-p, " time=%s", asctime( &utc ) );
927         ALOGE("%s\n",temp);
928     }
929 #endif
930 }
931
932
933 static void nmea_reader_addc( NmeaReader*  r, int  c )
934 {
935     if (r->overflow) {
936         r->overflow = (c != '\n');
937         return;
938     }
939
940     if (r->pos >= (int) sizeof(r->in)-1 ) {
941         r->overflow = 1;
942         r->pos      = 0;
943         return;
944     }
945
946     r->in[r->pos] = (char)c;
947     r->pos       += 1;
948
949     if (c == '\n') {
950         nmea_reader_parse( r );
951         r->pos = 0;
952     }
953 }
954
955 /*****************************************************************/
956 /*****************************************************************/
957 /*****                                                       *****/
958 /*****       C O N N E C T I O N   S T A T E                 *****/
959 /*****                                                       *****/
960 /*****************************************************************/
961 /*****************************************************************/
962
963 /* commands sent to the gps thread */
964 enum {
965     CMD_QUIT  = 0,
966     CMD_START = 1,
967     CMD_STOP  = 2
968 };
969
970
971 static void gps_state_start( GpsState*  s )
972 {
973     char  cmd = CMD_START;
974     int   ret;
975
976     do { ret=write( s->control[0], &cmd, 1 ); }
977     while (ret < 0 && errno == EINTR);
978
979     if (ret != 1)
980         D("%s: could not send CMD_START command: ret=%d: %s",
981           __FUNCTION__, ret, strerror(errno));
982 }
983
984
985 static void gps_state_stop( GpsState*  s )
986 {
987     char  cmd = CMD_STOP;
988     int   ret;
989
990     do { ret=write( s->control[0], &cmd, 1 ); }
991     while (ret < 0 && errno == EINTR);
992
993     if (ret != 1)
994         D("%s: could not send CMD_STOP command: ret=%d: %s",
995           __FUNCTION__, ret, strerror(errno));
996 }
997
998
999 static int epoll_register( int  epoll_fd, int  fd )
1000 {
1001     struct epoll_event  ev;
1002     int                 ret, flags;
1003
1004     /* important: make the fd non-blocking */
1005     flags = fcntl(fd, F_GETFL);
1006     fcntl(fd, F_SETFL, flags | O_NONBLOCK);
1007
1008     ev.events  = EPOLLIN;
1009     ev.data.fd = fd;
1010     do {
1011         ret = epoll_ctl( epoll_fd, EPOLL_CTL_ADD, fd, &ev );
1012     } while (ret < 0 && errno == EINTR);
1013     return ret;
1014 }
1015
1016
1017 static int epoll_deregister( int  epoll_fd, int  fd )
1018 {
1019     int  ret;
1020     do {
1021         ret = epoll_ctl( epoll_fd, EPOLL_CTL_DEL, fd, NULL );
1022     } while (ret < 0 && errno == EINTR);
1023     return ret;
1024 }
1025
1026 static void gps_nmea_thread_cb( GpsState* state )
1027 {
1028     D("%s()", __FUNCTION__ );
1029     state->callbacks.nmea_cb(state->reader.fix.timestamp,&state->nmea_buf[0],state->nmea_len);
1030     GPS_STATE_UNLOCK_FIX(state);
1031 }
1032
1033 static void gps_nmea_cb( GpsState* state , const char* buf, int len)
1034 {
1035     D("%s()", __FUNCTION__ );
1036     // Forward NMEA sentences ....
1037     if (state->callbacks.nmea_cb) {
1038
1039         GPS_STATE_LOCK_FIX(state);
1040         memcpy(&state->nmea_buf[0],buf,len);
1041         state->nmea_buf[len] = 0;
1042         state->nmea_len = len;
1043         state->callbacks.create_thread_cb("nmea",(start_t)gps_nmea_thread_cb,(void*)state);
1044     }
1045 }
1046
1047 static void gps_status_thread_cb( GpsState* state )
1048 {
1049     D("%s()", __FUNCTION__ );
1050     state->callbacks.status_cb(&state->gps_status);
1051     GPS_STATE_UNLOCK_FIX(state);
1052 }
1053
1054 static void gps_status_cb( GpsState* state , GpsStatusValue status)
1055 {
1056     D("%s()", __FUNCTION__ );
1057     if (state->callbacks.status_cb) {
1058         GPS_STATE_LOCK_FIX(state);
1059
1060         state->gps_status.size = sizeof(GpsStatus);
1061         state->gps_status.status = status;
1062         state->callbacks.create_thread_cb("status",(start_t)gps_status_thread_cb,(void*)state);
1063
1064         D("gps status callback: 0x%x", status);
1065     }
1066 }
1067
1068 static void gps_set_capabilities_cb( GpsState* state, unsigned long caps)
1069 {
1070     D("%s()", __FUNCTION__ );
1071     if (state->callbacks.set_capabilities_cb) {
1072         state->callbacks.create_thread_cb("caps",(start_t)state->callbacks.set_capabilities_cb,(void*)caps);
1073     }
1074 }
1075
1076 static void gps_location_thread_cb( GpsState* state )
1077 {
1078     D("%s()", __FUNCTION__ );
1079     state->callbacks.location_cb( &state->reader.fix );
1080     state->reader.fix.flags = 0;
1081     GPS_STATE_UNLOCK_FIX(state);
1082 }
1083
1084
1085 static void gps_location_cb( GpsState* state )
1086 {
1087     D("%s()", __FUNCTION__ );
1088     if (state->callbacks.location_cb) {
1089         GPS_STATE_LOCK_FIX(state);
1090         state->callbacks.create_thread_cb("fix",(start_t)gps_location_thread_cb,(void*)state);
1091     }
1092 }
1093
1094 static void gps_sv_status_thread_cb( GpsState* state )
1095 {
1096     D("%s()", __FUNCTION__ );
1097     state->callbacks.sv_status_cb( &state->reader.sv_status );
1098     state->reader.sv_status_changed = 0;
1099     GPS_STATE_UNLOCK_FIX(state);
1100 }
1101
1102
1103 static void gps_sv_status_cb( GpsState* state )
1104 {
1105     D("%s()", __FUNCTION__ );
1106     if (state->callbacks.sv_status_cb) {
1107         GPS_STATE_LOCK_FIX(state);
1108         state->callbacks.create_thread_cb("sv-status",(start_t)gps_sv_status_thread_cb,(void*)state);
1109     }
1110 }
1111
1112
1113 /* this is the main thread, it waits for commands from gps_state_start/stop and,
1114  * when started, messages from the QEMU GPS daemon. these are simple NMEA sentences
1115  * that must be parsed to be converted into GPS fixes sent to the framework
1116  */
1117 static void* gps_state_thread( void* arg )
1118 {
1119     GpsState*   state = (GpsState*) arg;
1120     NmeaReader  *reader;
1121     int         epoll_fd   = epoll_create(2);
1122     int         started    = 0;
1123     int         gps_fd     = state->fd;
1124     int         control_fd = state->control[1];
1125
1126     reader = &state->reader;
1127
1128     nmea_reader_init( reader );
1129
1130     // register control file descriptors for polling
1131     epoll_register( epoll_fd, control_fd );
1132     epoll_register( epoll_fd, gps_fd );
1133
1134     D("gps thread running");
1135
1136     gps_set_capabilities_cb( state , GPS_CAPABILITY_MSA | GPS_CAPABILITY_MSB );
1137
1138     D("after set capabilities");
1139
1140     gps_status_cb( state , GPS_STATUS_ENGINE_ON);
1141
1142     D("after set status");
1143
1144     // now loop
1145     for (;;) {
1146         struct epoll_event   events[2];
1147         int                  ne, nevents;
1148
1149         nevents = epoll_wait( epoll_fd, events, 2, -1 );
1150         if (nevents < 0) {
1151             if (errno != EINTR)
1152                 ALOGE("epoll_wait() unexpected error: %s", strerror(errno));
1153             continue;
1154         }
1155         D("gps thread received %d events", nevents);
1156         for (ne = 0; ne < nevents; ne++) {
1157             if ((events[ne].events & (EPOLLERR|EPOLLHUP)) != 0) {
1158                 ALOGE("EPOLLERR or EPOLLHUP after epoll_wait() !?");
1159                 goto Exit;
1160             }
1161             if ((events[ne].events & EPOLLIN) != 0) {
1162                 int  fd = events[ne].data.fd;
1163
1164                 if (fd == control_fd)
1165                 {
1166                     char  cmd = 255;
1167                     int   ret;
1168                     D("gps control fd event");
1169                     do {
1170                         ret = read( fd, &cmd, 1 );
1171                     } while (ret < 0 && errno == EINTR);
1172
1173                     if (cmd == CMD_QUIT) {
1174                         D("gps thread quitting on demand");
1175                         goto Exit;
1176                     }
1177                     else if (cmd == CMD_START) {
1178                         if (!started) {
1179                             D("gps thread starting  location_cb=%p", state->callbacks.location_cb);
1180                             started = 1;
1181
1182                             dev_start(gps_fd);
1183
1184                             gps_status_cb( state , GPS_STATUS_SESSION_BEGIN);
1185
1186                             state->init = STATE_START;
1187
1188                             if ( pthread_create( &state->tmr_thread, NULL, gps_timer_thread, state ) != 0 ) {
1189                                 ALOGE("could not create gps timer thread: %s", strerror(errno));
1190                                 started = 0;
1191                                 state->init = STATE_INIT;
1192                                 goto Exit;
1193                             }
1194
1195                         }
1196                     }
1197                     else if (cmd == CMD_STOP) {
1198                         if (started) {
1199                             void *dummy;
1200                             D("gps thread stopping");
1201                             started = 0;
1202
1203                             dev_stop(gps_fd);
1204
1205                             state->init = STATE_INIT;
1206
1207                             pthread_join(state->tmr_thread, &dummy);
1208
1209                             gps_status_cb( state , GPS_STATUS_SESSION_END);
1210
1211                         }
1212                     }
1213                 }
1214                 else if (fd == gps_fd)
1215                 {
1216                     char buf[512];
1217                     int  nn, ret;
1218
1219                     do {
1220                         ret = read( fd, buf, sizeof(buf) );
1221                     } while (ret < 0 && errno == EINTR);
1222
1223                     if (ret > 0) {
1224
1225                         gps_nmea_cb( state , &buf[0], ret);
1226
1227                         GPS_STATE_LOCK_FIX(state);
1228                         for (nn = 0; nn < ret; nn++)
1229                             nmea_reader_addc( reader, buf[nn] );
1230                         GPS_STATE_UNLOCK_FIX(state);
1231
1232                     }
1233                     D("gps fd event end");
1234                 }
1235                 else
1236                 {
1237                     ALOGE("epoll_wait() returned unkown fd %d ?", fd);
1238                 }
1239             }
1240         }
1241     }
1242 Exit:
1243
1244     gps_status_cb( state , GPS_STATUS_ENGINE_OFF);
1245
1246     return NULL;
1247 }
1248
1249 static void* gps_timer_thread( void*  arg )
1250 {
1251
1252   GpsState *state = (GpsState *)arg;
1253
1254   D("gps entered timer thread");
1255
1256   do {
1257
1258     D ("gps timer exp");
1259
1260     if (state->reader.fix.flags != 0) {
1261
1262       D("gps fix cb: 0x%x", state->reader.fix.flags);
1263
1264       gps_location_cb( state );
1265     }
1266
1267     if (state->reader.sv_status_changed != 0) {
1268
1269       D("gps sv status callback");
1270
1271       gps_sv_status_cb( state );
1272
1273     }
1274
1275     if (state->min_interval == 0) {
1276         state->min_interval = 1000;
1277     }
1278
1279     usleep(state->min_interval*1000);
1280
1281   } while(state->init == STATE_START);
1282
1283   D("gps timer thread destroyed");
1284
1285   return NULL;
1286
1287 }
1288
1289 static int open_serialport( const char* name )
1290 {
1291     int fd = -1;
1292     do {
1293         fd = open( name, O_RDWR );
1294     } while (fd < 0 && errno == EINTR);
1295
1296     if (fd < 0) {
1297         ALOGE("could not open serial device %s: %s", name, strerror(errno) );
1298         return fd;
1299     }
1300
1301     // disable echo on serial lines
1302     if ( isatty( fd ) ) {
1303         struct termios  ios;
1304         tcgetattr( fd, &ios );
1305         ios.c_lflag = 0;  /* disable ECHO, ICANON, etc... */
1306         ios.c_oflag &= (~ONLCR); /* Stop \n -> \r\n translation on output */
1307         ios.c_iflag &= (~(ICRNL | INLCR)); /* Stop \r -> \n & \n -> \r translation on input */
1308         ios.c_iflag |= (IGNCR | IXOFF);  /* Ignore \r & XON/XOFF on input */
1309         tcsetattr( fd, TCSANOW, &ios );
1310     }
1311
1312     return fd;
1313 }
1314
1315 static void gps_state_done( GpsState*  s )
1316 {
1317     // tell the thread to quit, and wait for it
1318     char   cmd = CMD_QUIT;
1319     void*  dummy;
1320     int ret;
1321
1322     D("gps send quit command");
1323
1324     do { ret=write( s->control[0], &cmd, 1 ); }
1325     while (ret < 0 && errno == EINTR);
1326
1327     D("gps waiting for command thread to stop");
1328
1329     pthread_join(s->thread, &dummy);
1330
1331     /* Timer thread depends on this state check */
1332     s->init = STATE_QUIT;
1333     s->min_interval = 1000;
1334
1335     // close the control socket pair
1336     close( s->control[0] ); s->control[0] = -1;
1337     close( s->control[1] ); s->control[1] = -1;
1338
1339     // Turn off GPS function
1340     serial_write(s->ctrl_fd,"AT^WPEND\r\n");
1341
1342     // close connection to the GPS
1343     close( s->fd ); s->fd = -1;
1344     close( s->ctrl_fd ); s->ctrl_fd = -1;
1345
1346     // Power down the GPS interface
1347     dev_power(0);
1348
1349     sem_destroy(&s->fix_sem);
1350
1351     memset(s, 0, sizeof(*s));
1352
1353     D("gps deinit complete");
1354
1355 }
1356
1357
1358 static void gps_state_init( GpsState*  state )
1359 {
1360     char   gps_data[PROPERTY_VALUE_MAX];
1361     char   gps_ctrl[PROPERTY_VALUE_MAX];
1362     char   gps_supl[PROPERTY_VALUE_MAX];
1363     char   buf[PROPERTY_VALUE_MAX+20];
1364     int    ret;
1365     int    done = 0;
1366
1367     struct sigevent tmr_event;
1368
1369     state->init       = STATE_INIT;
1370     state->control[0] = -1;
1371     state->control[1] = -1;
1372     state->fd         = -1;
1373     state->ctrl_fd    = -1;
1374     state->min_interval   = 1000;
1375
1376     if (sem_init(&state->fix_sem, 0, 1) != 0) {
1377       D("gps semaphore initialization failed! errno = %d", errno);
1378       return;
1379     }
1380
1381     // Power up the GPS interface
1382     dev_power(1);
1383
1384     // look for a kernel-provided gps_data port
1385     strcpy(gps_data,"/dev/ttyUSB3") ; //RvdB
1386     /* RvdB
1387     if (property_get("ro.kernel.gps.data",gps_data,"/dev/ttyUSB3") == 0) {
1388         D("no kernel-provided gps device data name");
1389         dev_power(0);
1390         return;
1391     } */
1392
1393     state->fd = open_serialport( gps_data );
1394     if (state->fd < 0) {
1395         ALOGE("could not open gps serial device %s: %s", gps_data, strerror(errno) );
1396         dev_power(0);
1397         return;
1398     }
1399
1400     D("gps will read from %s", gps_data);
1401
1402     // look for a kernel-provided gps_ctrl port
1403     strcpy(gps_ctrl,"/dev/ttyUSB4")  ;//RvdB
1404
1405     /*
1406     if (property_get("ro.kernel.gps.ctl",gps_ctrl,"/dev/ttyUSB4") == 0) {
1407         D("no kernel-provided gps device ctrl name");
1408         dev_power(0);
1409         return;
1410     } */
1411
1412     state->ctrl_fd = open_serialport( gps_ctrl );
1413     if (state->ctrl_fd < 0) {
1414         ALOGE("could not open gps serial device %s: %s", gps_ctrl, strerror(errno) );
1415         close(state->fd);
1416         state->fd = -1;
1417         dev_power(0);
1418         return;
1419     }
1420
1421     D("gps will be controlled by %s", gps_ctrl);
1422
1423     // Turn on GPS function
1424     serial_write(state->ctrl_fd,"AT^WPEND\r\n");
1425
1426     // look for a kernel-provided supl
1427     strcpy(gps_supl,"http://supl.nokia.com") ; //RvdB
1428     /*
1429     if (property_get("ro.kernel.gps.supl",gps_supl,"http://supl.nokia.com") == 0) {
1430         D("no kernel-provided supl");
1431         close(state->fd);
1432         state->fd = -1;
1433         close(state->ctrl_fd);
1434         state->ctrl_fd = -1;
1435         dev_power(0);
1436         return;
1437     } */
1438
1439     sprintf(buf,"AT^WPURL=%s\r\n",gps_supl);
1440     serial_write(state->ctrl_fd,buf);
1441
1442     // configure AGPS to work speed optimal
1443     serial_write(state->ctrl_fd,"AT^WPDOM=2\r\n");
1444
1445     // Power up GPS
1446     serial_write(state->ctrl_fd,"AT^WPDGP\r\n");
1447
1448     if ( socketpair( AF_LOCAL, SOCK_STREAM, 0, state->control ) < 0 ) {
1449         ALOGE("could not create thread control socket pair: %s", strerror(errno));
1450         goto Fail;
1451     }
1452
1453
1454     if ( pthread_create( &state->thread, NULL, gps_state_thread, state ) != 0 ) {
1455         ALOGE("could not create gps thread: %s", strerror(errno));
1456         goto Fail;
1457     }
1458
1459
1460     D("gps state initialized");
1461
1462     return;
1463
1464 Fail:
1465     gps_state_done( state );
1466 }
1467
1468
1469
1470 /*****************************************************************/
1471 /*****************************************************************/
1472 /*****                                                       *****/
1473 /*****       I N T E R F A C E                               *****/
1474 /*****                                                       *****/
1475 /*****************************************************************/
1476 /*****************************************************************/
1477
1478 static int gps_init(GpsCallbacks* callbacks)
1479 {
1480     GpsState*  s = _gps_state;
1481
1482     if (!s->init)
1483         gps_state_init(s);
1484
1485     if (s->fd < 0)
1486         return -1;
1487
1488     s->callbacks = *callbacks;
1489
1490     return 0;
1491 }
1492
1493 static void gps_cleanup(void)
1494 {
1495     GpsState*  s = _gps_state;
1496
1497     if (s->init)
1498         gps_state_done(s);
1499 }
1500
1501
1502 static int gps_start(void)
1503 {
1504     GpsState*  s = _gps_state;
1505
1506     if (!s->init) {
1507         D("%s: called with uninitialized state !!", __FUNCTION__);
1508         return -1;
1509     }
1510
1511     D("%s: called", __FUNCTION__);
1512     gps_state_start(s);
1513     return 0;
1514 }
1515
1516
1517 static int gps_stop(void)
1518 {
1519     GpsState*  s = _gps_state;
1520
1521     if (!s->init) {
1522         D("%s: called with uninitialized state !!", __FUNCTION__);
1523         return -1;
1524     }
1525
1526     D("%s: called", __FUNCTION__);
1527     gps_state_stop(s);
1528     return 0;
1529 }
1530
1531
1532 static int gps_inject_time(GpsUtcTime time, int64_t timeReference, int uncertainty)
1533 {
1534     return 0;
1535 }
1536
1537 /** Injects current location from another location provider
1538  *  (typically cell ID).
1539  *  latitude and longitude are measured in degrees
1540  *  expected accuracy is measured in meters
1541  */
1542 static int gps_inject_location(double latitude, double longitude, float accuracy)
1543 {
1544     return 0;
1545 }
1546
1547 static void gps_delete_aiding_data(GpsAidingData flags)
1548 {
1549 }
1550
1551 static int gps_set_position_mode(GpsPositionMode mode,  GpsPositionRecurrence recurrence,
1552          uint32_t min_interval, uint32_t preferred_accuracy, uint32_t preferred_time)
1553 {
1554     GpsState*  s = _gps_state;
1555
1556     if (!s->init) {
1557         D("%s: called with uninitialized state !!", __FUNCTION__);
1558         return -1;
1559     }
1560
1561     // only standalone supported for now.
1562     if (mode == GPS_POSITION_MODE_STANDALONE) {
1563     } else
1564     if (mode == GPS_POSITION_MODE_MS_BASED ||
1565         mode == GPS_POSITION_MODE_MS_ASSISTED) {
1566     }
1567
1568
1569     s->min_interval = min_interval;
1570
1571     D("gps fix frquency set to %d secs", min_interval);
1572
1573     return 0;
1574 }
1575
1576 /***** AGpsInterface *****/
1577
1578 /**
1579  * Opens the AGPS interface and provides the callback routines
1580  * to the implemenation of this interface.
1581  */
1582 static void agps_init( AGpsCallbacks* callbacks )
1583 {
1584     D("%s() is called", __FUNCTION__);
1585
1586     GpsState*  s = _gps_state;
1587
1588     if (!s->init) {
1589         D("%s: called with uninitialized state !!", __FUNCTION__);
1590         return;
1591     }
1592
1593     s->a_callbacks = *callbacks;
1594 }
1595
1596 /**
1597  * Notifies that a data connection is available and sets
1598  * the name of the APN to be used for SUPL.
1599  */
1600 static int agps_conn_open( const char* apn )
1601 {
1602     D("%s() is called", __FUNCTION__);
1603     D("apn=%s", apn);
1604
1605     GpsState*  s = _gps_state;
1606
1607     if (!s->init) {
1608         D("%s: called with uninitialized state !!", __FUNCTION__);
1609         return 0;
1610     }
1611
1612     return 0;
1613 }
1614
1615 /**
1616  * Notifies that the AGPS data connection has been closed.
1617  */
1618 static int agps_conn_closed( void )
1619 {
1620     D("%s() is called", __FUNCTION__);
1621
1622     GpsState*  s = _gps_state;
1623
1624     if (!s->init) {
1625         D("%s: called with uninitialized state !!", __FUNCTION__);
1626         return 0;
1627     }
1628
1629     return 0;
1630 }
1631
1632 /**
1633  * Notifies that a data connection is not available for AGPS.
1634  */
1635 static int agps_conn_failed( void )
1636 {
1637     D("%s() is called", __FUNCTION__);
1638
1639     GpsState*  s = _gps_state;
1640
1641     if (!s->init) {
1642         D("%s: called with uninitialized state !!", __FUNCTION__);
1643         return 0;
1644     }
1645
1646     return 0;
1647 }
1648
1649 /**
1650  * Sets the hostname and port for the AGPS server.
1651  */
1652 static int agps_set_server( AGpsType type, const char* hostname, int port )
1653 {
1654     char buf[512];
1655
1656     D("%s() is called", __FUNCTION__);
1657     D("type=%d, hostname=%s, port=%d", type, hostname, port);
1658
1659     GpsState*  s = _gps_state;
1660
1661     if (!s->init) {
1662         D("%s: called with uninitialized state !!", __FUNCTION__);
1663         return 0;
1664     }
1665
1666 #if 0
1667     sprintf(buf,"AT^WPURL=%s\r\n",hostname);
1668     serial_write(s->ctrl_fd,buf);
1669 #endif
1670
1671     return 0;
1672 }
1673
1674 static const AGpsInterface  sAGpsInterface = {
1675     sizeof(AGpsInterface),
1676     agps_init,
1677     agps_conn_open,
1678     agps_conn_closed,
1679     agps_conn_failed,
1680     agps_set_server
1681 };
1682
1683
1684 /***** GpsXtraInterface *****/
1685 static int xtra_init(GpsXtraCallbacks* callbacks)
1686 {
1687     D("%s() is called", __FUNCTION__);
1688     GpsState*  s = _gps_state;
1689
1690     s->xtra_callbacks = *callbacks;
1691
1692     return 0;
1693 }
1694
1695 static int xtra_inject_xtra_data(char* data, int length)
1696 {
1697     D("%s() is called", __FUNCTION__);
1698     D("xtra size = %d, data ptr = 0x%x\n", length, (int) data);
1699
1700     GpsState*  s = _gps_state;
1701     if (!s->init)
1702         return 0;
1703
1704     return 0;
1705 }
1706
1707 static const GpsXtraInterface sGpsXtraInterface = {
1708     sizeof(GpsXtraInterface),
1709     xtra_init,
1710     xtra_inject_xtra_data,
1711 };
1712
1713 static const void* gps_get_extension(const char* name)
1714 {
1715     D("%s('%s') is called", __FUNCTION__, name);
1716
1717     if (!strcmp(name, GPS_XTRA_INTERFACE)) {
1718         return &sGpsXtraInterface;
1719     } else if (!strcmp(name, AGPS_INTERFACE)) {
1720         return &sAGpsInterface;
1721     }
1722     return NULL;
1723 }
1724
1725 static const GpsInterface sGpsInterface = {
1726     sizeof(GpsInterface),
1727     gps_init,
1728     gps_start,
1729     gps_stop,
1730     gps_cleanup,
1731     gps_inject_time,
1732     gps_inject_location,
1733     gps_delete_aiding_data,
1734     gps_set_position_mode,
1735     gps_get_extension,
1736 };
1737
1738 // As under Android, there are no exceptions in C++ base system, we will hide all exported symbols
1739 // except the required ones. This will generate better code!
1740
1741 #if __GNUC__ >= 4
1742     #define DLL_PUBLIC __attribute__ ((visibility ("default")))
1743     #define DLL_LOCAL  __attribute__ ((visibility ("hidden")))
1744 #else
1745     #define DLL_PUBLIC
1746     #define DLL_LOCAL
1747 #endif
1748
1749
1750 static const GpsInterface* gps_get_hardware_interface(struct gps_device_t* dev)
1751 {
1752     ALOGV("get_interface was called");
1753     return &sGpsInterface;
1754 }
1755
1756 static int open_gps(const struct hw_module_t* module, char const* name,
1757         struct hw_device_t** device)
1758 {
1759     struct gps_device_t *dev = malloc(sizeof(struct gps_device_t));
1760     memset(dev, 0, sizeof(*dev));
1761
1762     dev->common.tag = HARDWARE_DEVICE_TAG;
1763     dev->common.version = 0;
1764     dev->common.module = (struct hw_module_t*)module;
1765     dev->get_gps_interface = gps_get_hardware_interface;
1766
1767     *device = (struct hw_device_t*)dev;
1768     return 0;
1769 }
1770
1771
1772 static struct hw_module_methods_t gps_module_methods = {
1773     .open = open_gps
1774 };
1775
1776 DLL_PUBLIC struct hw_module_t HAL_MODULE_INFO_SYM = {
1777     .tag = HARDWARE_MODULE_TAG,
1778     .version_major = 1,
1779     .version_minor = 0,
1780     .id = GPS_HARDWARE_MODULE_ID,
1781     .name = "GPS Module",
1782     .author = "Eduardo José Tagle",
1783     .methods = &gps_module_methods,
1784 };