STM32L476

Dependencies:   MbedJSONValue SDFileSystem WConstants mbed-dev DS1820 TinyGPSPlus epd1in54

Fork of A_SSL_Main by SilentSensors

main.cpp

Committer:
WaleedElmughrabi
Date:
2018-11-27
Revision:
11:9b49bd5a5f8c
Parent:
10:a4526c9b8332
Child:
13:0477a745dad2

File content as of revision 11:9b49bd5a5f8c:

////////////////////////////////////////////////////////////////////////////////////////////////////////
//  Company:    Silent Sensors Ltd
//  Project:    Silent Hub
//  Author:     Waleed Elmughrabi
////////////////////////////////////////////////////////////////////////////////////////////////////////

#include "mbed.h"
#include "DS1820.h"
#include "epd1in54.h"
#include "stdio.h"
#include "math.h"
#include "TinyGPSPlus.h"
#include "SDFileSystem.h"
#include "errno.h"
#include "MbedJSONValue.h"
#include <string>


////////////////////////////////////////////////////////////////////////////////////////////////////////
// Definitions and initialization
////////////////////////////////////////////////////////////////////////////////////////////////////////
#define TX5 PC_12
#define RX5 PD_2
#define GPSBaud 9600
#define SerialBaud 115200
#define SD_FILE_SYSTEM_H   
SDFileSystem*       fs;
FILE*               fp;
TinyGPSPlus tgps;
Serial serial(USBTX, USBRX,115200);                 //Local terminal Baud rate                              
SDFileSystem sd(PB_5, PB_4, PB_3, PB_12, "sd");     //uSD SPI

//Temp sensors
#define MAX_PROBES      16
#define DATA_PIN        PB_2
DS1820* probe[MAX_PROBES];

//E-ink Display
PinName rst; PinName dc; PinName busy; PinName mosi; PinName miso; PinName sclk; PinName cs;
unsigned char frame_black[EPD_HEIGHT*EPD_WIDTH/8];
Epd epd = Epd(PB_5, PB_4, PB_3, PA_8, PC_4, PC_7, PB_10);

const  char * system_message;                       //Journey configuration to be received from server
int deviceID = 1;
double longTest,latTest;
int tyear,tmonth,tday,thour,tmin,tsec;     
double liquidTemp = 0;
double ambientTemp = 0;
char cValt[32];
char chr_s[600];
std::string s;
const char * parameter;
char * readLastGeo;
int msg_index;
double geofencesNum;
int geotest;
char geo_extract[6];

DigitalOut en1(PC_5);
    DigitalOut en2(PC_6);
    DigitalOut en3(PC_8);
    DigitalOut en4(PC_9);
    
////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////
//      Polygon geofence
// the last vertix should be the same as the first vertix
////////////////////////////////////////////////////////////////////////////////////////////////////////
int pnpoly(int nvert, double *vertLong, double *vertLat, double testLong, double testLat)
{
  //Returns 1 if test point is inside polygon, zero otherwise
  //last vertix should be the same as the first
  int i, j, c = 0;
  for (i = 0, j = nvert-1; i < nvert; j = i++) {
    if ( ((vertLat[i]>testLat) != (vertLat[j]>testLat)) &&
     (testLong < (vertLong[j]-vertLong[i]) * (testLat-vertLat[i]) / (vertLat[j]-vertLat[i]) + vertLong[i]) )
       c = !c;
  }
  return c;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////
double distanceBetween(double lat1, double long1, double lat2, double long2)
{
  // returns distance in meters between two positions, both specified
  // as signed decimal-degrees latitude and longitude. Uses great-circle
  // distance computation for hypothetical sphere of radius 6372795 meters.
  // Because Earth is no exact sphere, rounding errors may be up to 0.5%.
  // Courtesy of Maarten Lamers
  double delta = radians(long1-long2);
  double sdlong = sin(delta);
  double cdlong = cos(delta);
  lat1 = radians(lat1);
  lat2 = radians(lat2);
  double slat1 = sin(lat1);
  double clat1 = cos(lat1);
  double slat2 = sin(lat2);
  double clat2 = cos(lat2);
  delta = (clat1 * slat2) - (slat1 * clat2 * cdlong);
  delta = sq(delta);
  delta += sq(clat2 * sdlong);
  delta = sqrt(delta);
  double denom = (slat1 * slat2) + (clat1 * clat2 * cdlong);
  delta = atan2(delta, denom);
  return delta * 6372795;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
//      Circle geofonce
////////////////////////////////////////////////////////////////////////////////////////////////////////
int inCircle(double xcentre, double ycentre, double xedge, double yedge, double testx, double testy)
{
    //Returns 1 if test point is inside circle, zero otherwise
    //The circle is defined by centre and a point on the circumference 
    double distance;
    int test;
    double radius;
    
    radius = distanceBetween(xcentre, ycentre, xedge, yedge);
    distance = distanceBetween(xcentre, ycentre, testx, testy);
    
     if(distance < radius){
            test = 1;
            }
        else{
            test = 0;
            }
  return (test);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////////////////////////////
//      Temperature sensor read
////////////////////////////////////////////////////////////////////////////////////////////////////////
double getTemp(int device) {  
    // Initialize the probe array to DS1820 objects
    int num_devices = 0;
    double temp;
    while(DS1820::unassignedProbe(DATA_PIN)) {
        probe[num_devices] = new DS1820(DATA_PIN);
        num_devices++;
        if (num_devices == MAX_PROBES)
            break;
    }
        probe[0]->convertTemperature(true, DS1820::all_devices);         //Start temperature conversion, wait until ready
        temp = probe[device]->temperature();
        wait(0.01);
        return temp;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////
//      Epd display
////////////////////////////////////////////////////////////////////////////////////////////////////////
int Display(double t, int g)
{
Epd epd = Epd(PB_5, PB_4, PB_3, PA_8, PC_4, PC_7, PB_10);
    
    sprintf(cValt,"%.2f", t);    
    memset(frame_black, 0xFF, sizeof(unsigned char)*EPD_HEIGHT*EPD_WIDTH/8);
    if (epd.Init(lut_full_update) != 0) {
        return -1;
    }
    /*Write strings to the buffer */
    epd.DrawStringAt(frame_black, 0, 10, "Temperature:", &Font24, COLORED);
    epd.DrawStringAt(frame_black, 60, 30, cValt, &Font24, COLORED);
    epd.DrawStringAt(frame_black, 0, 70, "In Geofence?", &Font24, COLORED);
    if (g == 1){
    epd.DrawStringAt(frame_black, 60, 90, "In Geo", &Font24, COLORED);
    }
    else {
        epd.DrawStringAt(frame_black, 60, 90, "No", &Font24, COLORED);
    }
    /* Display the frame_buffer */
    epd.SetFrameMemory(frame_black, 0, 0, epd.width, epd.height);
    epd.DisplayFrame();
    epd.Sleep();
    return 1;
    }

////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////
//      SD card functions
//////////////////////////////////////////////////////////////////////////////////////////////////////// 
int new_file(char* adr_file)//fonction to write on new file
{
    FILE *fp = fopen(adr_file, "w");
    if(fp == NULL) {
        serial.printf("Unable to write the file\r\n");
        return -1;
    } else {
        fprintf(fp, "Silent Hub - Log\r\n");
        fclose(fp);
        serial.printf("File successfully written!\r\n");
        return 0; //success
    }
}

char* read_file(char* adr_file)//fct to read a file
{
    FILE *file;
    serial.printf("\r\nRead: %s\r\n", adr_file);
    file = fopen(adr_file, "r");
    
    if(!file) { 
        error("Could not open file!\n");
        //return -1;
    }
    
    char buffer[600];
    while(fgets(buffer, 600, file)) {
        wait(1);
    }
    printf("Line: %s\n", buffer);
    fclose(file);

        return buffer; //success 
    
}

int add_data(char* adr_flie, char* msg)//fct to update a file
{
    FILE *fp = fopen(adr_flie, "a");
    if(fp == NULL) {
        serial.printf("Unable to update the file\r\n");
        return 0; //success
    } else {
        fprintf(fp, msg);
        fclose(fp);
        serial.printf("\r\nFile successfully update/written!\r\n");
        return -1;
    }
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////
//      JSON serialize
////////////////////////////////////////////////////////////////////////////////////////////////////////
//ToDo: pass arguments, currently some dummy values
//geoFenceNum: the geofence entered or left, value: 1(entered), 2(left)
string jsonSerializeDeviceToSystem(int deviceID, double longTest, double latTest, int geoFenceNum, int value, double liquidTemp, double ambientTemp, int tday, int tmonth, int tyear, int thour, int tmin, int tsec)
{
    MbedJSONValue statusReport;
    std::string s;
    char SDtime[100];
    sprintf(SDtime,"%d-%d-%d - %d:%d:%d", tday, tmonth, tyear, thour, tmin, tsec);
    
    //fill the object
    statusReport["timestamp"]= SDtime;
    statusReport["device"] = deviceID;
    statusReport["latitude"]= latTest;
    statusReport["longitude"] = longTest;
    statusReport["geoFenceNum"] = geoFenceNum;
    statusReport["geoFenceEnteryDeparture"] = value;
    statusReport["container"] = liquidTemp;
    statusReport["Ambient"] = ambientTemp;
    statusReport["heater"] = 34.5;
    statusReport["batteryVoltage"] = 3.67;
    statusReport["network"] = "Tele2";
    statusReport["signalStrength"] = -89;
    
    //serialize it into a JSON string
    s = statusReport.serialize();
    
  return s;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////////////////////////////
//      JSON parse
////////////////////////////////////////////////////////////////////////////////////////////////////////
double jsonParseSystemToDevice(const char * parameter, int msg_index)
{
// Journey message received from system parsed into values. Message description:
//"{\"config\":[device,temperatureRequired,temperatureInterval,numberOfGeos],\"route1\":[geoFenceNum,heating,temperatureRequired,pingOnArrival,pingOnDeparture,shape,outerCircle,latCentre,longCentre,latEdge,LongEdge,latEdge2,longEdge2],.........,\"routeX\":[geoFenceNum,heating,temperatureRequired,pingOnArrival,pingOnDeparture,shape,numOfVertices,lat1,long1,lat2,long2,..............,lat1,long1]}

MbedJSONValue journey;
parse(journey, system_message);
double msg; msg = journey[parameter][msg_index].get<double>(); return msg;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////

int main()
{
    en1=1;en2=1;en3=1;en4=1;
    Serial GPSSerial(TX5, RX5);
    GPSSerial.baud(GPSBaud);
    wait(0.001);
    DigitalOut SD_EN(PB_12);            //SD SPI enable (active low)
    DigitalOut Epd_EN(PA_8);            //Epd SPI enable (active low)

    //ToDo: To be replaced by the value received when subscribed to the Iot hub
    //Subscribe and save the message in system_message
    system_message = "{\"config\":[1.0,1.0,240.0,5.0],\"route1\":[1.0,0.0,1.0,1.0,1.0,1.0,54.5983852,-1.5708491,54.5969549,-1.5663735],\"route2\":[2.0,0.0,1.0,1.0,1.0,1.0,54.6542957,-1.4459836,54.6495902,-1.4430425],\"route3\":[3.0,0.0,1.0,1.0,1.0,1.0,54.7051416,-1.5638412,54.7101814,-1.5615844],\"route4\":[4.0,0.0,1.0,1.0,1.0,1.0,54.6298560,-1.3059736,54.6267899,-1.3075833],\"route5\":[5.0,1.0,1.0,1.0,1.0,2.0,5.0,54.6710093,-1.4587418,54.6730758,-1.4461951,54.6672642,-1.4436423,54.6678548,-1.4562232,54.6710093,-1.4587418]}";


    wait(1);
    serial.printf("Silent Hub v1.0  ........................\r\n"); 
    serial.printf("SystemCoreClock is %d Hz...........\r\n", SystemCoreClock); 
    wait (1);
   int sleepCounter = 0;
   //new_file("/sd/HeatingStationLog.txt");
   
   
   while(1) {     
        sleepCounter++;
        
        
        if(tgps.encode(GPSSerial.getc()))
        {
            tgps.encode(GPSSerial.getc());
            latTest = tgps.location.lat(); longTest = tgps.location.lng();                      //Location  
            tyear = tgps.date.year(); tmonth = tgps.date.month(); tday = tgps.date.day();       //Date
            thour = tgps.time.hour(); tmin = tgps.time.minute(); tsec = tgps.time.second();     //Time
        
            //this part is just for local terminal monitoring 
            serial.printf("\r\nLocation: %3.6f, %3.6f, Date: %d-%d-%d, Time: %d:%d:%d \r\n", latTest, longTest, tday, tmonth, tyear, thour, tmin, tsec);

            ambientTemp = getTemp(0);
            printf("Ambient Temperature %3.1foC\r\n", ambientTemp);
            liquidTemp = getTemp(1);
            printf("liquid Temperature %3.1foC\r\n", liquidTemp);
            Display(liquidTemp, geotest);
            wait(5); //little delay to prevent double writing
           
            //geofence testing
            parameter = "config";
            msg_index = 3;
            geofencesNum = jsonParseSystemToDevice(parameter,msg_index);
            serial.printf("\r\nNumber of geofences: %2.0f", geofencesNum);
            
            geotest = 0;
            int count=1; 
            int count2;
            double geo_lat_c; double geo_long_c; double geo_lat_e; double geo_long_e;
            
            while ((count <= geofencesNum)&&(geotest == 0)) 
            //Can also check latTest,longTest: to make sure we have a fix
            //while ((count <= geofencesNum)&&(geotest == 0)&& ((latTest != 0)||(longTest != 0)))     
            {
               
                
                sprintf(geo_extract,"route%d",count);
                parameter = geo_extract;
                msg_index = 5;
            
                if (jsonParseSystemToDevice(geo_extract,msg_index) == 1)    //circular geofence
                {
                    msg_index = 6;  geo_lat_c = jsonParseSystemToDevice(parameter,msg_index);
                    msg_index = 7;  geo_long_c = jsonParseSystemToDevice(parameter,msg_index);
                    msg_index = 8;  geo_lat_e = jsonParseSystemToDevice(parameter,msg_index);
                    msg_index = 9;  geo_long_e = jsonParseSystemToDevice(parameter,msg_index);
                
                    geotest = inCircle(geo_lat_c, geo_long_c, geo_lat_e, geo_long_e, latTest, longTest);
                    serial.printf("\r\nGeofence number = %d: \r\nIn geofence = %d:\r\n", count, geotest);
                }
                
                if (jsonParseSystemToDevice(geo_extract,msg_index) == 2)            //polygon geofence
                {
                    msg_index = 6;                                                  //The start of coordinates in the message
                    int vertices = jsonParseSystemToDevice(geo_extract,msg_index);  //number of polygon vertices
                    double geo_lat[vertices];
                    double geo_long[vertices];
                    msg_index = 7;
                        for (count2=0; count2 < vertices; count2++ )
                        {
                            geo_lat[count2] = jsonParseSystemToDevice(geo_extract,msg_index);
                            geo_long[count2] = jsonParseSystemToDevice(geo_extract,msg_index+1);
                            msg_index = msg_index + 2;   
                        }
                    
                    geotest = pnpoly(vertices, geo_long, geo_lat,longTest, latTest);
                    serial.printf("\r\nGeofence number = %d: \r\nIn geofence = %d:\r\n", count, geotest);
                }    
                count++;
                
            }
            count = count--;
            if (geotest == 0)       //ToDo &&make sure the last publish handshake was successful 
                {
                //msg to be saved on SD and published, will overwrite last saved message
                s = jsonSerializeDeviceToSystem(deviceID, longTest, latTest, count, geotest, liquidTemp, ambientTemp, tday, tmonth, tyear, thour, tmin, tsec);
                sprintf(chr_s,s.c_str());
                Epd_EN = 1;
                new_file("/sd/DeviceToSystemLog.txt");
                add_data("/sd/DeviceToSystemLog.txt",chr_s);
                read_file("/sd/DeviceToSystemLog.txt");
                
                //Save last geofence, will overwrite last saved value 
                char cValGeoNum[8];
                sprintf(cValGeoNum,"%d", count);
                new_file("/sd/LastGeofence.txt");
                add_data("/sd/LastGeofence.txt",cValGeoNum);
                read_file("/sd/LastGeofence.txt"); 
                serial.printf("\n\rEnd\n");
                wait(1);
                Epd_EN = 0;
                
                
                //To do: if timer >= x, sleep, then sysreset;
                //NVIC_SystemReset();  
                
                //If it is a heating station log temperature 
                
                
                }
                new_file("/sd/HeatingStationLog.txt");
                readLastGeo = read_file("/sd/LastGeofence.txt");
                int intVal = atoi(readLastGeo);
                serial.printf("\r\nlast Geo in int = %d:",intVal);
                sprintf(geo_extract,"route%d",intVal);
                if (jsonParseSystemToDevice(geo_extract,1) == 1.0);             //Check if it is a heating station
                {
                    char liq[32];char amb[32];
                    //const char seperator = ",";
                    sprintf(liq,"%.2f", liquidTemp);
                    add_data("/sd/HeatingStationLog.txt",liq);
                    add_data("/sd/HeatingStationLog.txt",",");
                    sprintf(amb,"%.2f", ambientTemp);
                    add_data("/sd/HeatingStationLog.txt",amb);
                    add_data("/sd/HeatingStationLog.txt",",");
                    read_file("/sd/HeatingStationLog.txt");
                }
                    
                
        }

        if (millis() > 5000 && tgps.charsProcessed() < 10)
        {
            serial.printf("No GPS detected: check wiring.\r\n");
            break;
        }
   
    }
  }