OSDN Git Service

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