/******************************************************************************/ /** Copyright 2006 MBARI - Monterey Bay Aquarium Research Institute */ /******************************************************************************/ /******************************************************************************/ /** Filename : LOBOGPS.C */ /** Author : Luke Coletti */ /** Project : 700144 */ /** Version : 2.00 */ /** Created : 09/14/06 */ /** Compiler : gcc version 3.0.1 */ /** OS, Box : IRIX Release 6.5 IP27, lepas.mbari.org */ /** Archived : */ /** Summary : Parses the records within the downloaded files, that are */ /** created via lobotrak, copies them into the appropriate */ /** mooring directories and creates a summary image and HTML table */ /******************************************************************************/ /** Modification History: */ /** 01/29/07 : Added GPS Speed and Heading processing. */ /******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define TRUE 1 #define FALSE 0 #define OK 0 #define ERROR (-1) #define START 1 #define CONTINUE 2 #define FINISH 3 #define GPS_FILES 2 #define IMG_TSTAMP_X 475 #define IMG_TSTAMP_Y 590 #define pi 3.1415926535897932 #define DToR (pi / 180) #define RToD (180 / pi) #define SENDMAIL "/usr/lib/sendmail -t" #define SENDER "coletti@mbari.org" #define RECIPIENT "coletti@mbari.org" enum LoboDataDirs{L01Data=0, L02Data, L03Data, L04Data, L05Data, LoboDataDirsEnd}; static char *data_dirs[] = {"L01", "L02", "L03", "L04", "L05"}; static char data_path_in[100] = "/u/coletti/lobo/outgoing"; static char data_path_out[100] = "/hosts/tornado/vol/vol0/ChemWebData/moorings/lobo"; static char html_path_out[100] = "/u/coletti/public_html"; static char jpeg_path_out[100] = "/u/coletti/public_html/images/trimtrac"; struct dirent **filelist; long lobofiles; int CopyTrimtracDataFile(char *fpath_in, char *fpath_out, char *id); int MoveLastfixDataFile(char *fpath_in, char *fpath_out); int GetGPSValues(char *fpath_in, char *Time, char *Lat, char *Lon, int *Speed, int *Heading, int *im_x, int *im_y, char *id); int WriteGPSValues(int select, char *fpath_out, char *Time, char *Lat, char *Lon, int *Speed, int *Heading, char *id); int WriteJPEGImage(int select, char *fpath_in, char *fpath_out, int im_x, int im_y, char *id); void DMSToHTMLString(double Angle, int n, char *DMS_String); int ScanLoboFileDir(char *fpath, char *id); int fmatch(struct dirent *d); void UpdateErrorLogFile(char *emsg); void SendEmail(char *subject, char *message); int main(int argc, char **argv, char **envp) { char gps_time[50]; char gps_lat[50]; char gps_lon[50]; char path_in[250]; char path_out[250]; char sbuf[250]; char ebuf[250]; int gps_speed, gps_heading; int choice, gotNewData, data_select, ret; int jpeg_x, jpeg_y; if( isatty(0) ){ fprintf(stderr,"This program was meant to run out of cron\n"); exit( OK ); } //test if input file system "Tempest" can be mounted! if( (ret = access(data_path_in, F_OK)) != OK ){ snprintf(sbuf, sizeof(sbuf)-1, "Tempest Mount Access Error"); snprintf(ebuf, sizeof(ebuf)-1, "ERROR, main() - access() ret = %d - %s", ret, data_path_in); SendEmail(sbuf, ebuf); UpdateErrorLogFile(ebuf); exit(1); } gotNewData = 0; choice = 0; while( choice < LoboDataDirsEnd ){ // move the files to ChemWebData // construct input directory memset(path_in, '\0', sizeof(path_in) ); snprintf(path_in, sizeof(path_in)-1, "%s/%s", data_path_in, data_dirs[choice]); // construct output directory memset(path_out, '\0', sizeof(path_out)); snprintf(path_out, sizeof(path_out)-1, "%s/%s/data", data_path_out, data_dirs[choice]); // scan directory for GPS file(s) only if( (lobofiles = ScanLoboFileDir(path_in, data_dirs[choice]) == GPS_FILES ) ){ ++gotNewData; //test if output file system "Tornado" can be mounted! if( (ret = access(path_out, F_OK)) != OK ){ snprintf(sbuf, sizeof(sbuf)-1, "Lobo [%s] Mount Access Error", data_dirs[choice]); snprintf(ebuf, sizeof(ebuf)-1, "ERROR, main() - prior to CopyTrimtracDataFile() - access() ret = %d - %s", ret, path_out); SendEmail(sbuf, ebuf); UpdateErrorLogFile(ebuf); } else{ CopyTrimtracDataFile(path_in, path_out, data_dirs[choice]); MoveLastfixDataFile(path_in, path_out); } } ++choice; } //end while if( gotNewData != 0 ){ data_select = START; choice = 0; while( choice < LoboDataDirsEnd ){ //process the files in ChemWebData // construct input directory memset(path_in, '\0', sizeof(path_in) ); snprintf(path_in, sizeof(path_in)-1, "%s/%s/data", data_path_out, data_dirs[choice]); // construct output directory memset(path_out, '\0', sizeof(path_out)); snprintf(path_out, sizeof(path_out)-1, "%s/%s/data", data_path_out, data_dirs[choice]); //test if input/output file system "Tornado" can be mounted! if( (ret = access(path_in, F_OK)) != OK ){ snprintf(sbuf, sizeof(sbuf)-1, "Lobo [%s] Mount Access Error", data_dirs[choice]); snprintf(ebuf, sizeof(ebuf)-1, "ERROR, main() - prior to GetGPSValues() - access() ret = %d - %s", ret, path_in); SendEmail(sbuf, ebuf); UpdateErrorLogFile(ebuf); ++choice; continue; } // scan directory for GPS file(s) only if( (lobofiles = ScanLoboFileDir(path_in, data_dirs[choice]) == GPS_FILES ) ){ if( (ret=GetGPSValues(path_in, gps_time, gps_lat, gps_lon, &gps_speed, &gps_heading, &jpeg_x, &jpeg_y, data_dirs[choice])) == TRUE ){ //snprintf(sbuf, sizeof(sbuf)-1, "Lobo [%s] TrimTrac Data", data_dirs[choice]); //snprintf(gps_data, sizeof(gps_data)-1, "%s %s %s %d %d %d %d", gps_time, gps_lat, gps_lon, gps_speed, gps_heading, jpeg_x, jpeg_y); //SendEmail(sbuf, gps_data); WriteGPSValues(data_select, html_path_out, gps_time, gps_lat, gps_lon, &gps_speed, &gps_heading, data_dirs[choice]); WriteJPEGImage(data_select, jpeg_path_out, jpeg_path_out, jpeg_x, jpeg_y, data_dirs[choice]); data_select = CONTINUE; } else{ snprintf(sbuf, sizeof(sbuf)-1, "Lobo [%s] TrimTrac Data Error", data_dirs[choice]); snprintf(ebuf, sizeof(ebuf)-1, "ERROR, main() - GetGPSValues() ret = %d - %s", ret, path_in); SendEmail(sbuf, ebuf); } } ++choice; } //end while if( data_select == CONTINUE ){ //we got something, so let's finish up... data_select = FINISH; WriteGPSValues(data_select, html_path_out, NULL, NULL, NULL, NULL, NULL, NULL); WriteJPEGImage(data_select, jpeg_path_out, jpeg_path_out, 0, 0, NULL); } } //end gotNewData if return( OK ); } int CopyTrimtracDataFile(char *fpath_in, char *fpath_out, char *id) { FILE *fptr_in, *fptr_out; char sbuf[250]; char ebuf[250]; char file_in[250]; char file_out[250]; char record[2000]; memset(file_in, '\0', sizeof(file_in)); snprintf(file_in, sizeof(file_in)-1, "%s/%s", fpath_in, "trimtrac.log"); fptr_in = fopen(file_in, "r"); if( fptr_in == NULL ){ fclose(fptr_in); snprintf(sbuf, sizeof(sbuf)-1, "Lobo [%s] Input File Access Error", id); snprintf(ebuf, sizeof(ebuf)-1, "ERROR, CopyGpsDataFile() - fopen() ret = NULL - %s", file_in); SendEmail(sbuf, ebuf); UpdateErrorLogFile(ebuf); return( -1 ); } memset(file_out, '\0', sizeof(file_out)); snprintf(file_out, sizeof(file_out)-1, "%s/%s", fpath_out, "trimtrac.log"); fptr_out = fopen(file_out, "a+"); if( fptr_out == NULL ){ fclose(fptr_out); snprintf(sbuf, sizeof(sbuf)-1, "Lobo [%s] Output File Access Error", id); snprintf(ebuf, sizeof(ebuf)-1, "ERROR, CopyGpsDataFile() - fopen() ret = NULL - %s", file_out); SendEmail(sbuf, ebuf); UpdateErrorLogFile(ebuf); return( -2 ); } while( fgets(record, sizeof(record), fptr_in) != NULL ){ fprintf(fptr_out, "%s", record); } // end while fclose(fptr_in); fclose(fptr_in); remove(file_in); return( OK ); } int MoveLastfixDataFile(char *fpath_in, char *fpath_out) { FILE *fptr_in; char cbuf[512]; char file_in[250]; int ret; memset(file_in, '\0', sizeof(file_in)); snprintf(file_in, sizeof(file_in)-1, "%s/%s", fpath_in, "lastfix.log" ); fptr_in = fopen(file_in, "r"); if( fptr_in == NULL ){ fclose(fptr_in); return( -10 ); } fclose(fptr_in); snprintf(cbuf, sizeof(cbuf), "(/u/coletti/bin/mv --force %s %s)", file_in, fpath_out); ret = system(cbuf); return( ret ); } int GetGPSValues(char *fpath_in, char *Time, char *Lat, char *Lon, int *Speed, int *Heading, int *im_x, int *im_y, char *id) { FILE *fptr_in; char file_in[250]; char sbuf[250]; char ebuf[250]; char record[150]; int ret; time_t e_secs; int gps_speed, gps_heading; long gps_alt; double gps_lat, gps_lon; double x1_lon, y1_lat; double px_deg, py_deg; struct tm *tp; memset(file_in, '\0', sizeof(file_in)); snprintf(file_in, sizeof(file_in)-1, "%s/%s", fpath_in, "lastfix.log"); fptr_in = fopen(file_in, "r"); if( fptr_in == NULL ){ fclose(fptr_in); snprintf(sbuf, sizeof(sbuf)-1, "Lobo [%s] Input File Access Error", id); snprintf(ebuf, sizeof(ebuf)-1, "ERROR, GetGPSValues() - fopen() ret = NULL - %s", file_in); SendEmail(sbuf, ebuf); UpdateErrorLogFile(ebuf); return( ERROR ); } while( fgets(record, sizeof(record), fptr_in) != NULL ){ ret = sscanf(record,"%lu, %lf, %lf, %ld, %d, %d", &e_secs, &gps_lat, &gps_lon, &gps_alt, &gps_speed, &gps_heading); if( ret == 6 ){ fclose(fptr_in); tp=localtime(&e_secs); strftime(Time, 50, "%a %d %b %Y %H:%M:%S", tp); DMSToHTMLString(gps_lat*DToR, 6, Lat); DMSToHTMLString(gps_lon*DToR, 6, Lon); *Speed = gps_speed; *Heading= gps_heading; //constants below are from geo-referenced image, trimtrac.jpg x1_lon = (121.0 + (49.0/60.0)) * -1.0; y1_lat = 36.0 + (52.0/60.0); px_deg = 5889.0; py_deg = 5880.0; *im_x = (int)(((gps_lon - x1_lon) * px_deg) + 80.0 ); *im_y = (int)(((y1_lat - gps_lat) * py_deg) + 60.0 ); return( TRUE ); } } fclose(fptr_in); return( FALSE ); } int WriteGPSValues(int select, char *fpath_out, char *Time, char *Lat, char *Lon, int *Speed, int *Heading, char *id) { FILE *fptr_out; char file_out[250]; char sbuf[250]; char ebuf[250]; char tbuf[80]; time_t timer; struct tm *tp; memset(file_out, '\0', sizeof(file_out)); snprintf(file_out, sizeof(file_out)-1, "%s/%s", fpath_out, "trimtrac.html"); if( select == START ){ remove(file_out); sleep(3); } fptr_out = fopen(file_out, "a+"); if( fptr_out == NULL ){ fclose(fptr_out); snprintf(sbuf, sizeof(sbuf)-1, "Lobo [%s] Output File Access Error", id); snprintf(ebuf, sizeof(ebuf)-1, "ERROR, WriteGPSValues() - fopen() ret = NULL - %s", file_out); SendEmail(sbuf, ebuf); UpdateErrorLogFile(ebuf); return( ERROR ); } if( select == FINISH ){ fprintf(fptr_out," \n"); fprintf(fptr_out,"\n"); fclose(fptr_out); return( OK ); } if( select == START ){ time(&timer); tp = localtime(&timer); strftime(tbuf, sizeof(tbuf), "%a %d %b %Y %H:%M:%S", tp); strcat(tbuf, " (PST8PDT)"); fprintf(fptr_out,"
\n"); fprintf(fptr_out," \n"); fprintf(fptr_out," \n"); fprintf(fptr_out," \n"); fprintf(fptr_out," \n"); fprintf(fptr_out," \n"); fprintf(fptr_out," \n", tbuf); fprintf(fptr_out," \n"); fprintf(fptr_out,"
LOBO Mooring GPS Positions
Table Generated on %s
\n"); fprintf(fptr_out," \n"); fprintf(fptr_out," \n"); fprintf(fptr_out," \n"); fprintf(fptr_out," \n"); fprintf(fptr_out," \n"); fprintf(fptr_out," \n"); fprintf(fptr_out," \n"); // fprintf(fptr_out," \n"); fprintf(fptr_out," \n"); } fprintf(fptr_out," \n"); fprintf(fptr_out," \n", id); fprintf(fptr_out," \n", Time); fprintf(fptr_out," \n", Lat); fprintf(fptr_out," \n", Lon); fprintf(fptr_out," \n", *Heading); // fprintf(fptr_out," \n", *Speed); fprintf(fptr_out," \n"); fclose(fptr_out); return( OK ); } int WriteJPEGImage(int select, char *fpath_in, char *fpath_out, int im_x, int im_y, char *id) { FILE *fptr_in; FILE *fptr_out; char file_in[250]; char file_out[250]; char sbuf[250]; char ebuf[250]; char tbuf[80]; char cbuf[512]; int color, ret; time_t timer; struct tm *tp; gdImagePtr im; memset(file_in, '\0', sizeof(file_in)); memset(file_out, '\0', sizeof(file_out)); if( select == START ) snprintf(file_in, sizeof(file_in)-1, "%s/%s", fpath_in, "trimtrac.jpg"); else if( select == CONTINUE ) snprintf(file_in, sizeof(file_in)-1, "%s/colu_%d.jpg", fpath_in, getpid()); else if( select == FINISH ){ snprintf(file_in, sizeof(file_in)-1, "%s/colu_%d.jpg", fpath_in, getpid()); snprintf(file_out, sizeof(file_out)-1, "%s/current.jpg", fpath_out); snprintf(cbuf, sizeof(cbuf), "(/u/coletti/bin/mv --force %s %s)", file_in, file_out); ret = system( cbuf ); remove( file_in ); return ( OK ); } else return( ERROR ); fptr_in = fopen(file_in, "rb"); if( fptr_in == NULL ){ fclose(fptr_in); snprintf(sbuf, sizeof(sbuf)-1, "Lobo [%s] Input File Access Error", id); snprintf(ebuf, sizeof(ebuf)-1, "ERROR, WriteJPEGImage() - fopen() ret = NULL - %s", file_in); SendEmail(sbuf, ebuf); UpdateErrorLogFile(ebuf); return( ERROR ); } im = gdImageCreateFromJpeg(fptr_in); fclose(fptr_in); color = gdImageColorAllocate(im, 255, 0, 0); gdImageArc(im, im_x, im_y, 25, 25, 0, 360, color); gdImageString(im, gdFontGetSmall(), im_x - (strlen(id) * gdFontGetSmall()->w / 2), im_y - gdFontGetSmall()->h / 2, id, color); if( select == START ){ time(&timer); tp = localtime(&timer); strftime(tbuf, sizeof(tbuf), "%a %d %b %Y %H:%M:%S", tp); strcat(tbuf, " (PST8PDT)"); color = gdImageColorAllocate(im, 51, 102, 153); gdImageString(im, gdFontGetSmall(), IMG_TSTAMP_X, IMG_TSTAMP_Y, "Image Generated on", color); color = gdImageColorAllocate(im, 0, 0, 0); gdImageString(im, gdFontGetSmall(), IMG_TSTAMP_X+115, IMG_TSTAMP_Y, tbuf, color); } snprintf(file_out, sizeof(file_out)-1, "%s/colu_%d.jpg", fpath_in, getpid()); fptr_out = fopen(file_out, "wb"); if( fptr_out == NULL ){ fclose(fptr_out); gdImageDestroy(im); snprintf(sbuf, sizeof(sbuf)-1, "Lobo [%s] Output File Access Error", id); snprintf(ebuf, sizeof(ebuf)-1, "ERROR, WriteJPEGImage() - fopen() ret = NULL - %s", file_out); SendEmail(sbuf, ebuf); UpdateErrorLogFile(ebuf); return( ERROR ); } gdImageJpeg(im, fptr_out, 95); fclose(fptr_out); gdImageDestroy(im); return( OK ); } /************************************************************************/ /* Function : ip */ /* Purpose : return the integral part of a double value. */ /* Comments : */ /************************************************************************/ double ip(x) double x; { double dummy, tmp; dummy = modf(x, &tmp); return tmp; } /*****************************************************************************/ /* Name: DMSToHTMLString */ /* Type: Procedure */ /* Purpose: Write an angle to a string in ø'" format. */ /* Arguments: */ /* Angle : the angle in radians */ /* n : the number of digits after the 'decimal' point. */ /* n = 1 gives DDD.d, n = 2 gives DDD.MM, and so on. */ /* DMS_String : pointer to string */ /*****************************************************************************/ void DMSToHTMLString(double Angle, int n, char *DMS_String) { char buffer[15]; static const double Delta[8] = {0.5, 0.05, 0.00833333333, 0.0008333333333, 0.00013888889, 0.00001388889, 0.00000138889, 0.00000013889}; int sign; if (Angle < 0.0) { sign = -1; Angle = -Angle; } else sign = 1; Angle = Angle * RToD + Delta[n]; if (n == 1) sprintf(DMS_String, "%+03.1fº", (sign < 0) ? -Angle : Angle); else { if (sign == -1) if (ip (Angle) == 0) sprintf(DMS_String, " -00º"); else sprintf(DMS_String, "%+03.0fº", ip (-Angle)); else sprintf(DMS_String, "%+03.0fº", ip (Angle)); Angle = (Angle - floor (Angle)) * 60; if (n == 3){ sprintf(buffer, "%04.1f'", Angle - 60 * Delta[3]); strcat (DMS_String, buffer); } else if (n > 1) { sprintf(buffer, "%02.0f'", floor (Angle)); strcat (DMS_String, buffer); if (n > 3) { Angle = (Angle - floor (Angle)) * 60; if (n == 4){ sprintf(buffer, "%02.0f\"", floor (Angle)); strcat (DMS_String, buffer); } else{ sprintf(buffer, "%0*.*f\"", n - 1, n - 4, fabs(Angle - 3600 * Delta[n])); strcat (DMS_String, buffer); } } } } } /************************************************************************/ /* Function : ScanLoboFileDir */ /* Purpose : make a list of all valid files in the outgoing/LOBO dir*/ /* Input : None */ /* Outputs : None */ /* Comments : */ /************************************************************************/ int ScanLoboFileDir(char *fpath, char *id) { char sbuf[250]; char ebuf[250]; int ret; ret = scandir(fpath, &filelist, fmatch, NULL); if( ret < 0 ){ snprintf(sbuf, sizeof(sbuf)-1, "Lobo [%s] Scan Directory Error", id); snprintf(ebuf, sizeof(ebuf)-1, "ERROR, ScanLoboFileDir() - scandir() ret = %d - %s", ret, fpath); SendEmail(sbuf, ebuf); UpdateErrorLogFile(ebuf); return( ERROR ); } else return( ret ); } int fmatch(struct dirent *d) { if( (strstr(d->d_name, "trimtrac.log") != NULL) || (strstr(d->d_name, "lastfix.log") != NULL) ) return( TRUE ); else return( FALSE ); } /************************************************************************/ /* Function : UpdateErrorLogFile */ /* Purpose : keep a usage log of all unsuccessful sessions */ /* Input : None */ /* Outputs : None */ /* Comments : */ /************************************************************************/ void UpdateErrorLogFile(char *emsg) { FILE *logfile; char timebuf[64]; time_t timer; struct tm *timeptr; time(&timer); timeptr = localtime(&timer); strftime(timebuf, sizeof(timebuf)-1, "%a %d %b %Y %H:%M:%S", timeptr); logfile = fopen("/u/coletti/lobo/logs/lobogps.log", "a+"); fprintf(logfile,"%s, %s, %ld\r\n", emsg, timebuf, getpid()); fflush(logfile); fclose(logfile); } void SendEmail(char *subject, char *message) { FILE *out; out = popen(SENDMAIL, "w"); fprintf(out, "From: %s <%s>\n", "LoboGPS", SENDER); fprintf(out, "To: %s\n", RECIPIENT); fprintf(out, "Subject: %s\n", subject); fprintf(out, "\n \n"); fprintf(out, "%s", message); fprintf(out, "\n \n"); pclose(out); }
MooringGPS Timestamp, PST8PDTGPS LatitudeGPS LongitudeGPS HeadingGPS Speed, MPH
%s%s%s%s%03dº%d