DWORD CalculationThread (LPVOID lpvoid) { (void)lpvoid; bool needcalculationsslow; NMEA_INFO tmpGPS; DERIVED_INFO tmpCALCULATED; FILETIME CreationTime, ExitTime, StartKernelTime, EndKernelTime, StartUserTime, EndUserTime ; needcalculationsslow = false; // let's not create a deadlock here, setting the go after another race condition goCalculationThread=true; // 091119 CHECK // wait for proper startup signal while (!MapWindow::IsDisplayRunning()) { Sleep(100); } // while (!goCalculating) Sleep(100); Sleep(1000); // 091213 BUGFIX need to syncronize !!! TOFIX02 TODO while (!MapWindow::CLOSETHREAD) { WaitForSingleObject(dataTriggerEvent, 5000); ResetEvent(dataTriggerEvent); if (MapWindow::CLOSETHREAD) break; // drop out on exit GetThreadTimes( hCalculationThread, &CreationTime, &ExitTime,&StartKernelTime,&StartUserTime); // make local copy before editing... LockFlightData(); FLARM_RefreshSlots(&GPS_INFO); memcpy(&tmpGPS,&GPS_INFO,sizeof(NMEA_INFO)); memcpy(&tmpCALCULATED,&CALCULATED_INFO,sizeof(DERIVED_INFO)); UnlockFlightData(); DoCalculationsVario(&tmpGPS,&tmpCALCULATED); if (!tmpGPS.VarioAvailable) { TriggerVarioUpdate(); // emulate vario update } if(DoCalculations(&tmpGPS,&tmpCALCULATED)){ #if (WINDOWSPC>0) && !TESTBENCH #else if (!INPAN) #endif { MapWindow::MapDirty = true; } needcalculationsslow = true; if (tmpCALCULATED.Circling) MapWindow::mode.Fly(MapWindow::Mode::MODE_FLY_CIRCLING); else if (tmpCALCULATED.FinalGlide) MapWindow::mode.Fly(MapWindow::Mode::MODE_FLY_FINAL_GLIDE); else MapWindow::mode.Fly(MapWindow::Mode::MODE_FLY_CRUISE); } if (MapWindow::CLOSETHREAD) break; // drop out on exit // This is activating another run for Thread Draw TriggerRedraws(&tmpGPS, &tmpCALCULATED); if (MapWindow::CLOSETHREAD) break; // drop out on exit if (SIMMODE) { if (needcalculationsslow || ( ReplayLogger::IsEnabled() ) ) { DoCalculationsSlow(&tmpGPS,&tmpCALCULATED); needcalculationsslow = false; } } else { if (needcalculationsslow) { DoCalculationsSlow(&tmpGPS,&tmpCALCULATED); needcalculationsslow = false; } } if (MapWindow::CLOSETHREAD) break; // drop out on exit // values changed, so copy them back now: ONLY CALCULATED INFO // should be changed in DoCalculations, so we only need to write // that one back (otherwise we may write over new data) LockFlightData(); memcpy(&CALCULATED_INFO,&tmpCALCULATED,sizeof(DERIVED_INFO)); UnlockFlightData(); // update live tracker with new values // this is a nonblocking call, live tracker runs on different thread LiveTrackerUpdate(&tmpGPS, &tmpCALCULATED); if (FlightDataRecorderActive) UpdateFlightDataRecorder(&tmpGPS,&tmpCALCULATED); if ( (GetThreadTimes( hCalculationThread, &CreationTime, &ExitTime,&EndKernelTime,&EndUserTime)) == 0) { Cpu_Calc=9999; } else { Cpustats(&Cpu_Calc,&StartKernelTime, &EndKernelTime, &StartUserTime, &EndUserTime); } } return 0; }
DWORD MapWindow::DrawThread (LPVOID lpvoid) { FILETIME CreationTime, ExitTime, StartKernelTime, EndKernelTime, StartUserTime, EndUserTime ; while ((!ProgramStarted) || (!Initialised)) { Sleep(100); } #if TRACETHREAD StartupStore(_T("############## DRAW threadid=%d\n"),GetCurrentThreadId()); #endif // THREADRUNNING = FALSE; THREADEXIT = FALSE; // Reset common topology and waypoint label declutter, first init. Done also in other places. ResetLabelDeclutter(); GetClientRect(hWndMapWindow, &MapRect); // Default draw area is full screen, no opacity DrawRect=MapRect; UpdateTimeStats(true); SetBkMode(hdcDrawWindow,TRANSPARENT); SetBkMode(hDCTemp,OPAQUE); SetBkMode(hDCMask,OPAQUE); // paint draw window black to start SelectObject(hdcDrawWindow, GetStockObject(BLACK_PEN)); Rectangle(hdcDrawWindow,MapRect.left,MapRect.top, MapRect.right,MapRect.bottom); BitBlt(hdcScreen, 0, 0, MapRect.right-MapRect.left, MapRect.bottom-MapRect.top, hdcDrawWindow, 0, 0, SRCCOPY); // This is just here to give fully rendered start screen UpdateInfo(&GPS_INFO, &CALCULATED_INFO); MapDirty = true; UpdateTimeStats(true); zoom.RequestedScale(zoom.Scale()); zoom.ModifyMapScale(); FillScaleListForEngineeringUnits(); bool lastdrawwasbitblitted=false; bool first_run=true; // // Big LOOP // while (!CLOSETHREAD) { WaitForSingleObject(drawTriggerEvent, 5000); ResetEvent(drawTriggerEvent); if (CLOSETHREAD) break; // drop out without drawing if ((!THREADRUNNING) || (!GlobalRunning)) { Sleep(100); continue; } // This is also occuring on resolution change if (LKSW_ReloadProfileBitmaps) { #if TESTBENCH StartupStore(_T(".... SWITCH: ReloadProfileBitmaps detected\n")); #endif // This is needed to update resolution change GetClientRect(hWndMapWindow, &MapRect); DrawRect=MapRect; FillScaleListForEngineeringUnits(); LKUnloadProfileBitmaps(); LKLoadProfileBitmaps(); LKUnloadFixedBitmaps(); LKLoadFixedBitmaps(); MapWindow::zoom.Reset(); // This will reset the function for the new ScreenScale PolygonRotateShift((POINT*)NULL,0,0,0,DisplayAngle+1); // Restart from moving map if (MapSpaceMode!=MSM_WELCOME) SetModeType(LKMODE_MAP, MP_MOVING); LKSW_ReloadProfileBitmaps=false; // These should be better checked. first_run is forcing also cache update for topo. ForceRenderMap=true; first_run=true; } GetThreadTimes( hDrawThread, &CreationTime, &ExitTime,&StartKernelTime,&StartUserTime); // Until MapDirty is set true again, we shall only repaint the screen. No Render, no calculations, no updates. // This is intended for very fast immediate screen refresh. // // MapDirty is set true by: // - TriggerRedraws() in calculations thread // - RefreshMap() in drawthread generally // extern int XstartScreen, YstartScreen, XtargetScreen, YtargetScreen; extern bool OnFastPanning; // While we are moving in bitblt mode, ignore RefreshMap requests from LK // unless a timeout was triggered by MapWndProc itself. if (OnFastPanning) { MapDirty=false; } // We must check if we are on FastPanning, because we may be in pan mode even while // the menu buttons are active and we are using them, accessing other functions. // In that case, without checking OnFastPanning, we would fall back here and repaint // with bitblt everytime, while instead we were asked a simple fastrefresh! // // Notice: we could be !MapDirty without OnFastPanning, of course! // if (!MapDirty && !ForceRenderMap && OnFastPanning && !first_run) { if (!mode.Is(Mode::MODE_TARGET_PAN) && mode.Is(Mode::MODE_PAN)) { int fromX=0, fromY=0; fromX=XstartScreen-XtargetScreen; fromY=YstartScreen-YtargetScreen; BitBlt(hdcScreen, 0, 0, MapRect.right-MapRect.left, MapRect.bottom-MapRect.top, hdcDrawWindow, 0, 0, WHITENESS); BitBlt(hdcScreen, 0, 0, MapRect.right-MapRect.left, MapRect.bottom-MapRect.top, hdcDrawWindow, fromX,fromY, // source SRCCOPY); POINT centerscreen; centerscreen.x=ScreenSizeX/2; centerscreen.y=ScreenSizeY/2; DrawMapScale(hdcScreen,MapRect,false); DrawCrossHairs(hdcScreen, centerscreen, MapRect); lastdrawwasbitblitted=true; } else { // THIS IS NOT GOING TO HAPPEN! // // The map was not dirty, and we are not in fastpanning mode. // FastRefresh! We simply redraw old bitmap. // BitBlt(hdcScreen, 0, 0, MapRect.right-MapRect.left, MapRect.bottom-MapRect.top, hdcDrawWindow, 0, 0, SRCCOPY); lastdrawwasbitblitted=true; } // Now we can clear the flag. If it was off already, no problems. OnFastPanning=false; continue; } else { // // Else the map wasy dirty, and we must render it.. // Notice: if we were fastpanning, than the map could not be dirty. // #if 1 // --------------------- EXPERIMENTAL, CHECK ZOOM IS WORKING IN PNA static double lasthere=0; // Only for special case: PAN mode, map not dirty (including requests for zooms!) // not in the ForceRenderMap run and last time was a real rendering. THEN, at these conditions, // we simply redraw old bitmap, for the scope of accelerating touch response. // In fact, if we are panning the map while rendering, there would be an annoying delay. // This is using lastdrawwasbitblitted if (INPAN && !MapDirty && !lastdrawwasbitblitted && !ForceRenderMap && !first_run) { // In any case, after 5 seconds redraw all if ( (LKHearthBeats-8) >lasthere ) { lasthere=LKHearthBeats; goto _dontbitblt; } BitBlt(hdcScreen, 0, 0, MapRect.right-MapRect.left, MapRect.bottom-MapRect.top, hdcDrawWindow, 0, 0, SRCCOPY); POINT centerscreen; centerscreen.x=ScreenSizeX/2; centerscreen.y=ScreenSizeY/2; DrawMapScale(hdcScreen,MapRect,false); DrawCrossHairs(hdcScreen, centerscreen, MapRect); continue; } #endif // -------------------------- _dontbitblt: MapDirty = false; PanRefreshed=true; } // MapDirty lastdrawwasbitblitted=false; MapWindow::UpdateInfo(&GPS_INFO, &CALCULATED_INFO); RenderMapWindow(MapRect); if (!ForceRenderMap && !first_run) { BitBlt(hdcScreen, 0, 0, MapRect.right-MapRect.left, MapRect.bottom-MapRect.top, hdcDrawWindow, 0, 0, SRCCOPY); InvalidateRect(hWndMapWindow, &MapRect, false); } // Draw cross sight for pan mode, in the screen center, // after a full repaint while not fastpanning if (mode.AnyPan() && !mode.Is(Mode::MODE_TARGET_PAN) && !OnFastPanning) { POINT centerscreen; centerscreen.x=ScreenSizeX/2; centerscreen.y=ScreenSizeY/2; DrawMapScale(hdcScreen,MapRect,false); DrawCompass(hdcScreen, MapRect, DisplayAngle); DrawCrossHairs(hdcScreen, centerscreen, MapRect); } UpdateTimeStats(false); // we do caching after screen update, to minimise perceived delay // UpdateCaches is updating topology bounds when either forced (only here) // or because MapWindow::ForceVisibilityScan is set true. UpdateCaches(first_run); first_run=false; ForceRenderMap = false; if (ProgramStarted==psInitDone) { ProgramStarted = psFirstDrawDone; } if ( (GetThreadTimes( hDrawThread, &CreationTime, &ExitTime,&EndKernelTime,&EndUserTime)) == 0) { Cpu_Draw=9999; } else { Cpustats(&Cpu_Draw,&StartKernelTime, &EndKernelTime, &StartUserTime, &EndUserTime); } } // Big LOOP #if TESTBENCH StartupStore(_T("... Thread_Draw terminated\n")); #endif THREADEXIT = TRUE; return 0; }
DWORD SerialPort::RxThread() { #if ( (WINDOWSPC == 0)) && !NEWCOMM // 100222 DWORD dwCommModemStatus = 0; // Specify a set of events to be monitored for the port. #endif DWORD dwBytesTransferred = 0; // 091117 initialized variables _Buff_t szString; FILETIME CreationTime, ExitTime, StartKernelTime, EndKernelTime, StartUserTime, EndUserTime; Purge(); #if TRACETHREAD StartupStore(_T("############## PORT=%d threadid=%d\n"), GetPortIndex(), GetCurrentThreadId()); if (GetPortIndex() = 0) _THREADID_PORT1 = GetCurrentThreadId(); if (GetPortIndex() = 1) _THREADID_PORT2 = GetCurrentThreadId(); if (GetPortIndex() != 1 && GetPortIndex() != 2) _THREADID_UNKNOWNPORT = GetCurrentThreadId(); #endif // Specify a set of events to be monitored for the port. _dwMask = EV_RXFLAG | EV_CTS | EV_DSR | EV_RING | EV_RXCHAR; #if ( (WINDOWSPC == 0)) && !NEWCOMM SetCommMask(hPort, _dwMask); #endif #if (WINDOWSPC<1) if (!_PollingMode) SetCommMask(hPort, _dwMask); #endif while ((hPort != INVALID_HANDLE_VALUE) && (::WaitForSingleObject(hStop, 0) == WAIT_TIMEOUT)) { GetThreadTimes(hReadThread, &CreationTime, &ExitTime, &StartKernelTime, &StartUserTime); UpdateStatus(); #if (WINDOWSPC>0) || NEWCOMM // 091206 // PC version does BUSY WAIT Sleep(50); // ToDo rewrite the whole driver to use overlaped IO on W2K or higher #else if (_PollingMode) Sleep(100); else // Wait for an event to occur for the port. if (!WaitCommEvent(hPort, &dwCommModemStatus, 0)) { // error reading from port Sleep(100); } #endif // Re-specify the set of events to be monitored for the port. // SetCommMask(hPort, dwMask1); // #if (WINDOWSPC == 0) 091206 #if ( (WINDOWSPC == 0)) && !NEWCOMM if (_PollingMode || (dwCommModemStatus & EV_RXFLAG) || (dwCommModemStatus & EV_RXCHAR)) // Do this only for non-PC #endif { // Loop for waiting for the data. do { // Read the data from the serial port. dwBytesTransferred = ReadData(szString); if (dwBytesTransferred > 0) { if (ProgramStarted >= psNormalOp) { // ignore everything until started std::for_each(begin(szString), begin(szString) + dwBytesTransferred, std::bind1st(std::mem_fun(&SerialPort::ProcessChar), this)); } } else { dwBytesTransferred = 0; } Sleep(50); // JMW20070515: give port some time to // fill... prevents ReadFile from causing the // thread to take up too much CPU if ((GetThreadTimes(hReadThread, &CreationTime, &ExitTime, &EndKernelTime, &EndUserTime)) == 0) { if (GetPortIndex() == 0) Cpu_PortA = 9999; else Cpu_PortB = 9999; } else { Cpustats((GetPortIndex() == 0) ? &Cpu_PortA : &Cpu_PortB, &StartKernelTime, &EndKernelTime, &StartUserTime, &EndUserTime); } if (::WaitForSingleObject(hStop, 0) != WAIT_TIMEOUT) { dwBytesTransferred = 0; } } while (dwBytesTransferred != 0); } // give port some time to fill Sleep(5); // Retrieve modem control-register values. #if ((WINDOWSPC == 0)) if (!_PollingMode) { // this is causing problems on PC BT, apparently. Setting Polling will not call this, but it is a bug GetCommModemStatus(hPort, &dwCommModemStatus); } #endif } DirtyPurge(); return 0; }
/*********************************************************************** PortReadThread (LPVOID lpvoid) ***********************************************************************/ DWORD ComPort::ReadThread() { #if (!defined(WINDOWSPC) || (WINDOWSPC == 0)) && !NEWCOMM // 100222 DWORD dwCommModemStatus=0; #endif DWORD dwBytesTransferred=0; // 091117 initialized variables BYTE inbuf[1024]; #ifdef CPUSTATS FILETIME CreationTime, ExitTime, StartKernelTime, EndKernelTime, StartUserTime, EndUserTime ; #endif // JMW added purging of port on open to prevent overflow Flush(); StartupStore(_T(". ReadThread running on port %d%s"),sportnumber+1,NEWLINE); // Specify a set of events to be monitored for the port. dwMask = EV_RXFLAG | EV_CTS | EV_DSR | EV_RING | EV_RXCHAR; // #if !defined(WINDOWSPC) || (WINDOWSPC == 0) 091206 #if (!defined(WINDOWSPC) || (WINDOWSPC == 0)) && !NEWCOMM SetCommMask(hPort, dwMask); #endif #if (WINDOWSPC<1) if (!PollingMode) SetCommMask(hPort, dwMask); #endif fRxThreadTerminated = FALSE; DWORD dwErrors=0; COMSTAT comStat; short valid_frames=0; while ((hPort != INVALID_HANDLE_VALUE) && (!MapWindow::CLOSETHREAD) && (!CloseThread)) { #ifdef CPUSTATS GetThreadTimes( hReadThread, &CreationTime, &ExitTime,&StartKernelTime,&StartUserTime); #endif ClearCommError(hPort,&dwErrors,&comStat); if ( dwErrors & CE_FRAME ) { //StartupStore(_T("... Com port %d, dwErrors=%ld FRAME (old status=%d)\n"), // sportnumber,dwErrors,ComPortStatus[sportnumber]); ComPortStatus[sportnumber]=CPS_EFRAME; ComPortErrRx[sportnumber]++; valid_frames=0; } else { if (++valid_frames>10) { valid_frames=20; ComPortStatus[sportnumber]=CPS_OPENOK; } } #if (WINDOWSPC>0) || NEWCOMM // 091206 // PC version does BUSY WAIT Sleep(50); // ToDo rewrite the whole driver to use overlaped IO on W2K or higher #else if (PollingMode) Sleep(100); else // Wait for an event to occur for the port. if (!WaitCommEvent(hPort, &dwCommModemStatus, 0)) { // error reading from port Sleep(100); } #endif // Re-specify the set of events to be monitored for the port. // SetCommMask(hPort, dwMask1); // #if !defined(WINDOWSPC) || (WINDOWSPC == 0) 091206 #if (!defined(WINDOWSPC) || (WINDOWSPC == 0)) && !NEWCOMM if (PollingMode || (dwCommModemStatus & EV_RXFLAG) || (dwCommModemStatus & EV_RXCHAR)) // Do this only for non-PC #endif { // Loop for waiting for the data. do { dwBytesTransferred = 0; // Read the data from the serial port. if (ReadFile(hPort, inbuf, 1024, &dwBytesTransferred, (OVERLAPPED *)NULL)) { if (ProgramStarted >= psNormalOp) { // ignore everything until started for (unsigned int j = 0; j < dwBytesTransferred; j++) { ProcessChar(inbuf[j]); } } ComPortRx[sportnumber]+=dwBytesTransferred; // 100210 } else { dwBytesTransferred = 0; } Sleep(50); // JMW20070515: give port some time to // fill... prevents ReadFile from causing the // thread to take up too much CPU #ifdef CPUSTATS if ( (GetThreadTimes( hReadThread, &CreationTime, &ExitTime,&EndKernelTime,&EndUserTime)) == 0) { Cpu_Port=9999; } else { Cpustats(&Cpu_Port,&StartKernelTime, &EndKernelTime, &StartUserTime, &EndUserTime); } #endif if (CloseThread) { dwBytesTransferred = 0; StartupStore(_T(". ComPort %d ReadThread: CloseThread ordered%s"),sportnumber+1,NEWLINE); } } while (dwBytesTransferred != 0); } // give port some time to fill Sleep(5); // Retrieve modem control-register values. #if (!defined(WINDOWSPC) || (WINDOWSPC == 0)) if (!PollingMode) // this is causing problems on PC BT, apparently. Setting Polling will not call this, but it is a bug GetCommModemStatus(hPort, &dwCommModemStatus); #endif } Flush(); fRxThreadTerminated = TRUE; StartupStore(_T(". ComPort %d ReadThread: terminated%s"),sportnumber+1,NEWLINE); return 0; }