Arduino Command-Line Utility ?

Actually, I may have put you wrong here. Off the top of my head, I thought println() added a \n character, however it apparently adds both a \r and a \n.

This is a bit of a quirk; different operating systems prefer different combinations of \r and \n, so have to pay particular attention.

Sorry about that.

the C# code I had posted was basically just hacked together and not tested

I would suggest you explore M$FT System.IO.Ports Namespace | Microsoft Learn to write proper code to handle that. I don't really write code for windows unless when I really have to (aka never :slight_smile: ) so the code above was probably not great.

1 Like

No, no, it worked !!! Thats all that matters.
Next step is a problem of string manipulation or some deep swim into SerialPort class with its many methods,events and fields. Ugh...
When I will find the answer, I will post it here as well. One hand cleaning-wash the other.
:wink:

given you are on a machine with a real OS, the best way is to create a task listening to the Serial port and collecting the incoming bytes in a buffer and once you receive the end marker push that message onto a queue.

then the main task is basically cycling

  • asking the queue if there is a new message available
  • if there is, pop the message, handle it
1 Like

haha, yes exactly my though, but ... HOuuuuuuu? :slight_smile: haha

If you were being lazy (or rather "how I did probably did it last time"), could even just have each event concatenate the data onto a string, and check if the last two characters are string contains '\r\n'.

it's not that complicated, something like this (using COM5 and 9600 bauds... you should use 115200 as there is no reason to go slow)

using System;
using System.Collections.Concurrent;
using System.IO.Ports;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    private static ConcurrentQueue<string> messageQueue = new ConcurrentQueue<string>();
    private static CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
    private static string endMarker = Environment.NewLine; // Default end marker is newline

    // THE MAIN CODE
    static async Task Main() {
      Task listeningTask = Task.Run(ListenToArduino);                               // Start the task to listen to Arduino
      Task processingTask = Task.Run(ProcessMessages);                              // Start the task to process the messages

      await Task.WhenAny(listeningTask, processingTask);                            // Wait for either task to complete
      cancellationTokenSource.Cancel();                                             // Cancel the other task if one completes
      await Task.WhenAll(listeningTask, processingTask);                            // Wait for the other task to complete
    }

    // THE TASK LISTENING TO THE ARDUINO
    static async Task ListenToArduino() {
      using (SerialPort serialPort = new SerialPort("COM5", 9600)) {              // adjust COM5 to be your port for the Arduino
        serialPort.Open();
        while (!cancellationTokenSource.Token.IsCancellationRequested) {            // repeat until the task has to die
          string receivedData = await serialPort.ReadLineAsync();                   // get a line (read until the next '\n')
          messageQueue.Enqueue(receivedData);                                       // dump it into the queue
        }
      }
    }

    // THE TASK PARSING THE MESSAGES
    static async Task ProcessMessages() {
      while (!cancellationTokenSource.Token.IsCancellationRequested) {            // repeat until the task has to die
        if (messageQueue.TryDequeue(out string message)) {                        // if there is a message pending, get it out of the queue
          Console.WriteLine("Received message: " + message);                      // write to the console
        }
        await Task.Delay(10);                                                    // Creates and wait for a task that will complete after a time delay. Adjust the delay as needed
      }
    }
}

of course instead of

          Console.WriteLine("Received message: " + message);                      // write to the console

that's where you would parse the message and do what's needed

2 Likes

Ive tried already everything I know.
There are 3 most used bool methods:
.StartsWith(..)
.EndsWith(..)
.Contains(..)
and
here is how I implement it:

        static void ArduinoPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            SerialPort port = (SerialPort)sender;
            string receivedData = port.ReadExisting(); // Read the available data from the serial port

            if (receivedData.StartsWith("\n"))
            {
                Console.WriteLine(receivedData);
            }
        }

and all of these 3 (most used) methods are returning some sort of different error.
Not really resolving the issue.
So its a matter of a deeper string manipulation or some weird class function specific for this type of task im not familiar with (yet).

what do your messages look like?

Ah, well there's no guarantee that your receivedData starts with "\n", it could have turned up anywhere in that string / byte array / set of serial data.

Also, every time you ReadExisting, the data disappears, so you really need to stack it all somewhere, like in that fancy queue setup, until you know you've the whole line read in.

if (receivedData.StartsWith("\n"))
Im always expecting 8 lines but with this I get less than 8 lines between - - - separator.


if (receivedData.EndsWith("\n"))
adding a group of 4 empty lines after ~5s per update

if (receivedData.Contains("\n"))

can you share the arduino code? (what are you sending over)?

can you try the new code I shared?

1 Like

Disclaimer, I've never written a line of C# in my life. (VB.NET was the direction I naively went in)

As a result, this code probably won't work, and it is certainly an inelegant solution, but maybe it gives you an idea of why your first version is giving odd results.

private string receivedData = "";

private void ArduinoPort_DataReceived(object sender, SerialDataReceivedEventArgs e) {
	SerialPort port = (SerialPort)sender;

	while(port.BytesToRead > 0) {
		char incoming = (char)port.ReadByte();
		this.receivedData += incoming;

		if (this.receivedData.Contains("\r\n")) {
			Console.WriteLine(this.receivedData);
			this.receivedData = "";
			break;
		}
	}
}
1 Like

I really dont think you need to fill your memory with the code behind.
But is no problem from my part to show it to you. All Im saying is not to split your attention on another direction than the one I started here and we did very well so far. We only have to solve at this point an annoying BUG !!! Thats it.
Alright then, so, you want the red pill, eh? (from matrix) haha
See code here @ post #61 and also check that page a bit up, for some pictures in it, that will clarify something ... probably. Dont get too deep into it. Just make an idea and get out from it. Is my advice.
Also this is how the output looks like right now from arduino perspective:

Not a hugely relevant observation to make, but it looks like your Arduino serial monitor is only looking for the "\n" not "\r\n" (as shown by the "newline" box), which is odd because the code in the link you posted uses only "\r".. yet it seems to be displaying fine.

My mistake not mentioning before. Either "\n" or "\r\n" , the results are the same. I re-test it now just to be sure and indeed, the exact same erroneous result as already explained.

that's used only if you use the Serial monitor to send data to the Arduino, it's not used when the Arduino sends data to the Serial monitor

1 Like

I would guess that you may have un-commented the Serial.println() statements on the version you are running currently on your Arduino?

Oh, that's interesting, I didn't know that! How does the serial monitor handle line encoding EOL for incoming data?