LEcture GPS Xbee sous interruption

gps-ea-acc023.cpp

Committer:
pascalreygner
Date:
2018-08-09
Revision:
3:9a24090ff482
Parent:
2:824735b4c3a3

File content as of revision 3:9a24090ff482:

/* Gestion carte GPS au format XBEE
 * fournisseur : Embedded Artists
 * Réf : EA-ACC-023
 * utilise Chipset MT3339 (Mediatek Labs)
 */

#include <gps-ea-acc023.h>
#include "mbed.h"
#include <stdlib.h>
#include <stdio.h>

using namespace gpsxbee_MT3339;
static GpsXbee gpsxbee;
RawSerial gps_uart(P4_22, P4_23);

void GpsXbee::GpsXbeeInit(void)
{
    NmeaSentence = NMEA_INVALID;
    gpsTrameRMC = TRAME_WAIT;
    gpsTrameGGA = TRAME_WAIT;
    gpsState = StateStartGps;
    gpsBufPos =0;

    gps_uart.baud(9600);
    gps_uart.attach(this,&GpsXbee::lecture,gps_uart.RxIrq);
}

GpsXbee::~GpsXbee()
{
    gps_uart.attach(NULL);// bloque IRQ réception GPS

}

void GpsXbee::InitRMC(void)
{
    rmc_hours =0;
    rmc_minutes =0;
    rmc_seconds =0;
    rmc_milliseconds =0;
    rmc_warning = 'V';
    rmc_latitude =0;
    rmc_longitude =0;
    rmc_nsIndicator = 'N';
    rmc_ewIndicator = 'W';
    rmc_speedKnots =0;
    rmc_jours =0 ;
    rmc_mois =0 ;
    rmc_ans =0 ;
}

void GpsXbee::InitGGA(void)
{
    gga_hours = 0;
    gga_minutes = 0;
    gga_seconds = 0;
    gga_milliseconds = 0;
    gga_latitude = 0;
    gga_longitude = 0;
    gga_nsIndicator = 0;
    gga_ewIndicator = 0;
    gga_fix = 0;
    gga_satellites = 0;
    gga_hdop = 0;
    gga_altitude = 0;
    gga_geoidal = 0;
}

void  GpsXbee::lecture(void)  // réception d'un caractère - analyse trame
{
    char car=0;
    if((LPC_UART2->LSR & 0x01)==1) { // solution si getc fonctionne pas
        car = LPC_UART2->RBR;
//    if(gps_uart -> readable() == 1) {
//       d = gps_uart -> getc();  // lecture caractère reçu
        switch(gpsState) {
            case StateStartGps:
                if (car == '$') {
                    gpsBuf[0] = '$';
                    gpsBufPos = 1;
                    gpsState = StateDataGps;
                }
                break;
            case StateDataGps:
                if (gpsBufPos >= MTK3339_BUF_SZ) { // erreur trame
                    gpsState = StateStartGps;
                    gpsTrameRMC = TRAME_ERR;
                    gpsTrameGGA = TRAME_ERR;
                } else if (car == '\r') { // fin de trame
                    gpsBuf[gpsBufPos] = 0;
                    gpsState = StateStartGps;
                    parseData(gpsBuf, gpsBufPos); // analyse trame

                    if (NmeaSentence == NmeaRmc ) { // décodage trame type "RMC"
                        if (rmc_warning == 'A') { // si données GPS valables : les afficher
                            sprintf(gpsDataRMC,"%.2i/%.2i/%.2i:%.2iH%.2imn%.2is - Lat. = %f%c - Long. = %f%c",rmc_jours,rmc_mois,rmc_ans,rmc_hours,rmc_minutes,rmc_seconds,getLatitudeAsDegrees(rmc_latitude,rmc_nsIndicator),rmc_nsIndicator,getLongitudeAsDegrees(rmc_longitude,rmc_ewIndicator),rmc_ewIndicator);
                            gpsTrameRMC = TRAME_OK;  // Trame complète OK

                        } else {
                            sprintf(gpsDataRMC,"NMEARMC : %.2i/%.2i/%.2i:%.2iH%.2imn%.2is --- Valeurs GPS incorrectes",rmc_jours,rmc_mois,rmc_ans,rmc_hours,rmc_minutes,rmc_seconds);
                        }
                    }
                    /* pour afficher les autres protocoles */
                    else if (NmeaSentence == NmeaGga) { // décodage trame type "RMC"
                        if (gga_fix == 1) {// si données GPS valables : les afficher
                            sprintf(gpsDataGGA,"%.2iH%.2imn%.2is --- Latitude = %f%c  --- Longitude = %f%c - Nb sat = %i",gga_hours,gga_minutes,gga_seconds,getLatitudeAsDegrees(gga_latitude,gga_nsIndicator),gga_nsIndicator,getLongitudeAsDegrees(gga_longitude,gga_ewIndicator),gga_ewIndicator,gga_satellites);
                            gpsTrameGGA = TRAME_OK;  // Trame complète OK
                        } else
                            sprintf(gpsDataGGA,"NMEAGGA : %.2iH%.2imn%.2is --- Valeurs GPS incorrectes",gga_hours,gga_minutes,gga_seconds);
                    }    // pour les autres types (VTG/GGA/GSV) affiche uniquement la trame reçue
                    else memcpy(gpsDataRMC,gpsBuf,sizeof(gpsBuf));
                } else {
                    gpsBuf[gpsBufPos++] = car; // enregistre caractère suivant de la trame
                }
                break;
        }
    }
}


/*
$GPRMC,hhmmss.ss,A,llll.ll,a,yyyyy.yy,a,x.x,x.x,ddmmyy,x.x,a*hh
1    = UTC of position fix
2    = Data status (V=navigation receiver warning)
3    = Latitude of fix
4    = N or S
5    = Longitude of fix
6    = E or W
7    = Speed over ground in knots
8    = Track made good in degrees True
9    = UT date
10   = Magnetic variation degrees (Easterly var. subtracts from true course)
11   = E or W
12   = Checksum
*/
void GpsXbee::parseRMC(char* data, int dataLen)
{
    double tm = 0;
    char* p = data;
    int pos = 0;

    InitRMC();

    p = strchr(p, ',');
    while (p != NULL && *p != 0) {
        p++;

        switch(pos) {
            case 0: // time: hhmmss.ss (heure GMT)
                tm = strtod(p, NULL);
                rmc_hours = (int)(tm / 10000);
                rmc_hours+=2;  // remise à l'heure d'été Paris
                if (rmc_hours == 24) rmc_hours = 0;
                if (rmc_hours == 25) rmc_hours = 1;
                rmc_minutes = ((int)tm % 10000) / 100;
                rmc_seconds = ((int)tm % 100);
                rmc_milliseconds = (int)(tm * 100) % 100;
                break;
            case 1: // V = warning
                rmc_warning = *p;
                break;
            case 2: // latitude: ddmm.mmmm
                rmc_latitude = strtod(p, NULL);
                break;
            case 3: // N/S indicator (north or south)
                if (*p == 'N' || *p == 'S') {
                    rmc_nsIndicator = *p;
                } else rmc_nsIndicator = '?';
                break;
            case 4: // longitude: dddmm.mm
                rmc_longitude = strtod(p, NULL);
                break;
            case 5: // E/W indicator (east or west)
                if (*p == 'E' || *p == 'W') {
                    rmc_ewIndicator = *p;
                } else rmc_ewIndicator = '?';
                break;
            case 6: // speed in knots
                rmc_speedKnots = strtod(p, NULL);
                break;
            case 7: // ?
                break;
            case 8: // Date : ddmmyy
                tm = strtod(p, NULL);
                rmc_jours = (int)(tm / 10000);
                rmc_mois = ((int)tm % 10000) / 100;
                rmc_ans = ((int)tm % 100);
                break;
        }
        pos++;
        p = strchr(p, ',');
    }
}

void GpsXbee::parseGGA(char* data, int dataLen)
{
    //http://aprs.gids.nl/nmea/#gga

    double tm = 0;

    InitGGA();

    char* p = data;
    int pos = 0;

    p = strchr(p, ',');
    while (p != NULL && *p != 0) {
        p++;

        switch(pos) {
            case 0: // time: hhmmss.sss
                tm = strtod(p, NULL);
                gga_hours = (int)(tm / 10000);
                gga_minutes = ((int)tm % 10000) / 100;
                gga_seconds = ((int)tm % 100);
                gga_milliseconds = (int)(tm * 1000) % 1000;
                break;
            case 1: // latitude: ddmm.mmmm
                gga_latitude = strtod(p, NULL);
                break;
            case 2: // N/S indicator (north or south)
                if (*p == 'N' || *p == 'S') {
                    gga_nsIndicator = *p;
                }
                break;
            case 3: // longitude: dddmm.mmmm
                gga_longitude = strtod(p, NULL);
                break;
            case 4: // E/W indicator (east or west)
                if (*p == 'E' || *p == 'W') {
                    gga_ewIndicator = *p;
                }
                break;
            case 5: // position indicator (1=no fix, 2=GPS fix, 3=Differential)
                gga_fix = strtol(p, NULL, 10);
                break;
            case 6: // num satellites
                gga_satellites = strtol(p, NULL, 10);
                break;
            case 7: // hdop
                gga_hdop = strtod(p, NULL);
                break;
            case 8: // altitude
                gga_altitude = strtod(p, NULL);
                break;
            case 9: // units
                // ignore units
                break;
            case 10: // geoidal separation
                gga_geoidal = strtod(p, NULL);
                break;
        }
        pos++;

        p = strchr(p, ',');
    }

}

int  GpsXbee::parseData(char* data, int len)
{
    // verify checksum
    if (len < 3 || (len > 3 && data[len-3] != '*')) { // invalid data
        return(-1);
    }
    int sum = strtol(&data[len-2], NULL, 16);
    for(int i = 1; i < len-3; i++) {
        sum ^= data[i];
    }
    if (sum != 0) {
        return(-1);
    }

    NmeaSentence = NMEA_INVALID;
    if (strncmp("$GPGGA", data, 6) == 0 ) {
        parseGGA(data,len);
        NmeaSentence = NmeaGga;
    }

    else if (strncmp("$GPRMC", data, 6) == 0) {
        parseRMC(data, len);
        NmeaSentence = NmeaRmc;
    }

    return(0);
}

double  GpsXbee::getLatitudeAsDegrees(double l,char ns)
{
    // convert from ddmm.mmmm to degrees only
    // 60 minutes is 1 degree

    int deg = (int)(l / 100);
    l = (l - deg*100.0) / 60.0;
    l = deg + l;
    if (ns == 'S') l = -l;

    return l;
}

double  GpsXbee::getLongitudeAsDegrees(double l,char ew)
{
    // convert from ddmm.mmmm to degrees only
    // 60 minutes is 1 degree

    int deg = (int)(l / 100);
    l = (l - deg*100) / 60;
    l = deg + l;
    if (ew == 'W') l = -l;

    return l;
}