Code for 'Smart Regulator' featured in 'Model Engineer', November 2020 on. Contains all work to August 2020 including all code described. Top level algorithm development is quite spares, leaving some work for you! Any questions - jon@jons-workshop.com

Dependencies:   mbed BufferedSerial Servo2 PCT2075 I2CEeprom FastPWM

gps_mod.cpp

Committer:
JonFreeman
Date:
2020-12-05
Revision:
5:6ca3e7ffc553
Parent:
4:28cc0cf01570

File content as of revision 5:6ca3e7ffc553:

#include "mbed.h"

//#ifdef GPS_

#include "mbed.h"
#include "gps_mod.h"
using namespace std;
#if defined  (TARGET_NUCLEO_L476RG)  //  Computer is low power ARM Cortex development system
#include "BufferedSerial.h"
    BufferedSerial gps_module   (A0, A1);
#endif
#if defined  (TARGET_DISCO_F746NG)  //  Computer is high-end ARM Cortex development system with touch lcd
#include "BufferedSoftSerial.h"
    BufferedSoftSerial gps_module   (A4, A5);
#endif
#ifdef  TARGET_NUCLEO_L432KC
#include "BufferedSerial.h"
    extern  BufferedSerial gps_module;
#endif
gps_mod::gps_mod()  //  Constructor
{
//BufferedSoftSerial gps_module   (_pinTx : A0, _pinRx : A1);
    state = WAITING4DOLLAR;
    destptr = dest;
    strcpy  (latstr, "Invalid\0");
    strcpy  (longstr, "Invalid\0");
    strcpy  (altistr, "Invalid\0");
    strcpy  (timestr, "??:??:??\0");
    chcnt = 0;
    inmsg = false;
    newdata = false;
    posfix[0] = 'x';
    posfix[1] = 0;
    return;
}

bool    gps_mod::new_data()  {
    bool    r;
    r = newdata;
    newdata = false;
    return  r;    
}

bool    gps_mod::fix_valid()
{
    if  (posfix[0] < '1' || posfix[0] > '3')    return  false;
    return  true;
}

char * gps_mod::date ()  {
    return  datestr;
}

char * gps_mod::heading ()   {
    return  headingstr;
}

char * gps_mod::mph ()   {
    return  speed_mphourstr;
}

char *     gps_mod::position_fix_indicator  ()
{
    return  posfix;
}

char * gps_mod::latitude()
{
    if  (fix_valid())    return  latstr;
    return  "No Fix ";
}

char * gps_mod::longitude()
{
    if  (fix_valid())    return  longstr;
    return  "No Fix ";
}

char * gps_mod::altitude()
{
    if  (fix_valid())    return  altistr;
    return  "No Fix ";
}

char * gps_mod::sat_count ()
{
    return  numofsats;
}

char * gps_mod::message(int mess_num)
{
    if  (mess_num < 0 || mess_num > 5)
        return  NULL;
    return  dest + mess_num * (MAXMSGLEN + 4);
}

char * gps_mod::time ()
{
//    char * t = message(0);
    return  timestr;
}

double gps_mod::lat_merged ()
{
    double  result = strtod (latstr, NULL);
    return  result + (strtod (latstr + 3, NULL) / 60.0);
}

double gps_mod::lon_merged ()
{
    double  result = strtod (longstr, NULL);
    return  result + (strtod (longstr + 4, NULL) / 60.0);
}

int gps_mod::update()
{
    static const char month_tab[] = "---\0Jan\0Feb\0Mar\0Apr\0May\0Jun\0Jul\0Aug\0Sep\0Oct\0Nov\0Dec\0";
    const int MAX_COMMAS_IN_MSG = 24;
    int date, month;
    while   (gps_module.readable())  {
        ch = gps_module.getc();
        switch  (state) {
            case    WAITING4DOLLAR:
                i = 0;
                if  (ch == '$') state = GOTDOLLAR;
                break;
            case    GOTDOLLAR:  //  accumulate 5 chars after '$'
                hdracc[i++] = ch;
                hdracc[i] = 0;
                if  (i > 4) {
                    i = -1;
                    state = GOTHDR;
                }
                break;
            case    GOTHDR: //  have read "$GP???" to get here
//                if  (ch != ',') pc.printf   ("Oops, comma missing\r\n");
                if      (strncmp(hdracc,"GPGGA",5) == 0)  i = 0;
                else if (strncmp(hdracc,"GPGLL",5) == 0)  i = 1;
                else if (strncmp(hdracc,"GPGSA",5) == 0)  i = 2;
                else if (strncmp(hdracc,"GPGSV",5) == 0)  i = 3;
                else if (strncmp(hdracc,"GPRMC",5) == 0)  i = 4;//161229.487,A,3723.24756, N,12158.34162,W,     0.13,       309.62,  120598,,*10
                //                                                  time     ?    lat            lon      ground speed knots|heading|date
                else if (strncmp(hdracc,"GPVTG",5) == 0)  i = 5;
                if  (i < 0) state = WAITING4DOLLAR;     //  Found invalid header info
                else    {                               //  Validated header info
                    destptr = message(i);
                    chcnt = 0;
                    state = WAITING4CR;
                }
                break;
            case    WAITING4CR:
                if  (ch == '\r')  {
                    state = WAITING4LF;     //  process new string data here
                    int comma_count = 0, comma_positions[MAX_COMMAS_IN_MSG + 2];
                    for (int j = 0; j < strlen(destptr) && j < MAXMSGLEN && comma_count < MAX_COMMAS_IN_MSG; j++)  {
                        if  (destptr[j] == ',') {
                            comma_positions[comma_count++] = j;
                            comma_positions[comma_count] = 0;
                        }
                    }
                    switch  (i) {
                        case    0:  //  GGA 183655.00,5110.25620,N,00320.09926,W,1,11,0.80,59.9,M,49.5,M,,*74
                            if  (comma_positions[0] == 9)    {   //  time data seems to exist
                                timestr[0] = dest[0];
                                timestr[1] = dest[1];
                                timestr[2] = ':';
                                timestr[3] = dest[2];
                                timestr[4] = dest[3];
                                timestr[5] = ':';
                                timestr[6] = dest[4];
                                timestr[7] = dest[5];
                                timestr[8] = 0;
                            } else    {
                                strcpy  (timestr, "Invalid");
                            }
                            posfix[0] = dest[comma_positions[4] + 1];
                            if  (fix_valid())   {
                                int a = 0, b = comma_positions[5] + 1;   //  get numof sats
                                if  (dest[b] == ',')    {
                                    numofsats[0] = '-';
                                    numofsats[1] = '-';
                                }
                                else    {
                                    numofsats[0] = dest[b++];
                                    numofsats[1] = dest[b++];
                                }
                                b = comma_positions[7] + 1;  //  get altitude
                                char c;
                                while   ((c = dest[b++]) != ',' && a < 7)
                                    altistr[a++] = c;
                                altistr[a] = 0;
                            }
                            numofsats[2] = 0;
                            break;
                        case    1:  //  GLL 5110.25606,N,00320.10001,W,183752.00,A,A*72
                            latstr[0] = destptr[0];
                            latstr[1] = destptr[1];
                            latstr[2] = '~';
                            latstr[3] = destptr[2];
                            latstr[4] = destptr[3];
                            latstr[5] = '.';
                            for (int k = 5; k < 10; k++)
                                latstr[k + 1] = destptr[k];
                            latstr[11] = ' ';
                            latstr[12] = destptr[11];   //  N or S
                            latstr[13] = 0;
                            for (int k = 0; k < 3; k++)
                                longstr[k] = destptr[k + 13];
                            longstr[3] = '~';
                            longstr[4] = destptr[16];
                            longstr[5] = destptr[17];
                            longstr[6] = '.';
                            for (int k = 7; k < 12; k++)
                                longstr[k] = destptr[k + 12];
                            longstr[12] = ' ';
                            longstr[13] = destptr[25];  //  E or W
                            longstr[14] = 0;
                            break;
                        case    2:  //  GSA A,3,11,22,01,03,17,23,19,14,09,,,,1.72,0.97,1.42*0E
                            break;
                        case    3:  //  GSV complex multiple
                            break;  //               0             1              2 3      4            5        67
                        case    4:  //  RMC 184111.00, A,5110.25663, N,00320.10076,W, 0.223,            ,  090816,,,A*6B
//                                  //      161229.487,A,3723.24756, N,12158.34162,W, 0.13,       309.62,  120598,,*10
//                                           time     ?    lat            lon  ground speed knots|heading|date
                            if  (comma_positions[6] + 1 == comma_positions[7])  //  no heading data exists
                                strcpy  (headingstr, "-/-");
                            else
                                sprintf(headingstr, "%.1f", strtod(destptr + comma_positions[6] + 1, NULL));
//                            pc.printf("%s ^%s^", destptr, headingstr);
                            date =  (destptr[comma_positions[7] + 1] - '0') * 10 + (destptr[comma_positions[7] + 2] - '0');
                            month = (destptr[comma_positions[7] + 3] - '0') * 10 + (destptr[comma_positions[7] + 4] - '0');
                            if  (month > 12 || month < 1)
                                month = 0;
                            month *= 4;
                            sprintf (datestr, "%d %s 20%d", date, &month_tab[month], strtol(&destptr[comma_positions[7] + 5], NULL, 10));
                            break;
                        case    5:  //  VTG       ,T   ,             ,M,0.098,N,0.181,K,A*2A course over ground and ground speed
                        //Adafruit $GPVTG,165.48,T,,M,0.03,N,0.06,K,A*37 
//$                                   GPVTG 309.62,T   ,             ,M,0.13, N,0.2,  K*6E
                            sprintf (speed_mphourstr, "%.1fmph", km2miles * strtod(destptr + comma_positions[5] + 1, NULL));
                            newdata = true;
                            break;  //      course true|course magnetic|knots|km/hour
                        default:
//                            pc.printf   ("Naf i = %d\r\n", i);
                            break;
                    }
                } else    { //  char is not CR
                    if  (chcnt > MAXMSGLEN)    chcnt = MAXMSGLEN;
                    destptr[chcnt++] = ch;
                    destptr[chcnt] = 0;
                }
                break;
            case    WAITING4LF:
//                if  (ch != '\n')
//                    pc.printf   ("Oops, no LF\r\n");
                state = WAITING4DOLLAR;
                break;
            default:
                break;
        }
    }
    return 0;
}   //      end of int gps_mod::update()

//#endif