I am trying to make a console application in c# that reads Serial Port and send data over TCP to another machine in network.
I have written the following code
class Program
{
static SerialPort mPort;
static void Main(string[] args)
{
mPort = new SerialPort();
mPort.BaudRate = 4800;
mPort.StopBits = StopBits.One;
mPort.Parity = Parity.None;
mPort.Handshake = Handshake.None;
mPort.DataBits = 8;
mPort.PortName = "COM4";
if (!mPort.IsOpen)
{
mPort.Open();
}
mPort.DataReceived += new SerialDataReceivedEventHandler(mPort_DataReceived);
}
private static void mPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
if (mPort.IsOpen)
{
}
}
catch
{
}
}
}
but application closed after hitting mPort.DataReceived += new SerialDataReceivedEventHandler(mPort_DataReceived); line in static void Main(string[] args) function.
Why it is not firing mPort_DataReceived event ??
This is basic console application behaviour. Just add:
mPort.DataReceived += ...
/// wait till something happens
Console.Read();
}
at the end of the main method. Then watch your event to get fired.
This approach is only a workaround for that behaviour.
The line
mPort.DataReceived += new SerialDataReceivedEventHandler(mPort_DataReceived);
is subscribing to the event. But you never wait for an event to occure.
After that line, your Main method returns. As this is the main method of your process, your process terminates after Main returns.
One simple way to keep the process running is to add something like
Console.ReadLine();
at the end of Main, so your program waits for the user to hit a key before it terminates.
The reason is, that your program simply terminates. You need a kind of loop to keep it alive, for example like this. It's running and checking if a key has been pressed, and stopps only if that was 'Escape'.
// Do initialisation work here
ConsoleKeyInfo cki = new ConsoleKeyInfo();
do
{
// Do frequently work here
if (Console.KeyAvailable)
{
cki = Console.ReadKey();
}
}
while (cki.Key != ConsoleKey.Escape);
Related
I'm trying to learn how to use Timers and I'm having troubles with the elapsed event.
What I have is a class where I check some messages from a databatch. But now I want to make a timer where every x period of time check that messages.
I made this code:
public class Program
{
static void Main(string[] args)
{
Message m = new Message();
m.init();
}
}
public class Messages{
private System.Timers.Timer tt;
public void init()
{
tt = new(_conf.Period);
tt.Elapsed += new System.Timers.ElapsedEventHandler(TimerElapsed);
tt.Start();
Console.ReadLine();
}
private void TimerElapsed(object? sender, ElapsedEventArgs e)
{
//Console.WriteLine for test it works
Console.WriteLine(DateTime.UtcNow);
//check my messages
}
}
This doesn't work because it never goes inside TimerElapsed. What am I doing wrong?
Thank you
EDIT: even as a field timer doesn't goes inside elapsed event.
EDIT2: well, I found my problem. I was testing the TimerElapsed with a Console.WriteLine(DateTime.UtcNow) inside of it and it only works if i put after all the code on Init a Console.ReadLine(); Ill edit my code again to show it. I don't understad why I need this readLine so if someone could explain to me would be great.
If you don't like the ReadLine() approach, you can use a polling loop like this instead:
public static void Main (string[] args) {
Messages m = new Messages();
m.init();
ConsoleKeyInfo cki;
do {
while (!Console.KeyAvailable) {
System.Threading.Thread.Sleep(50);
}
cki = Console.ReadKey(true);
} while (cki.Key != ConsoleKey.Escape);
}
This will keep the app alive until the user hits the Escape key.
You should see the timestamps printing at whatever interval you specified.
I want to terminate the Console app upon multiple confirmation from User. If the user enters "y", then the app should terminate, else it should be actively taking the Ctrl+C input event, until the user enters "y".
With this code, user is able to input Ctrl+C only once, after that Ctrl+C isn't taken as input again if he inputs value other than "y".
using System.Threading;
namespace TerminateProgram
{
class Program
{
public static ManualResetEvent mre;
public static bool exitCode = false;
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
//Console.CancelKeyPress += new ConsoleCancelEventHandler(cancelHandler);
//Setup and start timer...
mre = new ManualResetEvent(false);
Console.CancelKeyPress += new ConsoleCancelEventHandler(cancelHandler);
//The main thread can just wait on the wait handle, which basically puts it into a "sleep" state
//and blocks it forever
mre.WaitOne();
Console.WriteLine("exiting the app");
Thread.Sleep(1000);
}
//this method will handle the Ctrl+C event and will ask for confirmation
public static void cancelHandler(object sender, ConsoleCancelEventArgs e)
{
var isCtrlC = e.SpecialKey == ConsoleSpecialKey.ControlC;
if (isCtrlC)
{
string confirmation = null;
Console.Write("Are you sure you want to cancel the task? (y/n)");
confirmation = Console.ReadLine();
if (confirmation.Equals("y", StringComparison.OrdinalIgnoreCase))
{
e.Cancel = true;
exitCode = true;
mre.Set();
}
else
{
Console.CancelKeyPress += new ConsoleCancelEventHandler(cancelHandler);
}
}
}
}
}```
What you are trying to do in fundamentally out of normal reach for the console. It is the realm of GUI's like Windows Forms and WPF. Things that have a Event Queue. And where you do not block the Main/Only Thread with a long running operation. Of course you can retrofit a Event Queue to Console. In Console it is very easy to duplicate every other Environments Programm flow for testing.
That being said if you got a loop long, you can look at Inputs without blocking Progression, by using KeyAvalible as discussed here:
https://stackoverflow.com/a/5620647/3346583
I have a simple C# console application that attaches to an event. I need the program to keep running continuously so it can respond to the event. What is the right way to keep it running?
Here is my application:
using System;
using NAudio.CoreAudioApi;
namespace MaxVolume
{
class Program
{
private const float DesiredLevel = -15;
private static MMDevice _device;
static void Main(string[] args)
{
MMDeviceEnumerator mmde = new MMDeviceEnumerator();
_device = mmde.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia);
_device.AudioEndpointVolume.MasterVolumeLevel = DesiredLevel;
_device.AudioEndpointVolume.OnVolumeNotification += SetVolume;
}
static void SetVolume(AudioVolumeNotificationData data)
{
if (Math.Abs(data.MasterVolume - DesiredLevel) > 0.1)
{
_device.AudioEndpointVolume.MasterVolumeLevel = DesiredLevel;
}
}
}
}
You can call Console.ReadLine() (if you want to terminate on keystroke), or simply Thread.Sleep(Timeout.Infinite).
In case of async main method, one could also use await Task.Delay(-1);
You can just create a while-loop like so:
while(!eventFired) {}
and then have a field:
private bool eventFired = false;
and then finally when the event is fired make:
eventFired = true;
(if you want it to exit after the event was fired once, that is. if it should run forever see the other answers with sleep and readkey)
NOTE: this is using up a CPU and shouldn't be used in any production, but in a quick-and-dirty test setting it might be worth it.
My problem is that the console should stay opened. The timer cannot write anything into the console while Console.ReadLine() waits for an input. How do I prevent the console from closing without using Console.ReadLine(), Console.ReadKey() or system("pause")?
Here is my code:
namespace Closer {
public static class Program {
public static void Main () {
// Define timer
var t = new Windows.Forms.Timer() {
Enabled = true,
Interval = 30000
};
// Give timer the tick function
t.Tick += (object tSender, EventArgs tE) => {
// If it is half past eleven
if (DateTime.Now.Hour.ToString() + DateTime.Now.Minute.ToString() == "2330") {
// Close all osu!.exe's --- works
foreach (Process p in Process.GetProcessesByName("osu!")) {
p.Kill();
}
// Write a msg
Console.WriteLine("Done!");
}
};
// Prevent the console from closing --- Here's the problem
Console.ReadLine();
}
}
}
You are conflating two problems. Yes, an early release of .NET 4.5 made the mistake of having Console.ReadLine() take a lock that prevented threads from writing to the console. That was fixed, just turn on Windows Update to get the service release.
But the real problem is your Timer class selection. A System.Windows.Forms.Timer requires a message loop to get the Tick event to fire. You can only get a message loop by calling Application.Run(). A very suitable replacement for Console.ReadLine() btw, use Application.ExitThread() to get your app to terminate.
You should use System.Threading.Timer or System.Timers.Timer in a console mode app. Their callback is fired on a threadpool thread so don't require a dispatcher loop.
You should use System.Timers.Timer and everything works fine.
static void Main()
{
// Define timer
System.Timers.Timer t = new System.Timers.Timer()
{
Enabled = true,
Interval = 1000
};
// Give timer the tick function
t.Elapsed += (object tSender, System.Timers.ElapsedEventArgs tE) =>
{
Console.WriteLine("Done!");
};
Console.ReadLine();
}
You can try this:
Thread.CurrentThread.Join();
I know this is stupid, but this does what you need. And the process will never terminate (itself) you've to kill manually.
I have the following code, does this run an endless loop?
I am trying to schedule something every minute and the console application should run continuously until I close it.
class Program
{
static int curMin;
static int lastMinute = DateTime.Now.AddMinutes(-1).Minutes;
static void Main(string[] args)
{
// Not sure about this line if it will run continuously every minute??
System.Threading.Timer timer = new System.Threading.Timer(new TimerCallback(TimCallBack), null, 1000, 60000);
Console.Read();
timer.Dispose();
}
private static void TimCallBack(object o)
{
curMin = DateTime.Now.Minute;
if (lastMinute < curMin)
{
// Do my work every minute
lastMinute = curMin;
}
}
}
KISS - or are you competing for the Rube Goldberg award? ;-)
static void Main(string[] args)
{
while(true)
{
DoSomething();
if(Console.KeyAvailable)
{
break;
}
System.Threading.Thread.Sleep(60000);
}
}
I think your method should work assuming you don't press any keys on the console window. The answer above will definitely work but isn't the prettiest.
As soon as your main() exits, all the other threads will be automatically closed, too.
If it needs to run the whole time, might it be a better solution to create a service? Example here.
Why not add your application to the Windows Task scheduler and do just one "task" per startup of your console app (and don't bother thinking about scheduling yourself?)
And to answer your question: No your sample doesn't "Loop", it's event driven and will close on key press.
Using an event which times out for the stop might work, something like this:
class Program
{
static TimeSpan _timeSpan = new TimeSpan(0, 0, 5);
static ManualResetEvent _stop = new ManualResetEvent(false);
static void Main(string[] args)
{
Console.TreatControlCAsInput = false;
Console.CancelKeyPress += delegate (object sender, ConsoleCancelEventArgs e)
{
_stop.Set();
e.Cancel = true;
};
while (!_stop.WaitOne(_timeSpan))
{
Console.WriteLine("Waiting...");
}
Console.WriteLine("Done.");
}
}