This question already has answers here:
How to Call Windows API [duplicate]
(2 answers)
how to set timer resolution from C# to 1 ms?
(2 answers)
Closed 2 years ago.
I have a WPF application that controls a robot arm. It's also a human-in-the-loop system. So I would like it to be as close to real time as possible. I am using a DispatcherTimer to generate a "tick" regularly to update the robot arm. Sort of like a poor mans Gameloop:
public partial class MainWindow : Window
{
DispatcherTimer Timer;
public MainWindow()
{
InitializeComponent();
Timer = new DispatcherTimer(DispatcherPriority.Send);
Timer.Interval = TimeSpan.FromMilliseconds(10);
Timer.Tick += new EventHandler(OnTick);
}
private void OnTick(object sender, EventArgs e)
{
//1.Read input devices
//2.Do calculations
//3.Move robot arm
}
}
To be as near to real time as possible, this tick has to be generated as fast as possible, but because of limitations in Windows, the line...
Timer.Interval = TimeSpan.FromMilliseconds(10);
...has no real effect for values under ~15. It is limited by the fact that Windows schedules the "sleeps" and "wakes" of threads in 15.6ms intervals as explained nicely by Bruce Dawson here.
But, as is also explained in this article, this default scheduling interval can be changed by calling timeBeginPeriod in timeapi.h
Can someone show or point me to an example how to call WinAPI functions, like timeBeginPeriod(10); from a WPF application?
Related
I have a Windows forms application that I am trying to add accessibility to and have run into an issue with the speech synthesizer where it appears that the SpeechAsyncCancelAll runs in the user interface thread. Performance is totally dependent on the power of the PC.
This can be reproduced with a very simple application in Windows forms.
Create a form and add a numeric up down control. Then use this code:
using System.Windows.Forms;
using System.Speech;
using System.Speech.Synthesis;
namespace WindowsFormsApp8
{
public partial class Form1 : Form
{
SpeechSynthesizer _speech = new SpeechSynthesizer();
public Form1()
{
InitializeComponent();
}
private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
_speech.SpeakAsyncCancelAll();
_speech.SpeakAsync(numericUpDown1.Value.ToString());
}
}
}
On my development machine which is very powerful it runs without a problem and very fast when you hold down the up arrow. Each value is cancelled so you do not hear anything as the control increments and when you stop pressing the up arrow it announces the last value properly.
However, the minute this is run on a lesser PC, even a core i9 hexacore machine, the repeat on the increment slows to a crawl.
It looks to me that this is running on the user interface thread.
Any suggestions?
Thanks
Don't get yourself tricked by the "Async" in the name of the SpeakAsyncCancelAll() method name. As one can see in the source code of the SpeechSynthesizer and VoiceSynthesis classes, there is quite some synchronous code involved in order to communicate with a background thread that does the actual voice synthesis. This code is actually quite heavy in that it uses multiple lock statements.
A best practice solution for this situation (multiple successive user interactions could create a series of code reactions but in the end we only want the last one) is to not directly start the reaction, but start a timer and only perform the reaction if there was no other user interaction in the meantime.
public partial class Form1 : Form
{
private SpeechSynthesizer _speech = new SpeechSynthesizer();
public Form1()
{
InitializeComponent();
timer1.Interval = 500;
}
private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
// Reset timer
timer1.Stop();
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
timer1.Stop();
_speech.SpeakAsyncCancelAll();
_speech.SpeakAsync(numericUpDown1.Value.ToString());
}
}
You should allow the user to configure the timer interval to chose a good compromise based on their system performance and their individual usage patterns. People who need audio assistance often consider for good reasons a too long delay between user activity and an audio response as wasting their time. So it is important that users can configure such a delay to best fit their individual needs.
Let's assume you have taken Neil's excellent comment into consideration, and checked the repeat rate of the NumericUpDown control on the other PCs "without" calling the speech engine. Good.
Your code looks right. The SpeakAsyncCancelAll and SpeakAsync do not block and are "expected" to be running on a background thread. When I attempted to reproduce the problem (not a shocker) your code works fine on my PC using the test condition you describe. That being the case, maybe you could try a couple of variations on the slim chance that something makes a difference and yields some kind of clue by ruling out some unlikely issues.
Variation 1
Capture the "text to say" and post the work using BeginInvoke. This ensures that nothing could possibly be interfering with the ValueChanged or MouseDown messages from pumping in the message queue.
private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
// Make 100% sure that the up-down ctrl is decoupled from speak call.
var say = $"{numericUpDown1.Value}";
// Ruling out an unlikely problem
BeginInvoke((MethodInvoker)delegate
{
_speech.SpeakAsyncCancelAll();
_speech.SpeakAsync(say);
});
}
Variation 2
Since you have a suspicion that something is running on the UI thread that shouldn't be, go ahead and give explicit instructions to post it on a background Task. At least we can rule that out.
private void numericUpDown2_ValueChanged(object sender, EventArgs e)
{
// Make 100% sure that the up-down ctrl is decoupled from speak call.
var say = $"{numericUpDown2.Value}";
// Ruling out an unlikely problem
Task.Run(() =>
{
_speech.SpeakAsyncCancelAll();
_speech.SpeakAsync(say);
});
}
Variation 3 - Inspired by NineBerry's answer (added to test code project repo)
/// <summary>
/// Watchdog timer inspired by NineBerry.
/// https://stackoverflow.com/a/74975629/5438626
/// Please accept THAT answer if this solves your issue.
/// </summary>
int _changeCount = 0;
private void numericUpDown3_ValueChanged(object sender, EventArgs e)
{
var captureCount = ++_changeCount;
var say = $"{numericUpDown3.Value}";
Task
.Delay(TimeSpan.FromMilliseconds(250))
.GetAwaiter()
.OnCompleted(() =>
{
if(captureCount.Equals(_changeCount))
{
Debug.WriteLine(say);
_speech.SpeakAsyncCancelAll();
_speech.SpeakAsync(say);
}
});
}
Well the above answers do not solve the issue. However, all the tested computers were dell computers. By default when the OS is installed, Dell installs a sound utility called MaxWaves which allows different audio enhancements. Although all options are off in this utility, it appears that it buffers the sound and when an Async.CancelAll() call comes, it blocks until the sound duration is complete. Therefore everything appears to slow to a crawl.
Uninstalling this utility as well as disabling it as a service corrects the problem.
Everything now works correctly. Thank you for your answers.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 years ago.
Improve this question
I am currently developing an application in WinForm C# to display cyclically values from a device.
Here is a short example:
public partial class MainForn : Form
{
private System.Windows.Forms.Timer timer1;
public MainForn()
{
InitializeComponent();
timer1 = new System.Windows.Forms.Timer(this.components);
timer1.Enabled = true;
timer1.Tick += new System.EventHandler(this.timer1_Tick);
}
private void timer1_Tick(object sender, EventArgs e)
{
ReadDeviceData();
label1.Text = Convert.ToString(ReadDeviceData());
}
private int ReadDeviceData()
{
Thread.Sleep(300);//Simulation of long treatment for reading
Random rnd = new Random();
return rnd.Next();
}
}
In this example, UI is freezing during the 300ms of ReadDeviceData().
What is the best way to make ReadDeviceData() asynchronous, knowing that this method will be executed endless?
Thank you.
Complementary informations:
This communication is done with a CNC Fanuc which deliver an API which is a DLL:
Example inside ReadDeviceData() there is, in my soft, the following method to read variables:
FWLIBAPI short WINAPI cnc_wrmacror2(unsigned short FlibHndl, unsigned long s_no, unsigned long *num, double *data);
FlibHndl [ in ]
Specify the library handle. See "Library handle" for details.
s_no [ in ]
Specify the start custom macro variable number.
num [ in/out ]
Specify pointer to the number of custom macro variable.
The number which was written actually is returned.
data [ in ]
Pointer to the data of custom macro variable.
Disclaimer:
as I understood OP has control over the ReadDeviceData, since make and not call.
and
This is certainly not the "best" way, but as from the comments, its my best effort with the amount of info provided. If you have no control over the method ReadDeviceData, then Task.Run can be an option. But it leaves you with the timer tick issue... you might want semaphores or concurrent queues... in all means not the best solution either.
The best solution, IMO, would be to create a service class. Call your hardware async in a loop and drop the data in a variable or buffer.
Then, in you UI part: read this value based on an event or timer etc; and use it to update the UI.
It will give you some benefits; for one, your service could also do other stuff, like: flush the data to a database, independent of the UI.
Do note; depending on your data from the device this can be tricky. Its basically how a web cam works, and it's often a hurdle to get the buffer reading/writing correctly if you're implementing that yourself.
original post:
This should do the trick:
//random is seeded based on current time; so best to do it once
Random rnd = new Random();
//the has the extra async keyword
private async void timer1_Tick(object sender, EventArgs e)
{
//await this call because you need its data
var data = await ReadDeviceData();
//set the data; note: use the variable here
label1.Text = Convert.ToString(data);
}
//signature changed
private async Task<int> ReadDeviceData()
{
//await a Task.Delay. (Thread.Sleep is thread blocking)
await Task.Delay(300);//Simulation of long treatment for reading
return rnd.Next();
}
So this is with the aid of your simulation.
If you are actually contacting the hardware; hopefully it has an API which has some Task based methods. If so; its easy, if not: you'll need to convert it yourself, which is tricky.
In that case we need more info on the device API.
This question already has answers here:
NotifyIcon.ShowBalloonTip not keeps timeout
(4 answers)
Closed 5 years ago.
I have an application, that uses some tooltips. The "Timeout" is driving me crazy by now:
No matter, what timeout value I provide in the following snippet:
(Config is just a static class holding references during runtime)
public static void notify()
{
Config.NotifyIcon.Visible = true;
Config.NotifyIcon.BalloonTipText = "BalloonTipText";
Config.NotifyIcon.BalloonTipTitle = "BalloonTipTitle";
Config.NotifyIcon.BalloonTipIcon = ToolTipIcon.Info;
Config.NotifyIcon.ShowBalloonTip(1 * 60 * 1000);
}
The behaviour is "unexpected":
If I don't do anything, after the method is called - the BalloonTip stays unlimited it seems. (At least it was > 45 minutes by now)
But if the BalloonTip appears and I move the cursor - it vanishes after 2-3 seconds...
Test it on Windows 7 and Windows 10, both time the same problem.
Any Idea?
Microsoft says in the documentation for the ShowBalloonTip method that
This parameter is deprecated as of Windows Vista. Notification display times
are now based on system accessibility settings.
When you are not using the computer (moving the mouse or typing), Microsoft says:
In addition, if the user does not appear to be using the computer (no
keyboard or mouse events are occurring) then the system does not count this
time towards the timeout.
This question already has answers here:
Is it necessary to synchronize .NET SerialPort writes/reads?
(2 answers)
Closed 5 years ago.
SerialPort s = new SerialPort("COM32");
public MainWindow()
{
InitializeComponent();
s.DataReceived += dataAction;
}
private void dataAction(object sender, SerialDataReceivedEventArgs e)
{
}
the function dataAction can be run on same time with 2 event?
or dataAction apply only when the last event finish?
I must to know that to know If i need to put lock on this function
Event will trigger everytime they are called. If they are called multiple times from multiple threads they will be triggered synchronously.
However, in your specific case, it seems you register to a specific element which seems to be monothreaded (can't be sure as I don't know SerialPort api)
There's some strange mistake with timer and forms.
I am making editor for game. Editor has two forms - MainForm and PreviewForm. PreviewForm contains only control for OpenGL output (Custom control based on GLControl from OpenTK), named glSurface.
glSurface has two inline timers (Windows.Forms.Timer) - one for rendering, and one for updating game state. Timers fires in glSurface method Run(double updateRate, double frameRate).
So, I want to show PreviewForm and run updating and rendering from MainForm.
My code is:
PreviewForm = new PreviewForm();
PreviewForm.glSurface.Run(60d, 60d);
PreviewForm.Show(this); //Form is "modal"
Body of Run method:
if (Running)
throw new Exception("Already run");
_updateRate = updateRate;
_renderRate = frameRate;
var renderFrames = Convert.ToInt32(1000/frameRate);
var updateFrames = Convert.ToInt32(1000/updateRate);
RenderTimer.Interval = renderFrames;
UpdateTimer.Interval = updateFrames;
RenderTimer.Start();
UpdateTimer.Start();
Running = true;
Timers is being initialized in OnVisibleChanged event:
protected override void OnVisibleChanged(EventArgs e)
{
...
RenderTimer = new Timer();
UpdateTimer = new Timer();
RenderTimer.Tick += RenderTick;
UpdateTimer.Tick += UpdateTick;
...
}
Weird things start here.
When PreviewForm is showing, nothing happens. BUT when I close that form, both timers fire their events! I have tested for possible cross-thread interaction, but PreviewForm.InvokeRequired and glSurface.InvokeRequired are both false.
Please help me find out what the hell is going on.
In this case declare and initialise and start your timers all within the one code block:
{
.../...
RenderTimer = new Timer();
UpdateTimer = new Timer();
RenderTimer.Tick += RenderTick;
UpdateTimer.Tick += UpdateTick;
var renderFrames = Convert.ToInt32(1000/frameRate);
var updateFrames = Convert.ToInt32(1000/updateRate);
RenderTimer.Interval = renderFrames;
UpdateTimer.Interval = updateFrames;
RenderTimer.Start();
UpdateTimer.Start();
.../...
}
Without seeing the program flow this is the safest option. It appears the variables are local to the OnVisibleChanged event, so I'm not sure how you're not getting a null refernce exception when you're calling them from your if (Running).
The other thing you could do is make them class variables and ensure they are initialised before you use them. Then call start within the if statement.
As for the issue of them starting when the form closes, it's impossible to determine from the code you've shown.
Edit: There's a deeper problem.
You really shouldn't be using system timers to drive your game updates and rendering.
System timers on most platforms have low accuracy that's inadequate for high performance multimedia such as audio and most games. On Windows System.Windows.Forms.Timer uses Win32 timers which have particularly low accuracy, typically resulting in intervals at least 15ms off(see this answer). See this technical breakdown and this overview for more information. Basically, even if your code worked correctly your frames would stutter.
Most games "tick" by running an infinite loop in the main thread, doing the following each time(not necessarily in this order):
Call back into the framework to handle pending OS events.
Track the time difference since the last "tick" so frame-independent timing works.
Update the state of the game(such as physics and game logic, possibly in another thread).
Render the scene based on a previous update(possibly in another thread).
As noted by commenters, the main problem in your timer code is that initialization is split between Run and OnVisibleChanged. I was unable to reproduce the case where the timer fires after a sub form is closed. I suspect some other code you haven't posted is the cause. You'll save yourself a great deal of trouble if you use OpenTK.GameWindow. It handles the loop plumping for you, similar to XNA. This is an example of one way to integrate it with WinForms. See the manual for more information.
In Run, you set Interval and start each timer. No Tick callbacks are set. In OnVisibleChanged, you recreate the timers and assign Tick callbacks. No intervals are set, and the timer's haven't been started.
The timer initialization code in Run is essentially ignored because no tick callbacks are set and OnVisibleChanged recreates the timers. OnVisibleChanged triggers almost immediately after Run, shortly after you call PreviewForm.Show(this).
If you're dead set on using system timers, this should work:
// somewhere before Run(ideally in the initialization of the main form).
RenderTimer.Interval = Convert.ToInt32(1000 / frameRate);
RenderTimer.Tick += RenderTick;
UpdateTimer.Interval = Convert.ToInt32(1000 / updateRate);
UpdateTimer.Tick += UpdateTick;
void Run(double frameRate, double updateRate)
{
// ...
RenderTimer.Start();
UpdateTimer.Start();
// ...
Running = true;
}
// ...
protected override void OnVisibleChanged(EventArgs e)
{
// ...
// Don't initialize timers here.
// ...
}