After much research I am still stumped. I have a serial port object which is reading data continuously. What I am able to do it generate the dataReceived event, communicate with the port, and output the received values to the debug window. So, I'm pretty sure it's all working physically. The problem is when I try to pass the serial port output to my original thread I get an error. It says I can't have thread cross talk (or something to that effect). I've been trying to use a backgroundWorker but I'm not sure that is the solution I want plus with my novice skills it's a little over my head. And I tried to use invoke but the method doesn't seem to be available. (I might be calling from the wrong object?) Anyway section is below.
namespace Photometer
{
class csRadiometerILT1700
{
//manufacturer specs for baud rate, databits, and stop bits
static string portName="COM1";
static int baudRate = 1200;
static int dataBits = 8;
//instantialize a serial port object for the Radiometer
private SerialPort RadiometerSerial = new SerialPort(portName, baudRate, Parity.None, dataBits, StopBits.One);
//constructor
//public csRadiometerILT1700(Form ParentForm, Chart outputChart)
public csRadiometerILT1700()
{
//two handshaking properties of the ILT1700. Handshaking is enabled and
//http://stackoverflow.com/questions/6277619/problem-reading-serial-port-c-net-2-0-to-get-weighing-machine-output
RadiometerSerial.Handshake= Handshake.RequestToSend;
RadiometerSerial.DtrEnable = true;
RadiometerSerial.DataReceived += new SerialDataReceivedEventHandler(RadiometerSerial_DataReceived);
}
public void openPort()
{
if (!RadiometerSerial.IsOpen)
{
RadiometerSerial.Open();
}
}
public void closePort()
{
RadiometerSerial.Close();
}
string RadiometerVoltageReadingString;
int RadiometerVoltageReadingInt;
private void RadiometerSerial_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//It's here that this.invoke()... cannot be called.
RadiometerVoltageReadingString= (RadiometerSerial.ReadExisting().ToString()); //y-value
Debug.Print(RadiometerVoltageReadingString.ToString());
makeRadioReadingDouble(RadiometerVoltageReadingString);
}
private void makeRadioReadingDouble(string inputVoltageString)
{
List<double> outputVoltageDouble=new List<double>(2);
if (!(inputVoltageString == "\r\n" || inputVoltageString == ""))
{
string[] voltageValAndExpo = inputVoltageString.Split(new string[] { "e", "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
for (int inCounter = 0; inCounter < voltageValAndExpo.Count(); inCounter=inCounter+2)
{
double voltageVal = Convert.ToDouble(voltageValAndExpo[inCounter]);
double voltageExpo = Convert.ToDouble(voltageValAndExpo[inCounter + 1]);
outputVoltageDouble.Add(Math.Pow(voltageVal, voltageExpo));
}
}
}
}
}
This is all called when I form loads with the code
csRadiometerILT1700 Radiometer;
...
Radiometer = new csRadiometerILT1700();
Radiometer.openPort();
Any insight is appreciated.
EDIT:
I altered my csRadiometerILT1700 constructor to
public csRadiometerILT1700(Form inputForm)
{
//inputForm.Invoke(
//two handshaking properties of the ILT1700. Handshaking is enabled and
//http://stackoverflow.com/questions/6277619/problem-reading-serial-port-c-net-2-0-to-get-weighing-machine-output
RadiometerSerial.Handshake= Handshake.RequestToSend;
RadiometerSerial.DtrEnable = true;
RadiometerSerial.DataReceived += new SerialDataReceivedEventHandler(RadiometerSerial_DataReceived);
inputForm.Invoke(DataReceived);
}
and declare
public event Delegate DataReceived;
in the csRadiometerILT1700 class. But this gives me the error of "Datareceived must be of a delegate type." How do I resolve this now? Am I on the right track?
Your RadiometerILT1700 class needs an event to report it's received (and processed) data.
Your Form subscribes to that event
The Forms eventhandler uses this.Invoke() to overcome the cross-threading issue.
Invoke is a method on a Delegate or a Form or Control, since csRadiometerILT1700 is none of these it is not inheriting an Invoke implemenation from those classes.
You will need to raise another event to the caller of csRadiometerILT1700 and hadle that on you GUI somewhere (along with any cross thread issues.) Alternatively, you could provide csRadiometerILT1700 with a delegate it could use to callback, kind of like a hand rolled event.
Once you have the data in your Form you can use Control.InokeRequired to detect a cross thread situation and Control.Invoke to make the cross thread call.
anytime you try to post to the main thread from a different thread you'll get this error. You need to use a delegate and Invoke on the control you want to call from the thread that isn't the main form thread.
Assuming the error is actually:
Control control name accessed from a thread other than the thread it
was created on.
The problem is you can't affect your GUI from another thread. You need to invoke the form or control to pass control so it can be modified. You should be able to interact with most other elements, but not a form.
You should not call this.Invoke there, the way you are doing it is like trying to sync your own thread with your own instead with the UI. you should call formhandle.Invoke, or inside form class register for the event and then you can use this.invoke
Related
I'm quite new to C# and certainly OOP concepts.. so forgive the stupidity of my question.
I have a system I wish to communicate with, It has a number of commands that can be called with an associated response. (Communication is done via TCP/IP or Serial) (I implemented an Interface with SendMessage so that I can use multiple transport mechanisms)
I want to create a method for each command and then expose these, which is simple enough. The device also lets say 'broadcasts' messages as well which I want to act on, so I was using an event handler for this which works well..
At the moment in the event handler I catch OK and ERROR style messages, but ideally I would like to also be able to send the command from the above method and catch an error and return a bool value based on the command.
Can anyone think of a way I can do something like this and point me in the right direction?
Thanks
David
You can use helper to wait for event. Some ugly code from past:
public class ComWait
{
ManualResetEvent _waitEvent;
SomeEvent _eventHandler;
public ComWait()
{
_waitEvent = new ManualResetEvent(false);
_eventHandler = new SomeEvent(Watch);
}
void Watch()
{
_waitEvent.Set();
}
public bool Wait(int time = 3000)
{
_waitEvent.Reset();
SomeEvent += _eventHandler;
bool result = _waitEvent.WaitOne(time, false);
SomeEvent -= _eventHandler;
return result;
}
}
Usage is
ComWait wait = new ComWait();
if(!wait.Wait())
return; // timeout
// process
It will simply block synchronous method until event is rised or timeout occurs. It should be easy to add parameters: to unblock on specific event and to pass event handler parameters back to caller.
Otherwise I would simply have method inside communication class to use as a blocker:
readonly object _waitLock = new object();
public void Wait()
{
lock (_waitLock)
if (!Monitor.Wait(_waitLock, 3000))
throw new TimeoutException("No communications");
}
Signal at same time as you rise event:
lock (_waitLock)
Monitor.PulseAll(_waitLock);
I'm writing a program that listens on a Serial Port. I already have code that utilizes the VCP drivers (Virtual COM Port) to open a serial connection and then add an event handler for any time data is received. That code roughly looks like this:
public void OpenPort(string portNumber)
{
_port = new SerialPort(
portName: portNumber,
baudRate: 9600,
parity: Parity.None,
dataBits: 8,
stopBits: StopBits.One
);
_port.DataReceived += ReadData;
}
private void ReadData(object sender, SerialDataReceivedEventArgs e)
{
string data = _port.ReadExisting().Trim();
Console.WriteLine("Received: " + data);
}
This works great. It's very easy for me to understand how to set up events using the += notation. But I'm trying to switch over from using the VCP drivers to instead using the D2XX drivers provided by FTDI. I have most of the equivalent code that I need written, with the notable exception of being able to read data whenever a "data received" event occurs.
The D2XX driver includes one method for setting up event handlers whenever data is received, called SetEventNotification. Here's what the method signature looks like:
SetEventNotification(UInt32 eventMask, EventWaitHandle eventHandle);
The first parameter is straight-forward enough (they have some predefined uints you can pass in to determine when the event should trigger), but I've never worked directly with EventWaitHandles before, and I found the documentation difficult to grasp, so I'm having trouble getting started.
At the end of the day... I would like to have an event listener method which performs a read task, and which I can assign using the += operator, as I did above with the VCP driver.
Based on what I was reading, it looks like I'll have to create a new Thread that essentially polls continuously for the EventWaitHandle's signal? Or something like that? Any examples or sample code to get me started (or finished!) would be appreciated.
Here's what I have so far:
public void OpenPort(string portNumber)
{
_port = new FTDI();
var status = _port.OpenBySerialNumber(portNumber);
if (FTDI.FT_STATUS.FT_OK != status) throw new Exception();
status = _port.SetBaudRate((UInt32) 9600);
if (FTDI.FT_STATUS.FT_OK != status) throw new Exception();
status = _port.SetDataCharacteristics(
DataBits: FTDI.FT_DATA_BITS.FT_BITS_8,
StopBits: FTDI.FT_STOP_BITS.FT_STOP_BITS_1,
Parity: FTDI.FT_PARITY.FT_PARITY_NONE
);
if (FTDI.FT_STATUS.FT_OK != status) throw new Exception();
var evHandle = new EventWaitHandle(false, EventResetMode.AutoReset, "");
_port.SetEventNotification(FTDI.FT_EVENTS.FT_EVENT_RXCHAR, evHandle);
// ... now what?
}
public void ReadData(object sender, EventArgs e)
{
UInt32 bytesAvailable = 0;
_port.GetRxBytesAvailable(ref bytesAvailable);
string data;
UInt32 bytesRead = 0;
_port.Read(out data, bytesAvailable, ref bytesRead);
data = data.Trim();
Console.WriteLine("Received: " + data);
}
I'll have to create a new Thread that essentially polls continuously for the EventWaitHandle's signal
Polls, no. But waits, yes. All that an event handle can do is let a thread sleep until the event is signaled. Note that "event" here means something completely different from a C# "event", though of course you can use the former as part of an implementation of the latter.
Frankly, it's not clear at all why you are headed down this part. Are you dealing with data transmitted over the standard serial port? If so, then there should never be any need to use some third-party API; Windows and .NET provide all you need, and you should stick with that. What does using this third-party API gain you that you are unable to accomplish using the standard SerialPort class?
As far as the event itself goes, without more context (and no, it's unlikely anyone would sift through the PDF you linked to figure out how to produce a turn-key solution for you), all one can offer is a general outline of how you can use the event handle to implement an event:
public event EventHandler DataReceived;
private bool _done;
private void PortListener(EventWaitHandle waitHandle)
{
while (true)
{
waitHandle.WaitOne();
if (_done)
{
break;
}
EventHandler handler = DataReceived;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
public void StartListening(EventWaitHandle waitHandle)
{
_done = false;
new Thread(() => PortListener(waitHandle)).Start()
}
public void StopListening(EventWaitHandle waitHandle)
{
_done = true;
waitHandle.Set();
}
The above provides a DataReceived C# event that is raised any time the wait handle is signaled. It assumes an auto-reset event. You can also use manual reset, simply by (of course) manually resetting the event handle any time it's signaled and you've raised the C# event.
To do this, it simply maintains an internal flag _done indicating whether the thread should be running or not, and provides the Start... and Stop... methods, which clear the flag and start the thread with its loop, and set the flag and signal the event, respectively.
So, around a week ago I asked a question about activex and UDP. Here it is:
C# UDP Socket client and server
Now, I created two applications, one (the sender) to send pre-defined strings via UDP. The other is activex component that is called from a webpage, and it's thread is working in the background. Once an UDP message arrives, then it's doing it's stuff (writing in database, writing in log.txt, and so on).
The last thing i need is to return data (it's yet to be said if it will be string or something else). However, the method in the activex which is called must be a void, because if it's made to be string, the threading wont work, and only the first message will arrive.
My question is, how to do that? How to return data from a void function? For example, the web app now is calling the activex DLL like this:
ClassLibrary1.Class1 activex = new ClassLibrary1.Class1();
activex.StartThread();
And the StartThread() calls the listening thread and it's working in the background, and once UDP msg arrives, its doing some stuff like i said above.
How can i return value with the threads (events) and the web app will catch it and use it?
Thanks a lot.
You can use events (which implement the Observable pattern) to alert any listener that a new message has arrived:
public class NewMessageArgs : EventArgs
{
public string Message { get; private set; }
public NewMessageArgs(string message)
{
Message = message;
}
}
public class ActiveXComponent
{
public event EventHandler<NewMessageArgs> OnMessage;
public void StartThread()
{
while (true)
{
//do stuff
//raise "message received" event
if (OnMessage != null)
OnMessage(this, new NewMessageArgs("hi"));
}
}
}
You can then listen to these events like so:
ActiveXComponent activex = new ActiveXComponent();
activex.OnMessage += ProcessMessage;
activex.StartThread();
public void ProcessMessage(object sender, NewMessageArgs args)
{
var msg = args.Message;
//process
}
Basically you have to store some data in a spot where you can access it from both places (from the thread, and from the place where you started the thread). So you have a couple of options from the top of my head.
Store it in a database
Create a specific object (whatever type you need), and store it in a place where it is accessible from both places. For example, a singleton. A simpler better solution is to create a property on your ClassLibrary.Class1 class: set it from within the Class1-class, and get it from the place where you created an instance of your Class1-class.
Add an event to your Class1-class which fires when it is finished doing its job. And add some data to the EventArgs.
I'm assuming here you get notified when your thread is done doing whatever it is doing.
Edit: added events
The threading function can change the fields values of the class and you can access those fields, also your thread can fire events that other classes can subcribe to and then act on it.
Class1
{
private string value;
public string Value{get{return value;} set{value=value; FireTheEvent();}}
}
I have wrote a simple client that use TcpClient in dotnet to communicate. In order to wait for data messages from server i use a Read() thread that use blocking Read() call on socket. When i receive something i have to generate various events. These event occur in the worker thread and thus you cannot update a UI from it directly. Invoke() can be use but for end developer its difficult as my SDK would be use by users who may not use UI at all or use Presentation Framework. Presentation framework have different way of handling this. Invoke() on our test app as Microstation Addin take a lot of time at the moment. Microstation is single threaded application and call invoke on its thread is not good as it is always busy doing drawing and other stuff message take too long to process.
I want my events to generate in same thread as UI so user donot have to go through the Dispatcher or Invoke.
Now i want to know how can i be notified by socket when data arrive? Is there a build in callback for that. I like winsock style receive event without use of separate read thread. I also do not want to use window timer to for polling for data.
I found IOControlCode.AsyncIO flag in IOControl() function which help says
Enable notification for when data is
waiting to be received. This value is
equal to the Winsock 2 FIOASYNC
constant.
I could not found any example on how to use it to get notification. If i am right in MFC/Winsock we have to create a window of size(0,0) which was just used for listening for the data receive event or other socket events. But i don't know how to do that in dotnet application.
Ok I got it up and running. What I was really looking to was how to seamlessly post events to an UI thread, in which my connection is created. After going through framework code I came up with following proof of concept. SynchronizationContext can be use to bind my component to the UI thread that created it. Then I can post events to that UI thread directly, without using Invoke.
In the following example I created a ThreadUISafeTimer which uses a seperate thread, just like my socket client that uses one for reading and raising events. In this case, context is used to post the event if not null, otherwise the event is raised using the worker thread.
[DefaultEvent("Tick")]
public class ThreadUISafeTimer : Component
{
private const int True = 1;
private const int False = 0;
private int enabled = False;
private SynchronizationContext context;
public event EventHandler Tick = delegate { };
[DefaultValue(false)]
public ushort Interval { get; set; }
public ThreadUISafeTimer() {
Interval = 100;
this.Events.AddHandler("Tick", Tick);
//If this class is created by a UI thread it will always post the Tick event to it.
//otherwise it would be null and Tick would occur in a seperate thread.
context = SynchronizationContext.Current;
}
protected override bool CanRaiseEvents {
get {
return true;
}
}
[DefaultValue(false)]
public bool Enabled {
get {
return enabled == True;
}
set {
int newval = value ? True : False;
if (enabled != newval) {
if (newval == False)
Thread.VolatileWrite(ref enabled, False);
else {
enabled = True;
ThreadPool.QueueUserWorkItem(
new WaitCallback(delegate(object o) {
try {
do {
try {
Thread.Sleep(Interval);
if (Thread.VolatileRead(ref enabled) == True) {
var callback = new SendOrPostCallback(delegate(object arg) {
try {
Tick(this, EventArgs.Empty);
}
catch (Exception exp) {
Application.OnThreadException(exp);
return;
}
});
//If context is null raise Tick event from current thread
if (context == null)
callback(null);
else
//otherwise post it to the UI thread that owns this timer.
context.Post(callback, null);
}
}
catch (ThreadInterruptedException) {
}
} while (Thread.VolatileRead(ref enabled) == True);
}
catch (ThreadAbortException) {
}
}), null);
}
}
}
}
Take a look at this question which is roughly the same and solved by using the Event Broker pattern.
Sending instructions to a thread which is waiting for TCP?
Basically you would have one object with an event that all your threads subscribe to. It will also have a method that can be called which will invoke the event. It maybe sounds complicated, but its fairly simple.
Example code is here http://msforge.net/blogs/paki/archive/2007/11/20/EventBroker-implementation-in-C_2300_-full-source-code.aspx.
I have a windows forms program with a form MainForm. On a button press I start a code that runs (pulses) on every 0.5secs on another thread. I want to modify many things, like labels, progressbars on my MainForm, from the Pulse method. How is this possible?
So I would like to know, how to interract with variables, values, in that thread, and the MainForm. Modify each other, etc..
On foo button click, I tell my pulsator to start.
Pulsator.Initialize();
Here is the Pulsator class:
public static class Pulsator
{
private static Thread _worker;
public static void Initialize()
{
_worker = new Thread(Pulse);
_worker.IsBackground = true;
_worker.Start();
}
public static void Close()
{
if (_worker != null)
{
_worker.Abort();
while (_worker.IsAlive || _worker.ThreadState != ThreadState.Stopped)
{
//closing
}
}
}
public static void Pulse()
{
if (_worker != null)
{
while (true)
{
SomeOtherClass.Pulse();
Thread.Sleep(500);
}
}
else
{
SomeOtherClass.Pulse(); // yeah I know this doesnt needed
}
}
}
SomeOtherClass Pulse method looks like :
public static void Pulse()
{
//here I will have several values, variables, and I want to show results,
// values on my MainForm, like:
Random random = new Random();
MainForm.label1.Text = random.Next(123,321).ToString(); // I hope you know what I mean
}
Of course it's much complicated, it's just a silly example.
Generally, in WinForms it's not safe to modify the state of visual controls outside the thread that owns the control's underlying unmanaged resources (window handle). You have to use the Control.Invoke method to schedule executing the modification on the control's owning thread.
As others already mentioned, you have to use Control.Invoke to change the UI controls from the background thread.
Another option is to use System.ComponentModel.BackgroundWorker (it's available in the form designer toolbox). You could then take a regular forms timer, to call the RunWorkerAsync-Method and do your background work in the DoWork event handler, which is automatically called from another thread.
From there, you can hand data back to the main thread, by calling ReportProgress. This will raise the ProgressChanged event in the main thread, where you are free to update all your UI controls.
Why not use a System.Timers.Timer?
E.g.:
trainPassageTimer = new Timer(500);
trainPassageTimer.AutoReset = true;
trainPassageTimer.Elapsed += TimeElapsed;
...
private void TimeElapsed(object sender, ElapsedEventArgs elapsedEventArgs)
{
// Do stuff
// Remember to use BeginInvoke or Invoke to access Windows.Forms controls
}
C# 2 or higher (VS2005) has anonymous delegates (and C# 3 has lambdas which are a slightly neater version of the same idea).
These allow a thread to be started with a function that can "see" variables in the surrounding scope. So there is no need to explicitly pass it anything. On the downside, there is the danger that the thread will accidentally depend on something that it should not (e.g. a variable that is changing in other threads).
_worker = new Thread(delegate
{
// can refer to variables in enclosing scope(s).
});