High drawcall make delay when read variable from serial port

I have game that connected with arduino, my game have 500 drawcalls, when I try read variable from serial port, there’s delay about 1-5 sec. But when the drwacalls less than 300 there’s no delay when read the serial port. Is that the large amount of drawcalls make delay when read variable from serial port? Here’s my code :

using UnityEngine;
using System.Collections;
using System.IO;
using System.IO.Ports;
using System.Threading;

public class Micro : MonoBehaviour
{
    string strIn;
    string FileName;
    StreamReader reader;
    string COM;
    int EnableMicro;
    public static int a1 = 0;
    public static int a2 = 0;
    public static int d1 = 0;
    public static int d2 = 0;
    public static int d3 = 0;

    SerialPort serial;
    private string[] data;

    string[] fungsi;
    string[] nilai;
    float TimerMicro;
    string value;

    void Start()
    {
        LoadConfig();
        if (EnableMicro == 1)
        {
            serial = new SerialPort(COM, 9600, Parity.None, 8, StopBits.One);
            //serial.Open();
            OpenConnection();
        }
        //serial.ReadTimeout = 1;
    }

    void Update()
    {

        //Debug.Log(value);
        if (EnableMicro == 1)
        {
            //TimerMicro += Time.deltaTime;
            try
            {
                value = serial.ReadLine();
            }
            //if (TimerMicro > 1.0f)
            //{
            catch
            {
                value = ("a1=0 a2=0 d1=0 d2=0");
            }
            if (value != null)
            {
                fungsi = value.Split('=');
                try
                {
                    nilai = fungsi[1].Split(' ');
                    a1 = int.Parse(nilai[0]);
                }
                catch
                {
                    a1 = 0;
                }

                //fungsi = value.Split('=');
                try
                {
                    nilai = fungsi[2].Split(' ');
                    a2 = int.Parse(nilai[0]);
                }
                catch
                {
                    a2 = 0;
                }

                //fungsi = value.Split('=');
                try
                {
                    nilai = fungsi[3].Split(' ');
                    d1 = int.Parse(nilai[0]);
                }
                catch
                {
                    d1 = 0;
                }

                //fungsi = value.Split('=');
                try
                {
                    nilai = fungsi[4].Split(' ');
                    d2 = int.Parse(nilai[0]);
                }
                catch
                {
                    d2 = 0;
                }
            }
            //Debug.Log(value);
            //Debug.Log("Fungsi 1:" + fungsi[0] + " Fungsi2:" + fungsi[1] + " Fungsi3:" + fungsi[2] + " Fungsi4:" + fungsi[3]);

            //fungsi = value.Split('=');
            //nilai = fungsi[5].Split(' ');
            //d3 = int.Parse(nilai[0]);
            //Debug.Log("L=" + L + " R=" + R + " U=" + U + " D=" + D + " RUN=" + RUN);
            Debug.Log("a1=" + a1 + "   a2=" + a2 + "   d1=" + d1 + "   d2=" + d2);
            ////if (L == 1)
            ////    Debug.Log("Kiri");

            ////if (R == 1)
            ////    Debug.Log("Kanan");

            ////if (U == 1)
            ////    Debug.Log("Atas");

            ////if (D == 1)
            ////    Debug.Log("Bawah");

            //strIn=("L="+L+" R="+R+" U="+U+" D="+D+" RUN="+RUN);
            //Debug.Log(strIn);
            //return strIn;
            //}
        }
    }

    void OnGUI()
    {
        GUI.Label(new Rect(Screen.width - 100, (Screen.height) - 20, 120, 30), "a1: " + a1);
        GUI.Label(new Rect(Screen.width - 200, (Screen.height) - 20, 120, 30), "a2: " + a2);
        GUI.Label(new Rect(Screen.width - 300, (Screen.height) - 20, 120, 30), "d1: " + d1);
        GUI.Label(new Rect(Screen.width - 400, (Screen.height) - 20, 120, 30), "d2: " + d2);
    }

    public void LoadConfig()
    {
        FileName = "Config.txt";
        if (!File.Exists(FileName))
        {
            return;
        }
        else
        {
            reader = File.OpenText(FileName);
            string buffer;

            buffer = reader.ReadLine();
            string[] token = buffer.Split(':');
            COM = (token[1]);

            buffer = reader.ReadLine();
            token = buffer.Split(':');
            EnableMicro = int.Parse(token[1]);

            reader.Close();
        }
    }

    void OpenConnection()
    {
        if (serial != null)
        {
            if (serial.IsOpen)
            {
                serial.Close();
                Debug.Log("Closing port, because it was already open!");
            }
            else
            {
                try
                {
                    serial.Open();  // opens the connection
                    serial.ReadTimeout = 10;  // sets the timeout value before reporting error
                    Debug.Log("Port Opened!");
                }
                catch
                {
                    Debug.Log("com False");
                }
            }
        }
        else
        {
            if (serial.IsOpen)
            {
                // print("Port is already open");
                Debug.Log("Port is already open");
            }
            else
            {
                //print("Port == null");
                Debug.Log("Port == null");
            }
        }
    }
    void OnApplicationQuit()
    {
        if (serial != null)
            serial.Close();
    }
}

and this the pictures :

10904-serial.png

Anyone can solve my problem? Thank you :slight_smile:

You use a readtimeout of 10 ms, so each call to serial.ReadLine(); will block your whole game for 10ms (except when a line is available). You should handle hardware IO stuff in a seperate thread.

Something like that:

//SerialPortLineReader.cs
using System;
using System.Collections.Generic;
using System.Threading;
using System.IO.Ports;

public class SerialPortLineReader
{
    private SerialPort m_SerialPort = null;
    private Thread m_ReadLoop = null;
    private object m_LockHandle = new object();
    private List<string> m_Lines = new List<string>();

    public bool IsDataAvailable
    {
        get
        {
            lock (m_LockHandle)
            {
                return m_Lines.Count > 0;
            }
        }
    }

    public string ReadLine()
    {
        string tmp = null;
        lock (m_LockHandle)
        {
            if (m_Lines.Count > 0)
            {
                tmp = m_Lines[0];
                m_Lines.RemoveAt(0);
            }            
        }
        return tmp;
    }


    public SerialPortLineReader(SerialPort aSerialPort)
    {
        m_SerialPort = aSerialPort;
        m_ReadLoop = new Thread(_ThreadFunc);
        m_ReadLoop.IsBackground = true;
        m_ReadLoop.Start();
    }

    private void _ThreadFunc()
    {
        while (m_ReadLoop.ThreadState != ThreadState.StopRequested)
        {
            string tmp = m_SerialPort.ReadLine();
            lock (m_LockHandle)
            {
                m_Lines.Add(tmp);
            }
        }
    }
}

Use this class like that:

SerialPort port = new SerialPort( .... );
SerialPortLineReader reader = new SerialPortLineReader( port );
// ...

string line = reader.ReadLine();
if (line != null)
{
    //...

This will seperate the io reading from your gameloop and only sync when you want to access data.

Btw: I just thrown this class together without testing it, but it should work :wink: