Home > other >  How to set Timer in winform for executing 10 command?
How to set Timer in winform for executing 10 command?

Time:08-09

I have around 10 commands of Tx,Rx with time interval of 100 millisecond for each. So Basically a TxRx pair should be executed within every 100 milliseconds. unless the stop button is clicked. Where am I getting Wrong?

  1. Form1 btn_Start

set the time Interval to request and receive the message


 private void btn_Start_Click(object sender, EventArgs e)
 {
    Start();
 }

 private void Start()
 {
     btn_Start.Enabled = false;
     btn_Stop.Enabled = true;
     int Interval = 100;
            
     
     if (CANTimer.Enabled == false)
     {
                // CAN Timer confinguration
        CANTimer.Enabled = true;
        CANTimer.Interval = Convert.ToInt32(fCANInterval);  //Interval;
        CANTimer.Tick  = new System.EventHandler(this.CANTimer_Tick);
        CANTimer.Start();
     }
     else if (CANTimer.Enabled && Program_config_num == 0)
     {
        CANTimer.Stop();
        CANTimer.Interval = Convert.ToInt32(fCANInterval);  //Interval;
        CANTimer.Enabled = true;
        CANTimer.Start();
     }
 }
  1. Form1 CANTimer_Tick

Execute the command to Send and Receive Messages in every 100 milliseconds, till the btn_Stop is clicked

private void CANTimer_Tick(object sender, EventArgs e)
{
   ThreadPool.GetMaxThreads(out maxWorkerThreads, out maxCompletionPortThreads);
   ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThread);
    
   int unit_index = 1;
   if(IsConnected == false)
   {
     IsConnected = CANClass.connect();
     lbl_Status.Text = "Connected";
   }

   else
   {
     Req1_Send = CAN.Send_Req1(unit_index, CANClass); //Sends request for Msg1 to MCU through CANClass
     if ((Req1_Send == true) && (Msg1_Received == false))
     {
        ThreadPool.QueueUserWorkItem(ReadMsg1); //Reads the message and display
     }
     
     Req2_Send = CAN.Send_Req2(unit_index, CANClass); //Sends request for Msg2 to MCU through CANClass
     if ((Req2_Send == true) && (Msg2_Received == false))
     {
        ThreadPool.QueueUserWorkItem(ReadMsg2); //Reads the message and display
     }

     Req3_Send = CAN.Send_Req3(unit_index, CANClass); //Sends request for Msg3 to MCU through CANClass
     if ((Req3_Send == true) && (Msg3_Received == false))
     {
        ThreadPool.QueueUserWorkItem(ReadMsg3); //Reads the message and display
     }
     ............... till the Msg10
   }
}
  1. btn_Stop

Stop the connection


 private void btn_Stop_Click(object sender, EventArgs e)
 {
    Stop();
           
 }
       
 private void Stop()
 {
    btn_Start.Enabled = true;
    btn_Stop.Enabled = false;
    CanPacket.CanStop();
    IsConnected = false;
 }
```

CodePudding user response:

The thing with hardware controllers is that (usually) you don't know exactly how long they'll take to fill up the RX Buffer so that you can get the packet response from the TX-RX pair. If you're doing it on a timer tick you're between the terrible risk of buffer underrun (possibly hanging the controller) or wasting time by patting the wait time with margins.

Often it's better to loop in a Task where you perform the IO synchronously (hopefully this involves actual handshaking) for your "10 Commands" and then get the "100 ms spacing" after all the TX-RX pairs have completed and before the next iteration of the loop.

    private async void checkBoxRun_CheckedChanged(object sender, EventArgs e)
    {
        if (checkBoxRun.Checked)
        {
            richTextBox.Clear();
            await Task.Run(() => loop());
            labelIndicator.BackColor = Color.LightGray;
        }
    }
    private async Task loop()
    {
        do
        {
            await readCanBusSingle();
            if (!checkBoxRun.Checked) return;

            // Here's where the spacing of 100 ms or whatever happens.
            // I made it longer for test.
            await Task.Delay(TimeSpan.FromSeconds(1));

        }
        while (checkBoxRun.Checked);
    }
    private async Task readCanBusSingle()
    {
        string text;
        if (_busController.TryConnect())
        {
            BeginInvoke((MethodInvoker)delegate
            {
                labelIndicator.BackColor = Color.LightGreen;
                richTextBox.SelectionFont = new Font(richTextBox.Font, FontStyle.Bold);
                richTextBox.AppendText($"{Environment.NewLine}{DateTime.Now}: REQUEST{Environment.NewLine}");
                richTextBox.SelectionFont = new Font(richTextBox.Font, FontStyle.Regular);
            });
            foreach (RequestID requestID in Enum.GetValues(typeof(RequestID)))
            {
                var packet = new Packet { RequestID = requestID };

                // HARWARE CONTROLLER: Push some bytes into TXQueue
                _busController.SendReq(unitIndex: 1, packet: packet);

                // HARWARE CONTROLLER: Wait for RXQueue bytes to be present
                // Often this means a spin (not an await) until the full
                // reapi=onse is available in the MCU.
                await Task.Run(() =>
                {
                    while(_busController.Busy)
                    {
                        Task.Delay(10).Wait();
                    }
                });

                if (packet.MockResponse is uint[] bytes)
                {
                    text = string.Join(" ", bytes.Select(_ => _.ToString("X4")));
                }
                else
                {
                    text = $"{packet.MockResponse}";
                }
                BeginInvoke((MethodInvoker)delegate
                {
                    switch (packet.RequestID)
                    {
                        case RequestID.REQ1:
                            richTextBox.SelectionColor = Color.Navy;
                            break;
                        case RequestID.REQ2:
                            richTextBox.SelectionColor = Color.DarkGreen;
                            break;
                        case RequestID.REQ3:
                            richTextBox.SelectionColor = Color.Maroon;
                            break;
                        default: throw new InvalidOperationException();
                    }
                    richTextBox.AppendText($"{text}{Environment.NewLine}");
                    richTextBox.ScrollToCaret();
                });
            }
        }
        else
        {
            BeginInvoke((MethodInvoker)delegate
            {
                labelIndicator.BackColor = Color.LightSalmon;
                richTextBox.SelectionColor = Color.Red;
                richTextBox.AppendText($"{Environment.NewLine}Connection lost{Environment.NewLine}");
                richTextBox.ScrollToCaret();
            });
        }
    }

MOCK rtf console

Where:

public enum RequestID { REQ1, REQ2, REQ3 }

public class McuController
{
    internal bool TryConnect()
    {
        switch (Rando.Next(10))
        {
            case 0:
                // The mock controller fails every now and then
                return false;
            default:
                return true;
        }
    }
    internal async void SendReq(int unitIndex, Packet packet)
    {
        Busy = true;
        await packet.SetMockResponse(TimeSpan.FromMilliseconds(Rando.Next(10, 51)));
        Busy = false;
    }
    public static Random Rando { get; } = new Random();
    public bool Busy { get; private set; }
}
public class Packet
{
    public RequestID RequestID { get; set; }
    public int UnitID { get; set; }

    // MOCK
    public object MockResponse { get; set; }
    public async Task SetMockResponse(TimeSpan mockDelay)
    {
        await Task.Delay(mockDelay);
        switch (RequestID)
        {
            case RequestID.REQ1:
                // String
                MockResponse =
                    $"Unit {UnitID}";
                break;
            case RequestID.REQ2:
                // ByteArray
                MockResponse =
                    Enumerable.Range(0, 8)
                    .Select(_ => (uint)Rando.Next(45000, 55000))
                    .ToArray();
                break;
            case RequestID.REQ3:
                MockResponse =
                    mockDelay;
                break;
            default: throw new InvalidOperationException();
        }
    }
}
  • Related