bool GpsIdPort::Initialize() { _hLoc = ::CreateEvent(NULL, FALSE, FALSE, NULL); _hState = ::CreateEvent(NULL, FALSE, FALSE, NULL); _hGPS = ::GPSOpenDevice(_hLoc, _hState, NULL, 0); if (0 == _hGPS) { StartupStore(_T("Unable to Open GPS Intermediate driver %s"), NEWLINE); return false; } SetPortStatus(CPS_OPENOK); GPS_DEVICE dev = {0}; GPSResetData(dev); GPSGetDeviceState(&dev); StartupStore(_T("GPSID : DeviceState: %lX, ServiceState: %lX%s"), dev.dwDeviceState, dev.dwServiceState, NEWLINE); // StartupStore(_T("GPSID : LastDataTime: %s%s"), dev.ftLastDataReceived, NEWLINE); StartupStore(_T("GPSID : DrvPrefix; %s%s"), dev.szGPSDriverPrefix, NEWLINE); StartupStore(_T("GPSID : MxPrefix %s%s"), dev.szGPSMultiplexPrefix, NEWLINE); StartupStore(_T("GPSID : Name:%s%s"), dev.szGPSFriendlyName, NEWLINE); if (!StartRxThread()) { StartupStore(_T(". ComPort %u <%s> Failed to start Rx Thread%s"), GetPortIndex() + 1, GetPortName(), NEWLINE); return false; } return true; }
DWORD WINAPI CGPSDevice::GPSThreadProc(__opt LPVOID lpParameter) { DWORD dwRet = 0; GPS_POSITION gps_Position = {0}; GPS_DEVICE gps_Device = {0}; CGPSDevice * pDevice = (CGPSDevice*) lpParameter; HANDLE gpsHandles[GPS_CONTROLLER_EVENT_COUNT] = { pDevice->m_hNewLocationData, pDevice->m_hDeviceStateChange, pDevice->m_hExitThread }; gps_Position.dwSize = sizeof(gps_Position); gps_Position.dwVersion = GPS_VERSION_1; gps_Device.dwVersion = GPS_VERSION_1; gps_Device.dwSize = sizeof(gps_Device); do { dwRet = WaitForMultipleObjects( GPS_CONTROLLER_EVENT_COUNT, gpsHandles, FALSE, INFINITE); if (dwRet == WAIT_OBJECT_0) { dwRet = GPSGetPosition( pDevice->m_hGPS_Device, &gps_Position, MAX_AGE, 0); if (ERROR_SUCCESS != dwRet) { rho_geo_callcallback_error(); continue; } else pDevice->m_pController->SetGPSPosition(gps_Position); } else if (dwRet == WAIT_OBJECT_0 + 1) { dwRet = GPSGetDeviceState(&gps_Device); if (ERROR_SUCCESS != dwRet) continue; else pDevice->m_pController->SetGPSDeviceInfo(gps_Device); } else if (dwRet == WAIT_OBJECT_0 + 2) break; else RHO_ASSERT(0); } while( TRUE ); return 0; }
DWORD GpsIdPort::RxThread() { DWORD rc = 0; const int nh = 2; HANDLE handles[nh] = {0}; handles[0] = _hLoc; handles[1] = _hState; GPS_POSITION loc = {0}; GPSResetData(loc); GPS_DEVICE dev = {0}; GPSResetData(dev); bool listen = true; while (listen && !StopEvt.tryWait(0)) { DWORD dw = ::WaitForMultipleObjects(nh, handles, FALSE, 100); switch (dw) { case WAIT_OBJECT_0: rc = GPSGetPosition(_hGPS, &loc, 10000, 0); if(ERROR_SUCCESS == rc) { AddStatRx(1); NMEAParser::ParseGPS_POSITION(GetPortIndex(), loc, GPS_INFO); } GPSResetData(loc); break; case WAIT_OBJECT_0 + 1: rc = GPSGetDeviceState(&dev); if(ERROR_SUCCESS == rc) { AddStatRx(1); StartupStore(_T("GPSID : DeviceState: %lX, ServiceState: %lX%s"), dev.dwDeviceState, dev.dwServiceState, NEWLINE); } GPSResetData(dev); break; case WAIT_FAILED: listen = false; rc = ::GetLastError(); break; case WAIT_TIMEOUT: break; } } return rc; }
// We try to keep the GPS turned off as much as we can to preserve battery life. // When run() is called we turn on the GPS device and we leave it on // until the request is satisfied or periodic updates are stopped. // The methods requestUpdate() and startUpdates() will call start() if required. void QGeoInfoThreadWinCE::run() { mutex.lock(); gpsReachedOnState = false; m_gps = NULL; const int handleCount = 3; HANDLE handles[handleCount] = { m_newDataEvent, m_gpsStateChange, m_wakeUpEvent }; if (updatesScheduled || requestScheduled) { m_gps = GPSOpenDevice(m_newDataEvent, m_gpsStateChange, NULL, 0); } while (true) { if (stopping) break; if (!updatesScheduled && !requestScheduled) { if (m_gps != NULL) { GPSCloseDevice(m_gps); m_gps = NULL; } statusUpdated.wait(&mutex); if (updatesScheduled || requestScheduled) { gpsReachedOnState = false; m_gps = GPSOpenDevice(m_newDataEvent, m_gpsStateChange, NULL, 0); } } // If the periodic update is 0 then updates are returned as available. // If this is not the case then the next timeout will be set for whichever of // the request and periodic updates that is due next. // We cap the amount of time we spend waiting for updates. DWORD timeout = MaximumMainLoopWaitTime; QDateTime now = currentDateTime(); if (requestScheduled) { if (!updatesScheduled || (updatesInterval == 0) || (msecsTo(requestNextTime, updatesNextTime) >= 0)) { timeout = msecsTo(now, requestNextTime) + 100; } else { if (updatesInterval != 0) timeout = msecsTo(now, updatesNextTime) + 100; } } else { // updatesScheduled has to be true or we wouldn't still be in the larger while loop. if (updatesInterval != 0) timeout = msecsTo(now, updatesNextTime) + 100; } if (timeout > MaximumMainLoopWaitTime) timeout = MaximumMainLoopWaitTime; mutex.unlock(); DWORD dwRet = WaitForMultipleObjects(handleCount, handles, FALSE, timeout); mutex.lock(); // The GPS data has been updated. if (dwRet == WAIT_OBJECT_0) { // The other options are: // dwRet == WAIT_OBJECT_0 + 1 // => The GPS state has been updated. // dwRet == WAIT_OBJECT_0 + 2 // => We called QGeoInfoThreadWinCE::wakeUp(). // dwRet == WAIT_TIMEOUT // => WaitForMultipleObjects() timed out. GPS_POSITION posn; posn.dwVersion = GPS_VERSION_1; posn.dwSize = sizeof(posn); dwRet = GPSGetPosition(m_gps, &posn, timeout, 0); if (dwRet == ERROR_SUCCESS) { if (!validator->valid(posn)) { invalidDataReceived = true; } else { m_lastPosition = posn; hasLastPosition = true; updateTimeoutTriggered = false; // A request and a periodic update could both be satisfied at once. // We use this flag to prevent a double update. bool emitDataUpdated = false; // If a request is in process we emit the dataUpdated signal. if (requestScheduled) { emitDataUpdated = true; requestScheduled = false; } // If we are updating as data becomes available or if the update period has elapsed // we emit the dataUpdated signal. if (updatesScheduled) { QDateTime now = currentDateTime(); if (updatesInterval == 0) { emitDataUpdated = true; } else if (msecsTo(now, updatesNextTime) < 0) { while (msecsTo(now, updatesNextTime) < 0) updatesNextTime = updatesNextTime.addMSecs(updatesInterval); emitDataUpdated = true; } } if (emitDataUpdated) { hasLastPosition = false; mutex.unlock(); emit dataUpdated(m_lastPosition); mutex.lock(); } } } } if (dwRet != WAIT_OBJECT_0 || invalidDataReceived) { invalidDataReceived = false; // Third party apps may have the ability to turn off the gps hardware independently of // the Microsoft GPS API. // This checks for an unexpected power down and turns the hardware back on. // The GPS state has been updated. if (dwRet == WAIT_OBJECT_0 + 1) { GPS_DEVICE device; device.dwVersion = GPS_VERSION_1; device.dwSize = sizeof(device); dwRet = GPSGetDeviceState(&device); if (device.dwDeviceState == SERVICE_STATE_ON) { gpsReachedOnState = true; } else if ((device.dwDeviceState == SERVICE_STATE_OFF) && gpsReachedOnState) { // We do not want to mess with devices that are slow starting up, so we only // turn on devices that have previously reached the "On" state. gpsReachedOnState = false; m_gps = GPSOpenDevice(m_newDataEvent, m_gpsStateChange, NULL, 0); } } // We reach this point if the gps state has changed, if the wake up event has been // triggered, if we received data we were not interested in from the GPS, // or if a timeout occurred while waiting for gps data. // // In all of these cases we should check for request and periodic update timeouts. QDateTime now = currentDateTime(); bool emitUpdateTimeout = false; // Check for request timeouts. if (requestScheduled && msecsTo(now, requestNextTime) < 0) { requestScheduled = false; emitUpdateTimeout = true; } // Check to see if a periodic update is due. if (updatesScheduled && updatesInterval != 0 && (msecsTo(now, updatesNextTime) < 0)) { while (msecsTo(now, updatesNextTime) < 0) updatesNextTime = updatesNextTime.addMSecs(updatesInterval); if (hasLastPosition) { hasLastPosition = false; mutex.unlock(); emit dataUpdated(m_lastPosition); mutex.lock(); } else { if (timeoutsForPeriodicUpdates && !updateTimeoutTriggered) { updateTimeoutTriggered = true; emitUpdateTimeout = true; } } } if (emitUpdateTimeout) { mutex.unlock(); emit updateTimeout(); mutex.lock(); } } } if (m_gps != NULL) GPSCloseDevice(m_gps); mutex.unlock(); }