SerialPort wait for response - c#

Do we have in .NET 4.0 the opportunity to wait for a response and then to return the response?
Currently I'm doing it like this but it isn't really nice and I don't like it:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
byte[] options = new byte[]{1,1,0};
COMManager mgr = new COMManager("COM1");
byte[] result = mgr.GetResponse(options);
}
}
And my COM Manager Class
(I have to do the operation in a seperate class (dll)):
public class COMManager
{
SerialPort sp = null;
byte[] result = null;
bool completed = false;
public COMManager(string comport)
{
sp = new SerialPort(comport);
sp.DataReceived +=new SerialDataReceivedEventHandler(sp_DataReceived);
}
public byte[] GetResponse(byte[] option)
{
sp.Write(option, 0, option.Length);
//I don't like the way...
while (!completed) { }
completed = false;
return result;
}
void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
result = new byte[sp.BytesToRead];
sp.Read(result, 0, sp.BytesToRead);
completed = true;
}
}
In .NET 4.5 we may have the opportunity to use the "await" statement. But for the current project we only are allowed to use .NET 4.0.
Any ideas?

There's no point in using the DataReceived event if you don't want to read asynchronously. Simply call the Read() method directly in GetResponse().
Beware that you cannot assume you will get a complete response, you cannot ignore the return value of Read(). It usually returns a couple of bytes only, serial ports are pretty slow. So be sure to keep calling Read() until you got the entire response.

For your original question, to block the executing thread you can use a ManualResetEvent or AutoResetEvent which will get Set when your response has been obtained. There's a fairly good explanation on the page.
For threading, the rule of thumb is that if you're not extremely clear on what you're doing, don't do it.
Synchronous blocking when you have access to events seems like a waste. Considering that the data is a stream, this might end up being a hard to maintain abstraction.
There's a longer explanation of the above idea with an example over here.
You can also do this in async with TaskCompletionSource. Instead of set, you can call SetResult, and you await the .Task, but the idea is pretty much the same.

The clean way would be to wait on an AutoResetEvent and for for the receive callback to signal it.
By creating a wrapper with this method, you can effectivly await in every version of .Net.

Related

c# thread sleep on DataReceived event

I wrote this code on c#
public class SerialClass
{
SerialPort s;
public Serial()
{
InitSerialPort();
s.DataReceived += dataReciver;
}
private void dataReciver(object sender, SerialDataReceivedEventArgs e)
{
lock (obj)
{
while (s.BytesToRead >0)
{
var line = s.ReadLine();
if(line=="hello")
{
Thread.Sleep(500);
s.WriteLine("hello to you friend");
}
else //......
}
}
}
}
When i got "hello" from the serial I want to answer after 500 milliseconds "hello to you friend".
I heard so much , don't use sleep on you code..
What is the disadvantage here to use sleep? If more data will get on serialport so new event will enter to dataReciver because it will be open on secondery thread.
so what is the disadvantage and what is the better/best way to implement it without sleep?
I use lock because I want only 1 thread will be on this reading
If you've done it right, you shouldn't need the lock.
IMHO, you should avoid the DataReceived event altogether. Wrap SerialPort.BaseStream in a StreamReader, then loop in an async method to read. Regardless, I also would not put the delay, asynchronous or otherwise, in sequence with your reading. You should always be ready to read.
You didn't provide real code, so it's impossible to offer a real code solution, but here's how I'd have written the bit of code you posted:
public class Serial
{
SerialPort s;
public Serial()
{
InitSerialPort();
// Ignore returned task...constructors shouldn't wait. You could store
// the task in a class field, to provide a mechanism to observe the
// receiving state.
Task task = ReceiveLoopAsync();
}
private async Task ReceiveLoopAsync()
{
using (StreamWriter writer = new StreamWriter(s.BaseStream))
using (StreamReader reader = new StreamReader(s.BaseStream))
{
string line;
while ((line = reader.ReadLineAsync()) != null)
{
if (line == "hello")
{
// Ignore returned task...we don't really care when it finishes
Task task = RespondAsync(writer);
}
}
}
}
private async Task RespondAsync(StreamWriter writer)
{
await Task.Delay(500);
writer.WriteLine("hello to you friend");
}
}
I've left out niceties like exception handling and more robust handling of the tasks. But the above is the basic idea. Note that all receiving is done in a single loop, with no need for cross-thread synchronization.

What is the fastest possible way to read a serial port in .net?

I need a serial port program to read data coming in at 4800 baud. Right now I have a simulator sending 15 lines of data every second. The output of it seems to get "behind" and can't keep up with the speed/amount of data coming in.
I have tried using ReadLine() with a DataReceieved event, which did not seem to be reliable, and now I am using an async method with serialPort.BaseStream.ReadAsync:
okToReadPort = true;
Task readTask = new Task(startAsyncRead);
readTask.Start();
//this method starts the async read process and the "nmeaList" is what
// is used by the other thread to display data
public async void startAsyncRead()
{
while (okToReadPort)
{
Task<string> task = ReadLineAsync(serialPort);
string line = await task;
NMEAMsg tempMsg = new NMEAMsg(line);
if (tempMsg.sentenceType != null)
{
nmeaList[tempMsg.sentenceType] = tempMsg;
}
}
public static async Task<string> ReadLineAsync(
this SerialPort serialPort)
{
// Console.WriteLine("Entering ReadLineAsync()...");
byte[] buffer = new byte[1];
string ret = string.Empty;
while (true)
{
await serialPort.BaseStream.ReadAsync(buffer, 0, 1);
ret += serialPort.Encoding.GetString(buffer);
if (ret.EndsWith(serialPort.NewLine))
return ret.Substring(0, ret.Length - serialPort.NewLine.Length);
}
}
This still seems inefficient, does anyone know of a better way to ensure that every piece of data is read from the port and accounted for?
Generally speaking, your issue is that you are performing IO synchronously with data processing. It doesn't help that your data processing is relatively expensive (string concatenation).
To fix the general problem, when you read a byte put it into a processing buffer (BlockingCollection works great here as it solves Producer/Consumer) and have another thread read from the buffer. That way the serial port can immediately begin reading again instead of waiting for your processing to finish.
As a side note, you would likely see a benefit by using StringBuilder in your code instead of string concatenation. You should still process via queue though.

wait for static callback complete

I've a scenario:
MyApp calls cameraCapture
that fires a callbackFunction
after the callbackFunction (I have a photo captured) completes, I do more stuff.
So I have to wait for callbackFunction to complete before executing another function. How could i do this?
Here my code:
private static readonly Plustek_Camera.PFNCK_EVENT staticFnCamera = fnPFNCK_EVENT;
public static bool fnPFNCK_EVENT(int iEvent, int iParam, IntPtr pUserData)
{
//capture picture and save to folder
}
//I implement callback start camera and fire a callback staticFnCamera
var _status = CameraCtrl.Start(CameraCtrl.ScanMode, CameraCtrl.Resolution, CameraCtrl.ImageFormat, CameraCtrl.Alignment, staticFnCamera);
//waiting for staticFnCamera complete make sure image produced
ReadPassPortText();
If I understand correctly, you have some camera control that provides an asynchronous API to start capturing an image, but you want to wait synchronously for that operation to complete.
If so, there are lots of different ways to accomplish what you're trying to do. One such way would be to use a TaskCompletionSource:
TaskCompletionSource<bool> source = new TaskCompletionSource<bool>();
var _status = CameraCtrl.Start(CameraCtrl.ScanMode, CameraCtrl.Resolution,
CameraCtrl.ImageFormat, CameraCtrl.Alignment,
(iEvent, iParam, pUserData) =>
{
staticFnCamera(iEvent, iParam, pUserData);
source.SetResult(true);
});
//waiting for staticFnCamera complete make sure image produced
await source.Task;
ReadPassPortText();
Note that the above uses await, which is valid only in an async method. You haven't provided enough context to show exactly how that would work in your code, but I strongly recommend following the above. That will avoid blocking the currently running thread; the async method will return at that point, letting the thread continue to run, and will be resumed at the ReadPassPortText(); statement when the operation completes.
If for some reason you simply cannot use the await in your method, you can instead simply do source.Task.Wait();. This will, of course, block the currently executing thread at that statement.
The above requires .NET 4.5. There are other approaches that work with earlier versions of .NET, but you would need to be specific about your requirements to make it worth trying to describe those.
Edit:
Since you are using .NET 4.0, and presumably Visual Studio 2010, the above won't work for you "out-of-the-box". One option is to download the Async CTP for Visual Studio, which will give you the C# 5.0 compiler that would enable the above. But if that's not feasible for you, another option is to just do what the compiler would do on your behalf, by replacing the last two lines above with the following:
source.Task.ContinueWith(task => ReadPassPortText(),
TaskScheduler.FromCurrentSynchronizationContext());
That would attach the continuation delegate that call ReadPassPortText() to the Task object from the TaskCompletionSource, specifying the current synchronization context as the source of the scheduler to use to actually run the continuation.
The method would return after calling ContinueWith() (just as it would in the await version, except that here it's written out explicitly instead of the compiler doing it for you). When the Task object is set to the completed state, the previously-registered continuation will be executed.
Note that your original question isn't very clear about the context. If the code is running in the UI thread, then using FromCurrentSynchronizationContext() is important and will ensure that the continuation is executed in the UI thread as well. Otherwise, you can probably get away without specifying a scheduler in the call to ContinueWith().
This demonstrates an async-await pattern that you can use. As Peter Duniho points out in the comments, you will have to adapt the pattern to the API that you're using. Try playing with it here at this fiddle to understand how these things work.
using System;
using System.Threading.Tasks;
public class MyApp
{
public static void Main()
{
Console.WriteLine("1. MyApp calls camera capture.");
CameraCaptureAsync().Wait();
}
public async static Task CameraCaptureAsync()
{
Console.WriteLine("2. That calls callbackFunction");
var task = CallbackFunction();
Console.WriteLine("4. In the meantime.");
Console.WriteLine("5. Do some other stuff. ");
await task;
Console.WriteLine("7. Process the " + task.Result);
DoMoreStuff();
}
public async static Task<string> CallbackFunction()
{
Console.WriteLine("3. Which takes a picture.");
await Task.Delay(100);
Console.WriteLine("6. After the callback functions completes");
return "Photograph";
}
public static void DoMoreStuff()
{
Console.WriteLine("8. Do more stuff.");
}
}
After try some implement callback waiting, i try to resolve by adding another form for capturing images (frmSecond).
frmFirst call frmSecond and waiting in 5 to 7 seconds to make sure capture completed.
after that processing ReadPassPortText()
frmFirst Code:
frmReadPassport frmReadPass = new frmReadPassport();
frmReadPass.ShowDialog();
ReadPassPortText();
frmSecondCode
private CAMERACTRL CameraCtrl = null;
//Add static for call from camera start , make sure this alive
private static Plustek_Camera.PFNCK_EVENT staticFnCamera ;
public frmReadPassport()
{
InitializeComponent();
staticFnCamera = fnPFNCK_EVENT;
}
Timer formClose = new Timer();
private void frmReadPassport_Load(object sender, EventArgs e)
{
CaptureImages();
formClose.Interval = 7000; // 7 sec
formClose.Tick += new EventHandler(formClose_Tick);
formClose.Start();
}
private void formClose_Tick(object sender, EventArgs e)
{
//free camera first
// check if camera start then stop
ReleaseResourceCamera();
staticFnCamera =null;
formClose.Stop();
formClose.Tick -= new EventHandler(formClose_Tick);
this.Dispose();
this.Close();
}
private void CaptureImages()
{
CameraCtrl = new CAMERACTRL();
CameraCtrl.LoadCameraDll();
CameraCtrl.GetDeviceList();
String temp = CameraCtrl.GetParameter();
CameraCtrl.Start(CameraCtrl.ScanMode,CameraCtrl.Resolution,CameraCtrl.ImageFormat, CameraCtrl.Alignment, staticFnCamera);
}
public static bool fnPFNCK_EVENT(int iEvent, int iParam, IntPtr UserData)
{
captureImage();
return true;
}
}

WebClient DownloadStringAsync blocked - never finished

I have specific problem with WebClient in my Windows Phone app (using MVVM)
private string _lastCurrencyRatesJson;
private bool _lastCurrencyRatesJsonLoaded = false;
private void GetLastCoursesFromApiAsync()
{
var uri = new Uri(string.Format(OperationGetLastCourses, AppSettings.ApiEndpoint, AppSettings.ApiKey));
var client = new WebClient { Encoding = Encoding.UTF8 };
client.DownloadStringCompleted += client_DownloadStringCompleted;
client.DownloadStringAsync(uri);
}
void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
_lastCurrencyRatesJson = e.Result;
_lastCurrencyRatesJsonLoaded = true;
}
public List<CurrencyRate> GetLastCourses()
{
var worker = new Thread(GetLastCoursesFromApiAsync);
worker.Start();
while (!_lastCurrencyRatesJsonLoaded)
{
}
.....
The problem is that client_DownloadStringCompleted is never fired BUT when I change GetLastCourses this way:
public List<CurrencyRate> GetLastCourses()
{
var worker = new Thread(GetLastCoursesFromApiAsync);
worker.Start();
// whetever here, but any while...
client_DownloadStringCompleted is fired and data are obtained. It means, connectivity is ok.
I had very similar problems with DownloadStringTaskAsyn. Example:
private async Task<string> GetCoursesForDayFromApiAsJson(DateTime date)
{
var uri = new Uri(string.Format(OperationGetCoursesForDay, AppSettings.ApiEndpoint, AppSettings.ApiKey, date.ToString(DateFormat)));
var client = new WebClient { Encoding = Encoding.UTF8 };
return await client.DownloadStringTaskAsync(uri);
}
Again, at the line with await is application waiting for the data but the DownloadStringTaskAsync is never finished and my UI is still loading.
Any ideas what could be wrong?
SITUATION ONE DAY AGO
So, it looks that WP application is working just with one thread. It means, current thread have to be "finished" and then is DownloadStringTaskAsync finished and the code under the await executed. When I want to work with Task.Result I can not. Never.
When I create another Thread and I am trying to wait for thread completetion (using Join()), created Thread is never finsihed and the code after Join() is never executed.
There is any example on the Internet and I absolutely don't know, why exists some DownloadStringTaskAsync when it is not applicable.
You're blocking the UI thread by your while loop and at the same time, the DownloadStringCompleted event wants to execute on the UI loop. This causes a deadlock, so nothing happens. What you need to do is to let GetLastCourses() return (and whatever method calls that), so that the event handler can execute. This means that the code that handles the results should be in that event handler (not in GetLastCourses()).
With async-await, you didn't provide all of your code, but it's likely that you're encountering pretty much the same issue by calling Wait() or Result on the returned Task. If replace that with await, you code will work. Though that requires you to make all your code from GetCoursesForDayFromApiAsJson() up async.
I'd recommend to use the HttpClient class from Microsoft NuGet package and use the async/await downloading pattern rather than using event-based WebClient class:
Uri uri = new Uri(string.Format(OperationGetLastCourses, AppSettings.ApiEndpoint, AppSettings.ApiKey));
using (HttpClient client = new HttpClient())
{
string result = await client.GetStringAsync(uri);
}

Silverlight: Returning value from synchronous method using Rx

I am writing a simple Silverlight application and WCF Service.
I want to create a synchronous method that return a value.
The method itself, call an asynchronous method from WCF Services. After I call asynchronous method, I want to get it value, and return to sender.
I hear that Rx can solve this kind of problem.
This is my code :
private void btnCreate_Click(object sender, RoutedEventArgs e)
{
string myResult = getMyBook(txtBookName.Text);
MessageBox.Show("Result\n" + myResult);
// myResult will be use for another purpose here..
}
// I want this method can be called anywhere, as long as the caller still in the same namespace.
public string getMyBook(string bookName)
{
Servo.ServoClient svc = new ServoClient();
string returnValue = "";
var o = Observable.FromEventPattern<GetBookCompletedEventArgs>(svc, "GetBookCompleted");
o.Subscribe(
b => returnValue = b.EventArgs.Result
);
svc.GetBookAsync(bookName);
return returnValue;
}
When I click btnCreate, myResult variable still empty. Is that something wrong with my code? Or maybe I am just don't understand with Rx concept? I am new to Rx.
My goal is : I need to get the result (myResult variable) from asynchronous method, and then used in later code.
This is more suited to the async/await keywords than Rx. Rx is primarily for managing streams of data, whereas in this case all you want to do is manage an asynchronous call synchronously. You could try using Rx like so:
public string getMyBook(string bookName)
{
Servo.ServoClient svc = new ServoClient();
svc.GetBookAsync(bookName);
var o = Observable.FromEventPattern<GetBookCompletedEventArgs>(svc, "GetBookCompleted");
return o.First().EventArgs.Result;
}
However, if GetBookAsync raises the event before you subscribe, the thread will block forever. You could mess around with .Replay() and .Connect() but you should probably just use async/await!
Remember that GetBookAsync returns immediately, and will return the value stored in returnvalue. When the data arrives returnvalue will be out of scope, and by then btnCreate will have finished.
U could use await on the GetBookAsync, so that it will wait for the data to arrive before continuing. Don't forget that would mean u also need the async on the method.
Not a great example or use of either RX or await, but trying is how we learn!

Categories