00001 #include "stdafx.h"
00002 #include "cphidgetgps.h"
00003 #include "cusb.h"
00004 #include "csocket.h"
00005 #include "cthread.h"
00006 #include <math.h>
00007
00008
00009 static int checkcrc(char *data, int crc);
00010 static int parse_NMEA_data(char *data, CPhidgetGPSInfo *phid);
00011 static int parse_GPS_packets(CPhidgetGPSInfo *phid);
00012
00013
00014 CPHIDGETCLEARVARS(GPS)
00015 TESTPTR(phid);
00016
00017 phid->fix = PUNI_BOOL;
00018
00019 phid->heading = PUNK_DBL;
00020 phid->velocity = PUNK_DBL;
00021 phid->altitude = PUNK_DBL;
00022 phid->latitude = PUNK_DBL;
00023 phid->longitude = PUNK_DBL;
00024
00025 phid->haveTime = PUNK_BOOL;
00026 phid->haveDate = PUNK_BOOL;
00027
00028 return EPHIDGET_OK;
00029 }
00030
00031
00032
00033 CPHIDGETINIT(GPS)
00034 unsigned char buffer[8] = { 0 };
00035 int readtries;
00036 TESTPTR(phid);
00037
00038 phid->sckbuf_read=0;
00039 phid->sckbuf_write=0;
00040 ZEROMEM(phid->sckbuf, 256);
00041
00042 phid->lastFix = PUNK_BOOL;
00043 phid->lastLatitude = PUNK_DBL;
00044 phid->lastLongitude = PUNK_DBL;
00045 phid->lastAltitude = PUNK_DBL;
00046
00047 phid->fix = PUNK_BOOL;
00048 phid->heading = PUNK_DBL;
00049 phid->velocity = PUNK_DBL;
00050 phid->altitude = PUNK_DBL;
00051 phid->latitude = PUNK_DBL;
00052 phid->longitude = PUNK_DBL;
00053
00054 phid->haveTime = PUNK_BOOL;
00055 phid->haveDate = PUNK_BOOL;
00056
00057
00058 ZEROMEM(&phid->GPSData, sizeof(NMEAData));
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072 buffer[0]=0x03;buffer[1]=0x37;buffer[2]=0x01;buffer[2]=0x01;
00073 CUSBSendPacket((CPhidgetHandle)phid, buffer);
00074
00075
00076
00077
00078
00079
00080 readtries = 30;
00081 while((phid->fix==PUNK_BOOL || phid->haveTime==PUNK_BOOL || phid->haveDate==PUNK_BOOL) && readtries)
00082 {
00083 CPhidget_read((CPhidgetHandle)phid);
00084 readtries--;
00085 }
00086 if(phid->fix==PUNK_BOOL)
00087 phid->fix=PFALSE;
00088
00089 return EPHIDGET_OK;
00090 }
00091
00092
00093 CPHIDGETDATA(GPS)
00094 int i=0;
00095
00096 if (length < 0) return EPHIDGET_INVALIDARG;
00097 TESTPTR(phid);
00098 TESTPTR(buffer);
00099
00100
00101
00102
00103 for (i=0; i<buffer[0]; i++)
00104 {
00105 phid->sckbuf[phid->sckbuf_write++] = buffer[i+1];
00106 }
00107 parse_GPS_packets(phid);
00108
00109 return EPHIDGET_OK;
00110 }
00111
00112
00113 CPHIDGETINITEVENTS(GPS)
00114 if(phid->fix != PUNK_BOOL)
00115 FIRE(PositionFixStatusChange, phid->fix);
00116 if (phid->fix == PTRUE && (phid->latitude != PUNK_DBL || phid->longitude != PUNK_DBL || phid->altitude != PUNK_DBL))
00117 FIRE(PositionChange, phid->latitude, phid->longitude, phid->altitude);
00118 return EPHIDGET_OK;
00119 }
00120
00121
00122 CGETPACKET(GPS)
00123 return EPHIDGET_UNEXPECTED;
00124 }
00125
00126
00127 static int checkcrc(char *data, int crc) {
00128 unsigned int i=0;
00129 unsigned char check=0;
00130 for(i=1;i<strlen(data);i++)
00131 check^=data[i];
00132 if(check == crc)
00133 return 0;
00134 return 1;
00135 }
00136
00137
00138 static int parse_NMEA_data(char *data, CPhidgetGPSInfo *phid) {
00139 char *dataarray[50];
00140 int numfields = 0;
00141 int i,j,crc=0;
00142 double dintpart, decpart;
00143 int intpart;
00144 double tempD;
00145
00146
00147
00148
00149 j = (int)strlen(data);
00150 for(i=0;i<j;i++) {
00151 if(data[i] == '*') {
00152 crc = strtol(data+i+1,NULL,16);
00153 data[i] = '\0';
00154 if(checkcrc(data, crc))
00155 {
00156
00157
00158 LOG(PHIDGET_LOG_WARNING,"CRC Error parsing NMEA sentence.");
00159 return 1;
00160 }
00161 break;
00162 }
00163 }
00164
00165
00166 dataarray[0] = data;
00167 j = (int)strlen(data);
00168 for(i=0;i<j;i++) {
00169 if(data[i] == ',') {
00170 numfields++;
00171 dataarray[numfields] = data+i+1;
00172 data[i] = '\0';
00173 }
00174 }
00175
00176 if(strlen(dataarray[0]) != 6)
00177 {
00178 LOG(PHIDGET_LOG_WARNING,"Bad sentence type.");
00179 return 1;
00180 }
00181
00182
00183 if(!strncmp("GGA",dataarray[0]+3,3)) {
00184
00185
00186 if(strlen(dataarray[1]) >= 6) {
00187 decpart = modf(strtod(dataarray[1], NULL), &dintpart);
00188 intpart = (int)dintpart;
00189 phid->GPSData.GGA.time.tm_hour = (short)(intpart/10000);
00190 phid->GPSData.GGA.time.tm_min = (short)(intpart/100%100);
00191 phid->GPSData.GGA.time.tm_sec = (short)(intpart%100);
00192 phid->GPSData.GGA.time.tm_ms = (short)round(decpart*1000);
00193 phid->haveTime = PTRUE;
00194 }
00195 else
00196 phid->haveTime = PFALSE;
00197
00198
00199 if(strlen(dataarray[2])) {
00200 tempD = (int)(strtol(dataarray[2], NULL, 10) / 100) + (strtod((dataarray[2]+2),NULL) / 60);
00201 if(dataarray[3][0] == 'S')
00202 phid->GPSData.GGA.latitude = -tempD;
00203 else
00204 phid->GPSData.GGA.latitude = tempD;
00205 }
00206 else
00207 phid->GPSData.GGA.latitude = 0;
00208
00209 if(strlen(dataarray[4])) {
00210 tempD = (int)(strtol(dataarray[4], NULL, 10) / 100) + (strtod((dataarray[4]+3),NULL) / 60);
00211 if(dataarray[5][0] == 'W')
00212 phid->GPSData.GGA.longitude = -tempD;
00213 else
00214 phid->GPSData.GGA.longitude = tempD;
00215 }
00216 else
00217 phid->GPSData.GGA.longitude = 0;
00218
00219 phid->GPSData.GGA.fixQuality = (short)strtol(dataarray[6],NULL,10);
00220 phid->GPSData.GGA.numSatellites = (short)strtol(dataarray[7],NULL,10);
00221 phid->GPSData.GGA.horizontalDilution = strtod(dataarray[8],NULL);
00222
00223 phid->GPSData.GGA.altitude = strtod(dataarray[9],NULL);
00224 phid->GPSData.GGA.heightOfGeoid = strtod(dataarray[11],NULL);
00225
00226
00227 phid->fix = (phid->GPSData.GGA.fixQuality == 0) ? PFALSE : PTRUE;
00228 if(phid->fix)
00229 {
00230 phid->altitude = phid->GPSData.GGA.altitude;
00231 phid->latitude = phid->GPSData.GGA.latitude;
00232 phid->longitude = phid->GPSData.GGA.longitude;
00233 }
00234 else
00235 {
00236 phid->altitude = PUNK_DBL;
00237 phid->latitude = PUNK_DBL;
00238 phid->longitude = PUNK_DBL;
00239 }
00240
00241
00242 if(phid->fix != phid->lastFix)
00243 {
00244 FIRE(PositionFixStatusChange, phid->fix);
00245 phid->lastFix = phid->fix;
00246 }
00247
00248
00249 if (phid->fix == PTRUE
00250 && (phid->latitude != phid->lastLatitude || phid->longitude != phid->lastLongitude || phid->altitude != phid->lastAltitude)
00251 )
00252 {
00253 FIRE(PositionChange, phid->latitude, phid->longitude, phid->altitude);
00254 phid->lastLatitude = phid->latitude;
00255 phid->lastLongitude = phid->longitude;
00256 phid->lastAltitude = phid->altitude;
00257 }
00258 }
00259 else if(!strncmp("GSA",dataarray[0]+3,3)) {
00260 phid->GPSData.GSA.mode = dataarray[1][0];
00261 phid->GPSData.GSA.fixType = (short)strtol(dataarray[2],NULL,10);
00262 for(i=0;i<12;i++)
00263 phid->GPSData.GSA.satUsed[i] = (short)strtol(dataarray[i+3],NULL,10);
00264 phid->GPSData.GSA.posnDilution = strtod(dataarray[15],NULL);
00265 phid->GPSData.GSA.horizDilution = strtod(dataarray[16],NULL);
00266 phid->GPSData.GSA.vertDilution = strtod(dataarray[17],NULL);
00267 }
00268 else if(!strncmp("GSV",dataarray[0]+3,3)) {
00269 int numSentences, sentenceNumber, numSats;
00270
00271 numSentences = strtol(dataarray[1],NULL,10);
00272 sentenceNumber = strtol(dataarray[2],NULL,10);
00273 numSats = strtol(dataarray[3],NULL,10);
00274
00275 phid->GPSData.GSV.satsInView = (short)numSats;
00276 for(i=0;i<(numSentences==sentenceNumber?numSats-(4*(numSentences-1)):4);i++) {
00277 phid->GPSData.GSV.satInfo[i+((sentenceNumber-1)*4)].ID = (short)strtol(dataarray[4+(i*4)],NULL,10);
00278 phid->GPSData.GSV.satInfo[i+((sentenceNumber-1)*4)].elevation = (short)strtol(dataarray[5+(i*4)],NULL,10);
00279 phid->GPSData.GSV.satInfo[i+((sentenceNumber-1)*4)].azimuth = strtol(dataarray[6+(i*4)],NULL,10);
00280 phid->GPSData.GSV.satInfo[i+((sentenceNumber-1)*4)].SNR = (short)strtol(dataarray[7+(i*4)],NULL,10);
00281 }
00282 }
00283 else if(!strncmp("RMC",dataarray[0]+3,3)) {
00284 if(strlen(dataarray[1])>=6) {
00285 decpart = modf(strtod(dataarray[1], NULL), &dintpart);
00286 intpart = (int)dintpart;
00287 phid->GPSData.RMC.time.tm_hour = (short)(intpart/10000);
00288 phid->GPSData.RMC.time.tm_min = (short)(intpart/100%100);
00289 phid->GPSData.RMC.time.tm_sec = (short)(intpart%100);
00290 phid->GPSData.RMC.time.tm_ms = (short)round(decpart*1000);
00291 }
00292
00293 phid->GPSData.RMC.status = dataarray[2][0];
00294
00295
00296 if(strlen(dataarray[3])) {
00297 tempD = (int)(strtol(dataarray[3], NULL, 10) / 100) + (strtod((dataarray[3]+2),NULL) / 60);
00298 if(dataarray[4][0] == 'S')
00299 phid->GPSData.RMC.latitude = -tempD;
00300 else
00301 phid->GPSData.RMC.latitude = tempD;
00302 }
00303 else
00304 phid->GPSData.RMC.latitude = 0;
00305
00306 if(strlen(dataarray[5])) {
00307 tempD = (int)(strtol(dataarray[5], NULL, 10) / 100) + (strtod((dataarray[5]+3),NULL) / 60);
00308 if(dataarray[6][0] == 'W')
00309 phid->GPSData.RMC.longitude = -tempD;
00310 else
00311 phid->GPSData.RMC.longitude = tempD;
00312 }
00313 else
00314 phid->GPSData.RMC.longitude = 0;
00315
00316 phid->GPSData.RMC.speedKnots = strtod(dataarray[7],NULL);
00317 phid->GPSData.RMC.heading = strtod(dataarray[8],NULL);
00318
00319 if(strlen(dataarray[9])>=6) {
00320 intpart = strtol(dataarray[9], NULL, 10);
00321 phid->GPSData.RMC.date.tm_mday = (short)(intpart/10000);
00322 phid->GPSData.RMC.date.tm_mon = (short)(intpart/100%100);
00323 phid->GPSData.RMC.date.tm_year = (short)(intpart%100) + 2000;
00324 phid->haveDate = PTRUE;
00325 }
00326 else
00327 phid->haveDate = PFALSE;
00328
00329 tempD = strtod(dataarray[10],NULL);
00330 if(dataarray[11][0] == 'W')
00331 phid->GPSData.RMC.magneticVariation = -tempD;
00332 else
00333 phid->GPSData.RMC.magneticVariation = tempD;
00334
00335 phid->GPSData.RMC.mode = dataarray[12][0];
00336
00337 if(phid->GPSData.RMC.status == 'A')
00338 {
00339 phid->velocity = phid->GPSData.RMC.speedKnots * 1.852;
00340 phid->heading = phid->GPSData.RMC.heading;
00341 }
00342 else
00343 {
00344 phid->velocity = PUNK_DBL;
00345 phid->heading = PUNK_DBL;
00346 }
00347 }
00348 else if(!strncmp("VTG",dataarray[0]+3,3)) {
00349 phid->GPSData.VTG.trueHeading = strtod(dataarray[1],NULL);
00350 phid->GPSData.VTG.magneticHeading = strtod(dataarray[3],NULL);
00351 phid->GPSData.VTG.speedKnots = strtod(dataarray[5],NULL);
00352 phid->GPSData.VTG.speed = strtod(dataarray[7],NULL);
00353 phid->GPSData.VTG.mode = dataarray[9][0];
00354 }
00355 else {
00356 LOG(PHIDGET_LOG_INFO,"Unrecognized sentence type: %s", dataarray[0]+3);
00357 }
00358
00359 return 0;
00360 }
00361
00362
00363 static int parse_SkyTraq_response(unsigned char *data, CPhidgetGPSInfo *phid) {
00364 int msgLength = data[3];
00365 int crc = data[msgLength + 4];
00366 int i, crccheck=0;
00367 char buffer[256];
00368
00369 for(i=0;i<msgLength;i++)
00370 {
00371 crccheck^=data[i+4];
00372 }
00373 if(crc != crccheck)
00374 {
00375 LOG(PHIDGET_LOG_WARNING,"CRC Error parsing SkyTraq response.");
00376 return -1;
00377 }
00378
00379 switch(data[4])
00380 {
00381 case 0x83:
00382 LOG(PHIDGET_LOG_INFO, "SkyTraq ACK: 0x%02x", data[5]);
00383 break;
00384 case 0x84:
00385 LOG(PHIDGET_LOG_INFO, "SkyTraq NACK: 0x%02x", data[5]);
00386 break;
00387 default:
00388 LOG(PHIDGET_LOG_INFO, "Got a SkyTraq message: 0x%02x", data[4]);
00389 buffer[0]=0;
00390 for(i=0;i<msgLength-1;i++)
00391 {
00392 if(i%8==0 && i!=0)
00393 {
00394 LOG(PHIDGET_LOG_INFO, "%s", buffer);
00395 buffer[0]=0;
00396 }
00397 sprintf(buffer+strlen(buffer)," 0x%02x", data[i+5]);
00398 }
00399 if(buffer[0])
00400 LOG(PHIDGET_LOG_INFO, "%s", buffer);
00401 }
00402
00403 return 0;
00404 }
00405
00406
00407 static int parse_GPS_packets(CPhidgetGPSInfo *phid) {
00408
00409 unsigned char current_queuesize, msgsize, temp;
00410 int result, i=0;
00411
00412 do {
00413 result = 0;
00414
00415
00416
00417 i=0;
00418 while ((i < 255) && (phid->sckbuf_read != phid->sckbuf_write))
00419 {
00420 if(phid->sckbuf[phid->sckbuf_read] == '$' || phid->sckbuf[phid->sckbuf_read] == 0xa0)
00421 break;
00422 i++;
00423 phid->sckbuf_read++;
00424 }
00425
00426 current_queuesize = phid->sckbuf_write - phid->sckbuf_read;
00427
00428
00429 if(phid->sckbuf[phid->sckbuf_read] == 0xa0)
00430 {
00431 unsigned char tempbuffer[256];
00432 if(current_queuesize < 4)
00433 break;
00434 msgsize = 7 + phid->sckbuf[(unsigned char)(phid->sckbuf_read + 3)];
00435 if(current_queuesize < msgsize)
00436 break;
00437
00438 for (i = 0; i<msgsize; i++)
00439 tempbuffer[i] = phid->sckbuf[phid->sckbuf_read++];
00440
00441
00442 result=1;
00443
00444
00445 if(parse_SkyTraq_response(tempbuffer, phid))
00446 {
00447 LOG(PHIDGET_LOG_WARNING,"Error parsing SkyTraq response.");
00448 }
00449 }
00450 else
00451 {
00452 char tempbuffer[256];
00453
00454 temp = phid->sckbuf_read;
00455 msgsize = 0;
00456 for (i=0; i < current_queuesize; i++,temp++)
00457 {
00458 if(phid->sckbuf[temp] == '\n') {
00459 msgsize = i;
00460 break;
00461 }
00462 }
00463 if(!msgsize) break;
00464
00465 for (i = 0; i<msgsize; i++)
00466 tempbuffer[i] = phid->sckbuf[phid->sckbuf_read++];
00467 tempbuffer[i] = 0;
00468
00469
00470 result=1;
00471
00472
00473 if (current_queuesize >= 6 && tempbuffer[1] == 'G' && tempbuffer[2] == 'P')
00474 {
00475
00476
00477 if(parse_NMEA_data(tempbuffer, phid))
00478 {
00479 LOG(PHIDGET_LOG_WARNING,"Error parsing NMEA sentence.");
00480 }
00481 }
00482 else
00483 {
00484 LOG(PHIDGET_LOG_INFO, "GPS Message: %s", tempbuffer);
00485 }
00486 }
00487 }
00488 while(result);
00489
00490 return 0;
00491 }
00492
00493
00494
00495
00496 CCREATE(GPS, PHIDCLASS_GPS)
00497
00498
00499 CFHANDLE(GPS, PositionChange, double, double, double)
00500 CFHANDLE(GPS, PositionFixStatusChange, int)
00501
00502 CGET(GPS,Latitude,double)
00503 TESTPTRS(phid,pVal)
00504 TESTDEVICETYPE(PHIDCLASS_GPS)
00505 TESTATTACHED
00506 TESTMASGN(latitude, PUNK_DBL)
00507
00508 MASGN(latitude)
00509 }
00510
00511 CGET(GPS,Longitude,double)
00512 TESTPTRS(phid,pVal)
00513 TESTDEVICETYPE(PHIDCLASS_GPS)
00514 TESTATTACHED
00515 TESTMASGN(longitude, PUNK_DBL)
00516
00517 MASGN(longitude)
00518 }
00519
00520 CGET(GPS,Altitude,double)
00521 TESTPTRS(phid,pVal)
00522 TESTDEVICETYPE(PHIDCLASS_GPS)
00523 TESTATTACHED
00524 TESTMASGN(altitude, PUNK_DBL)
00525
00526 MASGN(altitude)
00527 }
00528
00529 CGET(GPS,Time,GPSTime)
00530 TESTPTRS(phid,pVal)
00531 TESTDEVICETYPE(PHIDCLASS_GPS)
00532 TESTATTACHED
00533 if(phid->haveTime == PUNK_BOOL)
00534 return EPHIDGET_UNKNOWNVAL;
00535
00536 MASGN(GPSData.GGA.time)
00537 }
00538
00539 CGET(GPS,Date,GPSDate)
00540 TESTPTRS(phid,pVal)
00541 TESTDEVICETYPE(PHIDCLASS_GPS)
00542 TESTATTACHED
00543 if(phid->haveDate == PUNK_BOOL)
00544 return EPHIDGET_UNKNOWNVAL;
00545
00546 MASGN(GPSData.RMC.date)
00547 }
00548
00549 CGET(GPS,NMEAData,NMEAData)
00550 TESTPTRS(phid,pVal)
00551 TESTDEVICETYPE(PHIDCLASS_GPS)
00552 TESTATTACHED
00553
00554
00555 if(CPhidget_statusFlagIsSet(phid->phid.status, PHIDGET_REMOTE_FLAG))
00556 return EPHIDGET_UNSUPPORTED;
00557
00558 MASGN(GPSData)
00559 }
00560
00561 CGET(GPS,Heading,double)
00562 TESTPTRS(phid,pVal)
00563 TESTDEVICETYPE(PHIDCLASS_GPS)
00564 TESTATTACHED
00565 TESTMASGN(heading, PUNK_DBL)
00566
00567 MASGN(heading)
00568 }
00569
00570 CGET(GPS,Velocity,double)
00571 TESTPTRS(phid,pVal)
00572 TESTDEVICETYPE(PHIDCLASS_GPS)
00573 TESTATTACHED
00574 TESTMASGN(velocity, PUNK_DBL)
00575
00576 MASGN(velocity)
00577 }
00578
00579 CGET(GPS,PositionFixStatus,int)
00580 TESTPTRS(phid,pVal)
00581 TESTDEVICETYPE(PHIDCLASS_GPS)
00582 TESTATTACHED
00583 TESTMASGN(fix, PUNK_BOOL)
00584
00585 MASGN(fix)
00586 }