Unable to read from Serial Port using C# Mono (RaspberryPi)

11,239

Solution 1

Have a look at stty command. It will let you set/read teminal settings

http://linux.about.com/od/lna_guide/a/gdelna38t01.htm will give a rundown on it's use. It would be easier to call out to than minicom, and the settings stay on the device.

Solution 2

I have done something like the same as you before. I had to read and write data through USB Serial adapter, and didnt use minicom. It may not be god code but i found that inorder to read the data I could create a new thread and have that check for data, my code include a lot of stuff but basicly i did this:

System.Threading.Thread newThread;
newThread = new System.Threading.Thread(this.check_get_data);

and the check_get_data method

public void check_get_data ()
    {
        byte tmpByte = 0;
        while (m_objSerialPort.BytesToRead != 0) {
            tmpByte = (byte)m_objSerialPort.ReadByte ();
            DoSomethingWithByte(tmpByte);
            Thread.Sleep(20);
        }
    }

this is currently running with two usbserials. dont know if it helps but hope you find your solution

Share:
11,239
Admin
Author by

Admin

Updated on June 04, 2022

Comments

  • Admin
    Admin almost 2 years

    I'm attempting to write a C# library which looks at all available USB serial ports on a Raspberry Pi so that I can enumerate, identify and communicate with a set of Arduinos connected to the Pi via a USB hub.

    I am able to make this work on my windows machine (several Arduinos connected to my desktop computer) and have even been able to make it work on my Pi however, I am struggling to understand how to generalize the fix.

    If I attempt to run the program by itself on the Pi, I am able to open the serial port and send data however, I cannot receive anything from the Arduinos: I get timeout exceptions. I understand that Mono's implementation of SerialPort is limited and I must use SerialPort.ReadByte() instead of Readline() and the data received events (my solution is based on code from HowToSystemIOPorts). My Serial port enumeration is using a method outlined in another stack exchange response here.

    My timeout is currently set to 4 seconds, which is several orders of magnitude longer than I expect to receive the message.

    After a lot of googling, I came across mention of using minicom to initialize the serial port here, which to my surprise allowed me to receive data from the Arduino. The biggest drawback is that I need to initialize the port using minicom and leave the process opening each time I boot the Pi. I also can't seem to figure out how to make this work with multiple Arduinos.


    Here is what I have tried so far:

    • Updated the Pi firmware and software to their latest versions
    • Attempted to use both an Arduino MEGA 2560 R3 and Arduino UNO
    • Changed the owner of the tty* ports (ttyACM0 and ttyUSB0 in this case) to both my user and group
    • Successfully configured the port via minicom, left the process running and start the program and read/wrote data. A manual process which only seems to work for one Arduino at a time
    • Successfully run the program in Windows without fault
    • Verified the Arduinos are recognized by the Pi running "dmesg | grep tty"

    Here is what I hope to solve:

    • Automatic setup/initialization of the Arduino serial ports. Whether through a shell script run before the main program or within Mono code so that the code below can run as intended.

    Here is my connection code:

        public bool StartArduinoComms()
        {
            string[] ports = GetPortNames();
            foreach (string port in ports)
            {
                mLogger.LogMessage(ProsthesisCore.Utility.Logger.LoggerChannels.Arduino, string.Format("Found serial port {0}", port));
            }
    
            bool foundCorrectArduino = false;
    
            var idPacket = new ArduinoMessageBase();
            idPacket.ID = ArduinoMessageValues.kIdentifyValue;
    
            string jsonOutput = Newtonsoft.Json.JsonConvert.SerializeObject(idPacket);
    
            foreach (string port in ports)
            {
                SerialPort serialPort = new SerialPort(port, kArduinoCommsBaudRate);
                serialPort.Parity = Parity.None;
                serialPort.DataBits = 8;
                serialPort.StopBits = StopBits.One;
    
                //Only check unopened ports
                if (!serialPort.IsOpen)
                {
                    serialPort.Open();
    
                    //Disable telemtry just incase
                    var toggle = new { ID = ArduinoMessageValues.kTelemetryEnableValue, EN = false };
                    string disableTelem = Newtonsoft.Json.JsonConvert.SerializeObject(toggle);
                    serialPort.Write(disableTelem);
    
                    //Discard any built up data
                    serialPort.DiscardInBuffer();
                    serialPort.Write(jsonOutput);
                    serialPort.ReadTimeout = kIDTimeoutMilliseconds;
    
                    string response = string.Empty;
                    for (int i = 0; i < kNumRetries; ++i)
                    {
                        try
                        {
                            //This is guaranteed to timeout if not configured through minicom
                            response = ReadLine(serialPort);
                            break;
                        }
                        //Catch case where the serial port is unavailable. MOve to next port
                        catch (TimeoutException)
                        {
                            continue;
                        }
                    }
    
                    if (!string.IsNullOrEmpty(response))
                    {
                        //Perform response validation
                    }
                    else
                    {
                        //Got no response
                    }
    
                    if (!foundCorrectArduino)
                    {
                        serialPort.Close();
                    }
                }
            }
    
            return foundCorrectArduino;
        }
        /// <summary>
        /// From https://stackoverflow.com/questions/434494/serial-port-rs232-in-mono-for-multiple-platforms
        /// </summary>
        /// <returns></returns>
        private static string[] GetPortNames()
        {
            int p = (int)Environment.OSVersion.Platform;
            List<string> serial_ports = new List<string>();
    
            // Are we on Unix?
            if (p == 4 || p == 128 || p == 6)
            {
                string[] ttys = System.IO.Directory.GetFiles("/dev/", "tty*");
                foreach (string dev in ttys)
                {
                    //Arduino MEGAs show up as ttyACM due to their different USB<->RS232 chips
                    if (dev.StartsWith("/dev/ttyS") || dev.StartsWith("/dev/ttyUSB") || dev.StartsWith("/dev/ttyACM"))
                    {
                        serial_ports.Add(dev);
                    }
                }
            }
            else
            {
                serial_ports.AddRange(SerialPort.GetPortNames());
            }
    
            return serial_ports.ToArray();
        }