Clamp framerate in Windows - c++

I have a simple loop
LARGE_INTEGER ticks_per_second;
::QueryPerformanceFrequency(&ticks_per_second);
MSG msg = { 0 };
while (true)
{
if (msg.message == WM_QUIT)
exit(0);
if (::PeekMessageW(&msg, NULL, 0U, 0U, PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessageW(&msg);
continue;
}
static double last_time_s = 0;
LARGE_INTEGER cur_time_li;
::QueryPerformanceCounter(&cur_time_li);
double cur_time_s = (double)cur_time_li.QuadPart / (double)ticks_per_second.QuadPart;
double diff_s = cur_time_s - last_time_s;
double rate_s = 1 / 30.0f;
uint32_t slept_ms = 0;
if (diff_s < rate_s)
{
slept_ms = (uint32_t)((rate_s - diff_s) * 1000.0);
::Sleep(slept_ms);
}
update();
::printf("updated %f %u\n", diff_s, slept_ms);
last_time_s = cur_time_s;
}
And want update() to be called 30 times per second, but not more often
With this code it goes wrong, in console I getting something like this:
updated 0.031747 1
updated 0.001997 31
updated 0.031912 1
updated 0.001931 31
updated 0.031442 1
updated 0.002084 31
Which is seems to be correct only for first update, second one called too fast, and I can't understand why
I understand that update, PeekMessageW and etc. also wasting time, but even if I create a while (true) loop and comment update() out, it's still printing similar result
I using DirectX 11 with vsync turned off for rendering (rendering inside update function):
g_pSwapChain->Present(0, 0);
How do I fix code to make update() stable called 30 times in one second?

I don't think casting to double is good idea.I would run something like this:
static LARGE_INTEGER last_time_s = { 0 };
::QueryPerformanceCounter(&cur_time_li);
time_diff_microsec.QuadPart = cur_time_li.QuadPart - last_time_s.QuadPart;
// To avoid precision lost, convert to seconds *before* dividing by ticks-per-second.
time_diff_microsec.QuadPart *= 1000000;
time_diff_microsec.QuadPart /= ticks_per_second.QuadPart;
double rate_s = 1 / 30.0f;
uint32_t slept_ms = 0;
if (time_diff_microsec.QuadPart >= rate_s)// if (diff_s < rate_s)
{
// slept_ms = (uint32_t)(rate_s - time_diff_microsec.LowPart);// *1000.0);
// ::Sleep(slept_ms);
//}
//update();
::printf("updated %lld %u\n", time_diff_microsec.QuadPart, slept_ms);
}
last_time_s.QuadPart = time_diff_microsec.QuadPart/ 1000000;
}
Just brief "sketch". Not verified that calculations are correct though.

Related

Arduino Programming adding milliseconds delay

So I'm trying to create an energy meter device which will read power every minute and then send it every 5 minutes through a LoRa server, using an MKR 1300 arduino. The problem is that as of now the hardware is removing a few milliseconds on the delay and so the time in the server ends up being p.e:
10:50:30
10:50:30
10:50:30
... 2 hours later
10:50:29
10:50:29
...
10:49:59
The code looks like this:
#include <MKRWAN.h>
#include "EmonLib.h"
LoRaModem modem;
String appEui = "1234567891011121";
String appKey = "ffffffffffffffffffffffffffffffff";
EnergyMonitor emon1;
EnergyMonitor emon2;
EnergyMonitor emon3;
double totalWatt;
int time_running;
int sending;
int totalKW;
int DELAY = 60000; // millis
void setup() {
Serial.begin(115200);
if (!modem.begin(EU868)) {
Serial.println("Failed to start module");
while (1) {}
};
Serial.print("Your module version is: ");
Serial.println(modem.version());
Serial.print("Your device EUI is: ");
Serial.println(modem.deviceEUI());
Serial.println("Connecting");
int connected = modem.joinOTAA(appEui, appKey);
if (!connected) {
Serial.println("Something went wrong; are you indoor? Move near a window and retry");
while (1) {}
}
Serial.println("Connected");
modem.minPollInterval(60);
analogReadResolution(9);
emon1.current(1, 53);
emon2.current(2, 53);
emon3.current(3, 53);
time_running = 0;
randomSeed(analogRead(A4));
}
void loop() {
unsigned long StartTime = millis();
totalWatt = 0;
unsigned long delay_send = 0;
int sending = 0;
double Irms1 = emon1.calcIrms(600);
if (Irms1 < 0.3) Irms1 = 0;
double Watt1 = Irms1 * 230;
double Irms2 = emon2.calcIrms(600);
if (Irms2 < 0.3) Irms2 = 0;
double Watt2 = Irms2 * 230;
double Irms3 = emon3.calcIrms(600);
if (Irms3 < 0.3) Irms3 = 0;
double Watt3 = Irms3 * 230;
totalWatt = Watt1 + Watt2 + Watt3;
totalKW = totalKW + totalWatt/1000;
if (time_running == 5) { //15 para 15 mins
double IrmsTotal = Irms1 +Irms2 + Irms3;
String msg = "{\"id\":\"avac_aud1\",\"kW\":"+String(totalKW)+", \"current\":"+String(IrmsTotal)+"}";
int err;
modem.beginPacket();
modem.print(msg);
err = modem.endPacket(true);
if (err > 0) {
//message sent correctly
time_running = 0;
totalKW = 0;
} else {
Serial.println("ERR");
time_running = 0;
}
}
time_running = time_running + 1;
if ((millis() - StartTime) > DELAY){
delay(10);
return;
} else{
delay(DELAY-(millis() - StartTime));
return;
}
}
I tried adding a variable ARD_DELAY (not shown above) to the code that in that last delay would subtract 7 to 8 milliseconds to try and fix this, but apparently, it only made it worse (now it removes 1 second every 1 hours instead of 2 hours) so today I'll try to add those 7 to 8 millis and see if it works, but I would really like to know why the heck this is happening because from what I can see from my code the delay should always account for the processed time including the data sending time.
Question is, how precise is your clock at all...
Still, I personally would rather go with the following approach:
#define DELAY (5UL * 60UL * 1000UL) // or whatever is appropriate...
static unsigned long timestamp = millis();
if(millis() - timestamp > DELAY)
{
// adding a fix constant will prevent accumulating deviations over time
timestamp += DELAY;
// run the every-5-min task...
}
Edit: combined 1-min and 5-min task:
Variant 1:
#define DELAY_SHORT (1UL * 60UL * 1000UL)
#define DELAY_LONG (5UL * 60UL * 1000UL)
static unsigned long timestampS = millis();
static unsigned long timestampL = timestampS;
if(millis() - timestampS > DELAY_SHORT)
{
timestamp += DELAY_SHORT;
// run the every-1-min task...
}
if(millis() - timestampL > DELAY_LONG)
{
timestamp += DELAY_LONG;
// run the every-5-min task...
}
Variant 2:
#define DELAY_1M (1UL * 60UL * 1000UL)
static unsigned long timestamp = millis();
if(millis() - timestamp > DELAY)
{
// adding a fix constant will prevent accumulating deviations over time
timestamp += DELAY;
// run the every-1-min task...
static unsigned int counter = 0;
if(++counter == 5)
{
counter = 0;
// run the every-5-min task...
}
}
Instead of trying to measure a start time and adding delay depending on that, you could keep track of the timing for your next cycle.
unsigned long next_cycle = DELAY;
...
void loop() {
...
delay( next_cycle - millis() );
next_cycle += DELAY;
}
If you also want to adjust for any time the program spends on initialization or similar, you can next_cycle = millis() + DELAY; before you enter your loop.

Waiting-time of thread switches systematicly between 0 and 30000 microseconds for the same task

I'm writing a little Console-Game-Engine and for better performance I wanted 2 threads (or more but 2 for this task) using two buffers. One thread is drawing the next frame in the first buffer while the other thread is reading the current frame from the second buffer. Then the buffers get swapped.
Of cause I can only swap them if both threads finished their task and the drawing/writing thread happened to be the one waiting. But the time it is waiting systematicly switches more or less between two values, here a few of the messurements I made (in microseconds):
0, 36968, 0, 36260, 0, 35762, 0, 38069, 0, 36584, 0, 36503
It's pretty obvious that this is not a coincidence but I wasn't able to figure out what the problem was as this is the first time I'm using threads.
Here the code, ask for more if you need it, I think it's too much to post it all:
header-file (Manager currently only adds a pointer to my WinAppBase-class):
class SwapChain : Manager
{
WORD *pScreenBuffer1, *pScreenBuffer2, *pWritePtr, *pReadPtr, *pTemp;
bool isRunning, writingFinished, readingFinished, initialized;
std::mutex lockWriting, lockReading;
std::condition_variable cvWriting, cvReading;
DWORD charsWritten;
COORD startPosition;
int screenBufferWidth;
// THREADS (USES NORMAL THREAD AS SECOND THREAD)
void ReadingThread();
// THIS FUNCTION IS ONLY FOR INTERN USE
void SwapBuffers();
public:
// USE THESE TO CONTROL WHEN THE BUFFERS GET SWAPPED
void BeginDraw();
void EndDraw();
// PUT PIXEL | INLINED FOR BETTER PERFORMANCE
inline void PutPixel(short xPos, short yPos, WORD color)
{
this->pWritePtr[(xPos * 2) + yPos * screenBufferWidth] = color;
this->pWritePtr[(xPos * 2) + yPos * screenBufferWidth + 1] = color;
}
// GENERAL CONTROL OVER SWAP CHAIN
void Initialize();
void Run();
void Stop();
// CONSTRUCTORS
SwapChain(WinAppBase * pAppBase);
virtual ~SwapChain();
};
Cpp-file
SwapChain::SwapChain(WinAppBase * pAppBase)
:
Manager(pAppBase)
{
this->isRunning = false;
this->initialized = false;
this->pReadPtr = NULL;
this->pScreenBuffer1 = NULL;
this->pScreenBuffer2 = NULL;
this->pWritePtr = NULL;
this->pTemp = NULL;
this->charsWritten = 0;
this->startPosition = { 0, 0 };
this->readingFinished = 0;
this->writingFinished = 0;
this->screenBufferWidth = this->pAppBase->screenBufferInfo.dwSize.X;
}
SwapChain::~SwapChain()
{
this->Stop();
if (_CrtIsValidHeapPointer(pReadPtr))
delete[] pReadPtr;
if (_CrtIsValidHeapPointer(pScreenBuffer1))
delete[] pScreenBuffer1;
if (_CrtIsValidHeapPointer(pScreenBuffer2))
delete[] pScreenBuffer2;
if (_CrtIsValidHeapPointer(pWritePtr))
delete[] pWritePtr;
}
void SwapChain::ReadingThread()
{
while (this->isRunning)
{
this->readingFinished = 0;
WriteConsoleOutputAttribute(
this->pAppBase->consoleCursor,
this->pReadPtr,
this->pAppBase->screenBufferSize,
this->startPosition,
&this->charsWritten
);
memset(this->pReadPtr, 0, this->pAppBase->screenBufferSize);
this->readingFinished = true;
this->cvWriting.notify_all();
if (!this->writingFinished)
{
std::unique_lock<std::mutex> lock(this->lockReading);
this->cvReading.wait(lock);
}
}
}
void SwapChain::SwapBuffers()
{
this->pTemp = this->pReadPtr;
this->pReadPtr = this->pWritePtr;
this->pWritePtr = this->pTemp;
this->pTemp = NULL;
}
void SwapChain::BeginDraw()
{
this->writingFinished = false;
}
void SwapChain::EndDraw()
{
TimePoint tpx1, tpx2;
tpx1 = Clock::now();
if (!this->readingFinished)
{
std::unique_lock<std::mutex> lock2(this->lockWriting);
this->cvWriting.wait(lock2);
}
tpx2 = Clock::now();
POST_DEBUG_MESSAGE(std::chrono::duration_cast<std::chrono::microseconds>(tpx2 - tpx1).count(), "EndDraw wating time");
SwapBuffers();
this->writingFinished = true;
this->cvReading.notify_all();
}
void SwapChain::Initialize()
{
if (this->initialized)
{
POST_DEBUG_MESSAGE(Result::CUSTOM, "multiple initialization");
return;
}
this->pScreenBuffer1 = (WORD *)malloc(sizeof(WORD) * this->pAppBase->screenBufferSize);
this->pScreenBuffer2 = (WORD *)malloc(sizeof(WORD) * this->pAppBase->screenBufferSize);
for (int i = 0; i < this->pAppBase->screenBufferSize; i++)
{
this->pScreenBuffer1[i] = 0x0000;
}
for (int i = 0; i < this->pAppBase->screenBufferSize; i++)
{
this->pScreenBuffer2[i] = 0x0000;
}
this->pWritePtr = pScreenBuffer1;
this->pReadPtr = pScreenBuffer2;
this->initialized = true;
}
void SwapChain::Run()
{
this->isRunning = true;
std::thread t1(&SwapChain::ReadingThread, this);
t1.detach();
}
void SwapChain::Stop()
{
this->isRunning = false;
}
This is where I run the SwapChain-class from:
void Application::Run()
{
this->engine.graphicsmanager.swapChain.Initialize();
Sprite<16, 16> sprite(&this->engine);
sprite.LoadSprite("engine/resources/TestData.xml", "root.test.sprites.baum");
this->engine.graphicsmanager.swapChain.Run();
int a, b, c;
for (int i = 0; i < 60; i++)
{
this->engine.graphicsmanager.swapChain.BeginDraw();
for (c = 0; c < 20; c++)
{
for (a = 0; a < 19; a++)
{
for (b = 0; b < 10; b++)
{
sprite.Print(a * 16, b * 16);
}
}
}
this->engine.graphicsmanager.swapChain.EndDraw();
}
this->engine.graphicsmanager.swapChain.Stop();
_getch();
}
The for-loops above simply draw the sprite 20 times from the top-left corner to the bottom-right corner of the console - the buffers don't get swapped during that, and that again for a total of 60 times (so the buffers get swapped 60 times).
sprite.Print uses the PutPixel function of SwapChain.
Here the WinAppBase (which consits more or less of global-like variables)
class WinAppBase
{
public:
// SCREENBUFFER
CONSOLE_SCREEN_BUFFER_INFO screenBufferInfo;
long screenBufferSize;
// CONSOLE
DWORD consoleMode;
HWND consoleWindow;
HANDLE consoleCursor;
HANDLE consoleInputHandle;
HANDLE consoleHandle;
CONSOLE_CURSOR_INFO consoleCursorInfo;
RECT consoleRect;
COORD consoleSize;
// FONT
CONSOLE_FONT_INFOEX fontInfo;
// MEMORY
char * pUserAccessDataPath;
public:
void reload();
WinAppBase();
virtual ~WinAppBase();
};
There are no errors, simply this alternating waitng time.
Maybe you'd like to start by looking if I did the synchronisation of the threads correctly? I'm not exactly sure how to use a mutex or condition-variables so it might comes from that.
Apart from that it is working fine, the sprites are shown as they should.
The clock you are using may have limited resolution. Here is a random example of a clock provided by Microsoft with 15 ms (15000 microsecond) resolution: Why are .NET timers limited to 15 ms resolution?
If one thread is often waiting for the other, it is entirely possible (assuming the above clock resolution) that it sometimes waits two clockticks and sometimes none. Maybe your clock only has 30 ms resolution. We really can't tell from the code. Do you get more precise measurements elsewhere with this clock?
There are also other systems in play such as the OS scheduler or whatever controls your std::threads. That one is (hopefully) much more granular, but how all these interactions play out doesn't have to be obvious or intuitive.

Pops / clicks when stopping and starting DirectX sound synth in C++ / MFC

I have made a soft synthesizer in Visual Studio 2012 with C++, MFC and DirectX. Despite having added code to rapidly fade out the sound I am experiencing popping / clicking when stopping playback (also when starting).
I copied the DirectX code from this project: http://www.codeproject.com/Articles/7474/Sound-Generator-How-to-create-alien-sounds-using-m
I'm not sure if I'm allowed to cut and paste all the code from the Code Project. Basically I use the Player class from that project as is, the instance of this class is called m_player in my code. The Stop member function in that class calls the Stop function of LPDIRECTSOUNDBUFFER:
void Player::Stop()
{
DWORD status;
if (m_lpDSBuffer == NULL)
return;
HRESULT hres = m_lpDSBuffer->GetStatus(&status);
if (FAILED(hres))
EXCEP(DirectSoundErr::GetErrDesc(hres), "Player::Stop GetStatus");
if ((status & DSBSTATUS_PLAYING) == DSBSTATUS_PLAYING)
{
hres = m_lpDSBuffer->Stop();
if (FAILED(hres))
EXCEP(DirectSoundErr::GetErrDesc(hres), "Player::Stop Stop");
}
}
Here is the notification code (with some supporting code) in my project that fills the sound buffer. Note that the rend function always returns a double between -1 to 1, m_ev_smps = 441, m_n_evs = 3 and m_ev_sz = 882. subInit is called from OnInitDialog:
#define FD_STEP 0.0005
#define SC_NOT_PLYD 0
#define SC_PLYNG 1
#define SC_FD_OUT 2
#define SC_FD_IN 3
#define SC_STPNG 4
#define SC_STPD 5
bool CMainDlg::subInit()
// initialises various variables and the sound player
{
Player *pPlayer;
SOUNDFORMAT format;
std::vector<DWORD> events;
int t, buf_sz;
try
{
pPlayer = new Player();
pPlayer->SetHWnd(m_hWnd);
m_player = pPlayer;
m_player->Init();
format.NbBitsPerSample = 16;
format.NbChannels = 1;
format.SamplingRate = 44100;
m_ev_smps = 441;
m_n_evs = 3;
m_smps = new short[m_ev_smps];
m_smp_scale = (int)pow(2, format.NbBitsPerSample - 1);
m_max_tm = (int)((double)m_ev_smps / (double)(format.SamplingRate * 1000));
m_ev_sz = m_ev_smps * format.NbBitsPerSample/8;
buf_sz = m_ev_sz * m_n_evs;
m_player->CreateSoundBuffer(format, buf_sz, 0);
m_player->SetSoundEventListener(this);
for(t = 0; t < m_n_evs; t++)
events.push_back((int)((t + 1)*m_ev_sz - m_ev_sz * 0.95));
m_player->CreateEventReadNotification(events);
m_status = SC_NOT_PLYD;
}
catch(MATExceptions &e)
{
MessageBox(e.getAllExceptionStr().c_str(), "Error initializing the sound player");
EndDialog(IDCANCEL);
return FALSE;
}
return TRUE;
}
void CMainDlg::Stop()
// stop playing
{
m_player->Stop();
m_status = SC_STPD;
}
void CMainDlg::OnBnClickedStop()
// causes fade out
{
m_status = SC_FD_OUT;
}
void CMainDlg::OnSoundPlayerNotify(int ev_num)
// render some sound samples and check for errors
{
ScopeGuardMutex guard(&m_mutex);
int s, end, begin, elapsed;
if (m_status != SC_STPNG)
{
begin = GetTickCount();
try
{
for(s = 0; s < m_ev_smps; s++)
{
m_smps[s] = (int)(m_synth->rend() * 32768 * m_fade);
if (m_status == SC_FD_IN)
{
m_fade += FD_STEP;
if (m_fade > 1)
{
m_fade = 1;
m_status = SC_PLYNG;
}
}
else if (m_status == SC_FD_OUT)
{
m_fade -= FD_STEP;
if (m_fade < 0)
{
m_fade = 0;
m_status = SC_STPNG;
}
}
}
}
catch(MATExceptions &e)
{
OutputDebugString(e.getAllExceptionStr().c_str());
}
try
{
m_player->Write(((ev_num + 1) % m_n_evs)*m_ev_sz, (unsigned char*)m_smps, m_ev_sz);
}
catch(MATExceptions &e)
{
OutputDebugString(e.getAllExceptionStr().c_str());
}
end = GetTickCount();
elapsed = end - begin;
if(elapsed > m_max_tm)
m_warn_msg.Format(_T("Warning! compute time: %dms"), elapsed);
else
m_warn_msg.Format(_T("compute time: %dms"), elapsed);
}
if (m_status == SC_STPNG)
Stop();
}
It seems like the buffer is not always sounding out when the stop button is clicked. I don't have any specific code for waiting for the sound buffer to finish playing before the DirectX Stop is called. Other than that the sound playback is working just fine, so at least I am initialising the player correctly and notification code is working in that respect.
Try replacing 32768 with 32767. Not by any means sure this is your issue, but it could overflow the positive short int range (assuming your audio is 16-bit) and cause a "pop".
I got rid of the pops / clicks when stopping playback, by filling the buffer with zeros after the fade out. However I still get pops when re-starting playback, despite filling with zeros and then fading back in (it is frustrating).

How to find out the next time when the clock will be adjusted for Daylight Saving?

I'm curious, if there's any way to find out the UTC date/time when the next Daylight Saving adjustment will take place?
Something akin to what Windows reports (see circled):
This information is provided in Windows by the EnumDynamicTimeZoneInformation function.
See http://msdn.microsoft.com/en-us/library/windows/desktop/hh706893%28v=vs.85%29.aspx
There is a database that has code and data: http://www.iana.org/time-zones
I don't think there's a specific API for this. I would just do a binary search, using localtime (and maybe time and mktime) from <ctime> (C++) or <time.h> (C).
A basic approach is to scan ahead three months at a time until the tm_isdst flag in the returned data structure is flipped. Then you can start binary searching between the last two two dates to figure out exactly when it flips.
See http://www.cplusplus.com/reference/ctime/tm/ for reference material.
I appreciate all your replies. And, yes, indeed I was asking about a WinAPI for Windows.
I did more research and came up with the following method that does what I wanted. It uses C++ and MFC's COleDateTime for easier date/time calculations. Other than that it's just C++ and WinAPIs. Please check if I understood the documentation for the DYNAMIC_TIME_ZONE_INFORMATION correctly. Here's the code:
int GetNextDaylightSavingAdjustmentTime(SYSTEMTIME* pOutDtNextDST_Local, int* pnOutAdjustmentMin)
{
//Get next time when DST adjustment will take place
//'pOutDtNextDST_Local' = if not NULL, receives the (local) time when next DST adjustment will take place
//'pnOutAdjustmentMin' = if not NULL, receives the amount of adjustment in minutes
//RETURN:
// = 1 if got the time, or
// = 0 if DST is not used
// = -1 if error (check GetLastError() for info)
int nOSError = NO_ERROR;
//Load API dynamically (in case of Windows XP)
BOOL (WINAPI *pfnGetDynamicTimeZoneInformation)(PDYNAMIC_TIME_ZONE_INFORMATION);
(FARPROC&)pfnGetDynamicTimeZoneInformation =
::GetProcAddress(::GetModuleHandle(L"Kernel32.dll"), "GetDynamicTimeZoneInformation");
DWORD tzID;
SYSTEMTIME StandardDate;
SYSTEMTIME DaylightDate;
int nBiasDaylight;
//Use newer API if possible
if(pfnGetDynamicTimeZoneInformation)
{
DYNAMIC_TIME_ZONE_INFORMATION dtzi = {0};
tzID = pfnGetDynamicTimeZoneInformation(&dtzi);
StandardDate = dtzi.StandardDate;
DaylightDate = dtzi.DaylightDate;
nBiasDaylight = dtzi.DaylightBias;
}
else
{
//Older API
TIME_ZONE_INFORMATION tzi = {0};
tzID = GetTimeZoneInformation(&tzi);
StandardDate = tzi.StandardDate;
DaylightDate = tzi.DaylightDate;
nBiasDaylight = tzi.DaylightBias;
}
int nRes = -1;
int nAdjMins = 0;
SYSTEMTIME stDstChange;
memset(&stDstChange, 0, sizeof(stDstChange));
SYSTEMTIME stDst;
if(tzID == TIME_ZONE_ID_STANDARD ||
tzID == TIME_ZONE_ID_DAYLIGHT)
{
stDst = tzID != TIME_ZONE_ID_DAYLIGHT ? DaylightDate : StandardDate;
if(stDst.wMonth >= 1 &&
stDst.wMonth <= 12 &&
stDst.wDay >= 1 &&
stDst.wDayOfWeek >= 0 &&
stDst.wDayOfWeek <= 6)
{
//Get adjustment bias
nAdjMins = tzID != TIME_ZONE_ID_DAYLIGHT ? -nBiasDaylight : nBiasDaylight;
if(stDst.wYear == 0)
{
//Relative date
SYSTEMTIME stLocal;
::GetLocalTime(&stLocal);
//Begin from the 1st day of the month &
//make sure that the date is in the future
COleDateTime dt;
for(int nYear = stLocal.wYear;; nYear++)
{
dt.SetDateTime(nYear, stDst.wMonth, 1, stDst.wHour, stDst.wMinute, stDst.wSecond);
if(dt > COleDateTime::GetCurrentTime())
break;
}
int nRequiredWeek = stDst.wDay >= 1 && stDst.wDay <= 5 ? stDst.wDay : 5;
for(int nCntDOW = 1;;)
{
//0=Sunday, 1=Monday; 2=Tuesday; 3=Wednesday; 4=Thursday; 5=Friday; 6=Saturday
int dow = dt.GetDayOfWeek() - 1;
ASSERT(dow >= 0 && dow <= 6);
if(dow == stDst.wDayOfWeek)
{
if(nCntDOW >= nRequiredWeek)
{
//Stop
break;
}
else
{
nCntDOW++;
}
}
//Go to next day
dt += COleDateTimeSpan(1, 0, 0, 0);
}
//Convert back to system time
if(dt.GetAsSystemTime(stDstChange))
{
//Success
nRes = 1;
}
else
{
//Failed
nOSError = ERROR_INVALID_FUNCTION;
ASSERT(NULL);
}
}
else
{
//Absolute date
stDstChange = stDst;
nRes = 1;
}
}
else
{
//Failed
nOSError = ERROR_INVALID_PARAMETER;
ASSERT(NULL);
}
}
else
{
//DST is not used
if(tzID == TIME_ZONE_ID_UNKNOWN)
{
nRes = 0;
}
else
{
//Error
nOSError = ERROR_INVALID_DATA;
ASSERT(NULL);
}
}
if(pOutDtNextDST_Local)
*pOutDtNextDST_Local = stDstChange;
if(pnOutAdjustmentMin)
*pnOutAdjustmentMin = nAdjMins;
::SetLastError(nOSError);
return nRes;
}
PS. And scratch my request for the UTC time. As I learned, it is easier to deal with local time in this situation.

Steptimer.getTotalSeconds within steptimer.h returning 0, c++ visual studio 2013, directx app

I'm trying to use the given code within steptimer.h to set up code that will run every two seconds. However with the code below, timer.GetTotalSeconds() always returns 0.
Unfortunately there isn't much information readily available on StepTimer.h (at least I believe due to a lack of useful search results), so I was hoping someone might be able to shed some light as to why the timer isn't recording the elapsed seconds. Am I using it incorrectly?
Code from Game.h, Game.cpp and StepTimer.h are included below. Any help is greatly appreciated.
From Game.cpp:
double time = timer.GetTotalSeconds();
if (time >= 2) {
laser_power++;
timer.ResetElapsedTime();
}
Initialised in Game.h:
DX::StepTimer timer;
From Common/StepTimer.h:
#pragma once
#include <wrl.h>
namespace DX
{
// Helper class for animation and simulation timing.
class StepTimer
{
public:
StepTimer() :
m_elapsedTicks(0),
m_totalTicks(0),
m_leftOverTicks(0),
m_frameCount(0),
m_framesPerSecond(0),
m_framesThisSecond(0),
m_qpcSecondCounter(0),
m_isFixedTimeStep(false),
m_targetElapsedTicks(TicksPerSecond / 60)
{
if (!QueryPerformanceFrequency(&m_qpcFrequency))
{
throw ref new Platform::FailureException();
}
if (!QueryPerformanceCounter(&m_qpcLastTime))
{
throw ref new Platform::FailureException();
}
// Initialize max delta to 1/10 of a second.
m_qpcMaxDelta = m_qpcFrequency.QuadPart / 10;
}
// Get elapsed time since the previous Update call.
uint64 GetElapsedTicks() const { return m_elapsedTicks; }
double GetElapsedSeconds() const { return TicksToSeconds(m_elapsedTicks); }
// Get total time since the start of the program.
uint64 GetTotalTicks() const { return m_totalTicks; }
double GetTotalSeconds() const { return TicksToSeconds(m_totalTicks); }
// Get total number of updates since start of the program.
uint32 GetFrameCount() const { return m_frameCount; }
// Get the current framerate.
uint32 GetFramesPerSecond() const { return m_framesPerSecond; }
// Set whether to use fixed or variable timestep mode.
void SetFixedTimeStep(bool isFixedTimestep) { m_isFixedTimeStep = isFixedTimestep; }
// Set how often to call Update when in fixed timestep mode.
void SetTargetElapsedTicks(uint64 targetElapsed) { m_targetElapsedTicks = targetElapsed; }
void SetTargetElapsedSeconds(double targetElapsed) { m_targetElapsedTicks = SecondsToTicks(targetElapsed); }
// Integer format represents time using 10,000,000 ticks per second.
static const uint64 TicksPerSecond = 10000000;
static double TicksToSeconds(uint64 ticks) { return static_cast<double>(ticks) / TicksPerSecond; }
static uint64 SecondsToTicks(double seconds) { return static_cast<uint64>(seconds * TicksPerSecond); }
// After an intentional timing discontinuity (for instance a blocking IO operation)
// call this to avoid having the fixed timestep logic attempt a set of catch-up
// Update calls.
void ResetElapsedTime()
{
if (!QueryPerformanceCounter(&m_qpcLastTime))
{
throw ref new Platform::FailureException();
}
m_leftOverTicks = 0;
m_framesPerSecond = 0;
m_framesThisSecond = 0;
m_qpcSecondCounter = 0;
}
// Update timer state, calling the specified Update function the appropriate number of times.
template<typename TUpdate>
void Tick(const TUpdate& update)
{
// Query the current time.
LARGE_INTEGER currentTime;
if (!QueryPerformanceCounter(&currentTime))
{
throw ref new Platform::FailureException();
}
uint64 timeDelta = currentTime.QuadPart - m_qpcLastTime.QuadPart;
m_qpcLastTime = currentTime;
m_qpcSecondCounter += timeDelta;
// Clamp excessively large time deltas (e.g. after paused in the debugger).
if (timeDelta > m_qpcMaxDelta)
{
timeDelta = m_qpcMaxDelta;
}
// Convert QPC units into a canonical tick format. This cannot overflow due to the previous clamp.
timeDelta *= TicksPerSecond;
timeDelta /= m_qpcFrequency.QuadPart;
uint32 lastFrameCount = m_frameCount;
if (m_isFixedTimeStep)
{
// Fixed timestep update logic
// If the app is running very close to the target elapsed time (within 1/4 of a millisecond) just clamp
// the clock to exactly match the target value. This prevents tiny and irrelevant errors
// from accumulating over time. Without this clamping, a game that requested a 60 fps
// fixed update, running with vsync enabled on a 59.94 NTSC display, would eventually
// accumulate enough tiny errors that it would drop a frame. It is better to just round
// small deviations down to zero to leave things running smoothly.
if (abs(static_cast<int64>(timeDelta - m_targetElapsedTicks)) < TicksPerSecond / 4000)
{
timeDelta = m_targetElapsedTicks;
}
m_leftOverTicks += timeDelta;
while (m_leftOverTicks >= m_targetElapsedTicks)
{
m_elapsedTicks = m_targetElapsedTicks;
m_totalTicks += m_targetElapsedTicks;
m_leftOverTicks -= m_targetElapsedTicks;
m_frameCount++;
update();
}
}
else
{
// Variable timestep update logic.
m_elapsedTicks = timeDelta;
m_totalTicks += timeDelta;
m_leftOverTicks = 0;
m_frameCount++;
update();
}
// Track the current framerate.
if (m_frameCount != lastFrameCount)
{
m_framesThisSecond++;
}
if (m_qpcSecondCounter >= static_cast<uint64>(m_qpcFrequency.QuadPart))
{
m_framesPerSecond = m_framesThisSecond;
m_framesThisSecond = 0;
m_qpcSecondCounter %= m_qpcFrequency.QuadPart;
}
}
private:
// Source timing data uses QPC units.
LARGE_INTEGER m_qpcFrequency;
LARGE_INTEGER m_qpcLastTime;
uint64 m_qpcMaxDelta;
// Derived timing data uses a canonical tick format.
uint64 m_elapsedTicks;
uint64 m_totalTicks;
uint64 m_leftOverTicks;
// Members for tracking the framerate.
uint32 m_frameCount;
uint32 m_framesPerSecond;
uint32 m_framesThisSecond;
uint64 m_qpcSecondCounter;
// Members for configuring fixed timestep mode.
bool m_isFixedTimeStep;
uint64 m_targetElapsedTicks;
};
}
Alrighty got what I wanted with the code below. Was missing the .Tick(####) call.
timer.Tick([&]() {
double time = timer.GetTotalSeconds();
if (time >= checkpt) {
laser_power++;
checkpt += 2;
}
});
Just fixed an integer checkpt to increment by 2 each time so that it runs every 2 seconds. There's probably a better way to do it, but it's 3.30am so I'm being lazy for the sake of putting my mind at ease.