4

I need to read a message coming from a CAN network every 20ms. For this purpose I made a function which works defined below. It's kind of work around, but does the job.

    public void Read_CAN_RC_Message()
    {
        bool a = true;
        while (a)
        {
            Stopwatch t = Stopwatch.StartNew();
            // My actual Function Starts Here
            int rMulti = CANbus.CAN_Receive_multiple_nonblock(recieveMsg, 5);

            if (0 < rMulti)
            {
                count++;

                for (int k = 0; k < rMulti; k++)
                {
                    if (recieveMsg[k].id == 0x400)
                    {
                        currentX = 0;
                        currentY = 0;
                        currentX = currentX | recieveMsg[k].data[3];
                        currentX = (currentX << 8) | recieveMsg[k].data[2];
                        currentX = (currentX << 8) | recieveMsg[k].data[1];
                        currentX = (currentX << 8) | recieveMsg[k].data[0];
                        currentY = currentY | recieveMsg[k].data[7];
                        currentY = (currentY << 8) | recieveMsg[k].data[6];
                        currentY = (currentY << 8) | recieveMsg[k].data[5];
                        currentY = (currentY << 8) | recieveMsg[k].data[4];
                    }
                // Function Ends here
                int timestep = t.Elapsed.Milliseconds; // To measure Time Needded to complete the Operation
                timeCheck.Rows.Add(timestep,str);             

            }
            while (t.Elapsed < timer20ms)
            {
                // Nothing
            }
        }
    }

I soon realized that the operation takes 2ms to complete and for remaining 18ms my processor is stuck in an infinite loop. So this operation requires its own separate thread which always works (using the Processor). Is there a neater a more professional way to do this. Please suggest. I need to run this application in a separate thread as it has to run always as soon as the application starts till it shuts down.

Abhishek Kumar
  • 342
  • 5
  • 22

5 Answers5

2

Use the Timer class. You can make it call your function every 20ms.

https://msdn.microsoft.com/en-us/library/system.threading.timer(v=vs.110).aspx

idstam
  • 2,848
  • 1
  • 21
  • 30
  • I am slightly confused on MSDN page. To say it lightly, I have never found it user friendly specially for the beginners. Can you please give an example. Thank you. – Abhishek Kumar Nov 03 '15 at 14:58
  • Keep in mind that the default Threading.Timer resolution in Windows varies by OS, but is usually15.6ms by default. This means you will NOT be able to get accurate ticks right on the 20ms boundary. It is possible to change the timer resolution to 1ms using p/Invoke like this https://stackoverflow.com/questions/15071359/how-to-set-timer-resolution-from-c-sharp-to-1-ms This is a **SYSTEM GLOBAL** setting though, not per process. – Bradley Uffner Nov 03 '15 at 15:07
  • 1
    Upon further reading, it looks like System.Threading.Timer doesn't even use the System Timer Resolution setting. It may be hard coded at 15.6ms as discussed here https://stackoverflow.com/questions/23215970/system-threading-timer-vs-system-threading-thread-sleep-resolution-net-timer – Bradley Uffner Nov 03 '15 at 15:11
  • It indeed is restricted to 15.6 ms. If I fix my cycle at 31 ms it works so good, but for 20 ms it creates an issue. it also works perfectly for 15ms cycle. Please help guys. I need 20 ms not 15 not 30. Heeeeelpieeee – Abhishek Kumar Nov 03 '15 at 16:14
1

you can use the Timer with 20ms Timer_Elpased. Or you can put your thread in sleep mode for 15-20 milli secs. Thread.Sleep(20)

Jigneshk
  • 350
  • 1
  • 7
  • I do not think its good to make thread sleep cyclically. Also, Its risky to make the thread sleep for a defined period. What if my process takes 25 milliseconds to complete. So I would refrain from doing so. – Abhishek Kumar Nov 03 '15 at 15:01
  • If you put the timer for 20 ms and process take 25 ms. In this case, you are still in middle of execution and same function call again. This is extremely bad, because you have to sync between 2 calls. Now I realize thread is good option. If it takes time, it takes time you cannot control it. But you can avoid the overlapping in Thread. – Jigneshk Nov 03 '15 at 15:07
  • The typical method for stopping a timer from overlapping its self is to make it a non-repeating timer, wrap its work in a stopwatch to measure elapsed time, then reset the timer to InitialTickInterval - EllapsedStopWatchTime and fire it off again when it completes its work. – Bradley Uffner Nov 03 '15 at 15:16
  • @BradleyUffner I did almost the same thing in my code. I saw the elapsed time using a Stopwatch. – Abhishek Kumar Nov 03 '15 at 15:21
0

I found a solution at other website. I am placing the Link, I have tested this and it works amazingly http://www.codeproject.com/Articles/98346/Microsecond-and-Millisecond-NET-Timer Hope it will help people in future. Thanks for all your help. It is really appreciated. @idstam Thanks for sending me the MSDN Link. It taught me a thing or two.

Abhishek Kumar
  • 342
  • 5
  • 22
0

In case of device that send data periodicaly you must use asynchronous way to get data.

To provide you complete solution or advice, show the full contract of CANbus dll.

Also it would be better if you explained the main task.

gabba
  • 2,815
  • 2
  • 27
  • 48
  • `CANbus.CAN_Receive_multiple_nonblock` is an External Function. I use it from an unmanaged dll. I am not able to understand your answer. I am flabbergasted to say the least. It just passed over my head. – Abhishek Kumar Nov 04 '15 at 12:17
  • @AbhishekKumar, I appologize for incomprehensible answer. Could you describe more detail interface of CANbus and tell why you need to read data exact evrery 20ms? CAN_Receive_multiple_nonblock provide you a bunch of messages. – gabba Nov 04 '15 at 16:54
  • CAN communication is a standardized protocol used in Automotive Industries. I use CAN J1939 Protocol for communication. I need 20 ms resolution as the device I am communicating with is an Embedded Controller which has a fixed cycle time. `CAN_Receive_multiple_nonblock` reads all the message in the communication queue till the queue is empty. Basically all the messages sent in one cycle from the Embedded Controller are read by this function. I have accomplished it. Please refer my answer. I found it on internet. I has tested it and it works spot on. Thanks for your politeness. Its rare. – Abhishek Kumar Nov 05 '15 at 06:55
  • @AbhishekKumar, I asked you about interface of "unmanaged dll" that you use to call extternal function "CANbus.CAN_Receive_multiple_nonblock". Probably it have async method that can provide you data right after it appearance. It is good that you have worked solution. I just tell that better not to do synchronization on high level. – gabba Nov 05 '15 at 10:28
  • Dear Gabba. No no such thing is there. I have looked at it and then only gone to this solution. Or else I would use that as an event to read the new messages. – Abhishek Kumar Nov 05 '15 at 11:02
0

I recommend Thread.Sleep with a few additional tricks:

  1. Request a high timer resolution: MSDN: Obtaining and Setting Timer Resolution. You can probably find the C# signatures on pinvoke.net

  2. Use the Stopwatch class to calculate the length of the wait period. Do not call Sleep if the period is less than 1ms.

  3. Increase your thread priority using the Thread class

  4. Do expensive calculations on another thread if possible.

  5. Optional: Use busy waiting after Thread.Sleep for up to 1 ms in order to get better pricision. Use Thread.SpinWait for this.

Combining 1. and 2. gave me enough precision to implement a frame brake for a game without causing stutter/lag.

Zotta
  • 2,513
  • 1
  • 21
  • 27