Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C#: How to determine settable baud rate for a serial port device?

I've just encountered a problem with the serial port but so far could not find an answer to it. Please let me know or give me some clues if I'm doing it wrong, Thanks. I'll try to explain the whole situation as detail as possible and ask my question in the end. Here goes.

I bought a USB to TTL converter using FTDI FT232RL chip and was curious about how serial network would work and how I could write my own program in C# instead of using hyper terminal. I started writing the program by reading some tutorials to give myself a quick start. After going through tutorials, I've noticed that all the tutorials I've read about uses similar methods when it comes to baud rate settings. They hard code the typical baud rates into their code instead of asking if the device would support that. I always try to write program as generic as possible, because of this, I started looking into how I can get retrieve information from the device. After searching, I've found this post answered by HiteshP very useful and have gone on using the reflection method suggested in the post. So here's what my code looks like:

private void UpdateBaudRateCollection()
{
    mySerialPort.PortName = cboAllPortNames.SelectedItem.ToString();
    mySerialPort.Open();
    object p = mySerialPort.BaseStream.GetType().GetField("commProp", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(mySerialPort.BaseStream);
    int dwSettableBaud = (int)p.GetType().GetField("dwSettableBaud", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public).GetValue(p);
    mySerialPort.Close();
    MessageBox.Show(dwSettableBaud.ToString("X"));
}

The result that I get from the MessageBox is 10066B70 which I have no idea what it represents as it is not shown in Microsoft's COMMPROP structure.

I did more search trying to figure out what 10066B70 meant but could not find any answer until I came across Basic serial port listening application by Amund Gjersøe. Maybe I had to perform AND operations with 10066B70 and the all the value given by Microsoft's COMMPROP structure. So I threw the value into the function.

private void SettableBaudRateOfDevice(int settableBaudRate)
{
    const int BAUD_075 = 0x00000001;
    const int BAUD_110 = 0x00000002;
    const int BAUD_150 = 0x00000008;
    const int BAUD_300 = 0x00000010;
    const int BAUD_600 = 0x00000020;
    const int BAUD_1200 = 0x00000040;
    const int BAUD_1800 = 0x00000080;
    const int BAUD_2400 = 0x00000100;
    const int BAUD_4800 = 0x00000200;
    const int BAUD_7200 = 0x00000400;
    const int BAUD_9600 = 0x00000800;
    const int BAUD_14400 = 0x00001000;
    const int BAUD_19200 = 0x00002000;
    const int BAUD_38400 = 0x00004000;
    const int BAUD_56K = 0x00008000;
    const int BAUD_57600 = 0x00040000;
    const int BAUD_115200 = 0x00020000;
    const int BAUD_128K = 0x00010000;
    const int BAUD_USER = 0x10000000;

    cboBaudRate.Items.Clear();

    if ((settableBaudRate & BAUD_075) > 0)
        cboBaudRate.Items.Add(75);
    if ((settableBaudRate & BAUD_110) > 0)
        cboBaudRate.Items.Add(110);
    if ((settableBaudRate & BAUD_150) > 0)
        cboBaudRate.Items.Add(150);
    if ((settableBaudRate & BAUD_300) > 0)
        cboBaudRate.Items.Add(300);
    if ((settableBaudRate & BAUD_600) > 0)
        cboBaudRate.Items.Add(600);
    if ((settableBaudRate & BAUD_1200) > 0)
        cboBaudRate.Items.Add(1200);
    if ((settableBaudRate & BAUD_1800) > 0)
        cboBaudRate.Items.Add(1800);
    if ((settableBaudRate & BAUD_2400) > 0)
        cboBaudRate.Items.Add(2400);
    if ((settableBaudRate & BAUD_4800) > 0)
        cboBaudRate.Items.Add(4800);
    if ((settableBaudRate & BAUD_7200) > 0)
        cboBaudRate.Items.Add(7200);
    if ((settableBaudRate & BAUD_9600) > 0)
        cboBaudRate.Items.Add(9600);
    if ((settableBaudRate & BAUD_14400) > 0)
        cboBaudRate.Items.Add(14400);
    if ((settableBaudRate & BAUD_19200) > 0)
        cboBaudRate.Items.Add(19200);
    if ((settableBaudRate & BAUD_38400) > 0)
        cboBaudRate.Items.Add(38400);
    if ((settableBaudRate & BAUD_56K) > 0)
        cboBaudRate.Items.Add(56000);
    if ((settableBaudRate & BAUD_57600) > 0)
        cboBaudRate.Items.Add(57600);
    if ((settableBaudRate & BAUD_115200) > 0)
        cboBaudRate.Items.Add(115200);
    if ((settableBaudRate & BAUD_128K) > 0)
        cboBaudRate.Items.Add(128000);
    if ((settableBaudRate & BAUD_USER) > 0)
        cboBaudRate.Items.Add(3000000);
}

After running the program, I get the following baud rates:

300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 3000000

Was happy that it worked until I compared it with the values shown in Windows's Device Manager for the device. The baud rates from the Device Manager was:

300, 600, 1200, 1800, 2400, 4800, 7200, 9600, 14400, 19200, 38400, 57600, 115200, 230400, 460800, 921600

I can understand that baud rate: 3000000 is not shown because I defined it myself but where did the rest of the values come from? I started wondering maybe it was defined in the driver. I started digging deeper and found FTDI's document AN232B-05 Configuring FT232R, FT2232 and FT232B Baud Rates. Inside the document, it says about FTDI's driver configuration file (ftdiport.inf). I searched for it and found it under windows system folder. The entry looks like this:

[FtdiPort.NT.HW.AddReg]
HKR,,"ConfigData",1,11,00,3F,3F,10,27,00,00,88,13,00,00,C4,09,00,00,E2,04,00,00,71,02,00,00,38,41,00,00,9C,80,00,00,4E,C0,00,00,34,00,00,00,1A,00,00,00,0D,00,00,00,06,40,00,00,03,80,00,00,00,00,00,00,D0,80,00,00

It looks the same with the one shown in FTDI's document section 2.3, Aliasing Using the Additional FT232B Sub-Integer Divisors. Following the instruction in section 2.3 and translating the ConfigData from ftdiport.inf, I get the following baud rates:

300, 600, 1200, 2400, 4800, 9600, 19230, 38461, 57692, 115384, 230769, 461538, 923076, 14406

Again, it is not the same as what the device manager is showing. Makes me wonder if the baud rate in the device manager is also hard coded.

I also tried counting how baud rate: 1800 from the device manager might look like in the ftdiport.inf file:

Required divisor = 3000000/1800 = 1666.666
Divisor = 1666
Sub-integer divisors = 0.6666
Closest Sub-integer divisors = 0.625
Closest achievable baud rate = 3000000/1666.625 = 1800.045  
Error = (1800.045-1800)/1800*100 = 0.0025%

Error is well within the allowed +/-3% margin of error as stated in the document, so the data entry in ftdiport.inf should have something that looks like this:

1666.625 Dec = 00014682 Hex
Data entry after re-order: 00014682 Hex => 82,46,01,00

Instead, [82,46,01,00] is nowhere to be found in ftdiport.inf file. I also performed dwMaxBaud from COMMPROP and got the result 10000000 which refers to:

BAUD_USER (0x10000000): Programmable baud rate.

So this means that the user can use any baud rate they like as long as it fulfills the baud rate of both transmitter and receiver and are within margin of error, right? (Just making sure I'm not getting it wrong as my brain is starting to get a bit fuzzy)

So by now, I'm very confused as I have 3 different results in my brain:

  1. What does 10066B70 from my program mean?
  2. Different results compared to the device manager's baud rate values with 10066B70 performing AND operations. Is this how it was meant to be done?
  3. Different results from the device manager's baud rate values and the document from FTDI. I have no idea which one to trust as both are official?

Thanks again for reading everything that I just wrote, I know it's quite long. Hopefully someone would be able to provide me with some answer to my questions.

*Note: I have not reach 10 reputation so I can't post more than 2 links, therefore I've put the links in the comment. Thanks again for your understanding.

like image 469
Bou Avatar asked Jul 07 '16 10:07

Bou


1 Answers

Fernhill makes software that can automatically and quickly try out large combinations of serial port settings to see which ones result in some kind of meaningful response.

Modbus Serial Autodetect Wizard

like image 145
skinnedKnuckles Avatar answered Sep 29 '22 00:09

skinnedKnuckles