Click here to Skip to main content
15,886,806 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hello!

I have a small program written in C# with windows forms to send data bytes using COM ports. I am testing the program on one computer, on two interconnected USB modules supporting serial communication, so that one transmits, the other receives and vice versa. This program allows to see sending data bytes and receiving bytes on two RichTextBoxes of the same application, but... Not as well as I expected. Picture below:

https://learn.microsoft.com/answers/storage/attachments/243193-image.png


The problem is in "Test" card. On the left side I see sending hex bytes. I assumed I wanted to be able to send 1000 random characters one by one (this is done by the for loop) and see the other com port receive those 1000 characters. These characters are seen as received on the right side of the window, however, only after the entire loop has run, i.e. when the entire 1000 characters packet have been sent. However, I dream about the situation that single characters, however, would be sent immediately as soon as they would be in the buffer - not when the entire loop was finally executed. So I mean sending and receiving particular bytes at the same time.
Currently, this option is only for me if I simply run the .exe file twice (in two windows) and make it to send and receive data in this way. I feel that I need a proper usage of multithreading in this situation, but at the moment I cannot find the way to deal with repetitive sending other than this simple for loop. Is there an option to fix that? Any help will be appreciate.



using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    
    using System.IO.Ports;
    
    namespace USB_tester
    {
    
     public partial class USB_tester : Form
     {
            System.IO.Ports.SerialPort port1;
            System.IO.Ports.SerialPort port2;
            delegate void Delegat1();
            delegate void Delegat2();
            Delegat1 moj_del1;
            Delegat2 moj_del2;
    
     public USB_tester()
     {
                InitializeComponent();
                port1 = new SerialPort();
                port2 = new SerialPort();
                port1.ReadTimeout = 500;
                port1.WriteTimeout = 500;
     port2.ReadTimeout = 500;
                port2.WriteTimeout = 500;
                Settings.Enter += new EventHandler(Ustawienia_Enter);
                port1.DataReceived += new SerialDataReceivedEventHandler(DataRecievedHandler1);
                port2.DataReceived += new SerialDataReceivedEventHandler(DataRecievedHandler2);
                moj_del1 = new Delegat1(ShowReceived1);
                moj_del2 = new Delegat2(ShowReceived2);
     }
     private void DataRecievedHandler1(object sender, SerialDataReceivedEventArgs e)
            {
    
                rtbTerminal1.Invoke(moj_del1);
            }
    
     private void DataRecievedHandler2(object sender, SerialDataReceivedEventArgs e)
            {
    
     rtbTerminal2.Invoke(moj_del2);
            }
    
            private void ShowReceived1()
            {
             label2.Text = port1.BytesToRead.ToString();
            
             for (int k = port1.BytesToRead; k > 0; k--)
             {
            
             ColoredTerminal(rtbTerminal1, port1.ReadByte().ToString("X") + " ", System.Drawing.Color.Blue);
             }
            }
     private void ShowReceived2()
            {
             label2.Text = port2.BytesToRead.ToString();
            
             for (int l = port2.BytesToRead; l > 0; l--)
             {
            
             ColoredTerminal(rtbTerminal2, port2.ReadByte().ToString("X") + " ", System.Drawing.Color.Blue);
             }
            }
     private void ColoredTerminal(System.Windows.Forms.RichTextBox RichTextBox, string Text, System.Drawing.Color Color)
            {
                var StartIndex = RichTextBox.TextLength;
                RichTextBox.AppendText(Text);
                var EndIndex = RichTextBox.TextLength;
                RichTextBox.Select(StartIndex, EndIndex - StartIndex);
                RichTextBox.SelectionColor = Color;
                RichTextBox.ScrollToCaret();
            }
    
            void Ustawienia_Enter(object sender, EventArgs e)
            {
                this.cbName1.Items.Clear();
                this.cbName2.Items.Clear();
                this.cbParity.Items.Clear();
                this.cbStop.Items.Clear();
                foreach (String s in SerialPort.GetPortNames()) this.cbName1.Items.Add(s);
                foreach (String s in SerialPort.GetPortNames()) this.cbName2.Items.Add(s);
                foreach (String s in Enum.GetNames(typeof(Parity))) this.cbParity.Items.Add(s);
                foreach (String s in Enum.GetNames(typeof(StopBits))) this.cbStop.Items.Add(s);
    
                cbName1.Text = port1.PortName.ToString();
                cbName2.Text = port2.PortName.ToString();
                cbBaud.Text = port1.BaudRate.ToString();
                cbData.Text = port1.DataBits.ToString();
                cbParity.Text = port1.Parity.ToString();
                cbStop.Text = port1.StopBits.ToString();
            }
            void ButSendClick(object sender, EventArgs e)
     {
     if (port1.IsOpen) 
                { 
                 Random rnd = new Random();
                 for (int i = 0; i <= 1000; i++)
                 {
                 int num = rnd.Next(0,255);
         string hexString = num.ToString("X2");
                    ColoredTerminal(rtbTerminal1, hexString + " ", System.Drawing.Color.Black); 
                    Byte[] tosend = BitConverter.GetBytes(num); 
                    port1.Write(tosend, 0, 1); 
                 }
                } 
                else System.Windows.Forms.MessageBox.Show("Make connection first"); 
            }
     void TabPage1Click(object sender, EventArgs e)
     {
    
     }
     void Label1Click(object sender, EventArgs e)
     {
    
     }
     void Label3Click(object sender, EventArgs e)
     {
    
     }
     void Label4Click(object sender, EventArgs e)
     {
    
     }
     void ButDefault(object sender, EventArgs e)
     {
    
     }
     void CbNameSelectedIndexChanged(object sender, EventArgs e)
     {
    
     }
     void CbBaudSelectedIndexChanged(object sender, EventArgs e)
     {
    
     }
     void RtbTerminalTextChanged(object sender, EventArgs e)
     {
    
     }
     void ButRefreshClick(object sender, EventArgs e)
     {
    
     }
     void ButDefaultClick(object sender, EventArgs e)
     {
         this.cbName1.Text = "COM3";
                this.cbName2.Text = "COM4";
                this.cbBaud.Text = "9600";
                this.cbData.Text = "8";
                this.cbParity.Text = "None";
                this.cbStop.Text = "One";
     }
     void ButCancelClick(object sender, EventArgs e)
     {
             cbName1.Text = port1.PortName.ToString(); 
             cbName2.Text = port2.PortName.ToString(); 
                cbBaud.Text = port1.BaudRate.ToString(); 
                cbData.Text = port1.DataBits.ToString(); 
                cbParity.Text = port1.Parity.ToString(); 
                cbStop.Text = port1.StopBits.ToString();
     }
     void PbStatus1Click(object sender, EventArgs e)
     {
                if (port1.IsOpen) 
                { 
                    pbStatus1.BackColor = System.Drawing.Color.Red; 
                    port1.Close(); 
                    labStatus1.Text = "No connection"; 
                    ColoredTerminal(rtbTerminal1, "\nConnection end - " + port1.PortName + "\n", System.Drawing.Color.Orange); 
                } 
                else 
                { 
                    try 
                    { 
                        port1.PortName = this.cbName1.Text;
                        port1.BaudRate = Int32.Parse(this.cbBaud.Text); 
                        port1.DataBits = Int32.Parse(this.cbData.Text); 
                        port1.Parity = (Parity)Enum.Parse(typeof(Parity), this.cbParity.Text); 
                        port1.StopBits = (StopBits)Enum.Parse(typeof(StopBits), this.cbStop.Text); 
                        port1.Open(); 
                        pbStatus1.BackColor = System.Drawing.Color.Green; 
                        labStatus1.Text = "Active connection (port:" + port1.PortName.ToString() + ", speed: " + port1.BaudRate.ToString() + ", data bits: " + 
                        port1.DataBits.ToString() + "\n stop bits: " + port1.StopBits.ToString() + ", parity: " + port1.Parity.ToString() + ")"; 
                        ColoredTerminal(rtbTerminal1, "Connection started - " + port1.PortName + "\n", System.Drawing.Color.Orange); 
                    } 
                    catch(Exception exc) 
                    { 
                        MessageBox.Show("Connection error:\n" + exc.Message); 
                    } 
                } 
     }
     void PbStatus2Click(object sender, EventArgs e)
     {
                if (port2.IsOpen) 
                { 
                    pbStatus2.BackColor = System.Drawing.Color.Red; 
                    port2.Close(); 
                    labStatus2.Text = "No connection"; 
                    ColoredTerminal(rtbTerminal2, "\nConnection end - " + port2.PortName + "\n", System.Drawing.Color.Orange); 
                } 
                else 
                { 
                    try 
                    { 
                        port2.PortName = this.cbName2.Text; 
                        port1.BaudRate = Int32.Parse(this.cbBaud.Text); 
                        port1.DataBits = Int32.Parse(this.cbData.Text); 
                        port1.Parity = (Parity)Enum.Parse(typeof(Parity), this.cbParity.Text); 
                        port1.StopBits = (StopBits)Enum.Parse(typeof(StopBits), this.cbStop.Text); 
                        port2.Open(); 
                        pbStatus2.BackColor = System.Drawing.Color.Green; 
                        labStatus2.Text = "Active connection (port:" + port2.PortName.ToString() + ", speed: " + port2.BaudRate.ToString() + ", data bits: " + 
                        port2.DataBits.ToString() + "\n stop bits: " + port2.StopBits.ToString() + ", parity: " + port2.Parity.ToString() + ")"; 
                        ColoredTerminal(rtbTerminal2, "Connection started - " + port2.PortName + "\n", System.Drawing.Color.Orange); 
                    } 
                    catch(Exception exc) 
                    { 
                        MessageBox.Show("Connection error:\n" + exc.Message); 
                    } 
                } 
                
     }
     void LabStatusClick(object sender, EventArgs e)
     {
    
     }
     void NumericSendValueChanged(object sender, EventArgs e)
     {
    
     }
     void Label7Click(object sender, EventArgs e)
     {
    
     }
     }
    }


What I have tried:

I tried to deal with "for" loop. The only situation when I see receiving chars in parallel to sended chars ("one by one") is when after line...
port1.Write(tosend, 0, 1); 


...I add
rtbTerminal2.Invoke(moj_del2);

...but it is not the right way to force receiving particulary bytes.

Best regards
Karlsson
Posted
Updated 21-Sep-22 1:47am
v4
Comments
Richard MacCutchan 21-Sep-22 7:12am    
Is the receiving code running in a separate thread?
Member 15774332 21-Sep-22 7:44am    
@Richard MacCutchan In fact, the mechanism for receiving data has been solved using delegates and the invoke command. If I hadn't used it, I mean, if I just paste inside DataRecievedHadler2

ShowReceived2()
method instead of

rtbTerminal2.Invoke(moj_del2);
, I would get an error saying "Invalid cross-thread operation:"
Richard MacCutchan 21-Sep-22 7:55am    
I would get an error saying "Invalid cross-thread operation:"
Well, if you cross-thread that is what happens.
Member 15774332 21-Sep-22 8:02am    
You're right, but I still can't get the app to receive data at the same time as sending. In practice, it looks like that if I have, for example, hex signs: AF 11 0C 5A DD DF... A3 4D 82 F2 99 E1 16, then only after displaying this "16" as sent, AF, 11, OC etc. will start to be displayed after right side of the program window. Receiving and transmitting do not want to work at the same time (well, unless, for example, I run two .exe programs at once and start communicating between them - then it will start working).
Richard MacCutchan 21-Sep-22 9:29am    
You need to do your sending and receiving in background tasks and your window updating in the main thread.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900