0

I am using .net 4.5 and since i got aware about some internet discussion about .net having wrong code implementation to rad serial data, i went with the code below.

The problems is however even despite i can see i create a COM port connection (to the right com port number), its never firing on data received. The data receiving is based upon a simple Arduino app, (Arduino monitor does show data gets send over serial), but .net never seams to fire upon serial events.

I've put breakpoints on eventread, it never gets hit

i've looked at other discussions here like .NET SerialPort DataReceived event not firing but so far they don't resolve the issue i have. I tried various combination of serial line setups, and believe the below ones are correct. as for Arduino part the line is setup as:

Serial.begin(9600);

I call my class like : `InfraredSensor mySens = new InfraredSensor("COM4",9600);'

class InfraredSensor
{
    private string Eventlogapp = "IRlogging"; 
    private SerialPort Port;
    public InfraredSensor(string COMport, int baudrate) //constructor
    {
        if (applicationlog != "") this.EventlogSapec = applicationlog;
        WriteEventLog(EventlogSapec, EventSource, "Initializing-IR:" + COMport, info, EventIRStarted);

        // I found that the .net standard implementation for com port reading is not OK (.net doesnt follow win32 api).
        // There are numerous readings about it, but a good way to read seams to be to use Serial BaseStream.ReadAsync
        // code below is based upon : http://www.c-sharpcorner.com/code/2880/serial-port-with-efficient-data-reading-in-c-sharp.aspx

        this.comport = COMport;
        SerialPort Port = new SerialPort(comport);

        Port.BaudRate = baudrate;
        Port.DataBits = 8;
        Port.Parity = Parity.None;
        Port.StopBits = StopBits.One;
        Port.Handshake = Handshake.None;

        Port.NewLine = Environment.NewLine;
        Port.ReceivedBytesThreshold = 2; // + linefeed 
        Port.DataReceived += ReadEvent;
        Port.Open();
        Port.DtrEnable = true;
       // i've tested from here i do have an open connection
       // its just dat ReadEvent never fires...
    }


      private void ReadEvent(object sender, SerialDataReceivedEventArgs e)
    {
        byte[] buffer = new byte[2];//todo i only send "A" or "B", for the debug moment 
        Action kickoffRead = null;

        kickoffRead = (Action)(() => Port.BaseStream.BeginRead(buffer, 0, buffer.Length, delegate (IAsyncResult ar)
        {
            try
            {
                int count = Port.BaseStream.EndRead(ar);
                byte[] dst = new byte[count];
                Buffer.BlockCopy(buffer, 0, dst, 0, count);
                RaiseAppSerialDataEvent(dst);
            }
            catch (Exception ex)
            {
                WriteEventLog(Eventlogapp, "IR", "Failure-IR:" + ex.Message, info, 204);
            }
            kickoffRead();
        }, null)); kickoffRead();
    }

    private void RaiseAppSerialDataEvent(byte[] Data)
    {
    // code never gets to here
        string msg = Encoding.Default.GetString(Data);
    int breakpointhere = 0;

        if (msg.Contains('A')) WriteEventLog(Eventlogapp, "IR", "Sensor A", info, 213);

        if (msg.Contains('B')) WriteEventLog(Eventlogapp, "IR", "Sensor B", info, 214);


    }
}

I ran out of ideas (and hair as its driving me nuts) what could cause this behaviour ?

Peter
  • 2,043
  • 1
  • 21
  • 45
  • Have you tried moving `Port.DtrEnable = true;` to before calling `Port.Open()`? I've not done serial comms with .NET before, but it wouldn't surprise me if it wasn't something silly like that. Other than that I'd recommend downloading some sort of serial data sniffer to make sure that port is *actually* receiving data. – Clint Jul 31 '17 at 13:43
  • Ensure that your `COMport` string is correct/matches up in device manager. I have experienced Windows changing the name of the port, despite being plugged into the same port, when a device was removed and replugged. Although, that might have been specific to my environment, so take it with a (large) teaspoon of salt. – marcushobson Jul 31 '17 at 13:51
  • @Clint yes i tried that, i wasnt sure either but some people sugested in another talk – Peter Jul 31 '17 at 14:27
  • @marcushobson i can clearly see its COM4, arduino IDE uses 4 as well. I'm also sure that IDE isnt locking port 4, i disconnect and reboot, i can even validate i have connection as Port.IsOpen works fine in constructor of the class. – Peter Jul 31 '17 at 14:29

2 Answers2

2

finally this took me 2 days ...

in arduino code i now use

serial.print("Mytext\n");  // using \n to be sure of escape character

for the serial line config i now use

this.comport = COMport;
this.Port = new SerialPort(comport);
this.Port.BaudRate = baudrate;
this.Port.DataBits = 8;
this.Port.Parity = Parity.None;
this.Port.StopBits = StopBits.One;
this.Port.Handshake = Handshake.None;
this.Port.RtsEnable = true;
      //  Port.NewLine = "\n";
       //   Port.ReceivedBytesThreshold = 2; // + linefeed 
        this.Port.DataReceived += new new SerialDataReceivedEventHandler(ReadEvent);

....
..
SerialDataReceivedEventHandler(ReadEvent);
//code didnt change inside but the method has changed see the +=
Peter
  • 2,043
  • 1
  • 21
  • 45
0

The DataReceived event fires when there is data coming through the serial port, but it can fire randomly. So you could get part of the message in one event and the other half of the message in another event. You should have some sort of key to know when you have the whole message. So build your string until you have the whole message then do something based on the message.

For example, my device's message is done when there is a Line Feed. So my code looks something like:

char ESC = (char)27;
char CR = (char)13;
char LF = (char)10;
StringBuilder sb = new StringBuilder();

private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
    string Data = serialPort1.ReadExisting();

    foreach (char c in Data)
    {
        if (c == LF)
        {
            sb.Append(c);

            //we have our message, do something, maybe like
            if (sb.ToString().Contains("A"))
            {
                //print A
            }
            else
            {
                //print B
            }
        }
        else
        {
            sb.Append(c);
        }
    }
}
Baddack
  • 1,947
  • 1
  • 24
  • 33
  • even if it would fire on '\n' i kinda doubt.. then it wouldnt cause the code i have now to fail since '\n' isnt an A or an B. its though a topic that has my my interest, cause i went trought the trouble just because of in .net 4.0 comports sometimes miss bytes, this was not allowed in my prj – Peter Aug 02 '17 at 06:21