This version is the one to be submitted as a part the Hackster.io contest, Unleash Invisible Intelligence

main.cpp

Committer:
gov1
Date:
2018-07-31
Revision:
0:a761fba7f8a8

File content as of revision 0:a761fba7f8a8:

#include "mbed.h"
#include "LoRa.h"
#include "MBed_Adafruit_GPS.h"
#include "MAX17055.h"

Serial pc (USBTX, USBRX);       // debug serial port
DigitalOut led1(LED1);          // debug blinker

/******************************************************************************/
/*************************** Power & Fuel Gauge *******************************/                                 
/******************************************************************************/
DigitalOut powerHLD(P2_2, 1); //keep power on when connected to battery
I2C i2c(I2C2_SDA, I2C2_SCL);
MAX17055 max17055(i2c);
int gaugeStatus;
int stateOfCharge, timeToEmpty;
float batteryVoltage, batteryCurrent, boardTemperature, tteReport;
#define FUEL_REFRESH 30 // 120 secs, 2 minutes for now, testing . . .

Timer fuelTimer;
Timer batteryEmergencyPause; // avoid sending alert right after starting unit up!
bool startBatteryEmergency;
bool inBatteryEmergencyState;
#define EMERBEGIN 180000 // 3 minutes  in millissecond after setup runs
void readFuelGauge(void);
/************************* End Power & Fuel Guage *****************************/

/******************************************************************************/
/***************************** LoRa TxRx **************************************/
/******************************************************************************/
#define GATEWAYID           0x30 // LoRa Gateway ID
#define LOCALADDRESSID      0x31 // this gamma canary ID
#define GPSDATA             0x40
#define CPMDATA             0x41
#define FUELDATA            0x42
#define LOWBATTERY          0x43
// #define CPMALERT            0x44

// data transmission/report intervals
// #define LOCATION_INTERVAL 15.0      // GPS location every 120 secs
// #define CPM_INTERVAL  60.0          // CPM every 60 secs
// #define FUEL_INTERVAL 90.0          // Fuel Gauge every 90 secs

// data transmission/report intervals
float LOCATION_INTERVAL = 15.0;         // GPS location every 120 secs
float CPM_INTERVAL      = 60.0;         // CPM every 60 secs
float FUEL_INTERVAL     = 90.0;         // Fuel Gauge every 90 secs

volatile int locationCountDown, cpmCountDown, fuelCountDown; 

Ticker transmissionTicker;
void transmitLoRaTicker(void)
{
    if (locationCountDown > 0) locationCountDown--;
    if (cpmCountDown > 0) cpmCountDown--;
    if (fuelCountDown >0) fuelCountDown--;
} 

void transmitLocation(void);
void transmitCPM(void);
void transmitFuel(void);
void batteryLowTransmit();
void onReceive(int packetSize);
/*************************** End LoRa *****************************************/

/******************************************************************************/
/******************************** GPS *****************************************/
/******************************************************************************/
double currentLatitude, currentLongitude, previousLatitude, previousLongitude;
Serial * _gpsSerial;

#define GPS_REFRESH 5000 // 2000 millisecs???
Timer gpsTimer; // GPS data collection/refresh timer

void transformGPSData(double lat, char p, double lon, char m);
// GPS command list at http://www.adafruit.com/datasheets/PMTK_A08.pdf
/**************************** End GPS *****************************************/

/******************************************************************************/
/*********************** Begin Radiation Monitoring ***************************/
/******************************************************************************/
// PMOD Port 1 pins for radiation sensor
volatile int signalCounter, noiseCounter;
InterruptIn signalPin(P1_0);
InterruptIn noisePin(P1_1);
// interrupt service routines(ISR) which count are called whenever signal or noise pins are triggered
void signalISR(){ signalCounter++; led1 = !led1;}
void noiseISR(){ noiseCounter++; } 

// #define CPMALERTLEVEL   50 // set very low or testing purposes.
// #DEFINE CPMMAXALERTS     3 // only three at a time to not bomb SMS network!
#define CPM_REFRESH     60 // 60 seconds in a minute
Timer cpmTimer; // CPM data collection, determine total current counts per minute

int currentSignalCount, currentNoiseCount, previousCPM, currentCPM;
int previousTotalSignalCount, previousTotalNoiseCount;

void calculateCPM();
/*********************** End Radiation Monitoring *****************************/


int main()
{
    /****************************** Setup *************************************/
    pc.printf(" ********* gamma canary v001 ********* \n");
    
    /** 0. Confirm running on battery power **/
    if (powerHLD.is_connected()) {pc.printf("Battery power connected...\n");}
    
    /** 1. LoRa TxRx initialization **/
    if (!LoRa.begin(915E6)) {pc.printf("LoRa not found!");} 
    else {  pc.printf("LoRa started...\n");}
    // LoRa.onReceive(onReceive);
    // LoRa.receive();
    transmissionTicker.attach(&transmitLoRaTicker,1.0);
    
    /** 2. GPS/NMEA Initialization **/
    currentLongitude = 0.00;
    previousLongitude = currentLongitude;
    currentLatitude = 0.00;
    previousLatitude = currentLatitude;
    
    _gpsSerial = new Serial(P3_1,P3_0); //serial object for use w/ GPS
    Adafruit_GPS myGPS(_gpsSerial); 
    myGPS.begin(9600);  
    char c;
    myGPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA); //these commands are defined in MBed_Adafruit_GPS.h; a link is provided there for command creation
    myGPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);
    myGPS.sendCommand(PGCMD_ANTENNA);
    gpsTimer.start();
    pc.printf("GPS setup done...\n");
    
    //** 3. Radiation Detecton - CPM(Counts Per Minute)
    currentSignalCount = 0;
    previousTotalSignalCount = 0;
    currentNoiseCount = 0;
    previousTotalNoiseCount = 0;
    currentCPM = 0;
    previousCPM = 0;
    signalPin.rise(&signalISR);     // attach ISR function to the rising edge
    noisePin.rise(&noiseISR);       // attach ISR function to the rising edge
    cpmTimer.start();
    pc.printf("Starting radiation monitoring...\n");

    /** 4. Fuel Gauge/Battery Monitoring **/
    max17055.init(0.05f);
    max17055.status(&gaugeStatus);
    fuelTimer.start();
    startBatteryEmergency = false;
    inBatteryEmergencyState = false;
    batteryEmergencyPause.start();
    pc.printf("MAX17055 status: %04X\r\n", (uint16_t)gaugeStatus);
    wait(3.0);
    pc.printf("Setup complete...\n");
    
    /***************************** End Setup **********************************/
    // loop()
    while(1)
    {
        
        /** GPS/Location Data Collection"loop" here **/
        c = myGPS.read();   //queries the GPS
        if ( myGPS.newNMEAreceived() ) 
        {
            if ( !myGPS.parse(myGPS.lastNMEA()) ) {
                continue;   
            }    
        }
        
        //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 (gpsTimer.read_ms() >= GPS_REFRESH) 
        {
            gpsTimer.reset();
            if (myGPS.fix) {
                // pc.printf("Location: %5.2f%c, %5.2f%c\n", myGPS.latitude, myGPS.lat, myGPS.longitude, myGPS.lon);
                // previousLatitude = currentLatitude;
                // previousLongitude = currentLongitude;            
                // currentLatitude = myGPS.latitude;
                // currentLongitude = myGPS.longitude;
                transformGPSData(myGPS.latitude, myGPS.lat, myGPS.longitude, myGPS.lon);
            }
        }        
        
        if (cpmTimer.read() >= CPM_REFRESH)
        {
            cpmTimer.reset();
            calculateCPM();    
        }
        
        if (fuelTimer.read() >= FUEL_REFRESH)
        {
            fuelTimer.reset();
            readFuelGauge();    
        }
        
        // special 1 time timer to begin battery monitoring for emergency lo battery warning
        
        if( batteryEmergencyPause.read_ms() >= EMERBEGIN )
        {
            batteryEmergencyPause.stop();
            startBatteryEmergency = true;  
        }
        
        /** LoRa Data Transmision **/
        if (locationCountDown == 0) 
        { 
            locationCountDown = LOCATION_INTERVAL;
            transmitLocation();      
        }
        if (cpmCountDown == 0) 
        {
            cpmCountDown = CPM_INTERVAL;
            transmitCPM();    
        }
        if (fuelCountDown == 0) 
        {
            fuelCountDown = FUEL_INTERVAL;
            transmitFuel();    
        }
        
    } // end loop
    
} 

/** GPS Functions **/
void transformGPSData(double lat, char parallel, double lon, char meridian)
{
    float degrees = floor(lat/100.00);
    double minutes = lat - (100.00*degrees);
    minutes /= 60.00;
    degrees += minutes;
    if (parallel=='S') { degrees *= -1.00; }
    
    double dLatitude = degrees;
    
    degrees = floor(lon/100.00);
    minutes = lon - (100.00*degrees);
    minutes /= 60.00;
    degrees += minutes;
    if (meridian == 'W') { degrees *= -1.00; }
    
    double dLongitude = degrees;
    currentLatitude = dLatitude;
    currentLongitude = dLongitude;
    pc.printf("LAT: %f ", dLatitude);
    pc.printf("LON: %f\n", dLongitude);
}

/** CPM functions **/
void calculateCPM()
{   
    
    currentSignalCount = signalCounter - previousTotalSignalCount;
    previousTotalSignalCount = signalCounter;
    
    currentNoiseCount = noiseCounter - previousTotalNoiseCount;
    previousTotalNoiseCount = noiseCounter;
    
    previousCPM = currentCPM;
    currentCPM = currentSignalCount - currentNoiseCount;
    
    pc.printf("signal: %d, noise: %d, ", currentSignalCount, currentNoiseCount);
    pc.printf("Current CPM: %d\n", currentCPM);
   
}

/** Fuel Guage Functions **/
void readFuelGauge()
{
    max17055.v_cell(&batteryVoltage);
    printf("%6.3fV ", batteryVoltage);
    
    max17055.current(&batteryCurrent);
    printf("%6.3fI ", batteryCurrent);
    
    max17055.temp(&boardTemperature);
    printf("%6.3fC ", boardTemperature);
    
    max17055.reportSOC(&stateOfCharge);
    if (startBatteryEmergency and !inBatteryEmergencyState)
    {
        pc.printf("emergency battery monitoring set\n");
        if (stateOfCharge < 51.0)
        {  
           inBatteryEmergencyState = true; // prevents sending messages over and over again, future versions to reset this when bat > 50 again;   
           batteryLowTransmit();
        }
    }
    printf(" SOC:%d\\% ",stateOfCharge);
    
    // max17055.tte1(&timeToEmpty);
    // tteReport = ((5.625)*timeToEmpty)/120.0;
    // printf(" TTE:%6.2fhours \n", tteReport);
    
}

/** LoRa TxRx Functions **/
void transmitLocation()
{
    // transmite GPS/Location data, lat/lon
    LoRa.beginPacket();
    
    // Packet Header 
    LoRa.printf("%c",LOCALADDRESSID); LoRa.printf("**");    
    LoRa.printf("%c",GPSDATA); LoRa.printf("**");    
    
    // Packet Contents
    LoRa.printf("%f",currentLatitude);LoRa.printf("**");
    LoRa.printf("%f",currentLongitude);LoRa.printf("**");
    
    LoRa.endPacket();
    pc.printf("LoRa GPS Packet Sent\n");    
}

void transmitCPM()
{
    // Transmit Radiation data: CPM = Counts Per Minute, current reading
    LoRa.beginPacket();
    
    // Packet Header 
    LoRa.printf("%c",LOCALADDRESSID); LoRa.printf("**");    
    LoRa.printf("%c",CPMDATA); LoRa.printf("**");    
    
    // Packet Contents
    LoRa.printf("%d",currentCPM);LoRa.printf("**");
    LoRa.printf("%d", "-1");LoRa.printf("**");
    
    LoRa.endPacket();
    pc.printf("LoRa CPM Packet Sent\n");  
}
void transmitFuel()
{
    // Transimet Battery/Fuel Gauge data: voltage, current, temp 
    LoRa.beginPacket();
    
    // Packet Header 
    LoRa.printf("%c",LOCALADDRESSID); LoRa.printf("**");    
    LoRa.printf("%c",FUELDATA); LoRa.printf("**");    
    
    LoRa.printf("%d",stateOfCharge);LoRa.printf("**"); 
    LoRa.printf("%f",tteReport);LoRa.printf("**"); // time to empty in hours
    LoRa.printf("%f",boardTemperature);LoRa.printf("**");
       
    // Packet Contents
    
    LoRa.endPacket();
    pc.printf("LoRa Fuel Gauge Packet Sent\n");
}

void batteryLowTransmit() 
{
    /** broadcast warning low battery/increased transmisson intervals **/
    
    // extend transmission intervals to conserve power
    LOCATION_INTERVAL  = 150.0;     
    CPM_INTERVAL       = 600.0;          
    FUEL_INTERVAL      = 900.0;          
    
    // Transimet Battery/Fuel Gauge data: voltage, current, temp 
    LoRa.beginPacket();
    
    // Packet Header 
    LoRa.printf("%c",LOCALADDRESSID); LoRa.printf("**");    
    LoRa.printf("%c",LOWBATTERY); LoRa.printf("**");    
    
    LoRa.printf("%d",stateOfCharge);LoRa.printf("**"); 
    
    LoRa.endPacket();
    pc.printf("LoRa Low Battery Packet Sent\n");
    
}

void onReceive(int packetSize)
{
    char msg[45];
    pc.printf("PACKET RECEIVED, SIZE:%d \n", packetSize);
    for (int i = 0; i<packetSize; i++)
    {   if ( i < 45) 
        {
            msg[i] = (char)LoRa._getc();
        }
    }
    pc.printf("RSSI:  %d, ", LoRa.packetRssi()); pc.printf("MSG:%s \n",msg); 
    if (msg[0] == LOCALADDRESSID)
    {
        pc.printf("received from %x\n", msg[0]);
    } 
    else {
        pc.printf("dont know who, %x is, ignore msg\n", msg[0]);    
    }
}