My development target is a Linux computer that has two physical serial ports located at /dev/ttyS0 and /dev/ttyS1. I also expect /dev/ttyS2 and /dev/ttyS3 to be defined.
Using stty -f /dev/ttyS0 and S1 reports the configuration of the two serial ports and reports something menaing "doesn't exist" for S2 and S3.
The hardware designers are talking about offering USB to Serial ports built onto the main board. They'll be DB9 connectors on the outside and just circuitry - no USB connectors on the inside. The number of USB-to-serial connections is not guaranteed and I know enough to design for "many" instead of one.
So, in setting up my port server daemon, I need to be able to determine which ttyS's and which ttyUSB's are "real" and which aren't. Will there ever be placeholdeer ttyUSB's? What if one were to be "unplugged" (say it was, indeed, a real USB coupler on the inside of the PC)?
Is there a better approach than popen()ing stty and examining its output to determine the status of the serial ports? Is there a C API for stty?
Thanks!
The "C-API" which stty uses is tcsetattr(3) and tcgetattr(3).
For finding TTYs without opening the device you may look at this question:
How to find all serial devices (ttyS, ttyUSB, ..) on Linux without opening them?
Related
I'm quite new to programming at linux and its file-based communication.
I need to create a virtual modem (or modem emulator) at linux machine. The idea is that the software module that sends commands to hardware modem on an FPGA,
At FPGA:
SoftwareModule <= ttyACM => HardwareModem
What I need to achieve at my computer:
SoftwareModule <=> MyModemEmulator acting like a fake UART
Purpose is that the software module can be tested on a linux machine where I have a fake software modem UART(?) port. So the software module sends the modem commands and my fake modem module catches and responds accordingly. So my module will be actually acting like a hardware modem.
What could be the steps I need to take for that? I'm quite new to working with serial ports and don't have deep knowledge of linux or hardware stuff.
I have come across 'socat' but I'm not sure if that can really serve the purpose.
So far I have only learned how to create a basic file system with FUSE (as it was suggested by someone), but I'm not sure how can I use it for my purpose. I'm not looking for a proprietary solution, and not looking for windows based solution either.
Please guide me to the right directions.
Thank you !
Creating a Fake Serial Port to Emulate Modem
What you refer to as a "serial port" in Linux is actually a serial terminal with many software layers.
Study Linux serial drivers, and the termios man page for salient functions that need to be emulated.
And you have not even considered how to factor in the USB component of the communication path.
At FPGA:
SoftwareModule <= ttyACM => HardwareModem
...
My computer with ubuntu does not have ttyACM
A /dev/ttyACMx device node is only created when a USB serial gadget is connected to the host.
So it's not surprising that you cannot find such a device node.
What I need to achieve at my computer:
SoftwareModule <=> MyModemEmulator acting like a fake UART
You have stated the issue poorly, since you (misguidedly) think that a "fake UART" (integrated with your "MyModemEmulator") is the appropriate solution.
Do not try to emulate both a serial terminal and an external modem on the Ubuntu host, since you are "quite new to programming at linux and serial ports" and the task of accurately emulating a serial terminal is risky and expensive.
What your goal should be is:
SoftwareModule <= ? => MyModemEmulator
and the question is "what is needed in the middle to interface these two units?".
IOW you have posted an XY problem.
There are a plethora of SBCs (single board computer) that have a USB gadget port and can be configured as a USB serial gadget that uses CDC ACM.
Since the actual "hardware modem on an FPGA" will use a USB CDC ACM connection, you should consider using an actual /dev/ttyACMx serial terminal, and emulating just the external device ("hardware modem") with a SBC.
In other words, instead of trying to achieve:
SoftwareModule <=> MyModemEmulator + fake USB serial terminal
it should be much easier to use existing interfaces and implement:
SoftwareModule <= USB => emulated HardwareModem
with a SBC running your Linux application for modem emulation using /dev/ttyGS0 (a USB serial terminal on the gadget end).
By using an actual USB CDC ACM connection and not implementing the "fake USB serial terminal", this approach eliminates an entire layer of SW+HW emulation and its possible false test results.
Addendum
If the use and/or cost of embedded Linux on a SBC concerns you, then there is an alternative scheme to emulate the "hardware modem" on your Ubuntu PC host instead of the SBC using a USB-to-RS232-to-USB connection.
Acquire a pair (i.e. quantity 2) of USB-to-RS232 adapters and a (very short) null-modem cable.
Connect the DB-9 ends of the adapters to the null-modem cable to make a single cable with both ends having a USB male type-A connector.
Plug one adapter into the PC to create the /dev/ttyUSB0 device node. Treat this as the equivalent to /dev/ttyACM0 for your SoftwareModule.
Plug the other adapter into the PC to create the /dev/ttyUSB1 device node. Treat this as the equivalent to /dev/ttyGS0 for your emulated "hardware modem".
Develop, execute, and debug your emulated "hardware modem" on the Ubuntu PC host (without the unnecessary task of "creating a fake serial port").
I have a device that acts as a serial port connected over USB. I have a class that interfaces with the device through a QSerialPort. Soon I will have multiple such devices and the program will need to reliably distinguish them to assign configured values to instances of the class.
Qt identifies serial devices by the portName field of the QSerialPortInfo helper object. This name is derived from the /dev/ path (e.g. /dev/tty.foo42 is port name "foo42") and this path does not remain associated with a particular device over reboots or deployment to a different machine. However, through libusb I can get a serial number, which is stable across reboots and different machines.
What I am still missing is a way to match the serial number, which can be identified in advance and recorded in a configuration file, to a port name, which can be used to open a QSerialPort. Currently deploying to MacOS, but in the future we may wish to deploy to Linux.
Searching existing questions mostly turns up ways to configure a Linux system to always assign a particular dev path to a particular device. A solution that involves configuring the operating system is acceptable, but something the application can do without that is preferable. A Mac specific solution is acceptable, but something that also works on Linux is preferable.
The documentation for QSerialPortInfo::serialNumber() (new in Qt 5.3) sounds like what you're after:
QString QSerialPortInfo::serialNumber() const
Returns the serial number string of the serial port, if available;
otherwise returns an empty string.
Note: The serial number may include letters.
Please let me know if there is any API, system call, function (in Linux) which I can use my C program to detect a COM port dynamically, i.e., whenever a USB modem dongle is inserted in the port I will be able to detect that COM port using the API, or system call, or function in my C program.
Depending on your modem, USB serial port device may show up as /dev/ttyUSBn or /dev/ttyACMn, where n is some number starting from 0.
You can configure udev rule to automatically react on device being inserted or removed.
If you want to do it on your own in C, you need to make use of netlink(7) sockets. If you don't want to fiddle with them, probably easier approach is to simply use utility udevadm provided by udev package (udevadm is using netlink internally), something like that:
udevadm monitor --kernel
If you are going to use it in your C program, simply call it in pipe like this:
stdbuf -o0 udevadm monitor --kernel
and setup select loop, so it can react immediately. Wrapping in stdbuf is necessary to avoid buffering provided by udevadm.
In Linux the serial ports aren't called COMx. They (real serial ports) are generally named /dev/ttySx where x is a number, starting at 0 for COM1, 1 for COM2, etc.
If you want a list, you should look in /dev for ttyS devices.
Here is a very detailed page for serial port programming on Linux:
Serial Programming HOWTO
Serial HOWTO
Finally, note that a quick Google search goes a long way for general questions like this!
Hello i have an application built some times ago in C++.
It is used to control an appliance via serial port.
I remember the guy that developed it saying that his software is directly accessing the serial port (directly accessing the memory).
Since PCs with serial ports are becoming rare these days, would the software still directly access the serial port if i used a PCI extension serial port?
Thanks
That depends a bit on how much backward-compatible driver support your PCIe serial port has.
If it provides direct I/O-space mapping of a (possibly virtual) 16550 UART's registers, you will need to change the "base address" in the software but then it might work. If the drivers do not, then it's not going to work.
The first four standard serial ports have the following base addresses and interrupts associated with them:
| base IRQ
-----------------
COM1 | 0x3f8 IRQ4
COM2 | 0x2f8 IRQ3
COM3 | 0x3e8 n/a
COM4 | 0x2e8 n/a
The software should probably be rewritten to use more high-level access to the port.
I believe that the vast majority of local bus serial port cards emulate a 16x50 RS-232 UART. Unless you intend to use some special card, such as those expensive multiport cards used for managing modem banks, it would probably be fine.
USB/RS-232 converters are a different story altogether - in general they will not work with software that accesses the serial port directly, as their driver only provides access via the OS serial port subsystem. Even if their driver somehow manages to emulate a proper local bus UART, those converters often have different behavior w.r.t. signal timing that might lead to issues with software that does unusual things with the serial port. For example, I have had issues with attaching IR remote control receivers to some USB/RS-232 converters. Using a converter that supports USB 2.0 helps somewhat, but it is still far from the real thing.
You should also keep in mind that if your application is designed for an older OS, newer versions of that operating system might not allow direct access to serial ports anymore.
If all else fails, you might still be able to improve the situation by using a virtual machine. For example, VirtualBox allows the guest OS to access the host serial ports, emulating a 16550A UART. This might allow you to work around a driver or an OS that does not support or allow direct access to a serial port.
I searched around i found some PCI cards that map their serial ports to the memory.
I will try one of those.
Thank you all.
I have another solution.
PCs are coming with mostly usb ports.
so you can use any usb to serial port converter. it is very cheap and works fine.
Is it possible to read/write from/to a specific USB port, avoiding all that USB handshaking stuff?
What I want to do is communicate with a microcontroller, for example, that doesn't have a USB driver on board via USB. I want my C++ application to be able to send data via a specific USB port and then to receive data from that same USB port.
Basically what I want to be able to do is treat that USB port like a serial port. Is this possible? Is there a workaround I can use?
Thanks in advance.
PS: I know this isn't the best way to go about communication with a uC, but let's assume, for some reason, I have to do it this way.
Edit: BTW I'm using Windows 7
The usual solution is to use an FTDI USB-to-serial chip, such as the FT232R, on your microcontroller board. Then, as far as your MCU is concerned, it's talking to a serial port, and on the host machine you just have to have the right drivers.
On my Mac, the FTDI chip shows up as a serial port at /dev/tty.usbmodem____, where ____ is some persistent unique ID assigned by the Mac on first detection. Unplugging and replugging, even weeks later, gets the same number, but it's a different number on a different Mac.
On Windows, it shows up as a new COM port if you have the drivers installed, IIRC. On Linux, it shows up as /dev/ttyUSB_ where _ is a serial number starting at 0, if you have FTDI serial driver support enabled in the kernel. This can get tricky if you plug in more than one FTDI chip.
If your microcontroller has a built-in USB port, then you need to find the software for it to identify itself as a standard CDC (Communication Device Class) serial port device (standard documentation available). Most OSs have support for this standard USB device class.
Use one of the USB to serial port adapters. The USB port will look just like a serial port to your C++ program.
In general you can do a close approximation of this using the HID interface: drivers are built in, and you can send feature reports in both directions. It isn't quite serial port simplicity (since it is packets, as opposed to a continuous byte stream) but hidapi makes it really simple and cross-platform.