64-bit Win7 - FTDI Serial Terminal Tester Help

Go To Last Post
23 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you have access to a 64-bit Win7 computer and would be willing to try my Simple Terminal with an Arduino or similar USB device, I'd really appreciate it!

http://downloads.smileymicros.co...

I'm communicating with a guy who can't get this to work on Win7 64-bit and I can't test it since I don't have that OS. The terminal is written in C# and the source code is also available at:

http://downloads.smileymicros.co...

Smiley

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Joe,

Win7, 64 bit, Home Premium, SP1, up to date.
I see my AVR FTDI converter in Device Control as Com4, but SimpleTerminal doesn't see any Com-ports.
Com4 (my AVR FTDI converter) is the only one available and your program tells, in the title-bar, that Com1 is closed. FYI, there is no Com1 on my system.

Br@y Terminal works fine.

Nard

A GIF is worth a thousend words   They are called Rosa, Sylvia and Tessa, You can find them https://www.linuxmint.com/

Dragon broken ? http://aplomb.nl/TechStuff/Dragon/Dragon.html for how-to-fix tips

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have W7 Professional. Same as Nard, seen as Com3 with device manager. No ports in "settings", "OpenPort" seems to default to Com1 and errors with IOexceptions.

TeraTerm finds it and works fine.

It all starts with a mental vision.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks guys.

I'm thinking it has something to do with the difference between the 32-bit integer and the 64-bit integer in that my older code assumes 32-bit which gets promoted some way in C# such that a critical serial port class variable gets used incorrectly. Of course without a 64-bit Win7 machine I have no way to try to hunt this down. I hope somebody with C# experience takes an interest and looks at the source code. If not, I'll need to borrow a 64-bit Win7 machine and try to figure this out myself.

Oh, and a big thanks to Microsoft for, as always, caring so much about legacy serial port software. I generally have to fix my code after every OS update.

Smiley

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Which FTDI chip are you using?

We've got big issues with FTDI's FT232RL a certain USB 3.0 Host chip from Intel on both HP and other computers. It's probably a bug in the USB host chips.

On other Win 7 64 bit computers it runs like a charm.

I'll ask for all the details tomorrow (it's almost 10PM here).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Joe, I found a work-around, for the time being ....

I forced my AVR FTDI converter in Device Manager to use Com1. I still don't see it when trying to select the Comport in SimpleTerminal, but hitting "OpenPort" in the menu, opens Com1, and the program works.
Btw, I am using USB2 type interface, not Jan's USB3.

Nard

A GIF is worth a thousend words   They are called Rosa, Sylvia and Tessa, You can find them https://www.linuxmint.com/

Dragon broken ? http://aplomb.nl/TechStuff/Dragon/Dragon.html for how-to-fix tips

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Joe,
Win7/64 Professional on the East Side of the country and I am getting the same errors Nard is reporting.

One thing I wanted to try out but am unable to because of the way your program works was to run it in compatibility mode, where I can pick other versions of windows to launch the program under. The option is not there when I right click and hit properties.

I will try it in a VM right now

EDIT:
No good there either. Same errors and then it crashes.

Sorry :(

EDIT EDIT:
I also cannot uninstall the program through Control Panels Uninstall Programs.

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

Last Edited: Tue. Apr 30, 2013 - 02:48 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Uninstall worked without a hitch here!

But apart from that the program didn't work, my board (Stellaris launchpad) showed up as COM5 in control panel, and the program tried to open COM1 which doesn't exist, giving an error.

- Brian

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

VICTORY!

I got it working with 64-bit Win7. Unfortunately you can't use the free C# Express from Microsoft, but you can use SharpDevelop - an open source C# compiler that you can get at:

http://www.icsharpcode.net/opens...

The problem is that you must compile for the platform x86. The default is 'anyCPU' which won't work (and is a long boring story). The free version of C# Express won't allow you to set the platform. You can pay Microsoft $500 for the paid version that will allow that, but since I wasn't sure it would work, I opted to try SharpDevelop. I did this on a friends (yes I have friends) laptop with 64-bit Win7 so I don't have the exact procedure at hand. When you download SharpDevelop you'll need to open a new project - you can't port the SimpleTerm project since it won't change the platform if you do. In the new project you import the existing files from the old SimpleTerm then delete the mainform that SharpDevelop created. Next you open the project properties and find the change platform part. You'll have to add 'x86' and then select it. Okay this isn't making sense so tomorrow or the next day I'll reconstruct what I did with pictures since I'm going to need to put this up on my blog anyway and I'll send you a copy when I get that done.

Looks like patience and persistence is paying off.

Joe

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Add stubbornness too! The refusal to let a computer win.

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The reason it is not working in AnyCPU is because the unmanaged code you are calling is compiled for x86.

To be honest the best solution here is to stay within managed code:

    Private Function ListComPorts() As List(Of String)
        ListComPorts = New List(Of String)

        For i = 1 To 100
            Dim IsPortGood As Boolean = True
            Using Port As New SerialPort("COM" & i)
                Try
                    Port.Open()
                Catch ex As System.IO.IOException
                    IsPortGood = False
                Finally
                    If IsPortGood Then ListComPorts.Add("COM" & i)
                End Try
            End Using
        Next
    End Function

This should list all available ports between 1 and 100, no matter if it is a virtual or physical port, and will work in any build configuration.

To have your solution working in VS Express, you need to edit the .sln solution file to add the "x86" build config manually.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The reason I started with unmanaged code is that the serial port class reads available ports from the registry and it is possible for ports to get stuck in the registry as open even though they aren't. Getting rid of them requires editing the registry and I'm not going to recommend anybody do that. My solution didn't have that problem but since it uses PInvoke with low level WinAPI calls, it is quite arcane and frankly it has been so long since I coded it that I'm not sure I could dump it without a lot of work. And up to the 64-bit problem the code worked so why fix it?

I guess the real solution is to look and see if anyone has written a better set of terminal tools for C# in the past few years and if so I may consider adopting that. Do you know of any such code?

I'll look at the concept of editing the .sln manually, that would be ideal and save $500 for folks wanting to continue with C# Express. I did note that after fixing the problem with SharpDevelop that if I reopenned the code in C# Express that the x86 fix remained.

And frankly I've decided to give Python a good look as soon as I can find the time. Building terminals with Python won't look as pretty but they will run on multiple platforms and as more folks doing this sort of work continue to move to Linux and the Mac, that might be a good idea.

Thanks for all the help,
Smiley

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Very few people still use the serial port, and for those that do the SerialPort class is usually plenty, so I doubt you will find any all in one terminal toolkit. The only problem with the class really is it's reliance on the registry. In all honesty it's not really a problem, if the registry is corrupt that really is the end user's problem, not yours. However using the code I posted above, you open every port and check if you catch an IOException. If you don't that means that the port can be opened. Pretty much the most reliable way to make sure.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hugoboss wrote:
Very few people still use the serial port,

I can't agree there.

We use a lot of serial ports, some "real" , and some USB based.
But Serial Comms isn't dead.

/Bingo

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I meant as a whole. Serial port is considered deprecated (or on its way to be). Most newer laptops no longer have an on-board DB9... Of course a forum full of hobby hardware developers will have lots of people using it, but as a user, name the last time you bought anything that connected to a serial port.

The fact is, most people should be using HID-USB instead of a serial port going forward.

Of course language support will be here for a while, hence the post above. Just don't expect Microsoft to update anything about it anytime soon, they will let it die just like they did with legacy parallel port access.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hugoboss wrote:
I meant as a whole. Serial port is considered deprecated (or on its way to be). Most newer laptops no longer have an on-board DB9...

Laptops? (At least) My last two desktop motherboards did not have a serial port! That goes back, hmm, I think to 2008, at least! :)

Can't remember if the motherboard I had before that had a serial port, all I know is I did have a serial port back in 2003-4-5-ish, I Programmed AT89C4051 through it!

- Brian

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The problem is that the USB is much more difficult to use even and especially if it is implemented on the microcontroller you are trying to use for other purposes. Dean's LUFA aside, it is just too complex for most folks to use AND you must pay a fortune for a VID is you are serious about it. The USB to RS232 Serial or to TTL is much easier for me to use and thus I keep using it. If I'm thinking hundreds of something them I'm still gonna try to implement communications via the UART. Thousands, maybe then the development time for real USB would be warranted. But I see the point of getting with the 21st century. Maybe next year.

Smiley

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I took a couple minutes and wrote a class for you that should easily replace your DevInfo and PortSettings classes. All you have to do is create a SerialPorts instance in your form, optionally setting default port settings, and it exposes a List(Of SerialPort) for all available ports, preconfigured with your settings. You can bind that list's items properties directly to your configuration controls without any extra code. It takes about 8 seconds when you create a SerialPorts instance to discover available COM ports.

Example usage:

    Dim PortsList As New SerialPorts With {.DefaultBaudRate = SerialPorts.BaudRates._115200,
                                           .DefaultDataBits = SerialPorts.DataBits._8,
                                           .DefaultHandshake = Handshake.None,
                                           .DefaultParity = Parity.None,
                                           .DefaultStopBits = StopBits.One,
                                           .DefaultReadBufferSize = 4096,
                                           .DefaultWriteBufferSize = 4096,
                                           .DefaultReadTimeout = 500,
                                           .DefaultWriteTimeout = 500}

    Dim WithEvents SelectedPort As SerialPort

    Private Sub ComboBox1_SelectedValueChanged(sender As ComboBox, e As EventArgs) Handles ComboBox1.SelectedValueChanged
        SelectedPort = PortsList.AvailablePorts.Select(Function(x)
                                                           Return If(x.PortName = sender.SelectedValue, x, Nothing)
                                                       End Function)
    End Sub

SerialPorts.vb:

Imports System
Imports System.IO.Ports
Imports System.Threading.Tasks

Public Class SerialPorts

    Public Enum BaudRates As Integer
        _75 = 75 : _110 = 110 : _134 = 134 : _150 = 150 : _300 = 300 : _600 = 600
        _1200 = 1200 : _1800 = 1800 : _2400 = 2400 : _4800 = 4800 : _7200 = 7200
        _9600 = 9600 : _14400 = 14400 : _19200 = 19200 : _38400 = 38400 : _57600 = 57600
        _115200 = 115200 : _128000 = 128000 : _230400 = 230400 : _256000 = 256000
        _460800 = 460800 : _512000 = 512000 : _921600 = 921600 : _1024000 = 1024000
        _1843200 = 1843200 : _2048000 = 2048000
    End Enum

    Public Enum DataBits As Integer
        _5 = 5
        _6 = 6
        _7 = 7
        _8 = 8
    End Enum

    Public Property AvailablePorts As List(Of SerialPort) = New List(Of SerialPort)

    Public Property DefaultBaudRate As BaudRates = BaudRates._9600
    Public Property DefaultParity As Parity = Parity.None
    Public Property DefaultStopBits As StopBits = StopBits.One
    Public Property DefaultDataBits As DataBits = DataBits._8
    Public Property DefaultHandshake As Handshake = Handshake.None

    Public Property DefaultReadTimeout As Integer = 500
    Public Property DefaultWriteTimeout As Integer = 500

    Public Property DefaultReadBufferSize As Integer = 2048
    Public Property DefaultWriteBufferSize As Integer = 2048

    Public Sub New()
        AvailablePorts = ListComPorts()
    End Sub

    Public Function IsPortGood(ByVal ComPort As String) As Boolean
        IsPortGood = True
        Using Port As New SerialPort(ComPort)
            Try
                Port.Open()
            Catch ex As System.IO.IOException
                IsPortGood = False
            End Try
        End Using
    End Function

    Private Function ListComPorts() As List(Of SerialPort)
        ListComPorts = New List(Of SerialPort)

        ' Parallel loop to fill the ports list
        Parallel.For(1, 257, Sub(i)
                                 ' Apply default port settings to discovered ports.
                                 If IsPortGood("COM" & i) Then
                                     ListComPorts.Add(New SerialPort("COM" & i, _
                                                                     DefaultBaudRate, _
                                                                     DefaultParity, _
                                                                     DefaultDataBits, _
                                                                     DefaultStopBits) _
                                                      With {.Handshake = DefaultHandshake, _
                                                            .ReadTimeout = DefaultReadTimeout, _
                                                            .WriteTimeout = DefaultWriteTimeout, _
                                                            .ReadBufferSize = DefaultReadBufferSize,
                                                            .WriteBufferSize = DefaultWriteBufferSize}
                                                      )

                                 End If
                             End Sub)

        ' Sort the list by port name
        Using Comparer As New NaturalOrderComparer
            ListComPorts.Sort(Function(x, y) Comparer.Compare(x.PortName, y.PortName))
        End Using

    End Function

End Class

NaturalOrderComparer.vb:

Imports System
Imports System.Collections.Generic
Imports System.Text.RegularExpressions

Public Class NaturalOrderComparer
    Inherits Comparer(Of String)
    Implements IDisposable

    Private Table As New Dictionary(Of String, String())

    Public Overrides Function Compare(x As String, y As String) As Integer
        If x = y Then Return 0

        Dim x1 As String() = Nothing
        Dim y1 As String() = Nothing

        If Not Table.TryGetValue(x, x1) Then
            x1 = Regex.Split(x.Replace(" ", ""), "([0-9]+)")
            Table.Add(x, x1)
        End If

        If Not Table.TryGetValue(y, y1) Then
            y1 = Regex.Split(y.Replace(" ", ""), "([0-9]+)")
            Table.Add(y, y1)
        End If

        Dim i As Integer = 0
        Do While i < x1.Length And i < y1.Length
            If Not x1(i) = y1(i) Then Return PartCompare(x1(i), y1(i))
            i = i + 1
        Loop

        If y1.Length > x1.Length Then
            Return 1
        ElseIf x1.Length > y1.Length Then
            Return -1
        Else
            Return 0
        End If
    End Function

    Private Shared Function PartCompare(Left As String, right As String) As Integer
        Dim x, y As Integer

        If Not Integer.TryParse(Left, x) _
        And Not Integer.TryParse(right, y) Then
            Return Left.CompareTo(right)
        Else
            Return x.CompareTo(y)
        End If
    End Function

#Region "IDisposable Support"
    Private disposedValue As Boolean

    Protected Overridable Sub Dispose(disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                Table.Clear()
            End If
            Table = Nothing
        End If
        Me.disposedValue = True
    End Sub

    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
#End Region

End Class
Last Edited: Sat. May 4, 2013 - 07:47 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Whoa and wow! Thanks hugoboss, I'll take some time to dig into this and see if I can't use it to simplify my terminal programs. I've been concerned all along that the PInvoke stuff was too arcane and a bit dangerous, but I haven't taken the time to try to fix it so your work will be a great incentive to upgrade and modernize my code.

I owe you one (at least one...)
Smiley

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It's no problem, let me know of any issues, I don't have any serial ports on here to test with... Note also that I use the Tasks.Parallel library to speed up the port enumeration a bit, so that requires .NET 4.0+. You can replace the Parallel.For loop by a normal For...Next, but that should about double the time it takes for enumeration (unless you rework the code to use pre-4.0 multithreading, with ThreadPool for example...).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Joe, did you look at this implementation:

http://msmvps.com/blogs/coad/archive/2005/03/23/39466.aspx

I used it for making my own simple terminal program

IIRC I use the C# express suite..

regards

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That link is one of the first things I looked at and IIRC I got some of the core ideas from it. The original problem is now fixed and hugoboss has provided a simpler approach to locating and opening the com ports so I'm good now.

Thanks,
Smiley

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just an update concerning this code. I recently was working on a project involving the serial port and tweaked my SerialPorts code a bit, it no longer requires the NaturalOrderComparer from above. It also only scans up to COM32, which honestly should cover 99.99999% of cases, and starts up much faster. If you instanciate and use the ports right away, make sure you check if .AvailablePorts is not null. Start up takes maybe 1-2 seconds, during which time .AvailablePorts is nothing. You can just "While _ports.AvailablePorts Is Nothing : End While" to wait it out.

 

SerialPorts.vb :

Imports System.Collections.Concurrent
Imports System.IO.Ports
Imports System.Threading.Tasks
Imports System.Threading

Public Class SerialPorts

    Public Enum BaudRates As Integer
        _75 = 75
        _110 = 110
        _134 = 134
        _150 = 150
        _300 = 300
        _600 = 600
        _1200 = 1200
        _1800 = 1800
        _2400 = 2400
        _4800 = 4800
        _7200 = 7200
        _9600 = 9600
        _14400 = 14400
        _19200 = 19200
        _38400 = 38400
        _57600 = 57600
        _115200 = 115200
        _128000 = 128000
        _230400 = 230400
        _256000 = 256000
        _460800 = 460800
        _512000 = 512000
        _921600 = 921600
        _1024000 = 1024000
        _1843200 = 1843200
        _2048000 = 2048000
    End Enum

    Public Enum DataBits As Integer
        _5 = 5
        _6 = 6
        _7 = 7
        _8 = 8
    End Enum

    Private _portsList As List(Of SerialPort) = Nothing

    Public ReadOnly Property AvailablePorts As List(Of SerialPort)
        Get
            Return _portsList
        End Get
    End Property

    Public Property DefaultBaudRate As BaudRates = BaudRates._9600

    Public Property DefaultParity As Parity = Parity.None

    Public Property DefaultStopBits As StopBits = StopBits.One

    Public Property DefaultDataBits As DataBits = DataBits._8

    Public Property DefaultHandshake As Handshake = Handshake.None

    Public Property DefaultReadTimeout As Integer = 500

    Public Property DefaultWriteTimeout As Integer = 500

    Public Property DefaultReadBufferSize As Integer = 2048

    Public Property DefaultWriteBufferSize As Integer = 2048

    Public Sub New()
        ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf ListComPorts))
    End Sub

    Public Function IsPortGood(ByVal comPort As String) As Boolean
        Using port As New SerialPort(comPort)
            Try
                port.Open()
                Return True
            Catch ex As Exception
                Return False
            End Try
        End Using
    End Function

    Private Sub ListComPorts()
        Dim lstPorts = New ConcurrentBag(Of SerialPort)

        Parallel.For(1, 32, Sub(i)
                                If IsPortGood("COM" & i) Then
                                    lstPorts.Add(New SerialPort("COM" & i, _
                                                                DefaultBaudRate, _
                                                                DefaultParity, _
                                                                DefaultDataBits, _
                                                                DefaultStopBits) _
                                                 With {.Handshake = DefaultHandshake, _
                                                       .ReadTimeout = DefaultReadTimeout, _
                                                       .WriteTimeout = DefaultWriteTimeout, _
                                                       .ReadBufferSize = DefaultReadBufferSize,
                                                       .WriteBufferSize = DefaultWriteBufferSize}
                                                 )
                                End If
                            End Sub)

        _portsList = lstPorts.OrderBy(Function(p) p.PortName.Replace("COM", "").Trim.PadLeft(2, "0")).ToList()
    End Sub

End Class

 

I also ran across a confirmed bug in the SerialPort class that has to do with how the object is disposed of internally and can cause in some situations an non-debuggable internal exception. There is a workaround in the form of a wrapper floating around, but I wasn't satisfied with having to modify all my existing projects to use the wrapper object, so I instead converted it to an extension method for the SerialPort class. To use it simply include it in your project and call .SafeDisconnect() instead of .Close() on your SerialPort instances.

 

SerialPortExtensions.vb :

Imports System.IO
Imports System.IO.Ports
Imports System.Reflection
Imports System.Runtime.CompilerServices
Imports System.Threading

Module SerialPortExtensions

    <Extension()>
    Public Sub SafeDisconnect(ByRef port As SerialPort)
        GC.SuppressFinalize(port)
        GC.SuppressFinalize(port.BaseStream)

        ShutdownEventLoopHandler(port.BaseStream)

        Try
            port.BaseStream.Close()
            port.Close()
        Catch ex As Exception
        End Try
    End Sub

    Private Sub ShutdownEventLoopHandler(ByRef internalStream As Stream)
        Try
            Dim erField = internalStream.GetType().GetField("eventRunner", BindingFlags.NonPublic Or BindingFlags.Instance)
            If erField IsNot Nothing Then
                Dim eventRunner = erField.GetValue(internalStream)
                Dim erType = eventRunner.GetType()

                Dim endEventLoopFieldInfo = erType.GetField("endEventLoop", BindingFlags.Instance Or BindingFlags.NonPublic)
                Dim eventLoopEndedSignalFieldInfo = erType.GetField("eventLoopEndedSignal", BindingFlags.Instance Or BindingFlags.NonPublic)
                Dim waitCommEventWaitHandleFieldInfo = erType.GetField("waitCommEventWaitHandle", BindingFlags.Instance Or BindingFlags.NonPublic)

                If Not (endEventLoopFieldInfo IsNot Nothing And _
                        eventLoopEndedSignalFieldInfo IsNot Nothing And _
                        waitCommEventWaitHandleFieldInfo IsNot Nothing) Then

                    Dim eventLoopEndedWaitHandle = CType(eventLoopEndedSignalFieldInfo.GetValue(eventRunner), WaitHandle)
                    Dim waitCommEventWaitHandle = CType(waitCommEventWaitHandleFieldInfo.GetValue(eventRunner), ManualResetEvent)

                    endEventLoopFieldInfo.SetValue(eventRunner, True)

                    Do
                        waitCommEventWaitHandle.Set()
                    Loop While Not eventLoopEndedWaitHandle.WaitOne((2000))
                End If
            End If
        Catch ex As Exception
        End Try
    End Sub

End Module

 

Last Edited: Sun. Jan 31, 2016 - 06:03 AM