简体   繁体   中英

Why System.IO.Ports.SerialPort.DataReceived event doesn't fire when modem is in DATA mode?

Currently on my university we're doing communication between these old 56k modems. As messages from PC to modem go through the serial port, I thought to use System.IO.Ports.SerialPort .NET class.

I wrote pretty big C# application to communicate with modem, dial to other modem and communicate through them. It all worked fine till I managed to establish connection between two modems. When this happens, both modems (as it should be) switch from COMMAND mode (where I can send Hayes' commands to modem) to DATA mode (where all data I send to modem are being forwarded to the other modem).

My application can send things to, as well as receive things from serial port. It's installed on both connected PC's. But when I type something in my application, eg "Hello", it isn't received on the other side. And here comes the weird part. Here's how I'm sending messages through the serial port ('port' is an instance of SerialPort class, 'data' is an instance of a string):

port.Write(data);

So it works. It have to work. Especially, because if I use my application to send on the one side and PuTTy to receive on the other - it works! PuTTy connected to valid serial port receives my message. It also implicate, that not only my message comes to the first modem; it is being send by network to the other modem, and then the other modem sends it through the serial port to receiving PC. But that's not all. When I use my application to receive, I use SerialPort.DataReceived event, like this (of course method has been +=ed to event handler):

void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    //this message box should pop up if event hit:
    MessageBox.Show("Data from serial port received!");
    //calling my method to handle incoming message
    DataReceived((SerialPort)sender); 
}

And it works, when modem (one connected to receiving PC) is in COMMAND mode. Eg when I send "AT" Hayes' command to modem (which means nothing more than a 'ping'), modem responds "OK", and I receive it. SerialPort.DataReceived event fires. But when this modem is in DATA mode (when I can't send Hayes' commands to it), and it receives a message from sending modem, and forwards it to serial port - nothing. Event doesn't even fire. I checked it well.

It's weird!

This only brings me to conclusion, that the way, in which modem sends message to serial port, is slightly different when in DATA mode and in COMMAND mode, and PuTTy somehow does understand that other way, and the SerialPort class does not.

I really don't understand this.

You stated that DataReceived event does not fire when modems are in command mode and as someone with personal experience in serial/modem communication I dare to say that you are doing some blocking operation when you collect data from the serial port.

Until now I had done several projects with SerialPort class to handle modem communication using .NET40 and communication worked as expected.

My best guess would be that yours method DataReceived((SerialPort)sender); is blocking further receiving of data.

I order to avoid dead-lock when collecting received data do-read data from port in the lock, but processed them outside the lock and make sure that processing do something and finishes (do not do anything lengthy or it will hang receiving), something like:

void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    var com = sender as SerialPort;
    var lst = new List<byte>();

    if (com != null)
    {
        lock (com)
        {
            do
            {
                if (com.BytesToRead == 0) break;
                var one = com.ReadByte();
                if (one >= 0 && one < 256) lst.Add(Convert.ToByte(one));
            } while (one >= 0 && one < 256);

            // lst.ToArray(); // get bytes
        }

        // ... // do something with received data
    }
}

you did not provide details about data handling, so I can only guess that within that code is some sort of block.

In provided sample there are two major points:

  1. read data exclusively but only if there is data to read, do not wait for data
  2. process received data outside the lock as fast as possible and finish function execution

Also, provided code (in similar form) was always used in multithreaded app, so [MTAThread] attribute on Main!

One of the fastest way to troubleshoot serial communication may be to install com0com, virtual serial port from http://com0com.sourceforge.net/ and to try direct communication without modem, just to make sure that data exchange works.

Actually you can use it in your application to. Just install one pair of virtual com ports, attach your application to one serial port, attach putty to other and when you see ATZ on putty just respond with OK\\r\\n :) But if you are using readouts of pins then putty can not help you, at least I do not know a way to change flags from putty.

I know that thread is a bit old, but some feedback is welcome.

Happy Codding.

The SerialDataReceivedEventHandler was not firing because the Handshake was not set correctly.

I had to use hardware flow controls, which is Handshake.RequestToSend and it is working for me now.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM