Why does my Coroutine return Debug.Log(Object) after 1 iteration?

I am sending x,y,z orientation data from a BNO055 IMU to Unity through a Serial Port. I can receive the data fine with a FixedUpdate(), however it was lagging so I decided to try a coroutine. It runs for 1 iteration and the returns:

Error!
UnityEngine.Debug:LogError(Object)

Could someone shed some light as to why this may happen? In the Serial Monitor of my Arduino, the data is being sent fine.

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

public class bno055_orientation : MonoBehaviour
{

float gyroX;
float gyroY;
float gyroZ;

float gyro_norm = 1.0f / 360.0f;

public float speed;
private Rigidbody rb;

public GameObject target;

Vector3 rotation;

public SerialPort stream;
public int baudrate = 115200;
public string port = "COM6";

int readTimeout = 50;

void Start()
{
    Open();
    StartCoroutine(AsynchronousReadFromArduino
        ((string s) => Debug.Log(s),// Callback
        () => Debug.LogError("Error!"), // Error callback
        10f                             // Timeout (seconds)
)
);
}

public void Open()
{
    stream = new SerialPort(port, baudrate);
    stream.ReadTimeout = readTimeout;
    stream.Open();
}

//Action is a delegate that points to a method which in turn accepts one or more arguments but returns no value. Implements an event.
public IEnumerator AsynchronousReadFromArduino(Action<string> callback, Action fail = null, float timeout = float.PositiveInfinity)
{
    DateTime initialTime = DateTime.Now;
    DateTime nowTime;
    TimeSpan diff = default(TimeSpan);
    string dataString = null;
    string[] vec3 = null;

    do
    {
        //Single read attempt
        try
        {
            dataString = stream.ReadLine();
            vec3 = dataString.Split(',');
        }
        catch (TimeoutException)
        {
            dataString = null;
        }

        if ((dataString != null) & (vec3.Length == 3))
        {

                Debug.Log(vec3.ToString());

                bool gyroXbool = float.TryParse(vec3[0], out gyroY);
                bool gyroYbool = float.TryParse(vec3[1], out gyroZ);
                bool gyroZbool = float.TryParse(vec3[2], out gyroX);

                gyroX = (gyroX < 180) ? gyroX + 180 : gyroX;
                gyroY = (gyroY < 180) ? gyroY + 180 : gyroY;
                gyroX = (gyroZ < 180) ? gyroZ + 180 : gyroZ;

                Debug.LogFormat("Gyro Offset: {0}, {1}, {2}", gyroX.ToString(), gyroY.ToString(), gyroZ.ToString());

                if (gyroXbool && gyroYbool && gyroZbool)
                {

                    target.transform.rotation = Quaternion.Euler(gyroX, gyroY, gyroZ);

                };
                callback(dataString);
                yield return null; //It will run first on call fo the StartCoroutine until a yield is hit. 
                                   //Then it will return from the coroutine and place it onto a stack based on the yield. 
                                   //If null, then it will run again next frame. Some coroutine may WaitForEndOfFrame if they need to perform action at that specific moment.
            }
            else
                yield return new WaitForSeconds(10f);

            nowTime = DateTime.Now;
            diff = nowTime - initialTime;
    } while (diff.Milliseconds < timeout);

    if (fail != null)
            fail();
        yield return null;
    } 

public void Close()
{
    stream.Close();
}

}

@behemothdan @patricioaljndro if you have any advice since I noticed you had some previous issues with coroutines then that would be great. Thanks if you can.

A coroutine will not help here at all. Coroutines are iterated also on the main thread. So it’s just part of the same main program loop. If you have a blocking call in a coroutine it will block your whole application. Coroutines are not threads. They are just a neat way to let the compiler automatically create a statemachine out of your “seemingly” linear code.

You should always do lowlevel hardware interactions on a seperate thread. Just recently someone else asked a similar question over here. You may want to have a look at my example code. I don’t have an arduino to actually test this. I have some Raspberry PIs and in the past i used PIC micro controllers but never used any inside Unity.