r3386 - in trunk/src/host/qemu-neo1973: . hw openmoko

andrew at sita.openmoko.org andrew at sita.openmoko.org
Fri Nov 9 17:32:25 CET 2007


Author: andrew
Date: 2007-11-09 17:32:22 +0100 (Fri, 09 Nov 2007)
New Revision: 3386

Added:
   trunk/src/host/qemu-neo1973/hw/gps.c
Modified:
   trunk/src/host/qemu-neo1973/Makefile.target
   trunk/src/host/qemu-neo1973/hw/modem.c
   trunk/src/host/qemu-neo1973/openmoko/download.sh
   trunk/src/host/qemu-neo1973/vl.h
Log:
Preliminary GPS emulator (GTA02).


Modified: trunk/src/host/qemu-neo1973/Makefile.target
===================================================================
--- trunk/src/host/qemu-neo1973/Makefile.target	2007-11-09 16:06:40 UTC (rev 3385)
+++ trunk/src/host/qemu-neo1973/Makefile.target	2007-11-09 16:32:22 UTC (rev 3386)
@@ -529,7 +529,7 @@
 VL_OBJS+= spitz.o ads7846.o ide.o serial.o nand.o ecc.o
 VL_OBJS+= $(AUDIODRV) wm8750.o wm8753.o
 VL_OBJS+= s3c2410.o s3c24xx_gpio.o s3c24xx_lcd.o s3c24xx_mmci.o s3c24xx_rtc.o
-VL_OBJS+= s3c24xx_udc.o neo1973.o pcf5060x.o jbt6k74.o
+VL_OBJS+= s3c24xx_udc.o neo1973.o pcf5060x.o jbt6k74.o gps.o
 VL_OBJS+= $(GSM_OBJS) modem.o
 VL_OBJS+= omap.o omap_lcdc.o omap1_clk.o omap_mmc.o palm.o tsc210x.o
 CPPFLAGS+= -DHAS_AUDIO $(GSM_CPPFLAGS)

Added: trunk/src/host/qemu-neo1973/hw/gps.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/gps.c	2007-11-09 16:06:40 UTC (rev 3385)
+++ trunk/src/host/qemu-neo1973/hw/gps.c	2007-11-09 16:32:22 UTC (rev 3386)
@@ -0,0 +1,662 @@
+/*
+ * Very simple GPS chip simulation for QEMU.  This GPS communicates
+ * through NMEA sentences, like the U-Blox ANTARIS 4 chipset.
+ *
+ * Copyright (c) 2007 OpenMoko, Inc.
+ * Written by Andrzej Zaborowski.
+ *
+ * Tricky maths based roughly on "gpsfeed+" Tcl/Tk code by
+ * Dimitrios C. Zachariadis.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include "vl.h"
+
+#include <math.h>
+
+#define GPS_MAX_SATS	32
+#define GPS_DTOR(deg)	((double) deg * M_PI / 180.0 / 3600.0)
+#define GPS_RTOD(rad)	((int) (rad * 180.0 / M_PI * 3600.0))
+#define GPS_LLTOI(ll)	((int) (ll * 3600.0))
+
+#define M_EPSILON	0.000001
+
+struct gps_data_s {
+    int enable;
+    CharDriverState chr;
+#define FIFO_LEN	4096
+    int out_start;
+    int out_len;
+    char outfifo[FIFO_LEN];
+    QEMUTimer *out_tm;
+    int64_t baud_delay;
+
+    enum {
+        proto_nmea_15 = 0x15,
+        proto_nmea_20 = 0x20,
+        proto_nmea_23 = 0x23,
+        proto_nmea_30 = 0x30,
+        proto_ubx,
+        proto_rtcm,
+    } gps_proto;
+
+    /* Dilution of precision */
+    int pdop;
+    /* Horizonal dilution of position */
+    int hdop;
+    /* Vertical dilution of precision */
+    int vdop;
+    /* Time in seconds since last DGPS update */
+    int dgpsdt;
+    /* DGPS station ID number */
+    int dgpsid;
+    /* Altitude, meters aboce mean sea level */
+    int altitude;
+    char altitude_unit;
+    /* Height of geoid (mean sea level) above WGS94 ellipsoid */
+    int gheight;
+    char gheight_unit;
+    /* Bearing */
+    int bear;
+    int dist;
+    /* Ground speed in knots */
+    int knots;
+    /* Magnetic Variation */
+    int magnvar;
+    int magnew;
+    int magnfix;
+
+    struct gps_pos_s {
+        int latitude;
+        int longitude;
+    } pos, pos_orig;
+    void (*pos_update)(struct gps_data_s *s);
+    int64_t vmtime_orig;
+    int64_t vmtime_last;
+
+    /* Number of satellites that were used for current solution */
+    int nsat;
+    /* Number of currently visible satellites */
+    int maxsat;
+    /* Satellite data */
+    struct {
+        int elevation;
+        int azimuth;
+        int cur_elevation;
+        int cur_azimuth;
+        int visible;
+        int snr;
+        int prn;
+    } sats[GPS_MAX_SATS];
+    /* Fix quality */
+    enum {
+        gps_fix_invalid = 0,
+        gps_fix_gps,
+        gps_fix_dgps,
+        gps_fix_pps,
+        gps_fix_real_time_kinematic,
+        gps_fix_float_rtk,
+        gps_fix_estimated_dead_reckon,
+        gps_fix_manual_input,
+        gps_fix_simulation,
+    } fix_q;
+    /* Fix type */
+    enum {
+        gps_type_none = 1,
+        gps_type_2d,
+        gps_type_3d,
+    } fix_type;
+    /* Fix timestamp */
+    struct tm fix_time;
+    char fix;
+
+    int tz_hour;
+    int tz_min;
+
+    QEMUTimer *newdata_tm;
+    int64_t rate;
+};
+
+static inline void gps_fifo_wake(struct gps_data_s *s)
+{
+    if (!s->enable || !s->out_len)
+        return;
+
+    if (qemu_chr_can_read(&s->chr) && s->chr.chr_read) {
+        s->chr.chr_read(s->chr.handler_opaque,
+                        s->outfifo + s->out_start ++, 1);
+        s->out_len --;
+        s->out_start &= FIFO_LEN - 1;
+    }
+
+    if (s->out_len)
+        qemu_mod_timer(s->out_tm, qemu_get_clock(vm_clock) + s->baud_delay);
+}
+
+static void gps_write(struct gps_data_s *s, const char *line)
+{
+    int len, off;
+
+    len = strlen(line);
+    if (len + s->out_len > FIFO_LEN) {
+        s->out_len = 0;
+        return;
+    }
+    off = (s->out_start + s->out_len) & (FIFO_LEN - 1);
+    if (off + len > FIFO_LEN) {
+        memcpy(s->outfifo + off, line, FIFO_LEN - off);
+        memcpy(s->outfifo, line + (FIFO_LEN - off), off + len - FIFO_LEN);
+    } else
+        memcpy(s->outfifo + off, line, len);
+    s->out_len += len;
+    gps_fifo_wake(s);
+}
+
+static void gps_fix_reset(struct gps_data_s *s)
+{
+    s->fix = 'V';
+    s->nsat = 0;
+    s->fix_q = gps_fix_invalid;
+    s->fix_type = gps_type_none;
+}
+
+static void gps_fix_acquire(struct gps_data_s *s)
+{
+    time_t now = time(0);
+
+    gmtime_r(&now, &s->fix_time);
+    s->nsat = MIN(s->maxsat, 4);
+}
+
+/* Set random initial satellite positions (elevations and azimuths).
+ * These are gonna change as the satellites move in orbit.  */
+static void gps_satellite_random(struct gps_data_s *s)
+{
+    int i;
+
+    srand(time(0));
+    for (i = 0; i < GPS_MAX_SATS; i ++) {
+        s->sats[i].elevation = (rand() % 180) - 90;
+        s->sats[i].azimuth = rand() % 360;
+        s->sats[i].prn = 2 + i;
+    }
+}
+
+/* Input parameters are in degrees.  */
+static void gps_diopteusis(int lat0, int lon0, int lat1, int lon1,
+                int *dist, int *bearing)
+{
+    double d, b, arc;
+    double lat0f = GPS_DTOR(lat0);
+    double lon0f = GPS_DTOR(lon0);
+    double lat1f = GPS_DTOR(lat1);
+    double lon1f = GPS_DTOR(lon1);
+
+    arc = sin(lat0f) * sin(lat1f) +
+            cos(lat0f) * cos(lat1f) * cos(lon0f - lon1f);
+
+    /* Find the distance travelled in knots.  */
+    d = acos(arc);
+    if (!isnormal(d))
+        d = 0.0;
+
+    /* Find the bearing.  */
+
+    /* Is lat0 at the pole or very near? */
+    if (abs(lat0f) - 0.5 * M_PI < M_EPSILON)
+        b = (lat0f > 0.0) ? M_PI : 0.0;
+    else if (d > 0.0) {
+        b = (sin(lat1f) - sin(lat0f) * cos(d)) / (cos(lat0f) * sin(d));
+        if (b > 1.0)
+            b = 1.0;
+        else if (b < -1.0)
+            b = -1.0;
+        b = (abs(d) < M_EPSILON) ? 0.0 : acos(b);
+    } else
+        b = 0.0;
+
+    *bearing = GPS_RTOD(b);
+    if (lon0 > lon1)
+        *bearing = 360 * 3600 - *bearing;
+    *dist = GPS_LLTOI(d);
+}
+
+static inline void gps_latlon_split(int ll, const char *letters, char *hemi,
+                int *deg, int *min, int *sec)
+{
+    if (ll > 0) {
+        *hemi = letters[0];
+        *deg = ll / 3600;
+        *min = (ll * 1000 / 60) % (60 * 1000);
+        *sec = ll % 60;
+    } else {
+        *hemi = letters[1];
+        *deg = -ll / 3600;
+        *min = (-ll * 1000 / 60) % (60 * 1000);
+        *sec = -ll % 60;
+    }
+}
+
+/* Update our position, find the distance D and the angle C,
+ * update satellites status.  */
+static void gps_makedata(struct gps_data_s *s)
+{
+    struct gps_pos_s pos0;
+    int64_t now = qemu_get_clock(vm_clock);
+    int elevation, i;
+    int secs = (now - s->vmtime_orig) / ticks_per_sec;
+
+    pos0 = s->pos;
+    s->pos_update(s);
+
+    /* Find distance (minutes) and bearing (degrees) */
+    gps_diopteusis(pos0.latitude, pos0.longitude,
+                    s->pos.latitude, s->pos.longitude, &s->dist, &s->bear);
+    s->knots = muldiv64(s->dist * 10, ticks_per_sec, now - s->vmtime_last);
+    s->vmtime_last = now;
+
+    /* Count visible satellites */
+    s->maxsat = 0;
+    /* Do calculations for all our satellites */
+    for (i = 0; i < GPS_MAX_SATS; i ++) {
+        /* Set the elevation for each satellite */
+        elevation = (int) (90.0 * sin(M_PI *
+                                (10.0 * s->sats[i].elevation +
+                                 secs) / 1800.0));
+        /* Arbitrarily, we consider a satellite visible if
+         * its elevation is > 30deg.  */
+        s->sats[i].visible = (elevation > 30);
+        s->maxsat += s->sats[i].visible;
+
+        s->sats[i].cur_elevation = elevation;
+        s->sats[i].cur_azimuth = (s->sats[i].azimuth + secs / 10) % 360;
+        s->sats[i].snr = (elevation > 5) ? (int) (60.0 * sin(M_PI *
+                                (elevation - 30.0) / 180.0)) : 0;
+    }
+
+    if (s->maxsat >= 3) {
+        if (!s->nsat) {
+            /* Record fix timestamp */
+            gps_fix_acquire(s);
+        }
+        s->fix = 'A';
+        s->fix_q = gps_fix_gps;
+        s->fix_type = gps_type_3d;
+    } else
+        gps_fix_reset(s);
+}
+
+static void gps_append_chksum(char *sentence)
+{
+    uint8_t reg = 0;
+
+    sentence ++;
+    while (*sentence)
+        reg ^= *(sentence ++);
+    sprintf(sentence, "*%02X\n", reg);
+}
+
+static char sentence[1024];
+
+/* RMC: Recommended Minimum sentence C */
+static void gps_nmea_gprmc(struct gps_data_s *s)
+{
+    char lat_hemi, lon_hemi;
+    int lat_deg, lon_deg, lat_min, lon_min, lat_sec, lon_sec;
+
+    /* NMEA format:
+     * $GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A
+     * ANTARIS4 format:
+     * $GPRMC,162254.00,A,3723.02837,N,12159.39853,W,0.820,188.36,110706,,,A*74
+     */
+
+    gps_latlon_split(s->pos.latitude, "NS",
+                    &lat_hemi, &lat_deg, &lat_min, &lat_sec);
+    gps_latlon_split(s->pos.longitude, "EW",
+                    &lon_hemi, &lon_deg, &lon_min, &lon_sec);
+
+    sprintf(sentence, "$GPRMC,%02i%02i%02i.00,%c,%02i%02i.%03i,%c,%03i%02i."
+                    "%03i,%c,%03i.%i,%03i.%i,%02i%02i%02i,%03i.%i,%c,%c",
+                    s->fix_time.tm_hour, s->fix_time.tm_min,
+                    s->fix_time.tm_sec, s->fix, lat_deg, lat_min / 1000,
+                    lat_min % 1000, lat_hemi, lon_deg, lon_min / 1000,
+                    lon_min % 1000, lon_hemi, s->knots / 10, s->knots % 10,
+                    s->bear / 10, s->bear % 10, s->fix_time.tm_mday,
+                    s->fix_time.tm_mon, s->fix_time.tm_year % 100,
+                    s->magnvar / 10, s->magnvar % 10, s->magnew, s->magnfix);
+    gps_append_chksum(sentence);
+    gps_write(s, sentence);
+}
+
+/* GSV: Satellites in View */
+static void gps_nmea_gpgsv(struct gps_data_s *s)
+{
+    int lines = (s->maxsat + 3) >> 2;
+    int line = 1;
+    int count = 0;
+    int i;
+
+    /* NMEA format:
+     * $GPGSV,2,1,08,01,40,083,46,02,17,308,41,12,07,344,39,14,22,228,45*75
+     * ...
+     * ANTARIS4 format:
+     * $GPGSV,4,1,14,25,15,175,30,14,80,041,,19,38,259,14,01,52,223,18*76
+     * ...
+     */
+    for (i = 0; i < GPS_MAX_SATS; i ++)
+        if (s->sats[i].visible) {
+            if (count == 0)
+                sprintf(sentence, "$GPGSV,%i,%i,%02i",
+                                lines, line ++, s->maxsat);
+
+            sprintf(sentence + strlen(sentence), ",%02i,%02i,%03i,%02i",
+                            s->sats[i].prn, s->sats[i].cur_elevation,
+                            s->sats[i].cur_azimuth, s->sats[i].snr);
+            count ++;
+
+            if (count == 4) {
+                gps_append_chksum(sentence);
+                gps_write(s, sentence);
+                count = 0;
+            }
+        }
+    if (count) {
+        gps_append_chksum(sentence);
+        gps_write(s, sentence);
+    }
+}
+
+/* GGA: GPS Fix Data */
+static void gps_nmea_gpgga(struct gps_data_s *s)
+{
+    char lat_hemi, lon_hemi;
+    int lat_deg, lon_deg, lat_min, lon_min, lat_sec, lon_sec;
+
+    /* NMEA format:
+     * $GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47
+     * ANTARIS4 format:
+     * $GPGGA,162254.00,3723.02837,N,12159.39853,W,1,03,2.36,525.6,M,-25.6,M,,
+     * *65
+     *
+     * The last two values are only valid when DGPS is in use and are:
+     * the time in seconds since last DGPS update and the DGPS station ID.
+     */
+
+    gps_latlon_split(s->pos.latitude, "NS",
+                    &lat_hemi, &lat_deg, &lat_min, &lat_sec);
+    gps_latlon_split(s->pos.longitude, "EW",
+                    &lon_hemi, &lon_deg, &lon_min, &lon_sec);
+
+    sprintf(sentence, "$GPGGA,%02i%02i%02i.00,%02i%02i.%03i,%c,"
+                    "%03i%02i.%03i,%c,%i,%02i,%i.%i,%i.%i,%c,%i.%i,%c,,",
+                    s->fix_time.tm_hour, s->fix_time.tm_min,
+                    s->fix_time.tm_sec, lat_deg, lat_min / 1000,
+                    lat_min % 1000, lat_hemi, lon_deg, lon_min / 1000,
+                    lon_min % 1000, lon_hemi, s->fix_q, s->maxsat,
+                    s->hdop / 10, s->hdop % 10, s->altitude / 10,
+                    s->altitude % 10, s->altitude_unit, s->gheight / 10,
+                    s->gheight % 10, s->gheight_unit);
+    gps_append_chksum(sentence);
+    gps_write(s, sentence);
+}
+
+/* GSA: Satellite Status */
+static void gps_nmea_gpgsa(struct gps_data_s *s)
+{
+    int i, count = 0;
+
+    /* NMEA format:
+     * $GPGSA,A,3,04,05,,09,12,,,24,,,,,2.5,1.3,2.1*39
+     * ANTARIS4 format:
+     * $GPGSA,A,2,25,01,22,,,,,,,,,,2.56,2.36,1.00*02
+     */
+
+    sprintf(sentence, "$GPGSA,%c,%i", 'A', s->fix_type);
+    for (i = 0; i < GPS_MAX_SATS; i ++)
+        if (s->sats[i].visible) {
+            sprintf(sentence + strlen(sentence), ",%02i", s->sats[i].prn);
+            count ++;
+            if (count >= s->nsat)
+                break;
+        }
+    for (i = count; i < 12; i ++)
+        strcat(sentence, ",");
+    sprintf(sentence + strlen(sentence), ",%i.%i,%i.%i,%i.%i",
+                    s->pdop / 10, s->pdop % 10, s->hdop / 10,
+                    s->hdop % 10, s->vdop / 10, s->vdop % 10);
+
+    gps_append_chksum(sentence);
+    gps_write(s, sentence);
+}
+
+/* GLL: Geographic position, Latitude and Longitude */
+static void gps_nmea_gpgll(struct gps_data_s *s)
+{
+    char lat_hemi, lon_hemi;
+    int lat_deg, lon_deg, lat_min, lon_min, lat_sec, lon_sec;
+
+    /* NMEA format:
+     * $GPGLL,4916.45,N,12311.12,W,225444,A,*31
+     * ANTARIS4 format:
+     * $GPGLL,3723.02837,N,12159.39853,W,162254.00,A,A*7C
+     */
+
+    gps_latlon_split(s->pos.latitude, "NS",
+                    &lat_hemi, &lat_deg, &lat_min, &lat_sec);
+    gps_latlon_split(s->pos.longitude, "EW",
+                    &lon_hemi, &lon_deg, &lon_min, &lon_sec);
+
+    sprintf(sentence, "$GPGLL,%02i%02i.%03i,%c,%03i%02i.%03i,%c,"
+                    "%02i%02i%02i.00,%c,%c",
+                    lat_deg, lat_min / 1000, lat_min % 1000, lat_hemi,
+                    lon_deg, lon_min / 1000, lon_min % 1000, lon_hemi,
+                    s->fix_time.tm_hour, s->fix_time.tm_min,
+                    s->fix_time.tm_sec, s->fix, 'A');
+    gps_append_chksum(sentence);
+    gps_write(s, sentence);
+}
+
+/* ZDA: Date and Time */
+static void gps_nmea_gpzda(struct gps_data_s *s)
+{
+    struct tm tm;
+    time_t now = time(0);
+
+    /* NMEA format:
+     * $GPZDA,201530.00,04,07,2002,00,00*6E
+     * ANTARIS4 format:
+     * $GPZDA,162254.00,11,07,2006,00,00*63
+     */
+
+    gmtime_r(&now, &tm);
+    sprintf(sentence, "$GPZDA,%02i%02i%02i.00,%02i,%02i,%04i,%02i,%02i",
+                    tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_mday,
+                    tm.tm_mon, tm.tm_year, s->tz_hour, s->tz_min);
+    gps_append_chksum(sentence);
+    gps_write(s, sentence);
+}
+
+/* VTG: Vector track (Velocity made good) and speed over the ground */
+static void gps_nmea_gpvtg(struct gps_data_s *s)
+{
+    /* NMEA format:
+     * $GPVTG,054.7,T,034.4,M,005.5,N,010.2,K*33
+     * ANTARIS4 format:
+     * $GPVTG,188.36,T,,M,0.820,N,1.519,K,A*3F
+     */
+
+    sprintf(sentence, "$GPZDA,%03i.%i,%c,%03i.%i,%c,%03i.%i,%c,%03i.%i,%c,%c",
+                    s->bear / 10, s->bear % 10, 'T', 34, 4, 'M',
+                    s->knots / 10, s->knots % 10, 'N',
+                    s->knots / 5, (s->knots * 2) % 10, 'K', 'A');
+    gps_append_chksum(sentence);
+    gps_write(s, sentence);
+}
+
+static void gps_nmea_send(void *opaque)
+{
+    struct gps_data_s *s = (struct gps_data_s *) opaque;
+
+    qemu_mod_timer(s->newdata_tm, qemu_get_clock(vm_clock) + s->rate);
+
+    gps_makedata(s);
+
+    /* Send a report */
+    gps_nmea_gprmc(s);
+    gps_nmea_gpvtg(s);
+    gps_nmea_gpgga(s);
+    gps_nmea_gpgsa(s);
+    gps_nmea_gpgsv(s);
+    gps_nmea_gpgll(s);
+    gps_nmea_gpzda(s);
+}
+
+static void gps_reset(struct gps_data_s *s)
+{
+    s->out_len = 0;
+    gps_fix_reset(s);
+}
+
+void gps_enable(CharDriverState *chr, int enable)
+{
+    struct gps_data_s *s = (struct gps_data_s *) chr->opaque;
+
+    s->enable = enable;
+    if (!enable)
+        qemu_del_timer(s->newdata_tm);
+    else {
+        gps_reset(s);
+        qemu_mod_timer(s->newdata_tm,
+                        qemu_get_clock(vm_clock) + 3 * ticks_per_sec);
+    }
+}
+
+static int gps_read(struct CharDriverState *chr, const uint8_t *buf, int len)
+{
+    /* We don't handle any input atm.  */
+    return len;
+}
+
+static void gps_out_tick(void *opaque)
+{
+    gps_fifo_wake((struct gps_data_s *) opaque);
+}
+
+static int gps_ioctl(struct CharDriverState *chr, int cmd, void *arg)
+{
+    QEMUSerialSetParams *ssp;
+    struct gps_data_s *s = (struct gps_data_s *) chr->opaque;
+    switch (cmd) {
+    case CHR_IOCTL_SERIAL_SET_PARAMS:
+        ssp = (QEMUSerialSetParams *) arg;
+        s->baud_delay = ticks_per_sec / ssp->speed;
+        break;
+
+    default:
+        return -ENOTSUP;
+    }
+    return 0;
+}
+
+static void gps_run_circles(struct gps_data_s *s)
+{
+    double angle_velocity = M_PI / 10;
+    double radius = 0.1; /* Degrees */
+    double t = (double) (qemu_get_clock(vm_clock) - s->vmtime_orig) /
+            ticks_per_sec;
+
+    s->pos.latitude = s->pos_orig.latitude + (int)
+            (3600.0 * radius * sin(t * angle_velocity));
+    s->pos.longitude = s->pos_orig.longitude + (int)
+            (3600.0 * radius * cos(t * angle_velocity));
+}
+
+static void gps_position_load(struct gps_data_s *s)
+{
+    int fd;
+    uint8_t buffer[4096];
+    char *line, *end;
+    int ret, len;
+    double val;
+
+    /* default */
+    s->pos.latitude = GPS_LLTOI(52.143721);
+    s->pos.longitude = GPS_LLTOI(21.063452);
+
+    fd = open("openmoko/position", O_RDONLY);
+    if (fd == -1)
+        return;
+    for (len = 0; len < sizeof(buffer) - 1; len += MAX(ret, 0)) {
+        ret = read(fd, buffer + len, sizeof(buffer) - 1 - len);
+        if (ret == 0)
+            break;
+        if (ret < 0 && errno != EINTR)
+            return;
+    }
+    close(fd);
+    for (line = buffer; line < (char *) buffer + len; line = end + 1) {
+        end = memchr(line, '\n', len - (line - (char *) buffer)) ?:
+                (buffer + len);
+        *end = 0;
+        if (sscanf(line, "Latitude: %lf", &val) > 0)
+            s->pos.latitude = GPS_LLTOI(val);
+        if (sscanf(line, "Longitude: %lf", &val) > 0)
+            s->pos.longitude = GPS_LLTOI(val);
+    }
+}
+
+CharDriverState *gps_antaris_serial_init(void)
+{
+    struct gps_data_s *s = (struct gps_data_s *)
+            qemu_mallocz(sizeof(struct gps_data_s));
+    time_t now = time(0);
+    s->chr.opaque = s;
+    s->chr.chr_write = gps_read;
+    s->chr.chr_ioctl = gps_ioctl;
+    s->out_tm = qemu_new_timer(vm_clock, gps_out_tick, s);
+    s->baud_delay = ticks_per_sec / 9600;
+
+    s->gps_proto = proto_nmea_20;
+    s->rate = ticks_per_sec * 4;
+    s->newdata_tm = qemu_new_timer(vm_clock, gps_nmea_send, s);
+
+    gps_position_load(s);
+    gps_satellite_random(s);
+    gps_fix_acquire(s);
+    gps_fix_reset(s);
+    s->tz_hour = 0;
+    s->tz_min = 0;
+    s->magnvar = 50;
+    s->magnew = 'E';
+    s->magnfix = 'A';
+    s->vdop = 12;
+    s->pdop = 34;
+    s->hdop = 56;
+    s->altitude = 2345;
+    s->altitude_unit = 'M';
+    s->gheight = 345;
+    s->gheight_unit = 'M';
+    s->pos_orig.latitude = s->pos.latitude;
+    s->pos_orig.longitude = s->pos.longitude;
+
+    s->vmtime_last = s->vmtime_orig = qemu_get_clock(vm_clock);
+    s->pos_update = gps_run_circles;
+    s->pos_update(s);
+
+    gmtime_r(&now, &s->fix_time);
+
+    return &s->chr;
+}

Modified: trunk/src/host/qemu-neo1973/hw/modem.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/modem.c	2007-11-09 16:06:40 UTC (rev 3385)
+++ trunk/src/host/qemu-neo1973/hw/modem.c	2007-11-09 16:32:22 UTC (rev 3386)
@@ -262,7 +262,7 @@
     s->call_notification(GN_CALL_Incoming, &call_info, &s->state);
 }
 
-CharDriverState *modem_init()
+CharDriverState *modem_init(void)
 {
     struct modem_s *s = (struct modem_s *)
             qemu_mallocz(sizeof(struct modem_s));

Modified: trunk/src/host/qemu-neo1973/openmoko/download.sh
===================================================================
--- trunk/src/host/qemu-neo1973/openmoko/download.sh	2007-11-09 16:06:40 UTC (rev 3385)
+++ trunk/src/host/qemu-neo1973/openmoko/download.sh	2007-11-09 16:32:22 UTC (rev 3386)
@@ -60,6 +60,17 @@
 download "$rootfs_image" "" || exit -1
 download "$uboot_image" dev_ || exit -1
 
+# Get this computer's aproximated geographic latitude/longitude for
+# QEMU GPS emulation start position, taking advantage of a working
+# internet connection.  If this fails or isn't accurate, we don't
+# really care, QEMU will then use some defaults.
+#
+# If the "position" file contains no position data or wrong data,
+# please consider contributing to the hostip.info database by
+# correcting the information at http://www.hostip.info/correct.html
+echo Retrieving position
+lynx -dump http://api.hostip.info/rough.php?position=true > position
+
 echo
 echo "    "Now use openmoko/flash.sh to install OpenMoko to NAND Flash.
 echo

Modified: trunk/src/host/qemu-neo1973/vl.h
===================================================================
--- trunk/src/host/qemu-neo1973/vl.h	2007-11-09 16:06:40 UTC (rev 3385)
+++ trunk/src/host/qemu-neo1973/vl.h	2007-11-09 16:32:22 UTC (rev 3386)
@@ -1621,6 +1621,10 @@
     void (*ring)(void *opaque);
 } modem_ops;
 
+/* gps.c */
+CharDriverState *gps_antaris_serial_init();
+void gps_enable(CharDriverState *chr, int enable);
+
 /* PCMCIA/Cardbus */
 
 struct pcmcia_socket_s {





More information about the commitlog mailing list