USB support in Linux

Linux specific questions.
Dinosaur
Posts: 1478
Joined: Jul 24, 2005 1:13
Location: Hervey Bay (.au)

USB support in Linux

Post by Dinosaur »

Hi All

The aim of converting to Linux is to have a GUI system for some of my machines
whilst I am in the USA for a couple of years.

Part of this is having USB support for talking to Advantech Adam Industrial controllers.
I have two options.
1. I can use a Adam-4561 usb to Rs485 converter which has an instrinsic Prolific controller.
This allows me to open a COM port and send command strings that convert to RS485 and thus end up
getting to various other RS485 devices.

2. I can use Adam devices that directly control I/O, but have not investigated what the intrinsic controller is. (if any)

Reading hundreds of google pages on the subject, I see that the ports appear to be addressed as /dev/ttySn or /dev/ttyUSBn
Some versions of Linux are different then others.
Concluding that I can't just do the Dos/Windows thing and Open Com "COMn:38400,n,8,1,cs0,ds0,cd0,rs" For Binary As #CP
I tried to open a port using the samples I have seen.
Open Com "/dev/ttySn........
Open Com "ttyUSBn......
and tried these from 1 to 15, but none would open when I had my device connected.

Using usb port statement lsusb I get detail on all ports, but I can't see how that relates to enumerating the com port.
dinosaur@jvp ~ $ lsusb
Bus 001 Device 002: ID 8087:8000 Intel Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 003 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 002 Device 005: ID 04f2:b3f6 Chicony Electronics Co., Ltd
Bus 002 Device 004: ID 04f3:0261 Elan Microelectronics Corp.
Bus 002 Device 006: ID 0489:e04e Foxconn / Hon Hai
Bus 002 Device 002: ID 046d:c52f Logitech, Inc. Unifying Receiver
Bus 002 Device 008: ID 10c4:ea60 Cygnal Integrated Products, Inc. CP210x UART Bridge / myAVR mySmartUSB light
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Assuming I recognise which Bus device is my Adam module (which I don't) How does this relate to setting up and opening a port ??

Disconnecting the USB Adam module and connecting a usb to RS232 converter changes the lsusb result
dinosaur@jvp ~ $ lsusb
Bus 001 Device 002: ID 8087:8000 Intel Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 003 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 002 Device 005: ID 04f2:b3f6 Chicony Electronics Co., Ltd
Bus 002 Device 004: ID 04f3:0261 Elan Microelectronics Corp.
Bus 002 Device 006: ID 0489:e04e Foxconn / Hon Hai
Bus 002 Device 002: ID 046d:c52f Logitech, Inc. Unifying Receiver
Bus 002 Device 009: ID 067b:2303 Prolific Technology, Inc. PL2303 Serial Port
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
so at least I can recognise the converter Bus002 Device 009.
By process of elimination I can see that the "Bus 002 Device 008: ID 10c4:ea60 Cygnal Integrated Products" must have been the
Adam device.
But still no idea as to how I can open that device.
Typing in "Prolific" or "PL2303" in the Software Manager doesn't give any result to show if a device driver is loaded
for that device.

Would really appreciate if someone could inform me of the proper procedure to
1. Identify the Port to be used.
2. How to convert the port information to a usable "Open Port" statement.
3. Allow me to identify if a device driver is installed to handle the device.

Regards
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: USB support in Linux

Post by caseih »

Dinosaur wrote:Reading hundreds of google pages on the subject, I see that the ports appear to be addressed as /dev/ttySn or /dev/ttyUSBn
Some versions of Linux are different then others.
Concluding that I can't just do the Dos/Windows thing and Open Com "COMn:38400,n,8,1,cs0,ds0,cd0,rs" For Binary As #CP
I tried to open a port using the samples I have seen.
Open Com "/dev/ttySn........
Open Com "ttyUSBn......
and tried these from 1 to 15, but none would open when I had my device connected.

Using usb port statement lsusb I get detail on all ports, but I can't see how that relates to enumerating the com port.

Assuming I recognise which Bus device is my Adam module (which I don't) How does this relate to setting up and opening a port ??
Enumerating devices on the usb bus does not automatically relate to opening a port (emulated serial). The serial port is a function of the driver associated with the usb device, which is set up by the udev daemon. Finding a list of serial ports on a system isn't so trivial either. You can look in /sys/class/tty and there is a list of ttys, some of which are serial ports. I think most programs just hard code their search path to be /dev/ttyS* or /dev/ttyUSB*.

The best way to work with your device in my opinion, is to set a custom udev rule to create a specific symlink in /etc that you can always guarantee is your device's virtual com port. Here's a rule I use for a special GCode stepper motor driver I use. This particular rule is called /etc/udev/rules.d/70-rtstepper.rules:

Code: Select all

SUBSYSTEM=="usb",ENV{DEVTYPE}=="usb_device",ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="ff45",MODE="0666",GROUP="wheel",SYMLINK+="rtstepper"
Whenever I plug in the device, I get a symlink /dev/rtstepper that points to the actual /dev/ttyUSB# node. This way the software can always find it by pointint to that.

If you did something similar for your device, I think you'd at least have a consistent device path anyway. You would of course put in your own vendor id and product id. Also if your userid is in the wheel group, you can make your mode more restrictive (say 0660).

This still leaves you with the problem of how to properly open a serial port in Linux using FreeBasic. According to the wiki (http://www.freebasic.net/wiki/wikka.php ... yPgOpenCom), the syntax you're looking for is something like:

Code: Select all

open com "/dev/mydevice:38400,n,8,1,cs0,ds0,cd0,rs" For Binary As #CP
Where /dev/mydevice could be /dev/ttyS0 for COM1, or /dev/ttyUSB0 for the first USB serial port, or /dev/<custom> for a udev-created port.

In thinking about this, on Linux what I'd do for the UI is present the user with a list of serial ports you find using hard-coded paths (/dev/ttyS*, /dev/ttyUSB*) but let the user specify his own device path. That way you have your bases covered.
Dinosaur
Posts: 1478
Joined: Jul 24, 2005 1:13
Location: Hervey Bay (.au)

Re: USB support in Linux

Post by Dinosaur »

Hi All

Gee caseih, I am glad I didn't ask a difficult question. :)

Remember I am a novice with Linux, so for the moment I want to take the route with least resistance.
First I had to install symlinks, but that was painless.
Then I typed in the command:
symlinks -v /sys/class/tty
and got (abbreviated)
relative: /sys/class/tty/ttyS0 -> ../../devices/platform/serial8250/tty/ttyS0
relative: /sys/class/tty/ttyS1 -> ../../devices/platform/serial8250/tty/ttyS1
relative: /sys/class/tty/ttyS2 -> ../../devices/platform/serial8250/tty/ttyS2
relative: /sys/class/tty/ttyS3 -> ../../devices/platform/serial8250/tty/ttyS3
relative: /sys/class/tty/ttyS4 -> ../../devices/platform/serial8250/tty/ttyS4
relative: /sys/class/tty/ttyS5 -> ../../devices/platform/serial8250/tty/ttyS5
relative: /sys/class/tty/ttyS6 -> ../../devices/platform/serial8250/tty/ttyS6
relative: /sys/class/tty/ttyS7 -> ../../devices/platform/serial8250/tty/ttyS7
relative: /sys/class/tty/ttyS8 -> ../../devices/platform/serial8250/tty/ttyS8
relative: /sys/class/tty/ttyS9 -> ../../devices/platform/serial8250/tty/ttyS9
up to ttyS31. But what does this screen actually tell me ?

From that information, am I to believe that I could poll these ports to see which one responds ?
If so, is my statement to be:
open com "/sys/class/tty/ttyS#:38400,n,8,1,cs0,ds0,cd0,rs" For Binary As #CP
or something else ?


EDIT:
When I plugged my Adam module in the addition was:
relative: /sys/class/tty/ttyUSB0 -> ../../devices/pci0000:00/0000:00:14.0/usb2/2-1/2-1:1.0/ttyUSB0/tty/ttyUSB0
So, will try to open that device in different ways.

My code for opening the port:

Code: Select all

        Open Com "/sys/class/tty/ttyUSB0:38400,n,8,1,cs0,ds0,cd0,rs" For Binary As #CP
        If ERR > 0 THEN
                ErrControl.Errer = 24
                ErrControl.Routine = "AdamInit"
                ErrControl.Message = "Couldn't open COM1:"
                ErrControl.ErrFile = "Com1:" 
                .InitOK = 0
                Close #CP
                Errer_Status                       
                Exit Sub
            Else
                .Handle = CP
                If PUT (#CP, , "$012" & CHR(&H0D)) Then
                    ErrControl.Errer   = 57
                    ErrControl.Routine = "Adam4055Init"
                    ErrControl.Message = "Can't write to COM1:"
                    ErrControl.ErrFile = "Com1:" 
                    .InitOK = 0
                    Close #CP
                    Errer_Status                       
                    Exit Sub
                EndIf
        END If
The various combinations I have tried always give me "Couldn't open COM1:"
Regards
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: USB support in Linux

Post by caseih »

The files in /sys are informational only. I don't think the actual device interface file is stored there. You'll want to open the proper /dev/ttyUSB# file instead.

Like I said the best way to make things consistent is to have udev make you a specific file in /dev/, say /dev/adam, that you can open with the open com syntax.

It's likely that you don't have permission to open the serial port as a normal user. You may have to alter your user permissions. Quick and dirty just run "sudo chmod a+rw /dev/ttyUSB0" (or whatever one is associated with the adam). Or see what group ownership the node has ("ls -l /dev/ttyUSB0") and then add your user to that group. By default on my Linux machine, nodes in /dev associated with serial ports are owned by root:dialout. So if I add my user to the dialout group (and log out and back in) I can open the serial port as my own, non-root, user. Not sure what distro you are using but there may be a graphical users and passwords tool. If not I can help you do it on the command line.

If all this work you can get udev to make the node with any permissions you need. The example conf file I posted gives my rtstepper permissions so anyone can read and write it. You can do the same to any usb serial device once you know the vendor and product ids.
Last edited by caseih on Aug 06, 2015 23:58, edited 1 time in total.
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: USB support in Linux

Post by caseih »

I discovered that USB serial devices are also symlinked into /dev/serial/ into more human readable names that should be consistent even if the underlying name like ttyUSB0 is changed (say to ttyUSB1). I'm not at all sure why the physical serial ports are not listed here as well. But at least the physical ports are consistent: COM1 is always /dev/ttyS0, etc.

Just for your information. /dev/tty# refers to consoles the Linux kernel can attach things to. For example the first textmode screen which you can get to with Ctrl-Alt-F1 is vt1, which is attached to /dev/tty0. In general they are not serial ports.

I just tried a short test on my machine and it works:

Code: Select all

Open Com "/dev/ttyUSB0:38400,n,8,1,cs0,ds0,cd0,rs" For Binary As #1

if err>0 then
	print err
end if
One way to determine which entries in /dev are serial ports is to run this command:

Code: Select all

cat /proc/tty/drivers | grep serial
which outputs:

Code: Select all

usbserial            /dev/ttyUSB   188 0-511 serial
serial               /dev/ttyS       4 64-95 serial
So you can at least see what the serial ports' device nodes look like. Another common device node for a usb serial port is sometimes /dev/ttyACM#. One of my arduinos shows up with that one.

Just FYI, ttyUSB0 is not COM1. COM1 would be /dev/ttyS0. Other than the built-in serial ports which are often labeled as such on the computer's exterior, there's no real use of the COM# nomenclature on Linux at all. Since serial devices are often added dynamically, we just refer to them by their node in /dev, and we can use /dev/serial/by_id or /dev/serial/by_path to get some consistency.

Hope that's as clear as mud.
Dinosaur
Posts: 1478
Joined: Jul 24, 2005 1:13
Location: Hervey Bay (.au)

Re: USB support in Linux

Post by Dinosaur »

Hi All

Firstly caseih, thank you for taking the time to help a newbie on this subject.
I really appreciate it.

I have progressed with the information you provided.
I made the changes by adding the line in /etc/udev/rules.d/
However I have a question about that.
What do the values "Mode" & "Group" mean.
I simply copied them as you had them, and after re-booting I was actually able to open the port.
Not able to get a command / reply yet , but need to understand that I have done all to get it right.


EDIT:

Code: Select all

SUBSYSTEM=="usb",ENV{DEVTYPE}=="usb_device",ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60",MODE="0666",GROUP="wheel",SYMLINK+="Adam4561"
From using lsusb, I get (abbreviated)
ID 10c4:ea60 Cygnal Integrated Products,
Am I to assume that the 10c4 is the idVendor and the ea60 is the idProduct ?
Regards
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: USB support in Linux

Post by caseih »

You're very welcome.

Yes you are reading the vendor id and product id correctly. Does the Adam symlink show up in /dev when you plug it in? If so, then you got it.

So to answer your questions, the MODE refers to permissions on accessing the device node entry in /dev. It's in standard unix octal numbering, but 0666 means read and write for the owner (root), the group (wheel), and everyone else. This numbering is the same numbering used by the chmod command.

The wheel group is an old unix standard group that gives users a few administrative privileges. Some things like shutdown and reboot from the command line require you to be in the wheel group. Depending on your distro, you may be in the wheel group already. Note that with 0666 as the mode on the file, it doesn't matter what group you're in, so the GROUP option probably could be left out entirely.

For more information on unix permissions, I'm sure there are lots of web pages. Here's a handy calculator for those unfamiliar with how to come up with the number: http://permissions-calculator.org/

When you change a udev rule, you don't have to reboot. You can run this command:
sudo udevadm control --reload-rules
Dinosaur
Posts: 1478
Joined: Jul 24, 2005 1:13
Location: Hervey Bay (.au)

Re: USB support in Linux

Post by Dinosaur »

Hi All

I still have one problem.
I can Open, Send , but not receive.
What are the chances that Linux does something like adding a terminator char to the Tx string ?
That would make my command bad, and I wouldn't get a reply.
Below my AdamInit code,

Code: Select all

Sub AdamInit()
    '-----------------------------------------------------------
    'Open Com Port and Test Adam controller.if Err Exit Sub
    'Send test Tx to Adam-4055
    'Check the Receive String.
    '-----------------------------------------------------------
    Dim As Integer CP, LS,ef
    Dim InStrings as ZString * 12
    ef = FreeFile
    Open "AdamStr.txt" for append as #ef
    With Adam485
        CP = FreeFile
        Open Com "/dev/ttyUSB0:38400,n,8,1,cs0,ds0,cd0,rs" For Binary As #CP
        If ERR > 0 THEN
                ErrControl.Errer = 24
                ErrControl.Routine = "AdamInit"
                ErrControl.Message = "Couldn't open USB0:"
                ErrControl.ErrFile = "USB0:" 
                .InitOK = 0
                Close #CP
                Errer_Status                       
                Exit Sub
            Else
                .Handle = CP
                If PUT (#CP, , "$012" & CHR(&H0D)) Then
                    ErrControl.Errer   = 57
                    ErrControl.Routine = "Adam4055Init"
                    ErrControl.Message = "Can't write to USB0:"
                    ErrControl.ErrFile = "USB0:" 
                    .InitOK = 0
                    Close #CP
                    Errer_Status                       
                    Exit Sub
                EndIf
        END If
        TimeShow
        .StartTime = Times.mSec
        .RxStr = ""
        Do	'Extra long time for the Linux test
    	    TimeShow
            If Times.mSec - .StartTime > 550 Then Exit do
        Loop
        .RxStr = Input(LOC(.Handle),#.Handle)
        InStrings = .RxStr
        Write #ef, Instrings, len(InStrings)	'Temp error file gets "",0
        close #ef
        'All OK up to here.
        If Instr(.RxStr,"!") > 0 Then
                LS = Len(.RxStr)
                .ErrStr = "&H" + Mid(.RxStr,2,LS-1)
                .InitOK = 1
            Else
                ErrControl.Errer   = 81
                ErrControl.Routine = "AdamInit"
                ErrControl.Message = "Bad data from USB0"
                ErrControl.ErrFile = "USB0"
                .InitOK = 0
                Errer_Status         
                Exit Sub
        EndIf
        .Flag = 0
    End With    
End Sub
Replacing /dev/ttyUSB0 with COM9 and running it in Windows works perfectly.
Any ideas really appreciated.

Regards
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: USB support in Linux

Post by caseih »

Yes a lot of serial protocols probably use both a CR and LF for end of line marking. By default, Linux and Unix often only use LF. You may need to output a CHR(13) at the end of each line, after which the PRINT statement would add a LF. Just a guess though.

You may try installing and running a serial terminal program like minicom to see if you can interact manually with it:
minicom -D /dev/ttyUSB0 -b 38400 -o

EDIT. Maybe I'm barking up the wrong tree. Looks like a byte protocol, not a line protocol. So maybe it's a matter of flushing the output buffers somehow. Linux could be buffering differently than Windows.
Dinosaur
Posts: 1478
Joined: Jul 24, 2005 1:13
Location: Hervey Bay (.au)

Re: USB support in Linux

Post by Dinosaur »

Hi All

caseih, the minicom program works.
Although it is a very basic Terminal program. It doesn't show typed entries, only received char and then always on the same
line leaving previous char's in place.
Anyhow, it proved that the link works.

So,either FB for Linux has some oddity or the char ZString is being corrupted by Linux and minicom has adapted for it.
Note that I am not using any instances of String * n .

I guess now the hard slog of finding why.
Will try stripping out the blanks before Tx.

Many thanks for your help

EDIT:
It works ???
No idea why, I installed minicom and GHex to look at the commands, and it started to work.
Did not modify my code.???
Will have to go back and perform an autopsy.

Regards.
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: USB support in Linux

Post by caseih »

It's possible minicom did something to the serial port settings. Buffering, flow control, or something. Does the FB program work when you unplug and plug back in the device after running minicom? If not, verify again that running minicom and then the FB program makes things work. If that's the case, then we have to figure out what minicom is doing to the serial port that FB needs to do also.
Dinosaur
Posts: 1478
Joined: Jul 24, 2005 1:13
Location: Hervey Bay (.au)

Re: USB support in Linux

Post by Dinosaur »

Hi All

caseih, the assumption is correct.
minicom is doing something to the port.
This morning before going to work I tried to run and the first error was "Couldn't open USB0:"
Did "sudo chmod a+rw /dev/ttyUSB0" and the next error was "Bad data from USB0" (no reply)
Fired up minicom and did 1 command (same as my init routine) "$012" and got a valid reply.
Quit minicom and ran my program and this time all OK.

As I said, doing an autopsy this weekend and will let you know.

Regards
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: USB support in Linux

Post by caseih »

When things are not working, run this command:

stty < /dev/ttyUSB0

Then after running minicom, do that command again and note the differences. If you can see something there, then we can try to figure out what flags, ioctls, etc, and see if we can figure out how to do it from FB. Could be something you can add to the open com statement.
Dinosaur
Posts: 1478
Joined: Jul 24, 2005 1:13
Location: Hervey Bay (.au)

Re: USB support in Linux

Post by Dinosaur »

Hi All

caseih, the stty command revealed one problem straight away.
speed 115200
-brkint -imaxbel
I open the port at 38400, and it opens, but I dont get a reply.
Run minicom and it sets the baud to 38400
Quit minicom, and run my program, and it works.
Run stty
dinosaur@jvp ~ $ stty < /dev/ttyUSB0
speed 38400 baud; line = 0;
min = 1; time = 5;
ignbrk -brkint -icrnl -imaxbel
-opost -onlcr
-isig -icanon -iexten -echo -echoe -echok -echoctl -echoke
Do I have to tell Linux to go to 38400 before I try to open the port at that speed.??
Run out of time for today.

Regards
Dinosaur
Posts: 1478
Joined: Jul 24, 2005 1:13
Location: Hervey Bay (.au)

Re: USB support in Linux

Post by Dinosaur »

Hi All

Problem is now identified as Baud rate.
When opening the port with FB program line:

Code: Select all

        Open Com "/dev/ttyUSB0:38400,n,8,1,cs0,ds0,cd0,rs" For Binary As #CP
it opens the port at the default Baud rate set by the Linux system.
On my system, it happens to be 115200.

So, by simply changing the baud rate on my Adam module, the system works immediately after power up.
If I want some other Baud rate, then a program like minicom sets the baud rate to the desired rate,
and when you quit from it, my program works.

So, to me that sounds like:
1. a bug in FB Linux where it is not setting the baud rate with the Open Com statement.
or
2. a unusual need by Linux Mint in the way the Baud rate is set.

In Dos, you could use a Mode statement to set the baud rate.
Is there such a statement in Linux ?

Regards
Post Reply