Test software for SatChat prototype hardware Platform - MAX32630FTHR

Dependencies:   USBDevice max32630fthr

main.cpp

Committer:
koziniec
Date:
2017-07-04
Revision:
15:7d75ecaeabdb
Parent:
14:8ff04e82bda2
Child:
16:c5634210628d

File content as of revision 15:7d75ecaeabdb:

/*  BLACK CODE INCLUDE START
    External libraries are worrying!
    Keep it simple and avoid anything non essential or obscure.
    Consider copying functions from libraries into the code so
    we have control. */
#include "mbed.h"
#include "max32630fthr.h"
#include <stdbool.h>
/*  BLACK CODE INCLUDE END */

/*  BLACK CODE DEFINE START */
#define ON 0
#define OFF 1
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
/*  BLACK CODE DEFINE END */

/*  BLACK CODE GLOBAL VAR START */
const int GPS_TIMEOUT=180;            //Wait three minutes maximum for GPS.
char gpsfix_last_utc_time[11] = {0};
char gpsfix_last_utc_date[7] = {0};
char gpsfix_longtitude[12] = {0};
char gpsfix_latitude[12] = {0};
char gpsfix_speed[8] = {0};     //Set but not used
char gpsfix_course[7] = {0};    //Set but not used
char gpsfix_variation[7] = {0}; //Set but not used
char gpsfix_mag_var_ew[1] = {0};//Set but not used
char gpsfix_ns = 0;
char gpsfix_ew = 0;
bool gps_data_present = false;  //If this is false we can't even use stale GPS data.
/*  BLACK CODE GLOBAL VAR END */

/*  BLACK CODE PERIPHERAL INIT START */
DigitalOut red_led(LED1,1);
DigitalOut green_led(LED2,1);
DigitalOut gps_led(LED3,1); //Blue
Serial pc(USBTX, USBRX);
Serial gps(P5_3, P5_4, 9600);
I2C i2c(P5_7,P6_0); // SDA, SCL
/*  BLACK CODE PERIPHERAL INIT END */

void gps_power(bool state)
/*  BLACK CODE
    MAX32630FTHR routine to control the output of the 3v3 line.
    This is achieved by issuing commands to the MAX14690 controller.
    In this case when the GPS is shutdown we clear any serial
    data to avoid issues with mbeds buggy serial code  */
{
    char    data[2];
    data[0] = 0x16;     //MAX14690 LDO3cfg register
    if (state == ON) {
        data[1] = 0xE2; //Enable LDO3
        i2c.write( 0x50, data, 2 );
        gps_led=ON;
    } else {
        data[1] = 0xE0; //Disable LDO3
        i2c.write( 0x50, data, 2 );
        gps_led=OFF;
        while (gps.readable()) {
                char dummy = gps.getc();    //Empty serial buffer because overflows reveal MBED bugs :-(
        }
    }
}

int get_epoch_from_last_gps_time(void)
/*  BLACK CODE
    Given appropriate global char arrays of time and date information,
    return a unix time epoch.
*/
{
    struct tm t;
    time_t epoch;
    char two_char_str[3] = {0};
    memcpy(two_char_str, gpsfix_last_utc_date+4, 2);
    t.tm_year = atoi(two_char_str)+100;         //Years since 1900
    memcpy(two_char_str, gpsfix_last_utc_date+2, 2);
    t.tm_mon = atoi(two_char_str)-1;            // Month, 0 - jan gpsfix_last_utc_date
    memcpy(two_char_str, gpsfix_last_utc_date, 2);
    t.tm_mday = atoi(two_char_str);             // Day of the month gpsfix_last_utc_date
    memcpy(two_char_str, gpsfix_last_utc_time, 2);
    t.tm_hour = atoi(two_char_str);
    memcpy(two_char_str, gpsfix_last_utc_time+2, 2);
    t.tm_min = atoi(two_char_str);
    memcpy(two_char_str, gpsfix_last_utc_time+4, 2);
    t.tm_sec = atoi(two_char_str);
    t.tm_isdst = 0;        // Is DST on? 1 = yes, 0 = no, -1 = unknown
    epoch = mktime(&t);
    return epoch;
    //BLACK CODE
}

int gps_update(void)
/*  BLACK CODE
    gps_update
    Reads NMEA data from a serial interface defined as "gps".
    The function waits for a valid $GPRMC sentence. It then decodes the sentence and populates the
    following global variables which are assumed to exist.
    
    gpsfix_last_utc_time[11] = {0}; char gpsfix_last_utc_date[7] = {0};char gpsfix_longtitude[12] = {0};
    char gpsfix_latitude[12] = {0}; char gpsfix_speed[8] = {0}; char gpsfix_course[7] = {0};
    char gpsfix_variation[7] = {0}; char gpsfix_mag_var_ew[1] = {0}; char gpsfix_ns = 0; char gpsfix_ew = 0;
    
    The following are also assumed to be part of the global declarations.
    #define EXIT_SUCCESS 0
    #define EXIT_FAILURE 1
    const int GPS_TIMEOUT=180;
    a gps_power() function that controls power to the GPS unit.
    
    If the function is successful it returns a 0.  If a valid fix is not obtined within the GPS_TIMEOUT 
    period a 1 is returned.
    
    The code has been tested with a uBlox 6M but other GPS units may work.
    The code is deliberately blocking as the mbed OS seems to crash on serial interrupts and buffer overflow.
    The serial port is continuously read while waiting for a fix. Once a fix is obtained or a timeout occurs
    the GPS is powered down and remaining data read out of the buffer.
*/
{
    gps_power(ON);
    time_t gps_on_time = time(NULL);    //Start time for GPS timeout calculation.
    bool wait_for_fix = true;           //Set this to false once a fix is obtained.
    while (wait_for_fix) {              //Keep monitoring the GPS until we get a fix.
        if ((time(NULL) - gps_on_time) > GPS_TIMEOUT) {
            gps_power(OFF);
            return EXIT_FAILURE;        //Return an error if the GPS takes too long for a fix.
        }
        int checksum = 0;
        char nmea_sentence[83] = {0};   //NMEA length max is 82 + 1 terminator. Fill with NULL terminators to save doing it later.
        while (gps.getc()!='$');        //wait for start of sentence
        int nmea_index = 0;
        nmea_sentence[nmea_index] = '$';    //Manually insert the '$' because we don't want it included in the checksum loop
        char nmea_char = gps.getc();        //get sentence first char from GPS
        while (nmea_char != '*') {          //Loop, building sentence and calc'ing CS until a * is seen
            checksum ^= nmea_char;          //Calc checksum as we read sentence
            if ((nmea_sentence[nmea_index] == ',')&&(nmea_char == ',')) {
                nmea_sentence[++nmea_index] = ' ';      //Pad consecutive comma with a space to make it possible to use strtok with empty values
            }
            nmea_sentence[++nmea_index] = nmea_char;    //build the sentence with the next character
            if (nmea_index > 81) {
                nmea_index=81;          //Don't overflow sentence buffer
            }
            nmea_char = gps.getc();     //get next char from GPS
        }
        //Last character was the '*' so next two are CS
        char hex_checksum[3] = {0};
        hex_checksum[0] = gps.getc();
        hex_checksum[1] = gps.getc();
        if (checksum == (int)strtol(hex_checksum, NULL, 16) ) {     //Compare calc and read checksums.
            //Valid sentence so check if it's a GPRMC
            const char gprmc[7] = "$GPRMC";
            char *token;
            token = strtok(nmea_sentence, ",");
            if (strcmp(token,gprmc) == 0) {     //GPRMC ?
                //pc.printf( " %s\n\r", token );  //Get the time
                if (token != NULL) {
                    token = strtok(NULL, ",");
                    if (*token != 32) {         //If there is a time present (anything but a space), record it.
                        //pc.printf("Time: %s\n\r",token);
                        gps_led =! gps_led;   //Flash blue LED
                        memcpy(gpsfix_last_utc_time, token, sizeof gpsfix_last_utc_time - 1);
                    }
                }
                if (token != NULL) {
                    token = strtok(NULL, ",");
                /*    if (*token == 'V') {
                        pc.printf("VOID");
                    } */
                } 
                if (*token == 'A') {                //Is this an 'A'ctive (valid) fix?
                    pc.printf("Got a fix\n\r");
                    gps_power(OFF);                 //Yes - No need for GPS now
                    wait_for_fix = false;           //Stop looping now we have a fix.
                    if (token != NULL) {
                        token = strtok(NULL, ",");
                        //pc.printf("Latitude: %s\n\r",token);
                        memcpy(gpsfix_latitude, token, sizeof gpsfix_latitude - 1);
                    }
                    if (token != NULL) {
                        token = strtok(NULL, ",");
                        //pc.printf("North/South: %s\n\r",token);
                        gpsfix_ns = *token;
                    }
                    if (token != NULL) {
                        token = strtok(NULL, ",");
                        //pc.printf("Longitude: %s\n\r",token);
                        memcpy(gpsfix_longtitude, token, sizeof gpsfix_longtitude - 1);
                    }
                    if (token != NULL) {
                        token = strtok(NULL, ",");
                        //pc.printf("East/West: %s\n\r",token);
                        gpsfix_ew = *token;
                    }
                    if (token != NULL) {
                        token = strtok(NULL, ",");
                        //pc.printf("Speed in knots: %s\n\r",token);
                    }
                    if (token != NULL) {
                        token = strtok(NULL, ",");
                        //pc.printf("True course: %s\n\r",token);
                    }
                    if (token != NULL) {
                        token = strtok(NULL, ",");
                        //pc.printf("Date: %s\n\r",token);
                        memcpy(gpsfix_last_utc_date, token, sizeof gpsfix_last_utc_date - 1);
                    }
                    if (token != NULL) {
                        token = strtok(NULL, ",");
                        //pc.printf("Variation: %s\n\r",token);
                    }
                    if (token != NULL) {
                        token = strtok(NULL, ",");
                        //pc.printf("Variation East/West: %s\n\r",token);
                    }
                }
            }
        }
    }
    return EXIT_SUCCESS;
    //BLACK CODE
}

main()
/*  Start of BLACK CODE region.  This area provides minimal SOS and position
    updating. It needs to be robust and well tested. Put all the fancy stuff 
    outside this area.  Changes here should be limited to fixing bugs and
    simplifying the code.
*/
{   //Set the power button behaviour.
    char    data[2];
    data[0] = 0x1A;     //MAX14690 BootCfg register
    data[1] = 0x30;     //Always-On Mode, off state via PWR_OFF_CMD
    i2c.write( 0x50, data, 2 );
    //Set the voltage to 3v3 for the GPS.
    data[0] = 0x17;     //MAX14690 LDO3Vset register
    data[1] = 0x19;     //3.3V
    i2c.write( 0x50, data, 2 );
    gps_power(OFF);

    pc.printf("\n\n\rOpen EPIRB - Simple mode\n\r");
    pc.printf("Press and hold both side buttons to signal rescue needed\n\r");
    pc.printf("Full functionality will start in:");
    for (int i=9; i > 0; i--) {
        time_t seconds = time(NULL);    //get current epoch
        pc.printf("%d",i);
        while(time(NULL) - seconds < 1) {
            if (false/*button_combination()==SOS_PRESSED*/) {
                //do the emergency code
                if (gps_update()==EXIT_SUCCESS) {
                    gps_data_present = true;
                    int gps_epoch = get_epoch_from_last_gps_time();
                    set_time(gps_epoch);
                    pc.printf("Got a GPS fix and time.\n\r");
                    pc.printf("Sending SOS in 10 seconds");
                    green_led=ON;
                } else {
                    pc.printf("\n\rGPS timed out and we have no existing fix.\n\r");
                    pc.printf("We can send an Iridium packet but coordinates are rough.\n\r");
                    pc.printf("Sending SOS in 10 seconds");
                    red_led=ON;
                }
                while(true) {}; //STOP HERE
            }
        }
        pc.printf("\b");            //Backspace
    }
/*  END OF BLACK CODE REGION - Put all the fancy stuff down here
*/
    pc.printf("\n\rStarting normal operation\n\r");
/*
    if (true) {         //Temp simulation
        while (1) {
            if (gps_update()==EXIT_SUCCESS) {
                gps_data_present = true;
                int gps_epoch = get_epoch_from_last_gps_time();
                set_time(gps_epoch);
                pc.printf("Got a GPS fix and time.\n\r");
            } else {
                pc.printf("GPS timed out and we have no existing fix.\n\r");
                pc.printf("We can send an Iridium packet but coordinates are rough.\n\r");
            }
            time_t seconds = time(NULL);
            //printf("Time as a basic string = %s", ctime(&seconds));
            wait(60);
            seconds = time(NULL);

            wait(33);
            seconds = time(NULL);
            printf("Time as a basic string = %s", ctime(&seconds));
            wait(60);
        } */
    }