Bug 8207 - Can't set 1000000 baud with System.IO.Ports.SerialPort.BaudRate
Summary: Can't set 1000000 baud with System.IO.Ports.SerialPort.BaudRate
Status: RESOLVED FIXED
Alias: None
Product: Class Libraries
Classification: Mono
Component: System (show other bugs)
Version: 2.10.x
Hardware: All All
: Normal normal
Target Milestone: Untriaged
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2012-11-04 03:54 UTC by romanovda
Modified: 2017-10-12 13:24 UTC (History)
11 users (show)

See Also:
Tags:
Is this bug a regression?: ---
Last known good build:


Attachments
Patch against support/serial.c (1.87 KB, patch)
2013-01-30 07:57 UTC, Chris H
Details | Diff

Description romanovda 2012-11-04 03:54:33 UTC
The following problem occurs on Linux Mint 13 (Ubuntu 12.04) with mono 2.10.8.1 (Debian 2.10.8.1-1ubuntu2.2)

I'm using a FTDI USB to Serial converter which supports up to 4000000
Baud. With "stty -F /dev/ttyUSB0 speed <baud rate>" I can set the baud rate to
1000000. But the highest value I can set in my SerialPort instance is 921600 . If
I set it to 1000000 "stty -F /dev/ttyUSB0" shows me that the device
actually runs with 9600 baud. 

Baud rate 1000000 is one of the "standard" baud rates. Setting baud rate to 1000000 works in python, C on the same Linux and on .NET on Windows.

Steps to reproduce:
-------------------
0) I think you need a device which supports at least 1000000 baud.

1) run the following code and compare the values with the output from "stty -F
/dev/ttyUSB0":

using System;
using System.IO.Ports;

namespace SerialPortTest
{
    class MainClass
    {

        public static void Main(string[] args)
        {
            SerialPort sp = new SerialPort("/dev/ttyUSB0");

            sp.Open();

            sp.BaudRate = 38400;
            Console.WriteLine("stty should now display " + sp.BaudRate +
                              " baud. press a key to continue");
            Console.ReadKey();

            sp.BaudRate = 921600;
            Console.WriteLine("stty should now display " + sp.BaudRate +
                              " baud. press a key to continue");
            Console.ReadKey();

            // ----- from here stty shows only 9600 baud -----
            sp.BaudRate = 1000000;
            Console.WriteLine("stty should now display " + sp.BaudRate +
                              " baud. press a key to continue");
            Console.ReadKey();

            sp.Close();
        }
    }
}
Comment 1 romanovda 2012-11-04 05:17:06 UTC
Looks like the old bug
https://bugzilla.novell.com/show_bug.cgi?id=445520
was fixed only up to 921600 leaving all higher baud rates unfixed
Comment 2 Chris H 2013-01-30 07:57:20 UTC
I'm attaching a patch against mono-2.10.8.1 (from Debian), that allows setting custom baud rates. Maybe this would also work for newer "standard" baud rates like 1000000.
Comment 3 Chris H 2013-01-30 07:57:47 UTC
Created attachment 3302 [details]
Patch against support/serial.c
Comment 4 Rodrigo Kumpera 2015-02-24 10:31:47 UTC
Hi Chris,

Sorry for the very long wait.

I reviewed your patch and it looks good. Before we can include it, it must be released under the MIT license.

In order to to do so, please email the patch to mono-dev and state "I release this patch under the MIT license."

Thanks.
Comment 5 Alexander Köplinger 2015-02-24 12:21:12 UTC
@Rodrigo FYI, there's a PR pending that does something similar: https://github.com/mono/mono/pull/1177
Comment 6 Chris H 2015-02-24 15:47:42 UTC
Sent mail to mono-devel-list.
Comment 7 Miguel de Icaza [MSFT] 2015-02-25 10:28:14 UTC
Applied patch
Comment 8 romanovda 2015-04-01 22:21:33 UTC
Still can't set the baud rate to 1000000 on Linux. 

Getting

System.ArgumentOutOfRangeException: Given baud rate is not supported on this platform

That is because 
mcs/class/System/System.IO.Ports/SerialPort.cs 
relay on 
mcs/class/System/System.IO.Ports/SerialPortStream.cs
which uses 
is_baud_rate_legal
from
support/serial.c

which is just a dumb switch with several predefined values.
Comment 9 Miguel de Icaza [MSFT] 2015-04-02 09:53:53 UTC
Perhaps because the code has not been released.

Because the switch statement has support for non-standard baud rates now.
Comment 10 romanovda 2015-04-02 10:14:35 UTC
Switch knows but is_baud_rate_legal doesn't use it. 
To be exact:

setup_baud_rate knows about non-standard baud rates. But is_baud_rate_legal doesn't use it. And SerialPort still throws an exception because of is_baud_rate_legal. 

is_baud_rate_legal (int baud_rate)
{
gboolean ignore = FALSE;
return setup_baud_rate (baud_rate, &ignore) != -1;
}

The title of the bug report "Can't set 1000000 baud with System.IO.Ports.SerialPort.BaudRate". I still can't set 1000000 baud rate. I wouldn't reopen the bug, if I hadn't test it.
Comment 11 romanovda 2015-04-02 10:18:42 UTC
As I understand the code, this would fix the issue:

gboolean
is_baud_rate_legal (int baud_rate)
{
   custom_baud_rate = FALSE;
   int result = setup_baud_rate (baud_rate, &custom_baud_rate);
   return  result != -1 || custom_baud_rate;
}
Comment 12 romanovda 2015-04-02 10:23:50 UTC
Looking closer at the code shows that I'm wrong. It should work now. I was using the master to test the issue. Have to recheck what goes wrong then
Comment 13 xamarin 2015-04-21 23:06:33 UTC
I'm running on Mac and see this exact problem with a baud rate of 2000000.
Comment 14 xamarin 2015-04-22 01:35:28 UTC
Found a workaround as follows:
a) Open the port using some safe, dummy baud rate (e.g. 9600)
b) Use reflection to dig out the file descriptor in the SerialPortStream (UGH!)
c) p/invoke to ioctl to set the desired baud rate:

        const uint IOSSIOSPEED = 0x80000000 | ((sizeof(uint) & 0x1fff) << 16) | ((uint)'T' << 8) | 2;

        [DllImport("/System/Library/Frameworks/IOKit.framework/IOKit")]
        extern public static int ioctl(int fileNumber, uint request, ref int baudRate);

        public static int SetBaudRate(int fileNumber, int baudRate)
        {
            var customBaudRate = baudRate;
            var result = ioctl(fileNumber, IOSSIOSPEED, ref customBaudRate);
            return result;
        }

Preliminary results are encouraging.

BTW, that IOSSIOSPEED value … Dang, the version of Xcode I was using really did not want to yield that information. Ultimately had to dig it out of preprocessor output.
Comment 15 arocholl 2015-05-12 12:04:05 UTC
So then what is the sequence to use a custom baudrate, say 500000, with this fix in place?

By using direct SerialPort.BaudRate=500000; does not work, I get exception as below: 

System.IO.IOException: Inappropriate ioctl for device
  at System.IO.Ports.SerialPortStream.ThrowIOException () [0x00000] in <filename unknown>:0 
  at System.IO.Ports.SerialPortStream..ctor (System.String portName, Int32 baudRate, Int32 dataBits, Parity parity, StopBits stopBits, Boolean dtrEnable, Boolean rtsEnable, Handshake handshake, Int32 readTimeout, Int32 writeTimeout, Int32 readBufferSize, Int32 writeBufferSize) [0x00000] in <filename unknown>:0 
  at (wrapper remoting-invoke-with-check) System.IO.Ports.SerialPortStream:.ctor (string,int,int,System.IO.Ports.Parity,System.IO.Ports.StopBits,bool,bool,System.IO.Ports.Handshake,int,int,int,int)
  at System.IO.Ports.SerialPort.Open () [0x00000] in <filename unknown>:0 
  at (wrapper remoting-invoke-with-check) System.IO.Ports.SerialPort:Open ()
  at USBPortTest.MainFormTestUSB.ConnectPort (System.String PortName) [0x00000] in <filename unknown>:0
Comment 16 arocholl 2015-05-12 12:11:35 UTC
To add context to my previous comment:

* Using Ubuntu 14
* Using Mono JIT compiler version 4.0.1 (tarball Tue Apr 28 11:49:45 UTC 2015) official distribution
* Exception raise when doing System.IO.Ports.SerialPort.Open() call, as listed in the exception. I do not get any exception when setting a baudrate.
Comment 17 xamarin 2015-05-12 13:35:48 UTC
If the serial port is not open, the baud rate validation does not run, IIRC. The only bounds checking done when the port is not open is a check for < 0.

Check this:

https://github.com/mono/mono/blob/c19e821763cc90c6b12b31bf394dd29e6923dfdb/mcs/class/System/System.IO.Ports/SerialPort.cs

To get things to work for my situation, I first did NOT set the baud rate to anything. The default baud rate is 9600. Just open the port at the default baud rate, then, prior to doing any communication, use the workaround above.

You could wrap SerialPort and provide your own Open() method that does this.
Comment 18 arocholl 2015-05-12 19:22:32 UTC
I get the same problem if I set the baudrate after opening the port. All these things fail to the same exception:

case 1)

- start with a closed port
- set BaudRate=9600 (or 38400)
- open port (works)
- define BaudRate=500000 (exception)

case 2)

- start with a closed port
- set BaudRate=500000
- open port (exception)

So in my Ubuntu testing, there is no way or workaround that seems to work at all for custom baudrate.
Comment 20 xamarin 2015-05-12 20:55:34 UTC
@arocholl:

Read the workaround I posted about p/Invoking out to ioctl. That's the workaround. Until the Mono runtime is released that allows for custom baud rates, some kind of workaround will be required.

On Mac, the stty 'ForceSetBaudRate' trick didn't work for me. I can't recall the precise error.

If you're using the Starter version of Xamarin.Mac, though, you won't be able to p/Invoke. Maybe some other command line call out could work for you, but I prefer the ioctl in-process workaround instead.
Comment 21 xamarin 2015-05-12 20:56:43 UTC
@arocholl:

D'oh… you're in Linux. So have you tried the workaround romanovda found on Stack Overflow?

Note You need to log in before you can comment on or make changes to this bug.