4

i am trying to get data from fingerprint scanner through c# application, but before the fingerprint can send, a my whole code executes.

I tried using delay function and System.Threading.Thread.Sleep(1000), so it can get data before the next step executes, but it all seems futile.

Could any one please provide any other option?

I am using "SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)" to get data.

MPelletier
  • 16,256
  • 15
  • 86
  • 137
sami manchnda
  • 41
  • 1
  • 1
  • 2

5 Answers5

3

This code works perfectly for me:

port = new SerialPort(port, 9600, Parity.None, 8, StopBits.One);
port.Open();
port.DiscardOutBuffer();
port.DiscardInBuffer();
port.DataReceived += OnScan;

void OnScan(object sender, SerialDataReceivedEventArgs args)
{
    SerialPort port = sender as SerialPort;

    string line = port.ReadExisting();
// etc
}
Serve Laurijssen
  • 9,266
  • 5
  • 45
  • 98
  • 2
    It does not waits for a data, it is just reads an existing ones. – Hi-Angel Oct 17 '14 at 07:43
  • @Hi-Angel I think code should work as expected. DataReceived will call the delegate OnScan only if data is received (and not immidiatly) – Offler Feb 19 '15 at 11:46
  • @Offler yes. But what the asker expected is a code to wait on SerialPort. It was in my case too: suppose I have some kind of serial connection, and I want to wait for a data within a few seconds, and if a data didn't came, then return to suppose the connection is broken. It's not quite the code Servè wrote. Btw, [here was my answer](http://stackoverflow.com/a/26422744/2388257) on the problem – Hi-Angel Feb 19 '15 at 12:37
  • @Hi-Angel But if you really only want to do this it could be easier to forget everything with the events. I have done the following to Access an arduino "serial = new SerialPort(port, baudRate) { ReadTimeout = 2000 };" and afterwards "try { int returnValue = serial.ReadByte(); return returnValue;} catch (TimeoutException) //will occur after 2 seconds -> broken". Afterwards you don't Need the hole bunch of Monitors and so on. (okay the communication to arduino is one own thread at a hobby project - everything within this thread runs in order...) – Offler Feb 20 '15 at 21:25
  • @Offler no, it's a pathos. I'm serious. – Hi-Angel Feb 27 '15 at 11:51
  • @Offler out of curiosity I just tried to google again, armed with the «ReadTimeout» knowledge. Of answers where I found the timeout mentioned those where either one of +100500 answers, either just used it in code without even an attempt to explain what it does *(It could be timeout to anything, right?)* and with «DataReceived» to add a confuse. Since I already had a bad experience with C WinAPI and serial ports, no wonder that I found nothing. I'm wonder, how many people would find it like an easter egg. – Hi-Angel Feb 27 '15 at 17:16
3

Unfortunately waiting for a serial port data in C# is tricky, there is nothing like poll().

There is SerialPort.DataReceived which takes functions to be called on incoming data. So you assign there a function to trigger an arbitrary event. Your another function — the one to actually wait — should wait for this event.

Below is a simple example, it is commented, but in short: the TestFunc initializes and opens a serial port (in particular assigns the DataReceived). The Proxy() is a function that will be called every time a data arrived, it triggers an event. And WaitForAData() indeed waits for the event that will be triggered by Proxy() when a data appears. Note the lock(){}s, without them surrounding Monitor's functions it won't work properly.

It's just an example, you would probably want to remake WaitForAData() function to trigger an exception in case of timeout. And to add a boolean variable in case if the Proxy() was triggered before you began waiting, then serial port already have data. But I tested it (cause I need such a function now ☺), and it works.

namespace MyNamespace
{

class MySerial
{
    ///A condition variable that signals when serial has a data
    private System.Object SerialIncoming;

    public MySerial()
    {
        SerialIncoming = new Object();
    }

    /**
     * A proxy function that will be called every time a data arrived
     */
    private void Proxy(Object unused1, SerialDataReceivedEventArgs unused2)
    {
        Console.WriteLine("Data arrived!");
        lock (SerialIncoming)
        {
            Monitor.Pulse(SerialIncoming);
        }
    }

    /**
     * Waits for a data for the time interval Timeout
     * \param Timeout a timeout in milliseconds to wait for a data
     * \returns true in if a data did arrived, and false else
     */
    public bool WaitForAData(int Timeout)
    {
        lock (SerialIncoming)//waits N seconds for a condition variable
        {
            if (!Monitor.Wait(SerialIncoming, Timeout))
                {//if timeout
                    Console.WriteLine("Time out");
                    return false;
                }
            return true;
        }
    }

    /* Just a test function: opens a serial with speed, and waits
     * for a data for the «Timeout» milliseconds.
     */
    public void TestFunc(string serial, int speed, int Timeout)
    {
        SerialPort ser = new SerialPort(serial);
        ser.BaudRate = speed;
        ser.DataReceived += Proxy;
        ser.Open();
        if (WaitForAData(Timeout))
            Console.WriteLine("Okay in TestFunc");
        else
            Console.WriteLine("Time out in TestFunc");
    }
}

}

UPDATE: the problem wasted ½ of my day, so I hope I will save someone's time: the code above won't work in mono (but works in MS implementation) because serial port events are not supported as of writing these words.

Hi-Angel
  • 4,933
  • 8
  • 63
  • 86
  • Can you help me with this:https://stackoverflow.com/questions/55026042/wait-for-response-from-the-serial-port-and-then-send-next-data – Prashant Pimpale Mar 11 '19 at 09:00
  • @PrashantPimpale sorry, I didn't work with C# for some years, and hopefully I won't in future :) Additionally, I also don't have serial ports handy, nor I know if Mono *(i.e. the only implementation on non-Windows systems since I don't have Windows handy)* fixed serial port events. Basically, ATM I have no means at all to try to help you with your question. – Hi-Angel Mar 11 '19 at 09:41
  • Ok, no problem! Thanks for the reply BTW! – Prashant Pimpale Mar 11 '19 at 09:47
1

If this is a Console application, you can use things like Console.ReadLine() etc. after calling the appropriate function of the COM Port component to start listening asynchronously. If this is a WinForms application. The message loop will of course keep showing your current form. In that case you can call asynchronous listening function in the Form_Load event or behind a button click.

The key point here is that you should call the asynchronous version of the listener function. There is no need to use delays or timers in that case.

dotNET
  • 33,414
  • 24
  • 162
  • 251
  • Thanks for the input. I am new to C#. Could you please explain how to define asynchronous listening function. And its an Windows Form application. – sami manchnda Jul 25 '13 at 06:03
  • I believe you're using `SerialPort` class. This class by default works in synchronous mode only, so you'll need to use it with `BackgroundWorker` component (or use your own background threading mechanism). Check MSDN on `BackgroundWorker` component's usage. It is pretty straight-forward and easy to use. The time you spend in learning this component will give you lots of returns in the coming days. – dotNET Jul 25 '13 at 06:16
0

Why not make a global marker (bool), that marks if you received anything and make a while(!marker) {} loop and you change the marker in the SerialPort_datareceived subrutine?

The thread.sleep might make you miss the SerialPort data sending?

DaMachk
  • 643
  • 4
  • 10
  • That would be because you have to make an inter-thread value change, so find how to hanges values in one thread to another. – DaMachk Jul 25 '13 at 09:08
0

The serial port is working in a separate thread. Therefore the serialPort_DataReceived event is fired from this thread.

So if your program only starts the serial port and then your main exits, you never receive the event. This is true if you have a console application.

When using a forms application, it keeps the form and the main thread alive until the user closes it.

joe
  • 8,344
  • 9
  • 54
  • 80
  • If some data is received and thread.sleep() is running then it will discard that data?? – sami manchnda Jul 25 '13 at 06:35
  • `Thread.Sleep` is for the current thread. The `DataReceived` event is called from a different thread, so you WILL receive the data. – joe Jul 25 '13 at 07:41