BOOL CGPSAPIReader::close() { // clear previous stored data. if (m_hDevice) { // terminate reading thread. SetEvent(m_hStopEvent); if (m_hThread) { int wait_for = 3 * READ_TIMEOUT; if (WaitForSingleObject(m_hThread, wait_for) == WAIT_TIMEOUT) { coreprintln("forced to kill thread after %s ms of waiting it for termination", wait_for); TerminateThread(m_hThread, 0); } CloseHandle(m_hThread); m_hThread = NULL; } // close the device. DWORD dwResult = GPSCloseDevice(m_hDevice); if (ERROR_SUCCESS == dwResult) { m_hDevice = NULL; return true; } } return false; }
HRESULT CGPSDevice::TurnOff() { CGPSDevice * pDevice = Instance(); if( !pDevice->m_hGPS_Device ) return E_UNEXPECTED; HRESULT hr = pDevice->StopThread(); pDevice->m_pController = NULL; DWORD dwRet = GPSCloseDevice(pDevice->m_hGPS_Device); pDevice->m_hGPS_Device = NULL; if( SUCCEEDED(hr) ) { if( ERROR_SUCCESS != dwRet ) hr = HRESULT_FROM_WIN32(GetLastError()); } return hr; }
// 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(); }