Re: while loop w/ sleep(1) doesnt work
I guess what I am saying is that Windows is not an RTOS #1 and #2 that not every version of Windows will provide what you need if you are using a thread. Windows XP will not be able to create a thread that reliably polls at the rate of 1ms. Windows Vista may be able to do this *more* reliably for you since it has been enchanced for multi-media purposes.
Windows XP has a 10 ms quantum.
Windiws Vista has 1 ms.
As a side note, Windows 9X and Me have 55ms quantum.
I have had speedier results with SetTimer than with threads.
There are those who believe that sleep() with a parameter of > 0 is evil.
eg: http://www.flounder.com/time.htm
Re: while loop w/ sleep(1) doesnt work
Quote:
Originally Posted by
acerunner316
i know about the canReadWait() function for kvaser. However, my app must also work with a few other CAN adapters that are user selectable. The APIs for these other devices do not have an equivalent function, so i have to write something in my app to do it.
I have worked with a variety of CAN bus products over the past decade, and have never seen a commercial driver/library package that did NOT support notification. A few (typically raw, older ones) required an update in order for the adapter to generate a system interrupt..
Re: while loop w/ sleep(1) doesnt work
Don't the other libraries have anything similar to this that you can use? http://www.kvaser.com/support/prodhe...m#using_handle
Re: while loop w/ sleep(1) doesnt work
Quote:
Originally Posted by
VladimirF
Also, the “busy wait” is only wrong if you are counting crows in your loop. If you have something like that:
Code:
while(!canRead())
;
not sure what you mean by "counting crow", but this is how this part of my program works
In response to user clicking start button, I do this:
while (!sequence complete)
{
//fill local buffer of CAN messages from hardware buffer using canRead()
//search buffer for reply to cmd
//if reply exist, send next cmd
//if reply doesn't exist, continue loop to read more messages
//sleep(1ms) to allow hardware buffer to fill
}
there's a lot more going on, but this is a very basic summary.
Re: while loop w/ sleep(1) doesnt work
Quote:
Originally Posted by
Codeplug
>> it's single thread.
If you're not familiar with it, making it multi-threaded may add more complications than you care to deal with right now. But without it, you'll need to find a way to keep the UI responsive while handling CAN communications.
The single threaded approach wouldn't be too hard if, for example, you had a modal dialog with a cancel button and some sort of progress indicator. You would then use a special message loop just for this modal dialog. This special message loop would periodically pump messages while handling CAN message/response pairs.
gg
no, i'm not familiar with multi-threading. I realize that's probably the better way to go in this situation...
Can you elaborate on the modal dialog method? thanks
Re: while loop w/ sleep(1) doesnt work
Quote:
Originally Posted by
ahoodin
I have had speedier results with SetTimer than with threads.
That's odd, I've tried using the SetTimer, and it is much much slower.
Btw, I'm running on a XP system.
Re: while loop w/ sleep(1) doesnt work
Quote:
Originally Posted by
TheCPUWizard
I have worked with a variety of CAN bus products over the past decade, and have never seen a commercial driver/library package that did NOT support notification. A few (typically raw, older ones) required an update in order for the adapter to generate a system interrupt..
I am using Kvaser, VectorCAN, and PeakCAN. If you know of such a function in those libraries, please advise. Thanks!
Re: while loop w/ sleep(1) doesnt work
Quote:
Originally Posted by
acerunner316
I am writing a software that periodically checks for CAN messages through calls to the driver libraries. And I must perform actions depending on the CAN messages I see.
At first I used a system timer and function call in response to the windows message WM_TIMER.
(i.e. SetTimer(1,10,NULL) and OnTimer() function where the processing of the messages occur.)
But that solution has proven to be too slow, and I need a faster loop. So I though to use a while loop with a sleep of 1ms so as not to lock up the cpu. However, I've read that the sleep interval can only be as low as 15ms, and anything below that will sleep for 15ms.
How can I create a faster loop without using all cpu resources?
long ago i had to do a similar thing and this is what i ended up doing:
Code:
HANDLE CMainFrame::m_hPortNotificationEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
// This sets up an event to notify the application if there
// are messages in the port‘s receive queue.
m_vErr = ncdSetNotification(m_vPortHandle,
(unsigned long *)&m_hPortNotificationEvent,
QUEUE_LEVEL);
if (m_vErr)
Error(m_vErr);
// then i created a thread in suspended state
// code inside the thread
DWORD WINAPI CMainFrame::ReceiveData(LPVOID pVoid)
{
DWORD dwResult = 0;
Vstatus vErr = 0;
Vevent *pEvent = NULL;
float fTimeStamp = 0;
char chTemp[100] = {0};
unsigned long ulMSGId = 0;
char chDataField[40] = {0};
CMainFrame *pThis = static_cast<CMainFrame *>(pVoid);
while(TRUE)
{
dwResult = WaitForSingleObject(m_hPortNotificationEvent, INFINITE);
switch(dwResult)
{
case WAIT_OBJECT_0:
// receive
for (;;) // read all events
{
vErr = ncdReceive1(m_vPortHandle,&pEvent);
if (vErr && vErr != VERR_QUEUE_IS_EMPTY)
{
if(pThis != NULL)
{
::MessageBox(pThis->m_hWnd, "A severe error has occured.\nHardware not present or badly installed.\nCheck (PCMCIA, Tranceiver cable, Connection to the MODAC) and try again.\nApplication will exit!",
IDS_S3,
MB_ICONERROR);
::SendMessage(pThis->m_hWnd, WM_CLOSE, 0, 0);
}
}
if (vErr == VERR_QUEUE_IS_EMPTY)
break;
if (pEvent->tag == V_RECEIVE_MSG)
{.......
if you're working with Vector's CANCard library all this should be familiar to you...
Re: while loop w/ sleep(1) doesnt work
Quote:
Originally Posted by
acerunner316
I am using Kvaser, VectorCAN, and PeakCAN. If you know of such a function in those libraries, please advise. Thanks!
PeakCAN (which is ancient) does not. Typically this driver is best used on a thread wtih Huerestic delays.
VectorCAN I cant find my documentation on, and most of the time I used it was with LabView (which has its own dedicated driver
Kvaser we already determined does have it....
Sounds like time for a decent class hierarchy and some background thread processing.
Re: while loop w/ sleep(1) doesnt work
So I found documentation for all 3:
I downloaded the "CAN Driver Library" from Vector here: https://www.vector-worldwide.com/vi_...center_en.html
It has a "VCAND.pdf" documenting their API, including the functions that Alin showed us.
I downloaded the "PCAN-PCI package" from Peak here: http://www.peak-system.com/Support.55.0.html?&L=1
It has a "PCANLight_enu.chm" that documents its API. It is indeed a bare-bones API. The MFC sample that comes with it actually polls using SetTimer().
And (again) the Kvaser API is documented online: http://www.kvaser.com/support/prodhelp/canlib38/
So I wanted to get that out there and available to readers of this thread.
Quote:
Originally Posted by
acerunner316
In response to user clicking start button, I do this:
Code:
while (!sequence complete)
{
//fill local buffer of CAN messages from hardware buffer using canRead()
//search buffer for reply to cmd
//if reply exist, send next cmd
//if reply doesn't exist, continue loop to read more messages
//sleep(1ms) to allow hardware buffer to fill
}
Getting back to your original issue - that you "need a faster loop" - Remove all calls to Sleep(). That's just wasting time. Instead, use canReadWait() with an arbitrary timeout (say 20ms) and let the loop run as fast as it wants to.
Under Vector, you can achieve the same effect of canReadWait(20ms) by setting up a notification event and calling "WaitForSingleObject(m_hPortNotificationEvent, 20)" (using Alin's code).
Under Peak, there is no "efficient waiting" for a message. My first attempt at this would be to create my own "canReadWait()" with something like this:
Code:
inline DWORD TimeElapsed(DWORD start, DWORD end)
{
if (end < start)
return (0xFFFFFFFF - start) + end;
return end - start;
}//TimeElapsed
DWORD Peak_canReadWait(TPCANMsg *MsgBuff, DWORD timeout)
{
DWORD res = CAN_Read(MsgBuff);
if (res == CAN_ERR_QRCVEMPTY)
{
DWORD start = GetTickCount();
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
for (;;)
{
res = CAN_Read(MsgBuff);
if (res != CAN_ERR_QRCVEMPTY)
break;
if (TimeElapsed(start, GetTickCount()) >= timeout)
break;
}//for
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
}//if
return res;
}//Peak_canReadWait
Here we are still letting the loop run as fast as it wants (no sleeps). This will show a lot of CPU utilization, but at least you'll be "playing nicer" by lowering the priority while polling.
>> Can you elaborate on the modal dialog method?
It doesn't necessarily require a modal dialog. It's just a way to allow for user input and read from the device in a single thread. In other words, it would allow you to have a "Cancel" button to allow the user to break out of the "while (!sequence complete)" loop.
gg
Re: while loop w/ sleep(1) doesnt work
codeplug, thanks for the details explanations and the code sample.
I've implemented the CanReadWait taht you describe above. Everything seems to work ok.
However, I have a read-only editbox that displays status and percentage of the entire procedure, and this doesn't update anymore. It goes up to about 10% and freezes. By looking at the CAN messages on a seperate software, I can see that the app is still running, only the interface seems to have frozen. If I click anything, the windows title displays the legendary "(not responding)" message until the entire process is done and I exist the while loop. Is there anyway to fix this?
Thanks
Re: while loop w/ sleep(1) doesnt work
Quote:
Originally Posted by
acerunner316
codeplug, thanks for the details explanations and the code sample.
I've implemented the CanReadWait taht you describe above. Everything seems to work ok.
However, I have a read-only editbox that displays status and percentage of the entire procedure, and this doesn't update anymore. It goes up to about 10% and freezes. By looking at the CAN messages on a seperate software, I can see that the app is still running, only the interface seems to have frozen. If I click anything, the windows title displays the legendary "(not responding)" message until the entire process is done and I exist the while loop. Is there anyway to fix this?
Thanks
did you at least take a look at my post? CAN messages are coming in way too fast for your interface to be responsive, so that's why you should be using a worker thread to do all the CAN processing and PostMessage to the UI when there is something you need to display.
Re: while loop w/ sleep(1) doesnt work
alin, yes I did read your post. thanks for that btw.
I am not familiar with multi-threading. I have only ever written simple dialog-based apps that perform a single task for each control item. Is multithreads the only way to go with what I'm trying to do here?
thanks
Re: while loop w/ sleep(1) doesnt work
Multithreading is hardly ever the only way, but it's often the most convenient. And with the trend towards multi-core architectures, it's just a good skill to have in any case.
Re: while loop w/ sleep(1) doesnt work
any recommendations on where I should start learning multi thread programming. Given that I am a self-taught programmer...well, windows programming. I learned intro C++ in school.