Send file over serial port with Linux and C - 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.

Related

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?

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

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.

can I call recv() for returning most one line?

When communicating with serial port, I can set the serial port in Canonical Mode so that each read() call will return util a line comes, and it will return at most one line.
assumes the line separator is \r\n.
Does TCP/IP communication support this feature?
I know that TCP/IP is based on stream and will take 'a','b','c' and '\r','\n' all the same, but I really don't want to parse the message char by char to find '\r','\n' in application.
I hope the TCP can do it for me...
any idea?
No, TCP/IP doesn't support "messages" of any kind.
You need to implement your own kind of protocol.
And if the protocol is that a "messages"'s end is indicated by \r\n and you do not know the amount of data up to this EOM indicator in advance you would need to take the burden to inspect the bytes as they flow in.
If you however could affort a blocking fgets() or similar in case a "message/line" does not fully arrive timely, you could wrap the socket using fdopen() and read it via a FILE* pointer.
Please see this answer: https://stackoverflow.com/a/14686048/694576

Using glib to send raw bytes to an FTDI device over USB

I am developing a simple application in C with GTK+2.0 GUI, on Linux of course, this application is designed to control a device which is connected over the USB port and is using FTDI driver to emulate RS232 asynchronious protocol over the USB port.
I am using the function g_io_channel_write_chars() to send data to the device. The problem is the sequence I am sending consist a lot of values that are ASCII but do not match any (visible) character.
For example, when I am sending \x40\x40\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01 it won't work. The program will stop with an error.
GLib:ERROR:/build/buildd/glib2.0-2.34.1/./glib/giochannel.c:2382:g_io_channel_write_chars: code should not be reached
Przerwane (core dumped)
If I use sprintf function to put this sequence in a table only first two values will be copied and this sequence will be send to the device without an error.
Then my question is, how can I send any bytes to the device. Is there an equivalent of g_io_channel_write_chars() for this? I've been studying the documentation of GIOChannel and haven't found anything like this. Thanks very much for your help.
You need to make sure the channel doesn't think it's sending text. The crash you're getting is probably due to GIO trying to validate your data against its idea of the channel's encoding.
Note that the default encoding is UTF-8, and since not all byte sequences are valid UTF-8, this can easily cause validation to fail for random binary data.
Call g_io_channel_set_encoding with the argument NULL, this will make it safe for binary data:
The encoding NULL is safe to use with binary data.

C Linux Device Programming - Reading Straight from /Dev

I have been playing with creating sounds using mathematical wave functions in C. The next step in my project is getting user input from a MIDI keyboard controller in order to modulate the waves to different pitches.
My first notion was that this would be relatively simple and that Linux, being Linux, would allow me to read the raw data stream from my device like I would any other file.
However, research overwhelmingly advises that I write a device driver for the MIDI controller. The general idea is that even though the device file may be present, the kernel will not know what system calls to execute when my application calls functions like read() and write().
Despite these warnings, I did an experiment. I plugged in the MIDI controller and cat'ed the "/dev/midi1" device file. A steady stream of null characters appeared, and when I pressed a key on the MIDI controller several bytes appeared corresponding to the expected Message Chunks that a MIDI device should output. MIDI Protocol Info
So my questions are:
Why does the cat'ed stream behave this way?
Does this mean that there is a plug and play device driver already installed on my system?
Should I still go ahead and write a device driver, or can I get away with reading it like a file?
Thank you in advanced for sharing your wisdom in these areas.
Why does the cat'ed stream behave this way?
Because that is presumably the raw MIDI data that is being received by the controller. The null bytes are probably some sort of sync tick.
Does this mean that there is a plug and play device driver already installed on my system?
Yes.
However, research overwhelmingly advises that I write a device driver for the MIDI controller. The general idea is that even though the device file may be present, the kernel will not know what system calls to execute when my application calls functions like read() and write().
<...>
Should I still go ahead and write a device driver, or can I get away with reading it like a file?
I'm not sure what you're reading or how you're coming to this conclusion, but it's wrong. :) You've already got a perfectly good driver installed for your MIDI controller -- go ahead and use it!
Are you sure you are reading NUL bytes? And not 0xf8 bytes? Because 0xf8 is the MIDI time tick status and is usually sent periodically to keep the instruments in sync. Try reading the device using od:
od -vtx1 /dev/midi1
If you're seeing a bunch of 0xf8, it's okay. If you don't need the tempo information sent by your MIDI controller, either disable it on your controller or ignore those 0xf8 status bytes.
Also, for MIDI, keep in mind that the current MIDI status is usually sent once (to save on bytes) and then the payload bytes follow for as long as needed. For example, the pitch bend status is byte 0xeK (where K is the channel number, i.e. 0 to 15) and its payload is 7 bits of the least significant byte followed by 7 bits of the most significant bytes. Thus, maybe you got a weird controller and you're seeing only repeated payloads of some status, but any controller that's not stupid won't repeat what it doesn't need to.
Now for the driver: have a look at dmesg when you plug in your MIDI controller. Now if your OSS /dev/midi1 appears when you plug in your device (udev is doing this job), and dmesg doesn't shoot any error, you don't need anything else. The MIDI protocol is yet-another-serial-protocol that has a fixed baudrate and transmits/receives bytes. There's nothing complicated about that... just read from or write to the device and you're done.
The only issue is that queuing at some place could result in bad audio latency (if you're using the MIDI commands to control live audio, which I believe is what you're doing). It seems like those devices are mostly made for system exclusive messages, that is, for example, downloading some patch/preset for a synthesizer online and uploading it to the device using MIDI. Latency doesn't really matter in this situation.
Also have a look at the ALSA way of playing with MIDI on Linux.
If you are not developing a new MIDI controller hardware, you shouldn't worry about writing a driver for it. It's the user's concern installing their hardware, and the vendor's obligation to supply the drivers.
Under Linux, you just read the file. Now to interpret and make useful things with the data.

Resources