basic lightning detector with gps and sd card logging

Dependencies:   AS3935 AdafruitGPS SDFileSystem TSI mbed ConfigFile

main.cpp

Committer:
cmkachur
Date:
2015-07-15
Revision:
13:3d717008645c
Parent:
12:7c58c7a6b25c

File content as of revision 13:3d717008645c:

#include "mbed.h"
#include "GPS.h"
#include "main.h"
#include "TSISensor.h"
#include "SDFileSystem.h"
#include "AS3935.h"
#include "ConfigFile.h" 
#include "datetime.h"
#include "time.h"
#include <string>

#define FW_VER  5

 // frdm-kl25z as3935 connections for spi1 
 // ------------------------------------------------
 // Header -- kl25z -- SD/MMC          
 // J2-20  -- PTE1  -- MOSI
 // J9-13  -- PTE4  -- CS
 // J2-14  -- GND   -- Vss (GND) 
 // J9-9   -- PTE2  -- SCK
 // J9-11  -- PTE3  -- MISO
  
AS3935 ld(PTE1, PTE3, PTE2, PTE4, "ld", 1000000); // MOSI, MISO, SCK, CS, SPI bus freq (hz)
InterruptIn IntLightning(PTA12); //IRQ AS3935
 

 // frdm-kl25z sd card connections spi0
 // ------------------------------------------------
 // Header -- kl25z -- SPI          
 // J2-8   -- PTD2  -- MOSI
 // J2-6   -- PTD0  -- CS
 // J9-12  -- GND   -- Vss (GND) 
 // J9-4   -- P3V3  -- Vdd (+3.3v)
 // J2-12  -- PTD1  -- SCK
 // J9-14  -- GND   -- Vss (GND)
 // J2-10  -- PTD3  -- MISO
 
SDFileSystem sd(PTD2, PTD3, PTD1, PTD0, "sd"); // MOSI, MISO, SCK, CS

Serial pc(USBTX, USBRX);
GPS gpsd(PTE20, PTE21);
DigitalOut red(LED_RED);
DigitalOut green(LED_GREEN);
//DigitalOut blue(LED_BLUE);  don't use the blue led, due to a board error, writing to the blue led kills spi
bool debug=false;
void writeLogFile(int interruptSource, int distance, long energy);
char logName[]="lightning_data.csv";
int rdistance, rinterrupt;
char directory[]="/sd/lightning_data";
int OriginInt=-1;
int gDistance=-1;
long energy=-1;
struct tm Clock;

typedef struct 
{
unsigned int bOutdoorMode; 
unsigned int noiseFloor; 
unsigned int wdogThresh; 
unsigned int bClrStat; 
unsigned int minNumLight; 
unsigned int spikeRej; 
unsigned int maskDisturber; 
unsigned int bUseRtc; 
}sys_cfg_t;

// default configuration values 
sys_cfg_t sysCfg = {    .bOutdoorMode   = 1,  
                        .noiseFloor     = 2, 
                        .wdogThresh     = 2, 
                        .bClrStat       = 0,  
                        .minNumLight    = 0, 
                        .spikeRej       = 2,
                        .maskDisturber  = 0, 
                        .bUseRtc        = 1,
                    }; 


void DetectLightning()
{
    /* After the signal IRQ goes high the external
    unit should wait 2ms before reading the interrupt register. */ 
    wait_ms(2);
    OriginInt = ld.interruptSource();
    gDistance = ld.lightningDistanceKm();
    energy   = ld.getEnergy();
}
 
 void writeLogFile(int interruptSource, int distance, long energy)
{
    char logFilePath[128];
    static bool header=false;
    FILE *fp;
    
    sprintf(logFilePath, "%s/%s", directory,logName);
    sd.mount();
    fp = fopen(logFilePath, "a");
    if(fp == NULL) {
        // retry
        wait_ms(200);
        fp = fopen(logFilePath, "a");
        if (fp == NULL)
        {
            printf("Could not open file %s for writing\r\n",logFilePath);
            sd.unmount();
            printf("unmount sd card \r\n");
            return;
        }
    }
    if (debug)
        pc.printf("Opened log file %s\r\n",logFilePath);
    // write the log file header
    if (header == false)    
    {
        fprintf(fp,"# date,time,raw timestamp,latitude,longitude,distance,interrupt,energy\r\n");
        header = true;
    }
    // write to the current log file
    char       time_str[32];
    time_t     seconds = time(NULL);
    seconds -= 14400;  // 14400 = 60*60*4, kludgy way of setting est
    struct tm *tminfo = localtime(&seconds);
    strftime(time_str, 32, "%m/%d/%Y,%T", tminfo);
    fprintf(fp,"%s,%ld,",time_str,seconds);
    fprintf(fp,"%5.7f,%5.7f,", gpsd.lat_deg, gpsd.lon_deg);
    fprintf(fp,"%d,",distance);
    fprintf(fp,"%d,",interruptSource);
    fprintf(fp,"%ld",energy);
    fprintf(fp,"\r\n");
    fflush(fp);
    f_sync((FIL*)fp); 
    fclose(fp);
    sd.unmount();
    pc.printf("Event: ");
    pc.printf(" %s - ", time_str);
    switch (interruptSource)
    {
        case 1:
            pc.printf("Noise level too high\r\n");
            break;
        case 4:
            pc.printf("Disturber\r\n");
            break;     
        case 8:
            pc.printf("Lightning detection, distance=%dkm energy=%ld\r\n", distance, energy);
            
            if (sysCfg.bClrStat)
                ld.clearStats();
            break;
        default:
            pc.printf("Unknown interrupt %d\r\n", OriginInt);

    }
 
    if (debug)
        pc.printf("Closed log file %s\r\n",logFilePath);
}     


void writeCfgFile(unsigned char *pBuff, unsigned char buffLen, unsigned char fwVer)
{
    char cfgFilePath[128];
    FILE *fp;
    unsigned char cnt = 0; 
    
    sprintf(cfgFilePath, "%s/%s", directory, "config_data.csv");
    sd.mount();
    fp = fopen(cfgFilePath, "w");
    if(fp == NULL) {
        // retry
        wait_ms(200);
        fp = fopen(cfgFilePath, "w");
        if (fp == NULL)
        {
            printf("Could not open file %s for writing\r\n",cfgFilePath);
            sd.unmount();
            printf("unmount sd card \r\n");
            return;
        }
    }
    if (debug)
        pc.printf("Opened log file %s\r\n",cfgFilePath);

    // write the header 
    fprintf(fp,"# FW_VER,REG0,REG1,REG2,REG3,REG4,REG5,REG6,REG7,REG8\r\n");
    
    // write the firmware version 
    fprintf(fp,"%d,", fwVer);

    // write all the configuration registers 
    for (cnt = 0; cnt < buffLen && cnt < MAX_CONFIG_REGS; ++cnt) 
        fprintf(fp,"0x%x,", pBuff[cnt]);
    
    fflush(fp);
    f_sync((FIL*)fp); 
    fclose(fp);
    sd.unmount();

    if (debug)
        pc.printf("Closed cfg file %s\r\n",cfgFilePath);
}     


bool readCfgFile(char *paDirectory, sys_cfg_t *paSysCfg)
{
    bool bRetVal = false; 
    FILE *fp;
    sys_cfg_t lSysCfg; 
    typedef struct
    {
        const char *token; 
        unsigned int *value; 
    }token_map_t; 
    
    token_map_t tokenMap[] = {  {"outdoor_mode",        &lSysCfg.bOutdoorMode}, 
                                {"noise_floor",         &lSysCfg.noiseFloor}, 
                                {"watchdog_threshold",  &lSysCfg.wdogThresh}, 
                                {"clear_stat",          &lSysCfg.bClrStat}, 
                                {"minimum_num_light",   &lSysCfg.minNumLight},
                                {"spike_reject",        &lSysCfg.spikeRej}, 
                                {"mask_disturber",      &lSysCfg.maskDisturber}, 
                                {"use_rtc",             &lSysCfg.bUseRtc}, 
                             }; 
    ConfigFile *plCfgFile;
    string fileName; 
    int count = sizeof(tokenMap) / sizeof(token_map_t);  
    char szValue[8]; 

    if ((NULL == paDirectory) || (NULL == paSysCfg))
        return false; 

    // start with whatever configuration params are passed in, in case some params are not found in the file
    lSysCfg = *paSysCfg; 

    plCfgFile = new ConfigFile(); 
    fileName  = paDirectory; 
    fileName += "/"; 
    fileName += "zeus.cfg"; 
        
    sd.mount();
    fp = fopen(fileName.c_str(), "r");
    printf ("\n\rReading configuration file [%s]\n\r", fileName.c_str()); 
    
    // try to read values from the configuration file 
    if (plCfgFile->read((char *)fileName.c_str()))
    {
        for (int i = 0; i < count; ++i) 
        {
            if  (plCfgFile->getValue((char *)tokenMap[i].token, szValue, sizeof(szValue)))
            {
                if (1 == sscanf(szValue, "%d", tokenMap[i].value))
                {
                    printf ("Convert success %s[%d]\n\r", tokenMap[i].token, *(tokenMap[i].value)); 
                }
            }
        }
                
        // copy out the new found values 
        *paSysCfg = lSysCfg; 
        bRetVal = true; 
    }
    else 
    {
        printf ("Failed to read configuration file[%s]\n\r", fileName.c_str()); 

        // try to create a default configuration file 
        for (int i = 0; i < count; ++i) 
        {
            if (snprintf(szValue, sizeof(szValue), "%d", *(tokenMap[i].value)))
            { 
                if  (plCfgFile->setValue((char *)tokenMap[i].token, szValue))
                {
                    printf ("Token creation success %s[%s]\n\r", tokenMap[i].token, szValue); 
                }
            }
        }
        if (plCfgFile->write((char *)fileName.c_str(), NULL, DOS))
            printf ("Success: Created default configuration file [%s]\n\r", fileName.c_str()); 
        else 
            printf ("Failed to create default configuration file [%s]\n\r", fileName.c_str()); 
    }
    
    if (plCfgFile)
        delete plCfgFile; 
        
    if (fp != NULL)                                                                                                    
        fclose(fp);
    
    sd.unmount();
    return bRetVal; 
}


int main()
{
    unsigned char regBuff[MAX_CONFIG_REGS]; 
    char c;
    Timer refresh_Timer; //sets up a timer for use in loop; how often do we print GPS info?
    const int refresh_Time = 1000; //refresh time in ms
    TSISensor tsi;   // touch slider
    unsigned long measFreq; 
    rdistance=-1;
    rinterrupt=-1;
    pc.baud(9600);
    // initializations for gps  
    green = 1;
    gpsd.setBaud(9600);
    gpsd.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA); 
    gpsd.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);
    gpsd.sendCommand(PGCMD_ANTENNA);
    gpsd.day=01;
    gpsd.month=01;
    gpsd.year=15;
    gpsd.hour=1;
    gpsd.minute=1;
    gpsd.seconds=1;
    red = 1;
    
    pc.printf("Touch slider to start lightning detector application\r\n");
    while(1) {
        green = 1;   // turn led off
        wait_ms(200);
        if (tsi.readPercentage())
            break;
        green = 0;  // turn led on
        wait_ms(200);
        if (tsi.readPercentage())
            break;
    }
    //Mount the filesystem
    sd.mount();
    mkdir(directory, 0777);
    sd.unmount();

    // read configuration values fro SD file system to allow override of defaults in sysCfg
    readCfgFile(directory, &sysCfg);

    pc.printf("\r\nInitialize lightning detector\r\n");
    //initializations for lightning detector
    ld.init();
    ld.clearStats();

    /* The precision of the calibration will depend on the 
    accuracy of the resonance frequency of the antenna. It is
    recommended to first trim the receiver antenna before the
    calibration of both oscillators is done. 
    */
    measFreq = ld.tuneAntenna(IntLightning);
    ld.calibrateRCOs(IntLightning);
    
    if (sysCfg.bOutdoorMode)
        ld.setOutdoors(); 
    else 
        ld.setIndoors(); 
            
    ld.setMinimumLightnings(sysCfg.minNumLight);
    ld.setSpikeRejection(sysCfg.spikeRej);
    ld.setNoiseFloor(sysCfg.noiseFloor);

    if (sysCfg.maskDisturber)
        ld.disableDisturbers();
    else 
        ld.enableDisturbers();
        
    ld.setWatchdogThreshold(sysCfg.wdogThresh);
    IntLightning.rise(&DetectLightning);
    
    int MinLight    = ld.getMinimumLightnings();
    int Noise       = ld.getNoiseFloor();
    int TuneCap     = ld.getTuneCap();
    int SpikeRej    = ld.getSpikeRejection();
    int WatchDog    = ld.getWatchdogThreshold();
     
    pc.printf("\r\n Min lightning: %i", MinLight);
    pc.printf("\r\n");
    pc.printf(" Gain: 0x%02x\r\n",ld.getGain());
    pc.printf(" Noise: %i", Noise);
    pc.printf("\r\n");
    pc.printf(" Tune CAP: %i", TuneCap);
    pc.printf("\r\n");
    pc.printf(" Spike rej: %i", SpikeRej);
    pc.printf("\r\n");
    pc.printf(" Watchdog: %i", WatchDog);
    pc.printf("\r\n");
    pc.printf(" LCO calibration: %ld Hz\n\r", measFreq);

    refresh_Timer.start();  //starts the clock on the timer

    // get a copy of all config registers
    ld.getConfigRegisters(regBuff, sizeof(regBuff));
   
    pc.printf("\n\rSystem Registers:\n\r");
    for (int i = 0; i < sizeof(regBuff); ++i)
        pc.printf("REG%d [0x%02x]:\n\r", i, regBuff[i]);
    pc.printf("\n\r");
   
    // write to the config file 
    writeCfgFile(regBuff, sizeof(regBuff), FW_VER); 
    
    bool gpsFix=false;
    bool rtcRunning=false;
    while (1)
    {
        if (OriginInt != -1)
        {
            // the ld detector generated an interrupt, log the event
            IntLightning.disable_irq();
            writeLogFile(OriginInt,gDistance, energy);
            
            OriginInt = -1;
            gDistance = -1;
            energy = -1;
            IntLightning.enable_irq();   
        }
        
        c = gpsd.read();   //queries the GPS
        if (debug)
        {
            if (c) { 
                printf("%c", c);  //this line will echo the GPS data if not paused
                continue;
            }
        }
        
        //check if we recieved a new message from GPS, if so, attempt to parse it,
        if ( gpsd.newNMEAreceived() ) 
        {
            if ( !gpsd.parse(gpsd.lastNMEA()) ) 
            {
                continue;   
            }    
            else 
            {
                // if the rtc is not running, update the rtc clock with the latest gps time stamp
                if ( rtcRunning == false )
                {
                    IntLightning.disable_irq();
                    // update system time with the lastest gps time stamp
                    SetDateTime(gpsd.year+2000,
                            gpsd.month-1,
                            gpsd.day,
                            gpsd.hour,
                            gpsd.minute,
                            gpsd.seconds);
                    IntLightning.enable_irq();   
                }
            }
        }
                            
        //check if enough time has passed to warrant printing GPS info to screen
        //note if refresh_Time is too low or pc.baud is too low, GPS data may be lost during printing
        if (refresh_Timer.read_ms() >= refresh_Time) 
        {
            if (green)
                green = 0; 
            else 
                green = 1;  
            
            if (gpsd.fix) {
                // got a gps fix
                if (gpsFix == false)
                {
                    // first time fix obtained
                    gpsFix = true;
                    
                    if (sysCfg.bUseRtc)
                    {
                        // bug check - rtc may not be running.  check if it is incrementing
                        time_t     seconds_a = time(NULL);  // get the current rtc second count
                        wait(2);   // wait two seconds
                        time_t     seconds_b = time(NULL);  // get the current rtc second count
                        if (seconds_a != seconds_b)
                        {
                            // rtc must be running
                            rtcRunning = true;
                            pc.printf("RTC is running\r\n");
                        }
                        else
                        {
                            // rtc is not running, we need to update the rtc every pass through the while loop
                            rtcRunning = false;  // the gps time will update the system time  
                            pc.printf("RTC is not running\r\n");
                        }
                    }
                    else 
                    {
                        rtcRunning = false;  // the gps time will update the system clock time 
                    }
                    
                    IntLightning.disable_irq();
                    // set the system with the latest gps time
                    SetDateTime(gpsd.year+2000,
                                gpsd.month-1,
                                gpsd.day,
                                gpsd.hour,
                                gpsd.minute,
                                gpsd.seconds);
                    IntLightning.enable_irq();   
                    
                    pc.printf("GPS fix obtained on %02d/%02d/20%02d_%02d:%02d:%02d (UTC)\r\n",gpsd.month,gpsd.day,gpsd.year,gpsd.hour,gpsd.minute,gpsd.seconds);
                    
                    pc.printf("Waiting for lighting detection...\r\n");
                }
            }
            else
            {
                gpsFix = false;
                pc.printf("Waiting for GPS FIX\r\n");
                red = 0; // turn led on
            }
          
            // restart the timer for the gps print loop  
            refresh_Timer.reset();    
        }
    }
}