passing arguments to ElapsedEventHandler C# - c#

This program is designed to open two COM ports and send data from one to the other ever 1 second. The user inputs which port transmits and which port recieves. The problem I am having is with the ElapsedEventHandler() takes in the OnTimedEvent() function which has two default arguments. I want the OnTimedEvent() function to write something to the send port and read it in on the recieve port, then display it to the console. Obviously my code will not work the way I have it now because the ports and message are not in the scope of OnTimedEvent(). What can I do to make that function work the way I want? Thanks in advance.
using System;
using System.IO.Ports;
using System.Timers;
public class serial_test1
{
public static void Main(string[] args)
{
string sender;
string recver;
string buff_out;
string message;
SerialPort send_port;
SerialPort recv_port;
if (args.Length == 1)
{
sender = "UART";
recver = "USB";
message = args[0];
}
else if (args.Length == 2)
{
sender = args[0];
message = args[1];
if (sender == "USB")
{
recver = "UART";
}
else
{
recver = "USB";
}
}
else
{
sender = "UART";
recver = "USB";
message = "TEST MESSAGE";
}
int baud = 115200;
int data_bits = 8;
Parity parity = Parity.None;
StopBits stop_bits = StopBits.One;
buff_out = message;
SerialPort UARTport = new SerialPort("COM1", baud, parity, data_bits, stop_bits);
SerialPort USBport = new SerialPort("COM7", baud, parity, data_bits, stop_bits);
UARTport.Open();
USBport.Open();
if (sender == "USB")
{
send_port = USBport;
recv_port = UARTport;
}
if (sender == "UART")
{
send_port = UARTport;
recv_port = USBport;
}
string header = "from " + sender + " port to " + recver + " port";
Console.WriteLine(header);
Timer aTimer = new System.Timers.Timer();
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
// Set the Interval to 1 second.
aTimer.Interval = 1000;
aTimer.Enabled = true;
UARTport.Close();
USBport.Close();
Console.ReadLine();
}
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
string buff_in;
send_port.WriteLine(buff_out);
buff_in = recv_port.ReadLine();
Console.WriteLine(buff_in);
}
}

I suggest using System.Threading.Timer instead, you can pass in a state object into the constructor that is passed in to the TimerCallback.

You can use one of these options:
01 - Simply use an auxiliar object
static string _value;
static void MyElapsedMethod(object sender, ElapsedEventArgs e)
{
Console.WriteLine(_value);
}
02 - Or use a closed class
class CustomTimer : System.Timers.Timer
{
public string Data;
}
private void StartTimer()
{
var timer = new CustomTimer
{
Interval = 3000,
Data = "Foo Bar"
};
timer.Elapsed += timer_Elapsed;
timer.Start();
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
string data = ((CustomTimer)sender).Data;
}

Related

CSHARP running while every X seconds but until bool is true

I would like to check updates from txt file on web server. and send a messagebox when there is version mismatch, I'm using this code and it works but I want it only to connect the server every 10 minutes and check the text file.
is there any option to do that?
maybe using another way to create this loop?
I also would like to send the messagebox only once
bool hasDisplayed = false;
private string UpdateCheckServer()
{
WebClient client = new WebClient();
Stream stream = client.OpenRead("http://localhost/update/update_version.txt");
StreamReader reader = new StreamReader(stream);
string serverversion = reader.ReadToEnd();
return serverversion;
}
private string UpdateCheckClient()
{
string ClientVersion = System.IO.File.ReadAllText("update_version.txt");
return ClientVersion;
}
private void UpdateCheckTimer()
{
while (!hasDisplayed)
{
if (starter.Enabled == true && UpdateCheckServer() == UpdateCheckClient())
{
//Nothing here
}
if (starter.Enabled == true && UpdateCheckServer() != UpdateCheckClient())
{
MessageBox.Show("not updated");
hasDisplayed = true;
}
}
An implementation based on timer can look like this:
private bool _equalVersion = true;
private System.Timers.Timer _timer = new System.Timers.Timer(1000 * 60 * 10); //millisecond * seconds * minutes
private void StartUpdateCheckTimer()
{
_timer.Elapsed += UpdateCheck;
_timer.Start();
}
private void UpdateCheck(object sender, ElapsedEventArgs e)
{
_timer.Stop();
_equalVersion = (UpdateCheckServer() == UpdateCheckClient());
if (!_equalVersion)
{
MessageBox.Show("not updated");
}
else
{
_timer.Start();
}
}
in this way you get a timer:
triggered each 10 minutes,
performing the check
notifying the version change (and stopping) or proceeding with the subsequent iterations
then you can add some more logic like for example reset of the check, more proper notification action (separating your check routine from the GUI part) and many more.
Another approach (as pointed out by #imsmn) can be to make your implementation System.Threading.Sleep based, but I'd suggest the first option based on timer.
After several tries and learning I managed to do that.
private string UpdateCheckServer()
{
WebClient client = new WebClient();
Stream stream = client.OpenRead("http://localhost/update/update_version.txt");
StreamReader reader = new StreamReader(stream);
string serverversion = reader.ReadToEnd();
return serverversion;
}
private string UpdateCheckClient()
{
string ClientVersion = System.IO.File.ReadAllText("update_version.txt");
return ClientVersion;
}
private void UpdateCheckTimer()
{
System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
t.Interval = 15000; // specify interval time as you want
t.Tick += new EventHandler(timer_Tick);
t.Start();
void timer_Tick(object sender, EventArgs e)
{
//Call method
if (starter.Enabled == true && UpdateCheckServer() != UpdateCheckClient())
{
t.Stop();
MessageBox.Show("not updated");
}
}
}

TCP-IP Connection Android App to C# Server

so what im actually trying to do is to comunicate with a DMX-Interface pluged to a PC/Host via an Xamarin Android App.
Allready got my Server running, works also with an console client i wrote first. So now I wrote the app,using the same Way as before, with a TCPClient and then writing the data via a stream.
Because I'm running the app in the emulator I use as IP 10.0.2.2 to connect, but I cannot establish a connection. The App crashes or I get a timeout exeption. Been trying and researching now for two days and now i'm desperate, so I attach my code here, hope anyone can help
Thanks, Johannes
App:
public class MainActivity : Activity
{
public Stream Stream;
TcpClient Client = null;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
//adding control elements from Resource.Layout.Main
Button at = FindViewById<Button>(Resource.Id.at);
Button enter = FindViewById<Button>(Resource.Id.enter);
Button thru = FindViewById<Button>(Resource.Id.thru);
Button all = FindViewById<Button>(Resource.Id.all);
Button one = FindViewById<Button>(Resource.Id.one);
Button two = FindViewById<Button>(Resource.Id.two);
Button three = FindViewById<Button>(Resource.Id.three);
Button four = FindViewById<Button>(Resource.Id.four);
Button five = FindViewById<Button>(Resource.Id.five);
Button six = FindViewById<Button>(Resource.Id.six);
Button seven = FindViewById<Button>(Resource.Id.seven);
Button eight = FindViewById<Button>(Resource.Id.eight);
Button nine = FindViewById<Button>(Resource.Id.nine);
Button zero = FindViewById<Button>(Resource.Id.zero);
Button comma = FindViewById<Button>(Resource.Id.comma);
Button connect = FindViewById<Button>(Resource.Id.connect);
Button clear = FindViewById<Button>(Resource.Id.clear);
at.Click += (o, e) =>
{
UpdateCmdLine("#");
};
clear.Click += (o, e) =>
{
FlushCmdLine();
};
enter.Click += (o, e) =>
{
TextView cmdLine = FindViewById<TextView>(Resource.Id.cmdLine);
ProcessData(cmdLine.Text);
FlushCmdLine();
};
thru.Click += (o, e) =>
{
UpdateCmdLine("/");
};
all.Click += (o, e) =>
{
UpdateCmdLine("#");
};
one.Click += (o, e) =>
{
UpdateCmdLine("1");
};
two.Click += (o, e) =>
{
UpdateCmdLine("2");
};
three.Click += (o, e) =>
{
UpdateCmdLine("3");
};
four.Click += (o, e) =>
{
UpdateCmdLine("4");
};
five.Click += (o, e) =>
{
UpdateCmdLine("5");
};
six.Click += (o, e) =>
{
UpdateCmdLine("6");
};
seven.Click += (o, e) =>
{
UpdateCmdLine("7");
};
eight.Click += (o, e) =>
{
UpdateCmdLine("8");
};
nine.Click += (o, e) =>
{
UpdateCmdLine("9");
};
zero.Click += (o, e) =>
{
UpdateCmdLine("0");
};
comma.Click += (o, e) =>
{
UpdateCmdLine(",");
};
connect.Click += (o, e) =>
{
try
{
TextView ip = FindViewById<TextView>(Resource.Id.ipField);
TextView port = FindViewById<TextView>(Resource.Id.portField);
TextView connectionStatus = FindViewById<TextView>(Resource.Id.connectedStatus);
Client = new TcpClient("10.0.2.2", 4711);
connectionStatus.Text = "Connected";
}
catch (System.Exception)
{
}
};
//implementing click functions
}
public void UpdateCmdLine(string update)
{
TextView cmdLine = FindViewById<TextView>(Resource.Id.cmdLine);
cmdLine.Text += update;
}
public void FlushCmdLine()
{
TextView cmdLine = FindViewById<TextView>(Resource.Id.cmdLine);
cmdLine.Text = "";
}
public int[] GetData(string channel, string value)
{
int[] data = new int[] {Int32.Parse(channel), Int32.Parse(value)};
return data;
}
public void SendData(int channel, int data)
{
if (Client.Connected)
{
Stream = Client.GetStream();
byte[] outgoingBytes = new byte[] {Convert.ToByte(channel),Convert.ToByte(data)};
Stream.Write(outgoingBytes,0,outgoingBytes.Length);
}
}
public void ProcessData(string cmdLine)
{
string[] divideStackedOps = cmdLine.Split(',');
foreach (string s in divideStackedOps)
{
if (s.Contains("/"))
{
string[] dividedThru = s.Split('/');
int channel1 = Int32.Parse(dividedThru[0]);
string[] dividedAt = dividedThru[1].Split('#');
int channel2 = Int32.Parse(dividedAt[0]);
int value = Int32.Parse(dividedAt[1]);
for (int e = channel2; e >= channel1; e--)
{
SendData(e, value);
}
}
else if (s.Contains("#"))
{
string[]dividedAll = s.Split('#');
int value = Int32.Parse(dividedAll[1]);
for (int e = 100; e > 0; e--)
{
SendData(e, value);
}
}
}
}
}
}
Server
public class DmxInterface
{
[DllImport("K8062D.dll")]
public static extern void StartDevice();
[DllImport("K8062D.dll")]
public static extern void SetData(int channel, int data);
[DllImport("K8062D.dll")]
public static extern void StopDevice();
[DllImport("K8062D.dll")]
public static extern void SetChannelCount(int count);
}
class Program
{
private static TcpListener Listener;
private static ArrayList Threads = new ArrayList();
public static Boolean ServerStopped;
public static void Main()
{
DmxInterface.StartDevice();
DmxInterface.SetChannelCount(10);
//Initialize Listener, start Listener
int port = 4711;
IPAddress ip = IPAddress.Parse("127.0.0.1");
Listener = new TcpListener(ip, port);
Listener.Start();
Console.WriteLine("Creating new listener on: "+ip+":"+port);
//Initialize MainServerThread, start MainServerThread
Console.WriteLine("Starting MainThread");
Thread mainThread = new Thread(Run);
mainThread.Start();
Console.WriteLine("Done");
while (!ServerStopped)
{
Console.WriteLine("Write 'stop' to stop Server...");
String cmd = "";
cmd = Console.ReadLine();
if (cmd.ToLower().Equals("stop"))
{
Console.WriteLine("stopping server");
ServerStopped = true;
}
else
{
Console.WriteLine("unknow command: " + cmd);
}
}
EndThreads(mainThread);
}
public static void EndThreads(Thread mainThread)
{
//stopping MainThread
mainThread.Abort();
Console.WriteLine("MainThread stopped");
//stopping all Threads
for (IEnumerator e = Threads.GetEnumerator(); e.MoveNext();)
{
//Getting next ServerThread
Console.WriteLine("Stopping the ServerThreads");
ServerThread serverThread = (ServerThread)e.Current;
//Stop it
serverThread.Stop = true;
while (serverThread.Running)
{
Thread.Sleep(1000);
}
}
//Stopping Listener
Listener.Stop();
Console.WriteLine("listener stopped");
Thread.Sleep(5000);
Console.Clear();
}
//opening a new ServerThread
public static void Run()
{
while (true)
{
Console.WriteLine("Listener waiting for connection wish");
//waiting for incoming connection wish
TcpClient client = Listener.AcceptTcpClient();
Threads.Add(new ServerThread(client));
}
}
}
class ServerThread
{
public bool Stop;
public bool Running;
private TcpClient client;
public ServerThread(TcpClient client)
{
this.client = client;
//starting new thread with run() function
Console.WriteLine("Starting new ServerThread");
new Thread(new ThreadStart(Run)).Start();
}
//threaded function
public void Run()
{
Stream stream = null;
Boolean gotstream = false;
Console.WriteLine("Reading incoming Data Stream");
Running = true;
while (!gotstream)
{
//making sure stream is not null to avoid exeption
if (client.GetStream() != null)
{
//getting stream, setting flag true
stream = client.GetStream();
gotstream = true;
}
}
Boolean loop = true;
byte[] incomingValues = new byte[] {255, 255};
Boolean gotData = false;
while (loop)
{
//checking if a remote host is still connected
if (client.Connected)
{
try
{
//reading Byte Array
stream.Read(incomingValues, 0, incomingValues.Length);
gotData = true;
}
catch (Exception e)
{
//catching exeptions
Console.WriteLine("Ooops, something wrent wrogn \n" + e);
loop = false;
}
if (gotData)
{
//converting bytes to int, sending DMX Values
int channel = Convert.ToInt32(incomingValues[0]);
int value = Convert.ToInt32(incomingValues[1]);
DmxInterface.SetData(channel, value);
Console.WriteLine("Received Data... \n Channel: " + channel + " Value: " + value);
}
}
else
{
//exiting loop if connection is lost
Console.WriteLine("connection lost");
Program.ServerStopped = true;
loop = false;
}
}
}
}
}

Allow triggered Datareceivedhandler event method to run once or for a set period of time?

I have a program designed to read data in from the serial port, display it on a chart and allow saving. This data is simply uint64 numbers sent one by one. The data is sent very rapidly (many times per second).
Currently, the data is read into a datatable, this functionality is done in the datareceivedhandler event method which is triggered automatically when data is received.
I want to have the following:
A 'runonce' button that allows a single capture of data to be read
A selectable time and 'timed' button that will allow data to be read for some period of time only
A 'continuous' button that will allow data capture forever
Any data that is not within the selected times/captures should be discarded (or never captured in the first place). There should be a 'stop capture' button that will stop the continuous or timed modes.
What would the best method for implementing this? I've attached my code below.
using System;
using System.ComponentModel;
using System.Data;
using System.Windows.Forms;
using System.IO;
using System.IO.Ports;
using System.Text.RegularExpressions;
namespace FieldProbe
{
public partial class MainForm : Form
{
SerialPort _port = new SerialPort(); //set up port
DataTable dt = new DataTable(); //set up datatable to hold output
int numSamples = 0;
public MainForm()
{
InitializeComponent();
}
private void MainForm_Load(object sender, EventArgs e)
{
var ports = SerialPort.GetPortNames(); //get list of ports connected to PC
cmbSerialPorts.DataSource = ports; //use list of ports as combobox options
_port.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler); //create pointer to datareceived event handler
dt.Clear(); //Clear datatable on start
dt.Columns.Add("index", typeof(int)); //index
dt.Columns.Add("dutyCycle", typeof(float)); //0.5 means equal on/off, 1.0 means permanently on
dt.Columns.Add("frequency", typeof(float)); //probe can go from 40MHz to 10GHz
dt.Columns.Add("distance", typeof(float)); //antenna to radiator distance in metres (usually 1m)
dt.Columns.Add("pulseWidth", typeof(float)); //calculated from duty cycle and frequency
dt.Columns.Add("level", typeof(int)); //output in V/m
chChart.Series["series1"].YValueMembers = "level";
chChart.Series["series1"].XValueMember = "index";
chChart.DataSource = dt;
chChart.DataBind();
}
private void btnConnect_Click(object sender, EventArgs e)
{
if (btnConnect.Text == "Connect") //if user clicks connect button
{
if (cmbSerialPorts.SelectedIndex > -1) //if port valid
{
//MessageBox.Show(String.Format("You selected port '{0}'", cmbSerialPorts.SelectedItem));
Connect(cmbSerialPorts.SelectedItem.ToString()); //go to connect function
}
else
{
MessageBox.Show("Please select a port first");
}
}
else //if user clicks disconnect button
{
btnConnect.Text = "Connect";
btnContinuous.Enabled = false;
btnSingle.Enabled = false;
btnTimed.Enabled = false;
nudTime.Enabled = false;
try
{
_port.Close();
}
catch
{
MessageBox.Show("Connection close failed- device may already be unplugged. Program will exit.");
Application.Exit();
}
}
}
private void btnSave_Click(object sender, EventArgs e)
{
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
saveFileDialog1.Filter = "csv files (*.csv)|*.csv*";
saveFileDialog1.RestoreDirectory = true;
saveFileDialog1.DefaultExt = "csv";
saveFileDialog1.AddExtension = true;
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
File.WriteAllText(saveFileDialog1.FileName, dtToCSV());
}
}
private void btnSingle_Click(object sender, EventArgs e)
{
}
private void Connect(string portName)
{
if (!_port.IsOpen)
{
_port.BaudRate = 9600; //CHANGE ME AFTER ARDUINO TESTING!!!!!!!!!!!!!!
_port.DataBits = 8;
_port.StopBits = StopBits.One;
_port.Parity = Parity.None;
_port.Handshake = Handshake.None;
_port.RtsEnable = true; //CHANGE ME AFTER ARDUINO TESTING!!!!!!!!!!!!!!
_port.DtrEnable = true; //CHANGE ME AFTER ARDUINO TESTING!!!!!!!!!!!!!!
_port.PortName = portName;
try
{
_port.Open(); //connect to port
btnConnect.Text = "Disconnect";
btnContinuous.Enabled = true;
btnSingle.Enabled = true;
btnTimed.Enabled = true;
nudTime.Enabled = true;
}
catch
{
MessageBox.Show("ERROR: Port invalid or in use!");
btnConnect.Text = "Connect";
btnContinuous.Enabled = false;
btnSingle.Enabled = false;
btnTimed.Enabled = false;
nudTime.Enabled = false;
}
}
}
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender; //set up serial port
string indata = sp.ReadExisting(); //read data from port
string indataString = Regex.Match(indata, #"\d+").Value; //extract number (still a string)
numSamples++; //increment x axis
try
{
int indataInt = Int32.Parse(indataString); //convert string to int
var pulseWidth = nudDutyCycle.Value / (nudFrequency.Value * 100); //formula to find pulse width from duy cycle & frequency
object[] o = { numSamples, nudDutyCycle.Value, nudFrequency.Value, nudDistance.Value, pulseWidth, indataInt }; //collect data
dt.Rows.Add(o); //add data to datatable
teIncomingData.invokeIfRequired(() => //add text to textbox (different thread)
{
teIncomingData.AppendText(indataString + Environment.NewLine);
});
}
catch { }
chChart.invokeIfRequired(() => //update chart (different thread)
{
chChart.DataBind();
});
}
private string dtToCSV()
{
string file = "";
foreach (DataColumn col in dt.Columns)
file = string.Concat(file, col.ColumnName, ",");
file = file.Remove(file.LastIndexOf(','), 1);
file = string.Concat(file, "\r\n");
foreach (DataRow row in dt.Rows)
{
foreach (object item in row.ItemArray)
file = string.Concat(file, item.ToString(), ",");
file = file.Remove(file.LastIndexOf(','), 1);
file = string.Concat(file, "\r\n");
}
return file;
}
public void saveFileDialog1_FileOk(object sender, CancelEventArgs e)
{ //do not delete me, this needs to exist for some reason for saving to work
}
}
public static class Invoker
{
public static void invokeIfRequired(this ISynchronizeInvoke obj, MethodInvoker action)
{
if(obj.InvokeRequired)
{
var args = new object[0];
obj.Invoke(action, args);
}
else
{
action();
}
}
}
}

Report progress using BackgroundWorker report only for the first time

I want my application will show on my form my class properties so I started my class with BackgroundWorker and create ProgressChanged.
my class:
public class DumpFile
{
PacketDevice _device;
public int _packetsCount;
public double _bitsPerSecond;
public double _packetsPerSecond;
public DateTime _lastTimestamp;
public delegate void dlgPackProgress(int progress);
public event dlgPackProgress evePacketProgress;
public DumpFile(PacketDevice device, string pcapPath)
{
_device = device;
_pcapPath = pcapPath;
_packetsCount = 1;
}
public void startCapturing()
{
OnPacketProgress(_packetsCount++);
using (PacketCommunicator communicator = _device.Open(65536, PacketDeviceOpenAttributes.Promiscuous, 1000)) //open the device
{
ThreadStart starter = delegate { openAdapterForStatistics(_device); };
new Thread(starter).Start();
using (PacketDumpFile dumpFile = communicator.OpenDump(_pcapPath)) //open the dump file
{
communicator.ReceivePackets(0, dumpFile.Dump); //start the capture
}
}
}
private void OnPacketProgress(int packet)
{
var handler = evePacketProgress;
if (handler != null)
{
handler(packet);
}
}
public void openAdapterForStatistics(PacketDevice selectedOutputDevice)
{
using (PacketCommunicator statCommunicator = selectedOutputDevice.Open(100, PacketDeviceOpenAttributes.Promiscuous, 1000)) //open the output adapter
{
ThreadStart start = delegate { test(selectedOutputDevice); };
new Thread(start).Start();
statCommunicator.SetFilter("tcp"); //compile and set the filter
statCommunicator.Mode = PacketCommunicatorMode.Statistics; //put the interface in statstics mode
statCommunicator.ReceiveStatistics(0, StatisticsHandler);
}
}
public void test(PacketDevice selectedOutputDevice)
{
using (PacketCommunicator communicator = selectedOutputDevice.Open(65536, PacketDeviceOpenAttributes.Promiscuous, 1000))
{
communicator.ReceivePackets(0, PacketHandler);
}
}
private void PacketHandler(Packet packet)
{
string result = _packetsCount.ToString() + ". " + packet.Timestamp.ToString("yyyy-MM-dd hh:mm:ss.fff") + " length:" + packet.Length;
_packetsCount++;
}
private void StatisticsHandler(PacketSampleStatistics statistics)
{
DateTime currentTimestamp = statistics.Timestamp; //current sample time
DateTime previousTimestamp = _lastTimestamp; //previous sample time
_lastTimestamp = currentTimestamp; //set _lastTimestamp for the next iteration
if (previousTimestamp == DateTime.MinValue) //if there wasn't a previous sample than skip this iteration (it's the first iteration)
{
return;
}
double delayInSeconds = (currentTimestamp - previousTimestamp).TotalSeconds; //calculate the delay from the last sample
_bitsPerSecond = statistics.AcceptedBytes * 8 / delayInSeconds; //calculate bits per second
_packetsPerSecond = statistics.AcceptedPackets / delayInSeconds; //calculate packets per second
}
}
start button who start capturing:
private void btnStartCapture_Click(object sender, EventArgs e)
{
timerSniffer.Start();
btnStartTabSniffer.Enabled = false;
btnStopTabSniffer.Enabled = true;
groupBoxSelectTabSniffer.Enabled = false;
bgWorker = new BackgroundWorker();
bgWorker.WorkerReportsProgress = true;
bgWorker.ProgressChanged += new ProgressChangedEventHandler(bgWSniffer_ProgressChanged);
bgWorker.DoWork += new DoWorkEventHandler(
(s3, e3) =>
{
DumpFile dumpFile = new DumpFile(deviceForCapturing, pcapFilePathSniffer);
tshark.evePacketProgress += new DumpFile.dlgPackProgress(
(packet) =>
{
bgWorker.ReportProgress(packet, dumpFile);
});
dumpFile.startCapturing();
});
bgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(
(s3, e3) =>
{
groupBoxSelectTabSniffer.Enabled = true;
});
bgWorker.RunWorkerAsync();
}
ProgressChanged:
private void bgWSniffer_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
var dumpFile = (DumpFile)e.UserState;
lblNumberOfPacketsTabSniffer2.Text = dumpFile._packetsCount.ToString("#,##0");
lblTrafficRateTabSniffer2.Text = (dumpFile._bitsPerSecond * 0.000001).ToString("0.##") + " Mbit/sec" + " (" + dumpFile._bitsPerSecond.ToString("#,##0") + " Bits/sec" + ")";
lblPacketsRateTabSniffer2.Text = dumpFile._packetsPerSecond.ToString("#,##0") + " Packets/sec";
}
the problem is that my application "get into" ProgressChanged functions but only in one time.
I think I missed something in my class.
I can only find one call to OnPacketProgress(), and it's outside of any loop.
public void startCapturing()
{
OnPacketProgress(_packetsCount++);
....
}
So Yes, that will only be called once.
You need something inside ReceivePackets()

serialport responding to EventHandler, but not ReadExisting or ReadLine?

i have a program that's reading from serial port in c#. i need to quickly write to a port, read from it, then close it. i cannot leave it open. i understand that serial ports read and write slowly, I've tried to set the ReadTimeout and WriteTimeout properties high, and added a thread.Sleep to try to drag the read and write times out for the devices. here's a little bit of code:
my method to write to port:
private void CheckPorts(string testMessage)
{
foreach (string s in SerialPort.GetPortNames())
{
portNumber = Int32.Parse(s.Remove(0, 3));
testSerial = new SerialPort(s, baudRate, Parity.None, 8, StopBits.One);
if (testSerial.IsOpen)
{
testSerial.Close();
}
testSerial.ReadTimeout = 2000;
testSerial.WriteTimeout = 1000;
testSerial.Open();
if (testSerial.IsOpen)
{
string received;
testSerial.DiscardInBuffer();
try
{
//testSerial.DataReceived += new SerialDataReceivedEventHandler(testSerialPort_DataReceived);
testSerial.Write(testMessage);
System.Threading.Thread.Sleep(2000);
received = testSerial.ReadExisting(); //EITHER I USE THIS OR EVENT HANDLER, NOT BOTH
}
catch (TimeoutException e)
{
testSerial.Close();
continue;
}
if (received.Length > 0)
{
MessageReceived(received);
}
testSerial.Close();
}
}
}
private void testSerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
string received = testSerial.ReadExisting();
int y = received.IndexOf("\r");
while (y == -1)
{
received = received + testSerial.ReadExisting();
y = received.IndexOf("\r");
}
if (testSerial.IsOpen)
{
testSerial.Close();
}
}
i'm wondering, if i absolutely have to use datahandler, how do i keep the serial port open long enough to read from it, but close the serialport before the next port needs to be opened?
see, the first method gets called a few times, and it iterates through a foreach loop, trying a message on a few ports, then trying to read a response. so, at some point i have to close the ports, or else the next time it goes through it, it doesn't work properly because the port is still open
HERE'S MY UPDATED CODE (still not working):
private void CheckPorts(string testMessage, int baudRate)
{
foreach (string s in SerialPort.GetPortNames())
{
var interval = 3000; // ms
var timer = new System.Timers.Timer(interval);
timer.Elapsed += (o, e) =>
{
timer.Enabled = false;
if (testSerial.IsOpen)
testSerial.Close(); // may not be necessary with Dispose?
testSerial.Dispose();
timer.Dispose();
};
portNumber = Int32.Parse(s.Remove(0, 3));
testSerial = new SerialPort(s, baudRate, Parity.None, 8, StopBits.One);
testSerial.ReadTimeout = 2000;
testSerial.WriteTimeout = 2000;
if (testSerial.IsOpen)
{
testSerial.Close();
}
testSerial.Open();
timer.Enabled = true;
if (testSerial.IsOpen)
{
string received;
//testSerial.DiscardInBuffer();
//autoEvent = new AutoResetEvent(false);
try
{
// testSerial.DataReceived += new SerialDataReceivedEventHandler(testSerialPort_DataReceived);
// autoEvent.Reset();
lblPortNum.Content = s;
lblPortNum.Refresh();
testSerial.Write(testMessage);
//System.Threading.Thread.Sleep(2000);
//testSerial.NewLine = "\r\n";
byte[] rBuff = new byte[2];
int rCnt = testSerial.Read(rBuff, 0, 2);
System.Text.Encoding enc = System.Text.Encoding.ASCII;
received = enc.GetString(rBuff);
//received = testSerial.ReadLine();
}
catch (TimeoutException e)
{
testSerial.Close();
continue;
}
if (received.Length > 0)
{
MessageReceived(received, Int16.Parse(s.Remove(0, 3)));
}
/*
if (autoEvent.WaitOne(2000))
{
// the port responded
// testSerial.Close();
autoEvent.Dispose();
lblPortNum.Content = "HEY I RESPONDED";
}
else
{
testSerial.Close();
autoEvent.Dispose();
continue;
// port did not respond within 2 seconds
}*/
//testSerial.Close();
}
}
}
UPDATED AGAIN (still not working properly)
private void CheckPorts(string testMessage, int baudRate)
{
foreach (string s in SerialPort.GetPortNames())
{
portNumber = Int32.Parse(s.Remove(0, 3));
// MUST BE LOCAL
var serialOneOfMany = new SerialPort(s, baudRate, Parity.None, 8, StopBits.One);
serialOneOfMany.ReadTimeout = 2000;
serialOneOfMany.WriteTimeout = 2000;
if (serialOneOfMany.IsOpen)
{
serialOneOfMany.Close();
}
// timer must be defined _after_ serialOneOfMany
var interval = 3000; // ms
var timer = new System.Timers.Timer(interval);
timer.Elapsed += (o, e) =>
{
timer.Enabled = false;
if (serialOneOfMany.IsOpen)
serialOneOfMany.Close(); // may not be necessary with Dispose?
serialOneOfMany.Dispose();
timer.Dispose();
};
if (serialOneOfMany.IsOpen)
{
string received;
try
{
lblPortNum.Content = s;
lblPortNum.Refresh();
serialOneOfMany.Write(testMessage);
byte[] rBuff = new byte[2];
int rCnt = serialOneOfMany.Read(rBuff, 0, 2);
System.Text.Encoding enc = System.Text.Encoding.ASCII;
received = enc.GetString(rBuff);
}
catch (TimeoutException e)
{
serialOneOfMany.Close();
continue;
}
if (received.Length > 0)
{
CheckIfTheMessageMatches(received, Int16.Parse(s.Remove(0, 3)));
}
}
}
}
so with this update, it just blows through the code, i can step through the code line by line, but it doesn't stop for 3 seconds at all. if i run it without any debugging breaks, it just goes through it i a fraction of a second
UPDATE 10-25-11
private void CheckPorts(string testMessage, int baudRate)
{
foreach (string s in SerialPort.GetPortNames())
{
string received = "";
testSerial = new SerialPort(s,baudRate, Parity.None, 8, StopBits.One);
lblStatus.Content = "Scanning...";
lblStatus.Refresh();
if (testSerial.IsOpen)
{
testSerial.Close();
}
else
{
testSerial.Open();
}
if (testSerial.IsOpen)
{
try
{
testSerial.NewLine = "\r";
lblPortNum.Content = s;
lblPortNum.Refresh();
testSerial.WriteTimeout= 500;
testSerial.ReadTimeout = 1000;
testSerial.WriteLine(testMessage);
System.Threading.Thread.Sleep(500);
/*THIS DOESN'T WORK
byte[] buffer = new byte[testSerial.BytesToRead];
int rCnt = testSerial.Read(buffer, 0, buffer.Length);
received = enc.GetString(buffer);*/
//received = Convert.ToString(testSerial.BaseStream.Read(buffer, 0, (int)buffer.Length));
received = testSerial.ReadLine();
int y = received.IndexOf("\r");
while (y == -1)
{
received = received + testSerial.ReadExisting();
y = received.Length;
}
if (lblInfo.Dispatcher.Thread == Thread.CurrentThread)
{
CheckIfTheMessageMatches(received, s);
received = received + lblInfo.Content;
lblInfo.Content = received;
}
else
{
lblInfo.Dispatcher.Invoke(DispatcherPriority.Normal, new ThreadCheck(threadCheck), received);
}
if (testSerial.IsOpen)
{
testSerial.Close();
}
/*I USE THIS WITH THE sPort.Read() METHOD
while (rCnt > 0)
{
if (lblInfo.Dispatcher.Thread == Thread.CurrentThread)
{
CheckIfTheMessageMatches(received, s);
rCnt = 0;
received = received + lblInfo.Content;
lblInfo.Content = received;
}
else
{
lblInfo.Dispatcher.Invoke(DispatcherPriority.Normal, new ThreadCheck(threadCheck), received);
}
}
*/
if (testSerial.IsOpen)
{
testSerial.Close();
}
}
catch (TimeoutException e)
{
testSerial.Close();
continue;
}
received = null;
}
}
lblStatus.Content = "Finished Scanning.";
lblPortNum.Content = "";
}
UPDATED CODE
here's some new code, still not working, dataeventhandler not even called once. i know it's getting messages because i have another program that works with the serial devices
private void CheckPorts(string testMessage, int baudRate)
{
foreach (string s in SerialPort.GetPortNames())
{
var serialOneOfMany = new SerialPort(s, baudRate, Parity.None, 8, StopBits.One);
serialOneOfMany.ReadTimeout = 700;
serialOneOfMany.WriteTimeout = 100;
var interval = 500; // ms
var timer = new System.Timers.Timer(interval);
timer.Elapsed += (o, e) =>
{
timer.Enabled = false;
if (serialOneOfMany.IsOpen)
serialOneOfMany.Close(); // may not be necessary with Dispose?
serialOneOfMany.Dispose();
timer.Dispose();
};
timer.Enabled = true;
lblStatus.Content = "Scanning...";
lblStatus.Refresh();
if (serialOneOfMany.IsOpen)
{
serialOneOfMany.Close();
}
else
{
serialOneOfMany.Open();
}
if (serialOneOfMany.IsOpen)
{
string received;
try
{
lblPortNum.Content = s;
lblPortNum.Refresh();
serialOneOfMany.WriteLine(testMessage);
System.Threading.Thread.Sleep(400);
serialOneOfMany.DataReceived += new SerialDataReceivedEventHandler(testSerialPort_DataReceived);
}
catch (TimeoutException e)
{
serialOneOfMany.Close();
continue;
}
}
}
lblStatus.Content = "Finished Scanning.";
lblPortNum.Content = "";
}
private void testSerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
SerialPort receivingSerial = sender as SerialPort;
string received = receivingSerial.ReadExisting();
int y = received.IndexOf("\r");
while (y == -1)
{
received = received + receivingSerial.ReadExisting();
y = received.IndexOf("\r");
}
if (lblInfo.Dispatcher.Thread == Thread.CurrentThread)
{
string name = receivingSerial.PortName;
received = received + lblInfo.Content;
lblInfo.Content = received;
CheckIfTheMessageMatches(received, name);
}
else
{
lblInfo.Dispatcher.Invoke(DispatcherPriority.Normal, new ThreadCheck(threadCheck), received);
}
if (receivingSerial.IsOpen)
{
receivingSerial.Close();
}
}
You should be able to do these simultaneously (assuming that's ok). You would then close them as the DataReceived event is raised (extraneous code removed). Just don't close the port in CheckPorts.
private void testSerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
SerialPort localSerialPort = sender as SerialPort;
... // use localSerialPort instead of global/class variable
if (localSerialPort.IsOpen)
{
localSerialPort.Close();
}
}
EDIT: Responding to comment.
You can always add a timer on the fly. If you put this in the foreach loop, you'll get a timer for every serial port that will dispose its given serial port after 3 seconds. It's important here that the timer is declared within the foreach loop.
var interval = 3000; // ms
var timer = new System.Timers.Timer(interval);
timer.Elapsed += (o,e) =>
{
timer.Enabled = false;
if (testSerial.IsOpen)
testSerial.Close(); // may not be necessary with Dispose?
testSerial.Dispose();
timer.Dispose();
}
timer.Enabled = true;
EDIT: Code updated so I'll update
Scope is very important with the code I provided. You should get rid of the non-local testSerial or use an entirely different name here.
portNumber = Int32.Parse(s.Remove(0, 3));
// MUST BE LOCAL
var serialOneOfMany = new SerialPort(s, baudRate, Parity.None, 8, StopBits.One);
serialOneOfMany.ReadTimeout = 2000;
serialOneOfMany.WriteTimeout = 2000;
if (serialOneOfMany.IsOpen)
{
serialOneOfMany.Close();
}
// timer must be defined _after_ serialOneOfMany
var interval = 3000; // ms
var timer = new System.Timers.Timer(interval);
timer.Elapsed += (o, e) =>
{
timer.Enabled = false;
if (serialOneOfMany.IsOpen)
serialOneOfMany.Close(); // may not be necessary with Dispose?
serialOneOfMany.Dispose();
timer.Dispose();
};
Check this info from Microsoft:
This method returns the contents of the stream and internal buffer of the SerialPort object as a string. This method does not use a time-out. Note that this method can leave trailing lead bytes in the internal buffer, which makes the BytesToRead value greater than zero.
Why don't use the usual Read method SerialPort.Read (Byte[], Int32, Int32)
Please have a look at this (I also used in an answer to a serial port related question asked by darthwillard). All the ports are opened one after another, the DataReceived events are bound (all you need to do there is to test the incoming message), but no waiting is required. The timer event handler can close all the ports or keep the one you want to use etc. I hope it helps!
private List<SerialPort> openPorts = new List<SerialPort>();
private void button3_Click(object sender, EventArgs e)
{
int baudRate = 9600;
string testMessage = "test";
txtPortName.Text = "Testing all serial ports";
foreach (string s in SerialPort.GetPortNames())
{
SerialPort newPort = new SerialPort(s, baudRate, Parity.None, 8, StopBits.One);
if (!newPort.IsOpen)
{
try
{
newPort.Open();
}
catch { }
}
if (newPort.IsOpen)
{
openPorts.Add(newPort);
newPort.DataReceived += new SerialDataReceivedEventHandler(serialOneOfMany_DataReceived);
newPort.Write(testMessage);
}
else
{
newPort.Dispose();
}
}
txtPortName.Text = "Waiting for response";
tmrPortTest.Enabled = true;
}
private void serialOneOfMany_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
txtPortName.Text = ((SerialPort)sender).PortName;
}
private void tmrPortTest_Tick(object sender, EventArgs e)
{
tmrPortTest.Enabled = false;
foreach (SerialPort port in openPorts)
{
if (port.PortName != txtPortName.Text)
{
port.Close();
port.Dispose();
}
}
}
Try setting your event handler before you write to the port, and then see if it doesn't catch your break point.
You can't use Thread.Sleep. It blocks the read from the device. You need to spawn a new thread.
You may be best with BackgroundWorker. Eg:
BackgroundWorker worker=new BackgroundWorker();
worker.DoWork += (s, dwe) =>
{
// do your serial IO here
worker.RunWorkerCompleted += (s, rwe) =>
{
// check for rwe.Error and respond
};
worker.RunWorkerAsync();
open the port in public form1
just after/below the InitializeComponent(); myport.open
and close the after data is received.
worked!

Categories

Resources