How to send a Linux EOF marker from Arduino

Hi,

When printing to the serial port I can get the output with a simple Linux command such as cat /dev/ttyUSB0.

However, the cat commands wait forever until I press Ctrl-C. If I was taking the input from the terminal instead, I could signal the end of file by pressing Ctrl-D which would terminate the cat command.

How do I signal from Arduino that there is no more data for now? Serial.end() and Serial.print(4, BYTE) does not work.

You could have the arduino send a ctrl-D:

#define CTRL(x) ('x' & 0x1F)
Serial.print((char)CTRL(D));

Have you tried sending the regular end-of-file character? (the ascii char with the decimal value of 0)

Tough luck, you can't. Your connection will stay active because you can't close it. Send some data so that your program know that no more input is expected. Coming from a serial terminal and read with getty, the Ctrl-D (ASCII 4) is considered the EOF character, but that won't work in all cases.

Korman

cat /dev/ttyUSB0|head -n 6 >> /root/arduino

Reads 6 lines of output from the arduino and appends to a file.

cat /dev/ttyUSB0|head -n 2

Reads two lines of output from the arduino to the screen

cat /dev/ttyUSB0|head -n 6|tail -n 3 > fredfile.txt

Reads six lines of output from the arduino and saves the last 3 to a file.

What do you want EOF for ?

#1 and #2: I will try that

#4: I want an EOF to signal the end of transmission so that the receiving program can continue doing something else like storing data in DB. Your idea of using head and tail is quite neat.

What I want is that the receiving program (on the pc) should process the data when it's there and be free to do something else while waiting for data.

Part of the problem is that you're using the cat program to receive your data instead of writing your own program to do it. The cat program keeps control of the console thread until the program ends. Even if you send the EOF, until the cat program ends, it will not give the system back control.

What you should do is write a 'c' or java program that receives the data and saves them to a file. That way, you can send whatever character you want as an EOF marker, and tell your program to end or quit looping waiting for data. This can be done very easily on linux.

Actually I am going to use php and fopen() but I thought there would be the same problem with waiting for data. I used cat only to experiment.

I have tried both #1 and #2 and none works. The chars are transmitted as some strange binary characters looking like dices.

However, head works fine....

Try this:

stty -F /dev/ttyUSB0 raw icanon eof \^d 9600

(or whatever baud rate you are using in place of 9600)

In your program use Serial.print(4,BYTE); to send an EOF. Then cat /dev/ttyUSB0 should reset the arduino, display the output and stop at the EOF. (It seems to give me a few bytes of rubbish at the beginning though, and occasionally not work at all.)

I use bash scripts running from cron every minute and that then processes stuff to produce these graphs :

http://pluggy.is-a-geek.com/

Since Linux is a full multitasking environment, it can do that whilst its doing something else. If its running from cron, its a effectively a background process.

What I posted before was just the meat of one of my scripts. The bit that deals with the arduino in full :

#!/bin/bash
stty -F /dev/ttyUSB0 cs8 115200 ignbrk -brkint -icrnl -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke noflsh -ixon -crtscts -clocal
#stty -F /dev/ttyUSB1 cs8 115200 ignbrk -brkint -icrnl -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke noflsh -ixon -crtscts -clocal
#cat /dev/ttyUSB5|head -n 2|tail -n 1 >> /root/arduino2 
date > /root/arduino
datest=`date`
cat /dev/ttyUSB0|head -n 6|tail -n 3 >> /root/arduino  # not active for setting up
cat /root/arduino|grep 'LEC'|tail -n1 > /root/arduino_lec
cat /root/arduino|grep 'BITS'|tail -n1 > /root/arduino_bits
cat /root/arduino|grep 'GAS'|tail -n1 > /root/arduino_gas
#cat /root/arduino|grep 'WF'|tail -n1 > /root/arduino_wf
#rm /root/wf2
total=0
#for (( c=3; c<=199; c++ ))
#do
#   value=`cat /root/arduino_wf|cut -d ' ' -f $c`
#   echo $c $value >> /root/wf2
#done
lastarduinotime=`cat arduino_bits|cut -d ' ' -f1`
let lastminute=$[lastarduinotime - 600] 
lastturn=`cat /root/arduino_lec|cut -d ' ' -f 25`
prevturn=`cat /root/arduino_lec|cut -d ' ' -f 24`
prev=`cat /root/previoustime`
toturns=`cat /root/toturns`
echo $lastturn > /root/previoustime
echo $lastarduinotime $lastminute  > /root/arduinodebug
turns=0
for (( c=1; c<=25; c++ ))
do
   value=`cat /root/arduino_lec|cut -d ' ' -f $c`
   if [[ $value -ge $lastminute ]]
   then
     let turns=$[$turns + 1]
     echo value $value >> /root/arduinodebug
   fi
done
gasturns=0
lastgasturn=`cat /root/arduino_gas|cut -d ' ' -f 26`
prevgas=`cat /root/arduino_gas|cut -d ' ' -f 25`
echo $lastgasturn > /root/gasprevioustime
for (( c=1; c<=26; c++ ))
do
   value=`cat /root/arduino_gas|cut -d ' ' -f $c`
   if [[ $value -ge $lastminute ]]
   then
     let gasturns=$[$gasturns + 1]
     echo gasvalue $value >> /root/arduinodebug
   fi
done
let gas=$[$gasturns * 6660] # 111 wh per gas meter turn = 11.1 kWh per cubic metre
watts=`cat arduino_bits|cut -d ' ' -f5|cut -d '.' -f1`
tpvalue=`cat /root/arduino_bits|cut -d ' ' -f21` # touchpad value 
if [[ $tpvalue -le 800 ]]
   then
     echo 'C' > /root/desiredtemp  
     echo '7' > /dev/ttyUSB0
   fi
let toturns=$[$toturns + $turns]  #  
echo $toturns > /root/toturns
avwatts=`cat /root/arduino_bits|cut -d ' ' -f22`
ctval=`cat /root/arduino_bits|cut -d ' ' -f21`
ctv=`echo "scale=1; ${ctval}*100" | bc`
echo time $lastarduinotime lasturns $lastturn $prevturn timeperrev $timerev $timerev2 turns $turns watts $watts gasturn $gasturns Prevgas $prevgas Lastgas $lastgasturn gas $gas ctv $ctval $ctv >> /root/arduinodebug

temp1=`cat /root/arduino_bits|cut -d ' ' -f11`
temp1d=`echo "scale=1; ${temp1}/16" | bc`
light=`cat /root/arduino_bits|cut -d ' ' -f17`
light2=`cat /root/arduino_bits|cut -d ' ' -f18`
tempp2=`cat /root/arduino_bits|cut -d ' ' -f13`
temp2=`echo "scale=1; ${tempp2}/16" | bc`
chtempp=`cat /root/arduino_bits|cut -d ' ' -f19`
chtemp=`echo "scale=1; ${chtempp}/16" | bc`
tempp5=`cat /root/arduino_bits|cut -d ' ' -f14`
temp5=`echo "scale=1; ${tempp5}/16" | bc`
temppp=`cat /root/arduino_bits|cut -d ' ' -f11`
temp4=`echo "scale=1; ${temppp}/16" | bc`
tempp=`cat /root/arduino_bits|cut -d ' ' -f12`
temp3=`echo "scale=1; ${tempp}/16" | bc`
lecrevs=`cat /root/arduino_bits|cut -d ' ' -f3`
gasrevs=`cat /root/arduino_bits|cut -d ' ' -f9`
echo $temp1 $temp2 $temp3 $temp4 $temp5 $chtemp $watts $avwatts $gas >> /root/arduinodebug
#graph -T gif --bitmap-size 800X400 -m 1  < /root/wf2 > /var/www/waveform.gif
echo $datest $lastarduinotime $lecrevs $gasrevs $chtemp >> /root/arduinolog
rrdtool update /var/lib/ctadc.rrd -t number N:$ctv
rrdtool update /var/lib/watts.rrd -t number N:$watts
rrdtool update /var/lib/avwatts.rrd -t number N:$avwatts
#rrdtool update /var/lib/temp1.rrd -t number N:$temp1
rrdtool update /var/lib/temp2.rrd -t number N:$temp2
rrdtool update /var/lib/temp3.rrd -t number N:$temp3
rrdtool update /var/lib/temp4.rrd -t number N:$temp4
rrdtool update /var/lib/temp5.rrd -t number N:$temp5
rrdtool update /var/lib/light.rrd -t number N:$light
rrdtool update /var/lib/light2.rrd -t number N:$light2
rrdtool update /var/lib/gas.rrd -t number N:$gas
rrdtool update /var/lib/chtemp.rrd -t number N:$chtemp
#curlstr=`echo $watts,$light,$light2,$temp1d,$temp2,$temp3,$temp4,$temp5,$chtemp,$gas`
#echo $curlstr > /root/curlstr
#curl --request PUT --header "X-PachubeApiKey: c29c66d4af1cc75bd167537a1b3dffe1ecca83716af76c040ce5fa0a60a5f50e" --data $curlstr "http://www.pachube.com/api/2480.csv"

I stop the arduino resetting each time with a 10uF capacitor between gnd and reset. The head and tail and dropping the first part of what s received is incase it 'joins' the arduino half way through a transmission. The arduino just sends stuff over and over at 115200 baud.

Stimmer: I will try that tomorrow.

Pluggy (and all of you): This is very interesting as I am actually working on the same, reading data from my electricity meter. I had problems with the sketch somehow getting stuck and I suspected some kind of congestion on the serial port. This was the initial reason for this thread as I thought that controlling the data flow with an EOF marker would cure the problem.

However, late yesterday night I stumpled upon this thread which is a nice introduction to interrupts. After reading the thread I realized that it was a very bad thing to have the Serial.Print() line in the ISR (triggered by a blink from the electricity meter).

I moved the print statement to the main loop, controlling it by a state variable set by the ISR instead. After this, my sketch has been running for hours without getting stuck! And without using any kind of EOF markers; the cat is just happily eating every bit of data now :slight_smile:

Nevertheless, the tips I got here has been most useful to me, especially about using head and tail together with cat.

A few notes to Pluggy: If possible, I would be very grateful to see your sketch :sunglasses:

I am aware of the problem with resetting the Arduino, but for some reason it does not happen on my Sheevaplug. I use no capacitor.

Its too big for a code block so heres a download link.

http://pluggy.is-a-geek.com/arduino/Homeautomation2_87.pde

I'm always tweaking it, so its constantly changing. Recent changes have been an attempt to improve the central heating control. Its quite involved........

Hmmm, the Sheevaplug doesn't reset the arduino, whilst a hacked Seagate Dockstar (basically the same platform) running Debian does.

Be aware, the above sketch uses a specially hacked version of the Dallas temperature library so won't compile even if you got all the libraries in place. :wink:

Thanks pluggy!

Stimmer #9: That works perfectly! I guess it is this parameter that does the trick, right? eof ^d