/* GPS+: Service plugin for Miranda IM Copyright 2007-2008 persei persei@miranda.im http://persei.miranda.im http://svn.miranda.im/mainrepo/gps+ Using of code in another IM projects forbidden without author write permission This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include "gps_class.h" GPSWorker::GPSWorker() { InitializeCriticalSection(&csInfoAccess); EnterCriticalSection(&csInfoAccess); navInfo = new NavInfo; gpsInfo = new GPSInfo; LeaveCriticalSection(&csInfoAccess); hPortReader = INVALID_HANDLE_VALUE; hPort = INVALID_HANDLE_VALUE; } GPSWorker::~GPSWorker() { if(hPortReader != INVALID_HANDLE_VALUE) Disconnect(); EnterCriticalSection(&csInfoAccess); delete navInfo; delete gpsInfo; LeaveCriticalSection(&csInfoAccess); DeleteCriticalSection(&csInfoAccess); } void GPSWorker::SetPort(int nPortN) { if (nPortN > 0 && nPortN < 255) { char PortN[10]; iPortN = nPortN; _ltoa(iPortN, PortN, 10); strcpy(Port, "\\\\.\\COM"); strcat(Port, PortN); } } int GPSWorker::GetPort() { return iPortN; } void GPSWorker::GetPortStr(char * PortStr) { strcpy(PortStr, Port); } void GPSWorker::GetNavInfo(NavInfo* retNavInfo) { EnterCriticalSection(&csInfoAccess); memcpy(retNavInfo, navInfo, sizeof(NavInfo)); LeaveCriticalSection(&csInfoAccess); } void GPSWorker::GetGPSInfo(GPSInfo* retGPSInfo) { EnterCriticalSection(&csInfoAccess); memcpy(retGPSInfo, gpsInfo, sizeof(GPSInfo)); LeaveCriticalSection(&csInfoAccess); } /* //Return tokens count int explode(char* sourceStr, char sep, char** tokens) { int i; char buf[255]; buf[0] = 0; for(i = 0; i < strlen(sourceStr); i++){ if(sourceStr[i] != sep){ } } } */ float GeoCoordToDegrees(float geoCoord) { float minutes = geoCoord - (int)(geoCoord / 100) * 100; return ((int)(geoCoord / 100)) + (minutes / 60); } int ParseTime(float time) { int hours, minutes; float seconds; hours = (int)(time / 1000); minutes = (int)(time / 100) - hours * 100; seconds = time - hours * 1000 - minutes * 100; return hours * 60 * 60 * 1000 + minutes * 60 * 1000 + (int)(seconds * 1000); } int CheckCRC(char* infoStr) { int recvCheckSum = 0, calcCheckSum = 0; char checkStr[255]; sscanf(infoStr, "$%[1234567890,.QWERTYUIOPASDFGHJKLZXCVBNM-+]*%x", checkStr, &recvCheckSum); for(int i = 0; i < strlen(checkStr); i++) { calcCheckSum ^= checkStr[i]; } return !(calcCheckSum - recvCheckSum); } void GPSWorker::ParseInfo(char* infoStr) { if(infoStr[0] != '$') { WrongMessage++; return; } if(CheckSum){ if(!CheckCRC(infoStr)) { return; } } if(WrongMessage == DisconnectOn){ Disconnect(); } WrongMessage = 0; if(strstr(infoStr, "$GPRMC")){ float time = 0; char valid = 0; float latitude = 0; char NorthSouth = 0; float longtitude = 0; char EastWest = 0; float sog = 0; float direction = 0; int date = 0; float magneticDeclination = 0; char magneticEastWest = 0; int checkSum = 0; sscanf(infoStr, "$GPRMC,%f,%c,%f,%c,%f,%c,%f,%f,%d,%f,%c*%x", &time, &valid, &latitude, &NorthSouth, &longtitude, &EastWest, &sog, &direction, &date, &magneticDeclination, &magneticEastWest, &checkSum); EnterCriticalSection(&csInfoAccess); navInfo->Latitude = (NorthSouth == 'N' ? 1 : -1) * GeoCoordToDegrees(latitude); navInfo->Longtitude = (EastWest == 'E' ? 1 : -1) * GeoCoordToDegrees(longtitude); navInfo->SOG = sog; navInfo->Time = ParseTime(time); navInfo->Direction = direction; navInfo->MagneticDeclination = (magneticEastWest == 'E' ? 1 : -1) * magneticDeclination; LeaveCriticalSection(&csInfoAccess); } if(strstr(infoStr, "$GPGGA")){ float time = 0; float latitude = 0; char NorthSouth = 0; float longtitude = 0; char EastWest = 0; int quality = 0; int satCount = 0; float hdop = 0; float altitude = 0; char altMarker = 0; float geoDiff = 0; char geoDiffMarker = 0; float diffDataAge = 0; int stantionId = 0; int checkSum = 0; sscanf(infoStr, "$GPGGA,%f,%f,%c,%f,%c,%d,%d,%f,%f,%c,%f,%c,%d,%d*%x", &time, &latitude, &NorthSouth, &longtitude, &EastWest, &quality, &satCount, &hdop, &altitude, &altMarker, &geoDiff, &geoDiffMarker, &diffDataAge, &stantionId, &checkSum); EnterCriticalSection(&csInfoAccess); navInfo->Altitude = altitude; navInfo->Latitude = (NorthSouth == 'N' ? 1 : -1) * GeoCoordToDegrees(latitude); navInfo->Longtitude = (EastWest == 'E' ? 1 : -1) * GeoCoordToDegrees(longtitude); navInfo->Quality = quality; gpsInfo->SatCount = satCount; navInfo->GeoDiff = geoDiff; gpsInfo->HDOP = hdop; navInfo->Time = ParseTime(time); LeaveCriticalSection(&csInfoAccess); } } DWORD __stdcall GPSWorker::PortReader(GPSWorker* th) { char cBuf[2]; char infoStr[1024]; DWORD dwBytesRead; while(1){ ReadFile(th->hPort, &cBuf, 1, &dwBytesRead, NULL); cBuf[1] = 0; if(dwBytesRead > 0){ strcat(infoStr, cBuf); if(cBuf[0] == '\n'){ th->ParseInfo(infoStr); infoStr[0] = 0; } } } } int GPSWorker::Connect() { if(hPortReader != INVALID_HANDLE_VALUE) return 2; WrongMessage = 0; hPort = CreateFile(Port, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if (hPort == INVALID_HANDLE_VALUE) return -1; else { hPortReader = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&GPSWorker::PortReader, (LPVOID)this, 0, 0); DCB dcb; GetCommState(hPort, &dcb); dcb.BaudRate = CBR_4800; dcb.ByteSize = 8; dcb.Parity = NOPARITY; dcb.StopBits = ONESTOPBIT; if (!SetCommState(hPort, &dcb)){ TerminateThread(hPortReader, 0); CloseHandle(hPort); hPortReader = INVALID_HANDLE_VALUE; hPort = INVALID_HANDLE_VALUE; return -2; } } return 1; } void GPSWorker::Disconnect() { if(hPortReader != INVALID_HANDLE_VALUE){ EnterCriticalSection(&csInfoAccess); TerminateThread(hPortReader, 0); CloseHandle(hPort); LeaveCriticalSection(&csInfoAccess); hPortReader = INVALID_HANDLE_VALUE; hPort = INVALID_HANDLE_VALUE; } } int GPSWorker::ReConnect() { Disconnect(); return Connect(); } int GPSWorker::IsConnected() { return hPortReader != INVALID_HANDLE_VALUE; } void GPSWorker::SetAutoDisconnect(int newDisconnOn) { DisconnectOn = newDisconnOn; } void GPSWorker::SetCheckSum(int newCheck) { CheckSum = newCheck; }