I think there is a nice workaround that solves the problem. Instead of reading data from the device /dev/ttyUSB0 or /dev/ttyACM0, it could be read from the named pipe, e.g. /tmp/arduino and the simple program (below) would be copying data from the device to pipe and holding the device open (thus avoiding setting DTR high). This also avoids dealing with all the difficulties of reading from the device. With the named pipe, tools like cat, less -f can be used or just any program with standard open + read without any need to issue ioctl commands to control tty. The program for copying the device to pipe would be running e.g. as upstart service and copying data from the device to the pipe (and perhaps producing some logs). The program has to take care of the SIGPIPE signal, to avoid being closed on closing any pipe reader process. The load on server would be negligible because of intentionally setting blocking on the input via fcntl. I have tested it and it seems to be working well. I am acutually trying to solve the same problem with interfacing Arduino. The nice side effect is that restart of Arduino can be done simply by restarting the upstart service whenever needed as it sets DTR high.
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <fcntl.h>
/* for simplicity, most error handling is ommited, make sure you add it before using in production code */
void ignore_signal(int sig)
{
static struct sigaction _sigact;
memset(&_sigact, 0, sizeof(_sigact));
_sigact.sa_handler = SIG_IGN;
sigaction(sig, &_sigact, NULL);
}
int main()
{
ignore_signal(SIGPIPE);
int flags;
flags = fcntl(0, F_GETFL, 0) & ~O_NONBLOCK;
fcntl(0, F_SETFL, flags);
char c;
int n;
while(1)
{
n = read(0,&c,1);
if(n!=1)
{
sleep(1);
}
else
{
write(1,&c,1); /* ignoring the case that return code = -1 and errno = EPIPE means that data from Arduino are lost whenever pipe is not read */
write(2,&c,1);
}
}
return 0;
}
The shell script to start it would be (needs to be re-implemented as upstart service):
#!/bin/bash
DEV=/dev/ttyUSB0
PIPE=/tmp/arduino
LOG=/var/log/arduino.log
if test ! -p $PIPE
then
rm -f $PIPE
mkfifo $PIPE
fi
./my_dd <$DEV >$PIPE 2>>$LOG &
dd if=$PIPE of=/dev/null count=0 bs=1
I think logrotate file needs to use copytruncate, because the file is still open (I had no chance to test this):
/var/log/arduino.log {
rotate 5
daily
compress
missingok
notifempty
create 640 root root
copytruncate
}
Additional note : Meanwhile I have realized that to avoid the broken pipe, it could probably be achieved with use of cat or dd in combination with trap command with parameter PIPE, that would be filtering the SIGPIPE signal too. The solution above works for me, so I was not experimenting with the trap command to achieve comparable results.
cdc_acm. But first things first, and the once-in-a-blue-moon that onboard RS-232 chips are used, even then probably nobody cares about being unable to control this. But with Arduinos, there's a clear and pressing concern. (In BOTH CASES, though, it's highly concerning that Windows has us so handily beat; I'd have expected this situation to be the other way around)cdc-acm.kokernel module, you can try commenting out this line fromdrivers/usb/class/cdc-acm.c.