[Last Call] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 445
  • Last Modified:

C# Communication with problems

I have problems in communication of my application.
I need to send 2 times the same command for my devices.
But only once I get the response data.
If answer the first time, do not send the command again.
If do not answer the first time, resubmit the command and get just one answer
or
Send commands two times and get just one answer.
The code is attach.
timer3.Enabled = true;
            inicio = DateTime.Now;
            #region TRABALHA ID01
            timr_ID06.Enabled = true;
            Thread.Sleep(150); // Dorme por 150 segundos
            string s_ID01_c = "id01";
            CommPort com = CommPort.Instance;
            s_ID01_c = ConvertEscapeSequences(s_ID01_c); ;
            com.Send(s_ID01_c);
            Thread.Sleep(150); // Dorme por 150 segundos
            com.Send(s_ID01_c);
            #endregion

            for (int i = 0; i <= 10; i++)
                for (int j = 0; j <= 20; j++)
                { }

            #region TRABALHA ID02
            //timr_ID06.Enabled = true;
            Thread.Sleep(150); // Dorme por 150 segundos
            string s_ID02_c = "id02";
            //CommPort com = CommPort.Instance;
            s_ID02_c = ConvertEscapeSequences(s_ID02_c); ;
            com.Send(s_ID02_c);
            Thread.Sleep(150); // Dorme por 150 segundos
            com.Send(s_ID02_c);
            #endregion

            for (int i = 0; i <= 10; i++)
                for (int j = 0; j <= 20; j++)
                { }

Open in new window

0
ocaccy
Asked:
ocaccy
  • 5
  • 4
  • 2
6 Solutions
 
Carlos VillegasFull Stack .NET DeveloperCommented:
Hello, I cant see in your code where you receive the response.. also I thought there is a design problem, if you must receive a response after sent a command you can do something like this:
string s_ID01_c = "id01";
CommPort com = CommPort.Instance;
s_ID01_c = ConvertEscapeSequences(s_ID01_c); ;
com.Send(s_ID01_c);
while (!com.NewDataAvailable)
{
    Thread.Sleep(150);
}

Open in new window

Your CommPort class must have something like the NewDataAvailable property that I use in the previous code, also you must include a timeout logic.
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
In your data arrival handler, you'd need to set some kind of class level flag that indicates that a response has arrived.

Before you send each command, reset that flag.  Immediately afterwards poll in a loop with DoEvents() until the flag is set.  Now you can decide what to do next in your sequence based upon the response.

0
 
Carlos VillegasFull Stack .NET DeveloperCommented:
Oh yes, the DoEvents method is important, if you are working on a windows form application my example must be something like:
string s_ID01_c = "id01";
CommPort com = CommPort.Instance;
s_ID01_c = ConvertEscapeSequences(s_ID01_c); ;
com.Send(s_ID01_c);
while (!com.NewDataAvailable)
{
    Thread.Sleep(150);
    Application.DoEvents();
}
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
ocaccyAuthor Commented:
Receive data.
#region Event handling - data received and status changed

        /// <summary>
        /// Prepare a string for output by converting non-printable characters.
        /// </summary>
        /// <param name="StringIn">input string to prepare.</param>
        /// <returns>output string.</returns>
        private String PrepareData(String StringIn)
        {
            // The names of the first 32 characters
            string[] charNames = {
                                 // "NUL", "SOH", "STX", "ETX", "EOT",
                //"ENQ", "ACK", "BEL", "BS", "TAB", "LF", "VT", "FF", "CR", "SO", "SI",
                //"DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", "CAN", "EM", "SUB",
                //"ESC", "FS", "GS", "RS", "US", "Space"
                                 };

            string StringOut = "";

            foreach (char c in StringIn)
            {
                if (Settings.Option.HexOutput)
                {
                    StringOut = StringOut + String.Format("{0:X2} ", (int)c);
                }
                else if (c < 32 && c != 9)
                {
                    StringOut = StringOut + "";// +"<"+charNames[c]+">";

                    //Uglier "Termite" style
                    //StringOut = StringOut + String.Format("[{0:X2}]", (int)c);
                }
                else
                {
                    StringOut = StringOut + c;
                }
            }
            return StringOut;
        }

        /// <summary>
        /// Partial line for AddData().
        /// </summary>
        private Line partialLine = null;

        /// <summary>
        /// Add data to the output.
        /// </summary>
        /// <param name="StringIn"></param>
        /// <returns></returns>
        private Line AddData(String StringIn)
        {
            String StringOut = PrepareData(StringIn);

            // if we have a partial line, add to it.
            if (partialLine != null)
            {
                // tack it on
                partialLine.Str = partialLine.Str + StringOut;
                outputList_Update(partialLine);
                return partialLine;
            }

            return outputList_Add(StringOut, receivedColor);
        }

        // delegate used for Invoke
        internal delegate void StringDelegate(string data);

        /// <summary>
        /// Handle data received event from serial port.
        /// </summary>
        /// <param name="data">incoming data</param>
        public void OnDataReceived(string dataIn)
        {
            //Handle multi-threading
            if (InvokeRequired)
            {
                Invoke(new StringDelegate(OnDataReceived), new object[] { dataIn });
                return;
            }

            // pause scrolling to speed up output of multiple lines
            bool saveScrolling = scrolling;
            scrolling = false;

            // if we detect a line terminator, add line to output
            int index;
            while (dataIn.Length > 0 &&
                ((index = dataIn.IndexOf("\r")) != -1 ||
                (index = dataIn.IndexOf("\n")) != -1))
            {
                String StringIn = dataIn.Substring(0, index);
                dataIn = dataIn.Remove(0, index + 1);

                logFile_writeLine(AddData(StringIn).Str);
                logFile_writeLine1(AddData(StringIn).Str);
                //listBox3.Items.Add(AddData(StringIn).Str);
                partialLine = null;	// terminate partial line
            }

            // if we have data remaining, add a partial line
            if (dataIn.Length > 0)
            {
                partialLine = AddData(dataIn);
            }

            // restore scrolling
            scrolling = saveScrolling;
            outputList_Scroll();
            listBox1_Scroll();
        }

Open in new window

0
 
Carlos VillegasFull Stack .NET DeveloperCommented:
Hello, as Idle_Mind suggested, add this field to your class:
bool dataReceived = false;

Open in new window


And update your OnDataReceived method with this:
public void OnDataReceived(string dataIn)
{
    //Handle multi-threading
    if (InvokeRequired)
    {
        Invoke(new StringDelegate(OnDataReceived), new object[] { dataIn });
        return;
    }

    // Set your flag
    this.dataReceived = true;

    // pause scrolling to speed up output of multiple lines
    bool saveScrolling = scrolling;
    scrolling = false;

    // if we detect a line terminator, add line to output
    int index;
    while (dataIn.Length > 0 &&
        ((index = dataIn.IndexOf("\r")) != -1 ||
        (index = dataIn.IndexOf("\n")) != -1))
    {
        String StringIn = dataIn.Substring(0, index);
        dataIn = dataIn.Remove(0, index + 1);

        logFile_writeLine(AddData(StringIn).Str);
        logFile_writeLine1(AddData(StringIn).Str);
        //listBox3.Items.Add(AddData(StringIn).Str);
        partialLine = null;	// terminate partial line
    }

    // if we have data remaining, add a partial line
    if (dataIn.Length > 0)
    {
        partialLine = AddData(dataIn);
    }

    // restore scrolling
    scrolling = saveScrolling;
    outputList_Scroll();
    listBox1_Scroll();
}

Open in new window


Then you can use this method to send your data:
void SendAndWait(CommPort com, string data)
{
    this.dataReceived = false;
    data = ConvertEscapeSequences(data);
    com.Send(data);

    // Wait for data
    DateTime start = DateTime.UtcNow;
    while (!this.dataReceived)
    {
        // Timeout if has not completed in 5 seconds
        if (DateTime.UtcNow.Subtract(start).TotalSeconds > 5)
            throw new TimeoutException();

        Thread.Sleep(10);
        Application.DoEvents();
    }
}

Open in new window


Usage example based on your code:
timer3.Enabled = true;
inicio = DateTime.Now;

#region TRABALHA ID01
timr_ID06.Enabled = true;
SendAndWait(CommPort.Instance, "id01");
#endregion

#region TRABALHA ID02
//timr_ID06.Enabled = true;
SendAndWait(CommPort.Instance, "id02");
#endregion

Open in new window

0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
*You may need this line:

    this.dataReceived = true;

at the bottom of your parsing routine so that you have valid data to work with.  Haven't looked that closely.
0
 
ocaccyAuthor Commented:
Hi, yv989c and Idle_Mind.

Thank you for yor help.

I put the line in

public partial class Form1 : Form
    {
        bool dataReceived = false;

This is OK?

this.dataReceived = true;

This line enters in the bottom on OnDataReceived method?
public void OnDataReceived(string dataIn)
{
    //Handle multi-threading
    if (InvokeRequired)
    {
        Invoke(new StringDelegate(OnDataReceived), new object[] { dataIn });
        return;
    }

    // Set your flag
    this.dataReceived = true;

    // pause scrolling to speed up output of multiple lines
    bool saveScrolling = scrolling;
    scrolling = false;

    // if we detect a line terminator, add line to output
    int index;
    while (dataIn.Length > 0 &&
        ((index = dataIn.IndexOf("\r")) != -1 ||
        (index = dataIn.IndexOf("\n")) != -1))
    {
        String StringIn = dataIn.Substring(0, index);
        dataIn = dataIn.Remove(0, index + 1);

        logFile_writeLine(AddData(StringIn).Str);
        logFile_writeLine1(AddData(StringIn).Str);
        //listBox3.Items.Add(AddData(StringIn).Str);
        partialLine = null;     // terminate partial line
    }

    // if we have data remaining, add a partial line
    if (dataIn.Length > 0)
    {
        partialLine = AddData(dataIn);
    }

    // restore scrolling
    scrolling = saveScrolling;
    outputList_Scroll();
    listBox1_Scroll();
///////////////////////////////////////////////////////////
    this.dataReceived = true;
}

Open in new window

0
 
ocaccyAuthor Commented:
I think I did something wrong.
Error-Message-1.PNG
Error-Message-2.PNG
0
 
Carlos VillegasFull Stack .NET DeveloperCommented:
Hello ocaccy, first you can try the Idle_Mind suggestion, by moving the location of the flag to the bottom, also I recommend to use a try/finally block, example:
public void OnDataReceived(string dataIn)
{
    //Handle multi-threading
    if (InvokeRequired)
    {
        Invoke(new StringDelegate(OnDataReceived), new object[] { dataIn });
        return;
    }

    try
    {
        // pause scrolling to speed up output of multiple lines
        bool saveScrolling = scrolling;
        scrolling = false;

        // if we detect a line terminator, add line to output
        int index;
        while (dataIn.Length > 0 &&
            ((index = dataIn.IndexOf("\r")) != -1 ||
            (index = dataIn.IndexOf("\n")) != -1))
        {
            String StringIn = dataIn.Substring(0, index);
            dataIn = dataIn.Remove(0, index + 1);

            logFile_writeLine(AddData(StringIn).Str);
            logFile_writeLine1(AddData(StringIn).Str);
            //listBox3.Items.Add(AddData(StringIn).Str);
            partialLine = null;     // terminate partial line
        }

        // if we have data remaining, add a partial line
        if (dataIn.Length > 0)
        {
            partialLine = AddData(dataIn);
        }

        // restore scrolling
        scrolling = saveScrolling;
        outputList_Scroll();
        listBox1_Scroll();
    }
    finally
    {
        // Set your flag
        this.dataReceived = true;
    }
}

Open in new window


If that dont work, I think that you must debug your AddData method, set a break point on it and watch what it do with your string, probably your exception is raised from that method, or your Str extension? method maybe.

I suggest that you debug carefully this section of your code:
// if we detect a line terminator, add line to output
int index;
while (dataIn.Length > 0 &&
    ((index = dataIn.IndexOf("\r")) != -1 ||
    (index = dataIn.IndexOf("\n")) != -1))
{
    String StringIn = dataIn.Substring(0, index);
    dataIn = dataIn.Remove(0, index + 1);

    logFile_writeLine(AddData(StringIn).Str);
    logFile_writeLine1(AddData(StringIn).Str);
    //listBox3.Items.Add(AddData(StringIn).Str);
    partialLine = null;     // terminate partial line
}

// if we have data remaining, add a partial line
if (dataIn.Length > 0)
{
    partialLine = AddData(dataIn);
}

Open in new window


That error may come from a Parse method, are you parsing a date in your AddData method?... It will be helpful if you show here the exception details, like the stack trace.
0
 
ocaccyAuthor Commented:
Hi yv989c and Idle_Mind.

Following the tips and advices.
I assembled the following code.
I'll put just a device, I put the same code for all devices, only changing the context of ID.
Are being trialled for the next 10 hours.
I put a timer with 100 ms for each ID.
If we decrease this value, not returns all IDs.
I commented the thread to shorten the time between readings.
I am capturing the reading time, and I can see that in the last two or three IDs, jumps to the next second.
I need all the devices are read within the space of one second.
As I have 6 devices, the total is 600 ms.
Is possible start reading the first 100 ms of the second, then end up reading with 800 or 900 ms?
So always be read within the same second for all devices.
I will return to give news.
respectfully,
ocaccy.
private void timer_01_Tick(object sender, EventArgs e)
        {
            #region TRABALHA ID01
            this.dataReceived = false;
            string s_ID01_c = "id01";
            CommPort com = CommPort.Instance;
            s_ID01_c = ConvertEscapeSequences(s_ID01_c); ;
            com.Send(s_ID01_c);

            // Wait for data
            DateTime start = DateTime.UtcNow;
            while (!this.dataReceived)
            {
                // Timeout if has not completed in 5 seconds
                if (DateTime.UtcNow.Subtract(start).TotalSeconds > 5)
                    throw new TimeoutException();

                //Thread.Sleep(10);
                Application.DoEvents();
            }

            //Thread.Sleep(150); // Dorme por 150 segundos
            //com.Send(s_ID01_c);
            timer_02.Enabled = true;
            timer_01.Enabled = false;
            #endregion

        }

Open in new window

0
 
ocaccyAuthor Commented:
Hi,

This works better than any time.
Sometimes a lack ID.
In my last test, we had:
11 hours of testing with three errors.
Three times that has not received data from an ID.
I'll stop and ask another question.
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

  • 5
  • 4
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now