STM32L476
Dependencies: MbedJSONValue SDFileSystem WConstants mbed-dev DS1820 TinyGPSPlus epd1in54
Fork of A_SSL_Main by
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; } } }