How to open a serial port with read/write lines reversed? - c

I know how to open a serial port using 'open' function:
open("/dev/portname", flags)
But I want two programs to open this port but with reversed read/write lines. For example when program 2 writes something to the port, program 1 can read it.

If you're using a Unix-like operating system, and if you don't need full serial port semantics, named pipes can be quite useful for doing this sort of thing.
If you need more control, you could perhaps use a pair of pseudoterminals, with a third program running in the background shuttling characters between the master ends.
And do see the related question "Virtual Serial Port for Linux" that the StackOverflow machinery already found for you.

You cannot typically do that in software.
Such things are normally done by hardware, and that is what cross-over cables and "null-modem" cables are good for.

Related

who call tty_open() in linux kernel?

For mouse, keyboard and joystick drivers, it may X call the 'open' then using these drivers.
( when I check CentOS 7 (text mode only) in VirtualBox, I didn't see X after executed lsof /dev/input/event2 ( keyboard ), but my keyboard still working )
How about tty_open() ?
According to a call trace, we can roughly know the sequence:
( at least, we know someone called 'sys_open' )
https://bugzilla.redhat.com/show_bug.cgi?id=630464
However, I still don't know who calls the 'open'?
When I check CentOS 7, text mode only, in VirtualBox, I didn't see X after executed lsof /dev/input/event2 (keyboard), but my keyboard still works
That is because you use the virtual console then, one of the /dev/ttyN devices. These are directly wired to the Linux input event subsystem inside the kernel itself (by the vt module); essentially all keyboard-like devices act as inputs to the currently active virtual terminal.
X itself uses a virtual console, just so that the kernel can switch between it and any text-based virtual consoles.
How about tty_open()?
If you run sudo lsof /dev/tty[0-9], you can see which processes are accessing a virtual console.
The processes with getty in their name are the ones that provide login terminals. (The ones that are used with serial terminals are very similar; in fact, many getty programs can handle both virtual consoles and serial terminals just fine.)
When you log in, that getty launches login (program!), which in turn starts the default shell defined for that user (see getent passwd username; it is the last field, and it must be one that is listed in /etc/shells to be allowed).
The kernel itself supports switching to a different virtual console via Ctrl+Alt+Fn (F1 for tty1, F2 for tty2, and so on). If you use suitable graphics drivers, you can even switch between Xorg and virtual consoles. (Usually, Xorg is run on tty6 or tty7, but that varies from distribution to distribution.) The Ctrl+Alt+← and Ctrl+Alt+→ can also usually be used to switch to the previous or next virtual console.
Thanks for Nominal Animal for the information.
I am tracing linux 2.0 ( https://mirrors.edge.kernel.org/pub/linux/kernel/v2.0/ ), thing maybe a little different.
Sorry, I can't find an online Linux 2.0 source to link reference.
For keyboard, in text mode, I think no one calling 'open' in kernel,
In 'int tty_init(void)' ( tty_io.c ), it will call 'kbd_init();'
then we can see:
request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL);
therefore, keyboard HW can work with this IRQ & callback ('keyboard_interrupt').
For tty_open(), I finally see it in main.c
open("/dev/tty1",O_RDWR,0);
For the newer version of kernel, I think this part migrated to getty application, that's why I can't find it in kernel source.
tty_* routines are UNIX hardware independent code to implement the terminal interface in the kernel. They are responsible of the tty disciplines, the job control stuff and the linemode processing of characters (including the generation of signals on Ctrl-C for example) They also implement the interface to tty/pty pairs and the like.
This is common code to include all the common functionality of the terminal drivers into any kind of hardware you can have attached for (console keyboard/display is just one example, but you have, at least, uart RS-232C interfaces, usb serial dongles, PCI serial line multiplexors, etc)
Terminal functionality dates from the ancient v7 unix, and has many improvements coming from BSD unix (like job control)
By the way, linux implementation of serial interface is not very good, you should look at the BSD implementation for a good one.

Forcing raw serial mode in C - linux

Not sure how to word the title, but what I'm trying to do is test my micro controller with my Linux PC to ensure data is correct. After hours of searching, I found out that the stty command can change how data is managed through the serial port and it turned out that by default if xon or xoff characters are received from the port, they don't get displayed. At first I thought my computer was too slow that I was losing characters at 57.6Kbps but that wasn't the case.
Back in the day when I was playing with the serial mouse in QuickBasic for DOS, I could use this command to start the serial port:
OPEN "com1:1200,n,7,1,op0" for binary as #1
So what I want to do now is create something simple in C that would allow me to open up the serial port in the rawest mode possible. I want it so that whatever data I give to it is sent to it unmodified. I also want to receive data unmodified. so if the controller decides to send a character the PC would recognize as a special control code, I still want to see the character, not have the PC go funny just because a character matches a control code.
One idea I thought of is to create a fork to the stty program and use nearly every (50+?) parameters added to the program making the requirement of program stack space a bit high.
Another idea I thought of is to do direct I/O with the port address itself (using inb and outb) but I'm not sure if the kernel would run those commands through anything else before the data reaches the port, but I'd rather use that as a last option in case I ever replace my computer and the serial port value changes (or becomes a serial port made through USB to serial converter hardware).
so rather than inb and outb and those variants (like inw), and without executing stty with specifying 50+ parameters in my program, is there a function in C I can use (without requiring a special library not included with a standard linux distribution) to force the serial port device as a raw device so I can do any I/O on it without the kernel modifying or dropping data?

Difference between Serial Port and Named Pipe

Is there a difference between a Serial Port stream and a Named Pipe (FIFO)? Especially in regards to Linux?
My understanding is that both:
Are full duplex
Can be read/written by process that are unrelated (as opposed to how regular Pipes work)
The only difference I can think of are:
Serial Ports have file descriptors to actual hardware (that the hardware is reading/writting to) whereas a Named Pipe is just a 'file' created on the kernal to store a data stream then 2 (or more?) processes can connect to and read/write.
Any other differences if any?
Also if I have one named pipe that I create in one process P1 (and another of my processes P2 connects to it) - can P1 use that one file descriptor to write and read to this named pipe? And P2 can do the same (both read and write). Or do I need to create 2 named pipes if I want P1 to be able to write and read to P2? The practical use is that P1 will write commands to P2 and also read results of those commands from P2 aswell.
Serial ports are for distinct machines to communicate with each other, not for IPC within the same machine. You can configure serial hardware for loopback, but the highest data rates supported by serial port hardware do not come anywhere close to the speed of any modern interconnect -- not USB or eSATA (for other interfaces with "serial" in their names) nor network interconnects such as ethernet (even wireless). Serial port speed is not even in the same solar system as a FIFO's.
As far as other characteristics go,
serial ports will be presented to the system as device files, and FIFOs also will be presented as files
as such, each can be opened concurrently by multiple unrelated processes, for both reading and writing
however, you need special privileges to create a serial port special file, plus actual hardware behind it for it to be useful, whereas anyone can make a FIFO
communication through serial ports is bi-directional; it can be full-duplex, but half-duplex modes are available as well.
FIFOs are unidirectional, but you can use them in pairs if necessary. In principle, one process could both write to and read from a FIFO, but it would need to be very careful if it wanted to avoid consuming its own messages and to avoid deadlocking.
Bottom line: for bidirectional IPC within one machine, FIFOs are far superior to serial ports. You should also consider a socket interface.

Create UDP-like library in C

I am looking to implement some kind of transmission protocol in C, to use on a custom hardware. I have the ability to send and receive through RF, but I need to rely in some protocol that validates the package integrity sent/received, so I though it would be a good idea to implement some kind of UDP library.
Of course, if there is any way that I can modify the existing implementations for UDP or TCP so it works over my RF device it would be of great help. The only thing that I think it needs to be changed is the way that a single bit is sent, if I could change that on the UDP library (sys/socket.h) it would save me a lot of time.
UDP does not exist in standard C99 or C11.
It is generally part of some Internet Protocol layer. These are very complex software (as soon as you want some performance).
I would suggest to use some existing operating system kernel (e.g. Linux) and to write a network driver (e.g. for the Linux kernel) for your device. Life is too short to write a competitive UDP like layer (that could take you dozens of years).
addenda
Apparently, the mention of UDP in the question is confusing. Per your comments (which should go inside the question) you just want some serial protocol on a small 8 bits PIC 18F4550 microcontroller (32Kbytes ROM + 2Kbytes RAM). Without knowing additional constraints, I would suggest a tiny "textual" like protocol (e.g. in ASCII lines, no more than 128 bytes per line, \n terminated ....) and I would put some simple hex checksum inside it. In the 1980s Hayes modems had such things.
What you should then do is define and document the protocol first (e.g. as BNF syntax of the message lines), then implement it (probably with buffering and finite state automaton techniques). You might invent some message format like e.g. DOFOO?123,456%BE53 followed by a newline, meaning do the command DOFOO with arguments 123 then 456 and hex checksum BE53

Send file over serial port with Linux and C

I'm developing an application that reads data from a serial port and sends it over a TCP connection, and vice versa. Unfortunately, while reading data from serial port, it never stops. It does not detect EOF mark, nor EOL or some other special character.
So, how could i detect an end of file (or "end of connection") over serial port in C and Linux?
Depends on how much control you have over the protocol used for the serial link. Unless the files implicitly include some end-of-file marker (and as I've understood your post they don't), you need to implement some kind of communication protocol in order to transfer files.
Some of the most simple procols used way back in the BBS days were XMODEM and it's derivatives. They may be simple enough for you to use.
If you have a full-blown computer at the other end of the serial line, it would probably be far simpler just to set up an PPP link over the serial line and do the communication over TCP/IP.
Serial link only sends bytes. There is no packet frame, no error checking so you can't send files reliably over raw serial link. You need to use some protocol like XMODEM, KERMIT etc.
It's not trivial to implement such protocol. It may be easier to run TCP/IP over the link if the other end is also a computer. Please check out SLIP or PPP.
The serial port gives "end of file" on a hangup condition, which is signalled out-of-band by the modem control lines (dropping of DCD). If you're connected with a null-modem, that'll never happen.
Use a framing mechanism, like the other answers have suggested. You may not need to go the whole hog with something like ZMODEM though - just prefixing your file with the file size and a CRC32 checksum should do, if the link is reasonably error-free and 8-bit clean.
Check your serial port configuration:
stty -F /dev/ttySx -a
Set cooked link instead of raw link:
stty -F /dev/ttySx cooked
cheap and dirty solution:
on linux, unix or osx just run 'screen -L <serial_device> <baudrate>'. At the other end write the output of your file to the console, in raw mode. -L logs it to a file the contents of which will be the file you transfered from the other end. Check the contents with xxd to verify they match what you had at the source.

Resources