Linux - Hardware This forum is for Hardware issues.
Having trouble installing a piece of hardware? Want to know if that peripheral is compatible with Linux? |
| Notices |
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
Are you new to LinuxQuestions.org? Visit the following links:
Site Howto |
Site FAQ |
Sitemap |
Register Now
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
 |
GNU/Linux Basic Guide
This 255-page guide will provide you with the keys to understand the philosophy of free software, teach you how to use and handle it, and give you the tools required to move easily in the world of GNU/Linux. Many users and administrators will be taking their first steps with this GNU/Linux Basic guide and it will show you how to approach and solve the problems you encounter.
Click Here to receive this Complete Guide absolutely free. |
|
 |
12-15-2007, 03:20 PM
|
#1
|
|
Member
Registered: Apr 2006
Location: Montreal,Quebec
Distribution: Gentoo
Posts: 822
Rep: 
|
Creating a bash script with serial port input
Hi, i got a device that send information over serail port (clear ANCSI code). I am looking for a way to recive those information in a bash script and using them.
I can use sudo cat /dev/ttyS0 to see the iunformation, but i want it so stop after each transmition and run few command. But i cant stop cat like that so it is not the right solution.
My script will look like:
Code:
#/bin/bash
useless=1
while [ $useless -ne 10 ];
do
#Recive the information here (and wait for it if possible)
xvkbd -xsendevent -text "The content from serial"
done
How can i recive information from port when it send it and use it?
|
|
|
|
12-16-2007, 04:43 AM
|
#2
|
|
Senior Member
Registered: Mar 2006
Posts: 1,896
Rep:
|
If your device sends "lines" that end in a newline character (a.k.a line feeds, a.k.a 0x0A), then I think the following would work:
Code:
sudo cat /dev/ttyS0 | while read var1 var2 var3; do
# Do stuff with $var1 $var2, $var3, etc here
done
See the bash man page for details on the read command and how input gets assigned to variables. You will execute the body of the do loop once for each line of input. When comming from a serial port, I am not sure what causes exit from the do loop -- perhaps an ASCII EOT character?
Depending on the format of your data stream, you may need to pipe the output of the serial device through some tr and or sed command(s) before piping to the while statement.
Also, be aware that prior to giving the commands, you may need to set options for the serial device use the stty command.
I hope this can at least get you started.
|
|
|
|
12-16-2007, 02:08 PM
|
#3
|
|
Member
Registered: Apr 2006
Location: Montreal,Quebec
Distribution: Gentoo
Posts: 822
Original Poster
Rep: 
|
Thanks for answering my question. Your idea is good and may work, but the device never send 0A, it only send letter and number, one by one. I could edit the application in the device, but i never used this kind of language and i am not sure if GCC can compile the apps for this thing. There is any way to just react to the transmition without cat?
|
|
|
|
12-16-2007, 03:17 PM
|
#4
|
|
Member
Registered: Apr 2006
Location: Montreal,Quebec
Distribution: Gentoo
Posts: 822
Original Poster
Rep: 
|
Sorry for double posting, but i found something. This script -do- break after each letter, but i dont know how i can use data from it.
#/bin/bash
cpt=1
while [ $cpt -ne 10 ];
do
sudo cat /dev/ttyS0 2>/dev/null| xvkbd -xsendevent -text "it almost work!"
echo "did break"
done
____
i did try
var1=`sudo cat /dev/ttyS0 2>/dev/null| break`
xvkbd -xsendevent -text $var1
but the break return nothing...
EDIT: also tested:
sudo cat /dev/ttyS0 2>/dev/null| > test22.txt
dont work, the file is created, but empty
Last edited by Elv13; 12-16-2007 at 03:21 PM.
|
|
|
|
12-17-2007, 03:13 AM
|
#5
|
|
Senior Member
Registered: Mar 2006
Posts: 1,896
Rep:
|
I am not familiar with xvkbd. I tried to do a quick review of it on the Internet, but it was not immediately obvious to me why it is relevant to this problem. (I'm not saying it isn't relevant, but with the time I put in I couldn't make the connection.) So unless you can point me to something to get me up to speed with it quickly, I don't think I can help you with it.
If there was a way to turn the breaks into some character (different than what your device puts out), you could use tr to turn those into new lines and you could use the construct i showed you. But I haven't been able to find anyway to do that. The stty command has provisions for having breaks cause an "interrupt signal" but I haven't figured out any way to use that. I am beginning to suspect that your needs are little bit more than can be handled with a bash script. Perhaps perl or python could be used to solve your problem, but I am not familiar with those. I am certain a (probably pretty simple) C program could solve the problem, but I am far to rusty to feel qualified to help you.
|
|
|
|
12-17-2007, 06:13 PM
|
#6
|
|
Member
Registered: Apr 2006
Location: Montreal,Quebec
Distribution: Gentoo
Posts: 822
Original Poster
Rep: 
|
xvkbd is a keyboard emulator. It translate input into keypress, it is exactly what i want
The only thing to find is how to put sudo cat /dev/ttyS0 2>/dev/null is a variable.
|
|
|
|
12-18-2007, 02:20 AM
|
#7
|
|
Senior Member
Registered: Mar 2006
Posts: 1,896
Rep:
|
Quote:
Originally Posted by Elv13
The only thing to find is how to put sudo cat /dev/ttyS0 2>/dev/null is a variable.
|
It seems to me the basic problem is the lack of newlines in your data stream. W/o that, I don't think the normal variable assignement is going to work. However, the bash read command can be told to read a certain number of characters only. However, when I tried
Code:
echo abcdefg | read -n2 var
echo $var
There was nothing in $var, for reasons I don't understand. However,
Code:
echo abcdefg | while read -n2 var; do
echo $var
done
produced the expected results. So I think something like the following might work for you
Code:
#!/bin/bash
PORT=/dev/ttyS0
MAX_CHARS=100
# There may be additional parameters you need to use with stty, and/or some of these may need to be deleted.
# But get the port set up appropriately ...
sudo stty -echo -brkint ignbrk -F $PORT
# Now read in data, pairing a letter with a number
CNT=0; SECOND=FALSE
sudo cat $PORT | while read -n1 CHAR; do
let "CNT += 1"
[ $CNT -gt $MAX_CHARS ] && break
case $CHAR in
[a-zA-Z]) PAIR=$CHAR; SECOND=TRUE; continue;;
[0-9]) [ $SECOND != TRUE ] && continue || PAIR=$PAIR$CHAR; SECOND=FALSE;;
*) SECOND=FALSE; continue;;
esac
# The $PAIR variable now contains a letter followed by a number, which you can
# use as you see fit.
done
I followed your example of accessing the serial port using sudo. It would probably be a little better to change the owner or group (and permissions) of the device so that you can access access it w/o sudo. For example, if the group of /dev/ttyS0 was serial, the group permission were rw and the user running this was a member of serial, then you would not need to use sudo.
|
|
|
|
06-03-2010, 11:47 AM
|
#8
|
|
LQ Newbie
Registered: Jun 2010
Posts: 2
Rep:
|
Quote:
Originally Posted by blackhole54
It seems to me the basic problem is the lack of newlines in your data stream...
|
I want to read some data from /dev/ttyS0 and code from blackhole54 is inspirational.
But variables in while loop is only local and it is not usable in next code.
It is good to see in next simplified code:
Code:
MAX_CHARS=100
CNT=0; SECOND=FALSE; PAIR="abc"
echo dfghfhuguhyou235v | while read -n1 CHAR; do
let "CNT += 1"
[ $CNT -gt $MAX_CHARS ] && break
case $CHAR in
[a-zA-Z]) PAIR=$CHAR; SECOND=TRUE; continue;;
[0-9]) [ $SECOND != TRUE ] && continue || PAIR=$PAIR$CHAR; SECOND=FALSE;;
*) SECOND=FALSE; continue;;
esac
echo 1: $PAIR $CNT/$MAX_CHARS
# The $PAIR variable now contains a letter followed by a number, which you can
# use as you see fit.
done
echo 2: $PAIR $CNT/$MAX_CHARS
This script writes:
1: u2 14/100
2: abc 0/100
But it should writes:
1: u2 14/100
2: u2 14/100
I want to use data in variable $PAIR and $CNT "global", but I don't know what is need to change.
|
|
|
|
06-03-2010, 01:33 PM
|
#9
|
|
LQ Newbie
Registered: Jun 2010
Posts: 2
Rep:
|
More simplified code:
Code:
#!/bin/bash
P=1
echo abc | while read -n1 CHAR; do
P=$P$CHAR
echo -n $P,
done
echo;echo $P
Writes:
1a,1ab,1abc,1abc,
1
Should writes:
1a,1ab,1abc,1abc,
1abc
Note: In real code is "cat /dev/ttyS0" instead "echo abc".
It is only for test.
|
|
|
|
06-03-2010, 11:23 PM
|
#10
|
|
LQ 5k Club
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Debian Squeeze (server), Slackware 13.37 (netbook), Slackware64 14.0 (desktop),
Posts: 8,357
|
Quote:
Originally Posted by bizonik
But variables in while loop is only local and it is not usable in next code.
|
The solution is to avoid having the while command in a pipe:
Code:
while read -n1 CHAR
do
<whatever you want to do>
done < /dev/ttyS0
That loop will hang waiting for input from /dev/ttyS0. There is a timeout option for the read command which you may find useful. AFAIK there is no way to implement a "non-blocking" read in shellscript so read with a short timeout is the closest approximation that is simply achievable.
|
|
|
|
06-08-2010, 07:01 AM
|
#11
|
|
Senior Member
Registered: Mar 2006
Posts: 1,896
Rep:
|
Quote:
Originally Posted by bizonik
I want to read some data from /dev/ttyS0 and code from blackhole54 is inspirational.
But variables in while loop is only local and it is not usable in next code.
It is good to see in next simplified code:
Code:
MAX_CHARS=100
CNT=0; SECOND=FALSE; PAIR="abc"
echo dfghfhuguhyou235v | while read -n1 CHAR; do
let "CNT += 1"
[ $CNT -gt $MAX_CHARS ] && break
case $CHAR in
[a-zA-Z]) PAIR=$CHAR; SECOND=TRUE; continue;;
[0-9]) [ $SECOND != TRUE ] && continue || PAIR=$PAIR$CHAR; SECOND=FALSE;;
*) SECOND=FALSE; continue;;
esac
echo 1: $PAIR $CNT/$MAX_CHARS
# The $PAIR variable now contains a letter followed by a number, which you can
# use as you see fit.
done
echo 2: $PAIR $CNT/$MAX_CHARS
This script writes:
1: u2 14/100
2: abc 0/100
But it should writes:
1: u2 14/100
2: u2 14/100
I want to use data in variable $PAIR and $CNT "global", but I don't know what is need to change.
|
catkin correctly identified your problem and the solution: if you use a pipe to get the information into the while loop, then the while loop runs in a subprocess and any changes to the variables occuring in the while loop cannot be seen outside it. If you bring the information into the while loop by redirecting it from the done statement, then everything is the same process and changes to variables will persist.
The following modification to your script illustrates this (I've highlighted modifications in red, put typed commands in bold and added a blank line for readability):
Code:
$ cat /tmp/test
#!/bin/bash
MAX_CHARS=100
CNT=0; SECOND=FALSE; PAIR="abc"
while read -n1 CHAR; do
let "CNT += 1"
[ $CNT -gt $MAX_CHARS ] && break
case $CHAR in
[a-zA-Z]) PAIR=$CHAR; SECOND=TRUE; continue;;
[0-9]) [ $SECOND != TRUE ] && continue || PAIR=$PAIR$CHAR; SECOND=FALSE;;
*) SECOND=FALSE; continue;;
esac
echo 1: $PAIR $CNT/$MAX_CHARS
break
done < <(echo dfghfhuguhyou235v)
echo 2: $PAIR $CNT/$MAX_CHARS
$ /tmp/test
1: u2 14/100
2: u2 14/100
Note that I used a bash feature called process substitution to redirect the information into the loop. Some (most?) other shells don't have this feature so if you are using a different shell you may have to find a different way to redirect into the loop. I also added a break statement after a pair was matched -- otherwise additional iterations of the loop would destroy the values of the variables you were looking for.
If you really want/need to pipe the information into the loop instead of redirect it, the only thing I know is to have the loop write the info to a file and then read it back out of the file when you are out of the loop. It's a bit ugly, but it works.
Last edited by blackhole54; 06-08-2010 at 07:06 AM.
|
|
|
|
| Thread Tools |
Search this Thread |
|
|
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -5. The time now is 02:55 AM.
|
|
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.
|
Latest Threads
LQ News
|
|