Question
Is there a way to get multiple async methods (tasks or threads) to wait until certain individual conditions happen?
I am trying to get a call/response system working with an arduino controlling a mechanism via the serial port.
The controlling computer creates a Task/thread that handles each job assigned to the arduino asynchronously (home the mechanism, set position, move, etc.) The arduino reports back with how it is doing on each job ("successfully homed", "moved to position", etc.) which allows the job to continue along its code path.
However, everything I've tried has some issue with it, and so I'm looking for some advice on how to proceed.
Here are things I've tried. (Feel free to ask specifics about these.)
while(!doneWaiting){thread.sleep(5);}
loops when I was using a thread-based system instead of a task based system. This ate up the entire CPU when I had multiple threads waiting for a response from the arduino (for example, I was trying to moveAxis1 and moveAxis4 at the same time, and both were waiting for permission to proceed, crashing the program due to over-use of memory.)Repeatedly parsing the
SerialPort
input for the string that signified for that job to proceed. Also ate up memory and would occasionally ignore the "OK to proceed with job" response.Eventually I implemented the
serialPort.DataReceived
event and usedManualResetEvents.WaitOne()
. When new data was found in theSerialPort
, it wouldManualResetEvents.Set()
and allow the code to flow pastWaitOne()
. This would be the best option, but it triggers ALL waiting threads as opposed to one particular waiting thread at a time. I need some threads to wait for their personal response while others are allowed to continue.
Here is my current implementation, which is nonfunctional.
class Program
{
public static SerialPort serialPort = new SerialPort("COM9", 9600, Parity.None, 8, StopBits.One);
public static string newDataContent = string.Empty;
public static bool homed = false;
static TaskCompletionSource<bool> homeRelease = new TaskCompletionSource<bool>(); //this is the important bit
static void Main(string args[])
{
serialPort.DtrEnable = true;
serialPort.DataReceived += new SerialPortDataReceivedEventHandler(serialPort_ReadArduinoData);
serialPort.Open();
//...
char cmdType = Console.ReadLine().ToLower().ToCharArray()[0];
switch(cmdType)
{
case 'h':
Task.Run(Home);
break;
//...the rest of the commands...
}
}
}
Here is the what the Home task looks like. It is paused in the middle with `homeRelease.Task;` and awaits its completion.
static async Task Home()
{
Console.WriteLine("Running Task Home()");
WriteMyCommand(2, 0, serialPort); //this function is proven working. Writes the command to the arduino.
Console.WriteLine("awaiting homeRelease...");
await homeRelease.Task;
Console.WriteLine("...homeRelease Received");
homed = true;
homeRelease.SetResult(false);
}
The serialData_ReadArduinoData
event looks like this:
public static void serialPort_ReadArduinoData(object sender, SerialDataReceivedEventArgs e)
{
SerialPort spL = (SerialPort)sender;
byte[] buf = new byte[spL.BytesToRead];
spL.Read(buf,0,buf.Length);
newDataContent = $"{System.Text.Encoding.ASCII.GetString(buf)}";
Console.WriteLine($"Received: {newDataContent}");
switch(newDataContent[1])
{
case '2': //response Home command
Console.WriteLine("Detected home response");
homeRelease.SetResult(true);
break;
//rest of switch statement
}
}
When I do one home command, the system works as expected, and pauses the Home task at the await until the "arduino has homed" signal is complete. However, when I request another instance of the same job, I get the error, 'An attempt was made to transition a task to a final state when it had already completed.'
Is there a way I could get multiple of these threads/tasks/jobs to wait for an individual flag raised by the switch statement in serialPort_ReadArduinoData
that allows them to continue working? Or is this approach just completely deranged?
I am totally stumped as to where I could go next. Any assistance would be very much appreciated: I am over deadline and also not a professional programmer.