NMEA HAL层 与 java层 的接口

NMEA--- National Marine Electronics Association, GPS导航专用名词~

HAL 层代码如下:

#define NMEA_MAX_SIZE 83

typedef struct {
    int pos;
    int overflow;
    int utc_year;
    int utc_mon;
    int utc_day;
    int utc_diff;
    GpsLocation fix;
    GpsStatus    gps_status;
#ifdef Svpnd_Version    
    GpsCallbacks callback;
    GpsSvStatus sv_status;
    int sv_status_changed;
#else
    gps_location_callback callback;
#endif
    char in[ NMEA_MAX_SIZE+1 ];
} NmeaReader;

#define MAX_NMEA_TOKENS 83

typedef struct {
    int count;
    Token tokens[ MAX_NMEA_TOKENS ];
} NmeaTokenizer;

static int
nmea_tokenizer_init( NmeaTokenizer* t, const char* p, const char* end )
{
    int count = 0;
    char* q;

    /* the initial '$' is optional */
    if (p < end && p[0] == '$')
        p += 1;

    /* remove trailing newline */
    if (end > p && end[-1] == '\n') {
        end -= 1;
        if (end > p && end[-1] == '\r')
            end -= 1;
    }

    /* get rid of checksum at the end of the sentecne */
    if (end >= p+3 && end[-3] == '*') {
        end -= 3;
    }

    while (p < end) {
        const char* q = p;

        q = memchr(p, ',', end-p);
        if (q == NULL)
            q = end;

        /*if (q > p) { */
            if (count < MAX_NMEA_TOKENS) {
                t->tokens[count].p = p;
                t->tokens[count].end = q;
                count += 1;
            }
        /*}*/
        if (q < end)
            q += 1;

        p = q;
    }

    t->count = count;
    return count;
}

static Token
nmea_tokenizer_get( NmeaTokenizer* t, int index )
{
    Token tok;
    static const char* dummy = "";

    if (index < 0 || index >= t->count) {
        tok.p = tok.end = dummy;
    } else
        tok = t->tokens[index];

    return tok;
}

/* this is the state of our connection to the qemu_gpsd daemon */
typedef struct {
    int init;
    int fd; // UART FD

    #if GPS_GPIO_INCLUDE
    int fdGps; // GPS_GPIO FD

    #endif
    GpsCallbacks callbacks;
    pthread_t thread;
    int control[2];
    char device[32];
    sem_t fix_sem;
    
    /* QemuChannel channel; // We are not use QEMU */
} GpsState;

static void
nmea_reader_update_utc_diff( NmeaReader* r )
{
    time_t now = time(NULL);
    struct tm tm_local;
    struct tm tm_utc;
    long time_local, time_utc;

    gmtime_r( &now, &tm_utc );
    localtime_r( &now, &tm_local );

    time_local = tm_local.tm_sec +
                 60*(tm_local.tm_min +
                 60*(tm_local.tm_hour +
                 24*(tm_local.tm_yday +
                 365*tm_local.tm_year)));

    time_utc = tm_utc.tm_sec +
               60*(tm_utc.tm_min +
               60*(tm_utc.tm_hour +
               24*(tm_utc.tm_yday +
               365*tm_utc.tm_year)));

    r->utc_diff = time_utc - time_local;
}


static void
nmea_reader_init( NmeaReader* r )
{
    GpsCallbacks empty;

    memset( r, 0, sizeof(*r) );

    r->pos = 0;
    r->overflow = 0;
    r->utc_year = -1;
    r->utc_mon = -1;
    r->utc_day = -1;
    
    #ifdef Svpnd_Version
     r->callback = empty;
    #else
     r->callback = NULL;
     #endif
     r->fix.size = sizeof(r->fix);
     r->gps_status.size =sizeof(r->gps_status);

    
    nmea_reader_update_utc_diff( r );
}



#ifdef Svpnd_Version
static void
nmea_reader_set_callback( NmeaReader* r, GpsCallbacks cb )
{
    r->callback.location_cb = cb.location_cb;
    r->callback.status_cb = cb.status_cb;
    r->callback.sv_status_cb = cb.sv_status_cb;
    
    if (r->fix.flags != 0) {
        D("%s: sending latest fix to new callback", __FUNCTION__);
        r->callback.location_cb( &r->fix );
        r->fix.flags = 0;
    }
}

#else
static void
nmea_reader_set_callback( NmeaReader* r, gps_location_callback cb )
{
    r->callback = cb;
    if (cb != NULL && r->fix.flags != 0) {
        D("%s: sending latest fix to new callback", __FUNCTION__);
        r->callback( &r->fix );
        r->fix.flags = 0;
    }
}

#endif

static int
nmea_reader_update_accuracy( NmeaReader* r,
                             Token accuracy )
{
    double acc;
    Token tok = accuracy;

    if (tok.p >= tok.end)
        return -1;

    r->fix.accuracy = str2float(tok.p, tok.end);

    if (r->fix.accuracy == 99.99){
      return 0;
    }

    r->fix.flags |= GPS_LOCATION_HAS_ACCURACY;
    return 0;
}


static int
nmea_reader_update_time( NmeaReader* r, Token tok )
{
    int hour, minute;
    double seconds;
    struct tm tm;
    time_t fix_time;

    if (tok.p + 6 > tok.end)
        return -1;

    if (r->utc_year < 0) {
        /* no date yet, get current one */
        time_t now = time(NULL);
        gmtime_r( &now, &tm );
        r->utc_year = tm.tm_year + 1900;
        r->utc_mon = tm.tm_mon + 1;
        r->utc_day = tm.tm_mday;
    }

    hour = str2int(tok.p, tok.p+2);
    minute = str2int(tok.p+2, tok.p+4);
    seconds = str2float(tok.p+4, tok.end);

    tm.tm_hour = hour;
    tm.tm_min = minute;
    tm.tm_sec = (int) seconds;
    tm.tm_year = r->utc_year - 1900;
    tm.tm_mon = r->utc_mon - 1;
    tm.tm_mday = r->utc_day;
    tm.tm_isdst = -1;

    fix_time = mktime( &tm ) + r->utc_diff;
    r->fix.timestamp = (long long)fix_time * 1000;
    return 0;
}

static int nmea_reader_update_cdate( NmeaReader* r, Token tok_d, Token tok_m, Token tok_y )
{
  if ( (tok_d.p + 2 > tok_d.end) || (tok_m.p + 2 > tok_m.end) || (tok_y.p + 4 > tok_y.end) )
    return -1;
  r->utc_day = str2int(tok_d.p, tok_d.p+2);
  r->utc_mon = str2int(tok_m.p, tok_m.p+2);
  r->utc_year = str2int(tok_y.p, tok_y.end+4);
  return 0;
}

static int
nmea_reader_update_date( NmeaReader* r, Token date, Token time )
{
    Token tok = date;
    int day, mon, year;

    if (tok.p + 6 != tok.end) {
        D("date not properly formatted: '%.*s'", tok.end-tok.p, tok.p);
        return -1;
    }
    day = str2int(tok.p, tok.p+2);
    mon = str2int(tok.p+2, tok.p+4);
    year = str2int(tok.p+4, tok.p+6) + 2000;

    if ((day|mon|year) < 0) {
        D("date not properly formatted: '%.*s'", tok.end-tok.p, tok.p);
        return -1;
    }

    r->utc_year = year;
    r->utc_mon = mon;
    r->utc_day = day;

    return nmea_reader_update_time( r, time );
}


static double
convert_from_hhmm( Token tok )
{
    double val = str2float(tok.p, tok.end);
    int degrees = (int)(floor(val) / 100);
    double minutes = val - degrees*100.;
    double dcoord = degrees + minutes / 60.0;
    return dcoord;
}


static int
nmea_reader_update_latlong( NmeaReader* r,
                            Token latitude,
                            char latitudeHemi,
                            Token longitude,
                            char longitudeHemi )
{
    double lat, lon;
    Token tok;

    tok = latitude;
    if (tok.p + 6 > tok.end) {
        D("latitude is too short: '%.*s'", tok.end-tok.p, tok.p);
        return -1;
    }
    lat = convert_from_hhmm(tok);
    if (latitudeHemi == 'S')
        lat = -lat;

    tok = longitude;
    if (tok.p + 6 > tok.end) {
        D("longitude is too short: '%.*s'", tok.end-tok.p, tok.p);
        return -1;
    }
    lon = convert_from_hhmm(tok);
    if (longitudeHemi == 'W')
        lon = -lon;

    r->fix.flags |= GPS_LOCATION_HAS_LAT_LONG;
    r->fix.latitude = lat;
    r->fix.longitude = lon;
    return 0;
}


static int
nmea_reader_update_altitude( NmeaReader* r,
                             Token altitude,
                             Token units )
{
    double alt;
    Token tok = altitude;

    if (tok.p >= tok.end)
        return -1;

    r->fix.flags |= GPS_LOCATION_HAS_ALTITUDE;
    r->fix.altitude = str2float(tok.p, tok.end);
    return 0;
}


static int
nmea_reader_update_bearing( NmeaReader* r,
                            Token bearing )
{
    double alt;
    Token tok = bearing;

    if (tok.p >= tok.end)
        return -1;

    r->fix.flags |= GPS_LOCATION_HAS_BEARING;
    r->fix.bearing = str2float(tok.p, tok.end);
    return 0;
}


static int
nmea_reader_update_speed( NmeaReader* r,
                          Token speed )
{
    double alt;
    Token tok = speed;

    if (tok.p >= tok.end)
        return -1;

    r->fix.flags |= GPS_LOCATION_HAS_SPEED;
    r->fix.speed = str2float(tok.p, tok.end);
    return 0;
}


static void
nmea_reader_parse( NmeaReader* r )
{
   /* we received a complete sentence, now parse it to generate
    * a new GPS fix...
    */
    NmeaTokenizer tzer[1];
    Token tok;

   D("Received: '%.*s'", r->pos, r->in);
    if (r->pos < 9) {
        D("Too short. discarded.");
        return;
    }

    nmea_tokenizer_init(tzer, r->in, r->in + r->pos);
#if GPS_DEBUG
    {
        int n;
        for (n = 0; n < tzer->count; n++) {
            Token tok = nmea_tokenizer_get(tzer,n);
        }
    }
#endif

    tok = nmea_tokenizer_get(tzer, 0);
    if (tok.p + 5 > tok.end) {
        return;
    }

    /* ignore first two characters.*/
    tok.p += 2;
    if ( !memcmp(tok.p, "GGA", 3) ) {
        /* GPS fix */
        Token tok_time = nmea_tokenizer_get(tzer,1);
        Token tok_latitude = nmea_tokenizer_get(tzer,2);
        Token tok_latitudeHemi = nmea_tokenizer_get(tzer,3);
        Token tok_longitude = nmea_tokenizer_get(tzer,4);
        Token tok_longitudeHemi = nmea_tokenizer_get(tzer,5);
        Token tok_altitude = nmea_tokenizer_get(tzer,9);
        Token tok_altitudeUnits = nmea_tokenizer_get(tzer,10);

        nmea_reader_update_time(r, tok_time);
        nmea_reader_update_latlong(r, tok_latitude,
                                      tok_latitudeHemi.p[0],
                                      tok_longitude,
                                      tok_longitudeHemi.p[0]);
        nmea_reader_update_altitude(r, tok_altitude, tok_altitudeUnits);
    }else if ( !memcmp(tok.p, "GLL", 3) ) {
    Token tok_fixstaus = nmea_tokenizer_get(tzer,6);
    if (tok_fixstaus.p[0] == 'A') {
     Token tok_latitude = nmea_tokenizer_get(tzer,1);
     Token tok_latitudeHemi = nmea_tokenizer_get(tzer,2);
     Token tok_longitude = nmea_tokenizer_get(tzer,3);
     Token tok_longitudeHemi = nmea_tokenizer_get(tzer,4);
     Token tok_time = nmea_tokenizer_get(tzer,5);
     nmea_reader_update_time(r, tok_time);
     nmea_reader_update_latlong(r, tok_latitude, tok_latitudeHemi.p[0], tok_longitude, tok_longitudeHemi.p[0]);
    }
    }
    #ifdef Svpnd_Version
    else if ( !memcmp(tok.p, "GSV", 3) ) {
    Token tok_noSatellites = nmea_tokenizer_get(tzer, 3);
    int noSatellites = str2int(tok_noSatellites.p, tok_noSatellites.end);
        
    if (noSatellites > 0) {
     Token tok_noSentences = nmea_tokenizer_get(tzer, 1);
     Token tok_sentence     = nmea_tokenizer_get(tzer, 2);
    
     int sentence = str2int(tok_sentence.p, tok_sentence.end);
     int totalSentences = str2int(tok_noSentences.p, tok_noSentences.end);
     int curr;
     int i;
            
     if (sentence == 1) {
     r->sv_status_changed = 0;
     r->sv_status.num_svs = 0;
     }
    
        curr = r->sv_status.num_svs;
    
        i = 0;
    
        while (i < 4 && r->sv_status.num_svs < noSatellites){
         Token    tok_prn = nmea_tokenizer_get(tzer, i * 4 + 4);
         Token    tok_elevation = nmea_tokenizer_get(tzer, i * 4 + 5);
         Token    tok_azimuth = nmea_tokenizer_get(tzer, i * 4 + 6);
         Token    tok_snr = nmea_tokenizer_get(tzer, i * 4 + 7);
    
         r->sv_status.sv_list[curr].prn = str2int(tok_prn.p, tok_prn.end);
         r->sv_status.sv_list[curr].elevation = str2float(tok_elevation.p, tok_elevation.end);
         r->sv_status.sv_list[curr].azimuth = str2float(tok_azimuth.p, tok_azimuth.end);
         r->sv_status.sv_list[curr].snr = str2float(tok_snr.p, tok_snr.end);
    
         r->sv_status.num_svs += 1;
    
         curr += 1;
    
         i += 1;
     }
    
     if (sentence == totalSentences) {
        r->sv_status_changed = 1;
     }
    
     D("%s: GSV message with total satellites %d", __FUNCTION__, noSatellites);
    
    }        
    
    }
    #endif
    
    else if ( !memcmp(tok.p, "GSA", 3) ) {
    #ifdef Svpnd_Version
        /* do something ? */
        {

        Token tok_fixStatus = nmea_tokenizer_get(tzer, 2);
        int i;

        if (tok_fixStatus.p[0] != '\0' && tok_fixStatus.p[0] != '1') {

            Token tok_accuracy = nmea_tokenizer_get(tzer, 15);

            nmea_reader_update_accuracy(r, tok_accuracy);

            r->sv_status.used_in_fix_mask = 0ul;

            for (i = 3; i <= 14; ++i){

                Token tok_prn = nmea_tokenizer_get(tzer, i);
                int prn = str2int(tok_prn.p, tok_prn.end);

                if (prn > 0){
                    r->sv_status.used_in_fix_mask |= (1ul << (32 - prn));
                    r->sv_status_changed = 1;
                    D("%s: fix mask is %d", __FUNCTION__, r->sv_status.used_in_fix_mask);
         D(" [log hit][%s:%d] fix.flags=0x%x ", __FUNCTION__, __LINE__, r->fix.flags);
               }

           }

       }

       D(" [log hit][%s:%d] fix.flags=0x%x ", __FUNCTION__, __LINE__, r->fix.flags);

    }
    #endif
        /* do something ? */
    } else if ( !memcmp(tok.p, "RMC", 3) ) {
        Token tok_time = nmea_tokenizer_get(tzer,1);
        Token tok_fixStatus = nmea_tokenizer_get(tzer,2);
        Token tok_latitude = nmea_tokenizer_get(tzer,3);
        Token tok_latitudeHemi = nmea_tokenizer_get(tzer,4);
        Token tok_longitude = nmea_tokenizer_get(tzer,5);
        Token tok_longitudeHemi = nmea_tokenizer_get(tzer,6);
        Token tok_speed = nmea_tokenizer_get(tzer,7);
        Token tok_bearing = nmea_tokenizer_get(tzer,8);
        Token tok_date = nmea_tokenizer_get(tzer,9);

        D("in RMC, fixStatus=%c", tok_fixStatus.p[0]);
        if (tok_fixStatus.p[0] == 'A')
        {
            nmea_reader_update_date( r, tok_date, tok_time );

            nmea_reader_update_latlong( r, tok_latitude,
                                           tok_latitudeHemi.p[0],
                                           tok_longitude,
                                           tok_longitudeHemi.p[0] );

            nmea_reader_update_bearing( r, tok_bearing );
            nmea_reader_update_speed ( r, tok_speed );
        }
    }
    else if ( !memcmp(tok.p, "VTG", 3) ) {
     Token tok_fixStatus = nmea_tokenizer_get(tzer,9);
     if (tok_fixStatus.p[0] != '\0' && tok_fixStatus.p[0] != 'N') {
     Token tok_bearing = nmea_tokenizer_get(tzer,1);
     Token tok_speed = nmea_tokenizer_get(tzer,5);
     nmea_reader_update_bearing( r, tok_bearing );
     nmea_reader_update_speed ( r, tok_speed );
     }
    }
    else if ( !memcmp(tok.p, "ZDA", 3) ) {
     Token tok_time;
     Token tok_year = nmea_tokenizer_get(tzer,4);
     if (tok_year.p[0] != '\0') {
     Token tok_day = nmea_tokenizer_get(tzer,2);
     Token tok_mon = nmea_tokenizer_get(tzer,3);
     nmea_reader_update_cdate( r, tok_day, tok_mon, tok_year );
     }
     tok_time = nmea_tokenizer_get(tzer,1);
     if (tok_time.p[0] != '\0')
     nmea_reader_update_time(r, tok_time);
    }
    else {
     tok.p -= 2;
     D("unknown sentence '%.*s", tok.end-tok.p, tok.p);
    }
    if (r->fix.flags != 0) {
#if GPS_DEBUG
        char temp[256];
        char* p = temp;
        char* end = p + sizeof(temp);
        struct tm utc;

        p += snprintf( p, end-p, "sending fix" );
        if (r->fix.flags & GPS_LOCATION_HAS_LAT_LONG) {
            p += snprintf(p, end-p, " lat=%g lon=%g", r->fix.latitude, r->fix.longitude);
        }
        if (r->fix.flags & GPS_LOCATION_HAS_ALTITUDE) {
            p += snprintf(p, end-p, " altitude=%g", r->fix.altitude);
        }
        if (r->fix.flags & GPS_LOCATION_HAS_SPEED) {
            p += snprintf(p, end-p, " speed=%g", r->fix.speed);
        }
        if (r->fix.flags & GPS_LOCATION_HAS_BEARING) {
            p += snprintf(p, end-p, " bearing=%g", r->fix.bearing);
        }
        if (r->fix.flags & GPS_LOCATION_HAS_ACCURACY) {
            p += snprintf(p,end-p, " accuracy=%g", r->fix.accuracy);
        }
        gmtime_r( (time_t*) &r->fix.timestamp, &utc );
        p += snprintf(p, end-p, " time=%s", asctime( &utc ) );
        D(temp);
#endif
    #ifdef Svpnd_Version
     if (r->callback.location_cb) {
            r->callback.location_cb( &r->fix );
            r->fix.flags = 0;
        }
    
    #else
        if (r->callback) {
             r->callback( &r->fix );
             r->fix.flags = 0;
         }
        #endif
        
        else {
             /* D("no callback, keeping data until needed !"); */
        }
    }
    /* sv status !!! */
    #ifdef Svpnd_Version
     if (r->sv_status_changed != 0) {
           if (r->callback.sv_status_cb) {
                 r->callback.sv_status_cb( &(r->sv_status) );
               r->sv_status_changed = 0;
             }else {
               /* D("no callback, keeping status data until needed !");*/
           }

        }
     #endif
}


static void
nmea_reader_add( NmeaReader* r, char *buff,int count)
{
    char i,c;
for( i=0;i<count;i++)
{
   c=buff[i];
    if (r->overflow) {
        r->overflow = (c != '\n');
        return;
    }

    if (r->pos >= (int) sizeof(r->in)-1 ) {
        r->overflow = 1;
        r->pos = 0;
    return;
    }

    r->in[r->pos] = (char)c;
    r->pos += 1;

    if (c == '\n') {
         GPS_STATE_LOCK_FIX(gps_state);
        nmea_reader_parse( r );
        r->pos = 0;
     GPS_STATE_UNLOCK_FIX(gps_state);
    }
 }
}


static void
nmea_reader_addc( NmeaReader* r, int c )
{
    if (r->overflow)
   {
        r->overflow = (c != '\n');
        return;
    }

    if (r->pos >= (int) sizeof(r->in)-1 )
   {
        r->overflow = 1;
        r->pos = 0;
        return;
    }

    r->in[r->pos] = (char)c;
    r->pos += 1;

    if (c == '\n')
   {
         GPS_STATE_LOCK_FIX(gps_state);
        nmea_reader_parse( r );
        r->pos = 0;
     GPS_STATE_UNLOCK_FIX(gps_state);
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值