OSDN Git Service

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