Porting DOS program to linux to read/write serial port over usb - linux

I have old DOS program which works with serial port. And I need to port it to linux. I've connected my serial device to linux via USB (using rs232 cable). It appears as /dev/ttyUSB0.
Can I use functions inb, outb (instead of DOS equivalent inp, outp) for reading or writing in device from my code? (inb and outb special function for lowlevel reading-writing bytes to specific port address). I don't understand how to determine proper port number.
Maybe there is another approach - for example open file '/dev/ttyUSB0'. But in this case I have a problem reading device registers such as modem control register (MCR) or line status register (LSR).

You can use inb/outb or mmap (eg. devmem, depends on architecture) for onboard standard serial port but it is not recommended in userland. You need root priviledges, you can cause conflict with kernel's driver and you have to be sure that your hardware (eg. 16C550) is full compatible with your code.
To trigger your program when serial port added can use udev rule or old hotplug. To determine port in case of USB serial port converter you can use USB bus id and port id. You can check the numbers via lsusb -t command.
serial port configuration: http://linux.die.net/man/3/termios
check if there are received data (LSR): select()
data inb / outb -> read() / write()
MSR (DCD, RI, CTS) / MCR (DTR, RTS if hardware flow control disabled) -> ioctl() or tty_ioctl
You can learn from picocom source code
Possible problem for realtime application: delays caused by USB bus polling and process/thread switching.

Related

RS-422 to usb convertor does work but Serial Com port does not

I am trying to get my com port working with my device and am having trouble doing so. I have already tested the serial output from my device using a RS-422 to USB convertor and data was being shown on my screen terminal flawlessly thorough /dev/ttyUSB0. My goal is to forgo the convertor and connect directly to my com port, /dev/ttyS0. The problem is when using screen to view my data on /dev/ttyS0 all I get is nonsensical data.
My device uses a slightly faster baud rate of 230400 so I though that might be an issue so I contacted the manufacturer but they stated the com port is capable of high speeds with an RS-422 protocol. I then followed up by doing getting a loopback cable and seeing if Tx matches Rx and it does. Ultimately, I am very confused as to why the RS-422 - USB convertor does the trick but when trying to simply use the serial port I get garbage data.
For clarity, My PC does indeed have a COM port to connect to serially. The bios settings let me pick if the port uses RS-422, RS-232, and RS-485. I have a gps connecting to my device and my device connects to my PC either through the COM port(does not work) or by usb with the convertor(does work). I expect a steady stream of positional data which I get only when using the convertor. When using the COM port I get random Char/numbers and unkown symbols(�). Only things I can think of is:
A. my COM port is broken(though it passed the loobback test)
B. Missing some sort of driver in order to run with a 230400 baud rate
C. Somehow the convertor is able to translate the ascii characters but the serial port cannot.

How ports for communicating with I/O devices are chosen and how do they know when the CPU talks to one of them?

I was wondering how a port for a given device controller is chosen and how it knows the values on address/data/control bus are for him.
Let's take the 8259A PIC for example, which is connected that way to the address/data/control bus:
8952A Programmable Interrupt Controller
I can see the active low CS (Chip Select) pin that is used to enable the PIC and be able to read/write on it, is connected to the address bus... But to what line? (That is the part I don't get). How does the address bus know when to activate the CS pin?
I believe that CS pin must be activated when the address bus is 0x20 or 0x21 (ports used by master PIC) and the CPU did not assert the M/#IO control line to read/write from/into I/O space (with the IN and OUT x86 instructions). But I don't get why the CS pin is connected to whatever address bus line since other ports are used by other devices controller.

Imitating specific USB device

I recently got hands on an workout device which has a USB to PC interface and logs workouts on a lousy Windows Application. My intention is to read out the USB and build a custom application for presenting that data.
When connected to a linux machine the device registers in /dev/ttyUSB0, can be seen with lsusb and stty reports the baudrate among other information. I fire up minicom with the stty settings and as soon as the workout is initiated the device sends a series of 41 bytes
I assume that those bytes represent an announcement to the the PC interface.
What I would like to do is to imitate the workout device and send those 41 bytes to the PC interface myself in order to see what the PC side does upon initiation. Is there a way to imitate the device so that the PC software will recognize it?
if the device is /dev/ttyUSB0 it is very likel implementing a virtual COM port, this is USB Communication Device class CDC (ACM).
the operating system knows what driver / kernel module it has to load because when you plug in the device in USB protocol descriptors are exchanged ( the device sends its device descriptor to the host, according to this the host loads the driver / kernel module ), you can see this information with lsusb -v. Specifically the device sends the following descriptors to the host : device descriptor, configuration descriptor, interface descriptor, endpoint descriptor : http://www.beyondlogic.org/usbnutshell/usb1.shtml
for imitating a device you have to write a firmware on a MCU with exaclty these descriptors and additionally with identic VID ( vendor id ) and PID ( product id )
the 41 bytes you receive flow over the virtual COM port and so in RS-232 protocol ( you are able to receive them with minicom ) and so they are above USB level, however they are part of the payload in USB packets. if you have a proprietary driver in windows of your device in windows these 41 bytes are very likely addressed to the driver ( whichs source code you very likely do not have ...). this is very common there are multimeters with RS-232 interface and one has to send a D = 44 (hex) = 01000100 (bin) to receive any data
so you can try to sniff the virtual COM port ( RS-232 protocol ) directly using a RS-232 sniffer, i.e. https://www.eltima.com/rs232-sniffer.html
alternatively you can try is to sniff the underlying USB traffic with wireshark ( or usbmon in linux ) and extract the payload from the USB packets to record the communication between the windows driver and ther device
https://ask.wireshark.org/question/36/how-to-capture-usb-packets-please/
https://www.youtube.com/watch?v=EfkC7kmIMt8 ( USB in Wireshark )
https://www.kernel.org/doc/Documentation/usb/usbmon.txt
( https://www.kernel.org/doc/html/v4.13/driver-api/usb/URB.html )

How create a virtual io device in Linux that proxies data to real device?

I have an interesting problem. I am working on an embedded box with multiple instances of Linux running each on an ARM processor. They are connected over internal 1GBps network. I have a serial port device node attached to processor A (Lets say Linux-A running on it). I have a program running on processor B (Lets say on Linux-B) access the serial port device as if it is attached to Linux-B locally.
My program invokes term i/o type api calls on device node to control tty echo, character mode input. What I am wondering is if there is a way to create a virtual serial device that is available on Linux-B somehow talking to real serial device on Linux-A over internal network.
I am thinking something along the lines of:
Linux-B has /dev/ttyvirtual. Anything that gets written to it gets transported over network socket to Linux-A serialserver. The serial server exrcises the api calls on real device lets say /dev/ttys0.
Any data waiting on ttys0 gets transported back to /dev/ttyvirtual.
What are all the things involved to get this done fast?
Thanks
Videoguy
Update:
I found a discussion at
http://fixunix.com/bsd/261068-network-socket-serial-port-question.html with great pointers.
Another useful link is http://blog.philippklaus.de/2011/08/make-rs232-serial-devices-accessible-via-ethernet/
Take a look at openpty(3). This lets you create a pseudo-TTY (like /dev/pts/0, the sort that ssh connections use), which will respond as a normal TTY would, but give you direct programmatic control over the connections.
This way you can host a serial device (eg. /dev/pts/5) that you forward data between a network connection, and then other apps can perform serial operations on it without knowing about the underlying network bridge.
I ended up using socat
Examples can be found here: socat examples
You socat back to back on both the machines. One listens on a tcp port and forwards data to local virtual port or pty. The socat on other box uses real device as input and forwards any data to tcp port.

Coding for Ethernet PHY Loopback Test

I have to write a Ethernet PHY loopback test in Linux. I've never done it before and had no clue where to start. After some researching, I came up with the plan for the test, and I wonder if anyone can help me to verify it and give me some pointers to my questions.
This is a external loopback setup. It connects the TX+/- to RX+/- pins for each internal PHY's on the Ethernet switch chip.
So the loopback high level packet path is as follow:
CPU->PHY0(chip)->Ethernet switch(chip)'s internal PHY->PHY0(chip)->CPU
For this test, I plan to
configure the internal PHYs on the Ethernet switch with specific MAC addresses,
pack the Ethernet test packet using CPU's MAC address as the source address and the
MAC address configured in step 1. as the destination address,
send and wait to receive the test packet,
compare sent and received data pattern.
Any suggestions? Also, I wonder if there are functions in Linux that I can use to generate the packets for step 2, and send the packets for step 3.
Thank you very much.
Most Phys can be switched to a test mode. We used the bootloader to write directly to the
Phy and switch to testing mode.
There is also an ioctl taken from documentation/networking/phy.txt
Ethtool convenience functions.
int phy_mii_ioctl(struct phy_device *phydev,
struct mii_ioctl_data *mii_data, int cmd);
The MII ioctl. Note that this function will completely screw up the state
machine if you write registers like BMCR, BMSR, ADVERTISE, etc. Best to
use this only to write registers which are not standard, and don't set off
a renegotiation.

Resources