LinuxQuestions.org
Visit Jeremy's Blog.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 06-03-2009, 02:55 PM   #1
01000111
LQ Newbie
 
Registered: Jun 2009
Posts: 3

Rep: Reputation: 0
Unhappy Serial port I/O with Bash?


Greetings all,
I am attempting to write a script to communicate with a photovoltaic inverter via a serial port on a Damn Small Linux PC. The inverter reads/writes binary data, and I've figured out how to handle that via od and awk, but I can't seem to actually communicate with the inverter. I know it works 'cause if I reboot my DSL PC to WinXP, I have a VBScript that works just fine... so communication and hardware is not the issue. Please take a look at the following and let me know if you have any suggestions. Right now, whenever I try to read from /dev/ttyS0, the script just hangs. The lines below that start with ####### are all my attempts so far, and they all hang. The last ###### is what I expect to get back from the inverter.

Thanks in advance,
01000111


#!/bin/bash
stty -F /dev/ttyS0 raw ispeed 2400 ospeed 2400 cs8 -ignpar -cstopb -echo

#Get total watt-hours generated
echo $'\x80\x80\x80\x01\x01\x01\x11\x14' > /dev/ttyS0
######read -n 1 InStr < /dev/ttyS0
######InStr=`dd if=/dev/ttyS0 count=1 bs=1`
######(cat > InStr) < /dev/ttyS0
######InStr=$'\x80\x80\x80\x03\x01\x01\x02\x03\x04\xff'
InStrLen=${#InStr}
for ((x=0;x<$InStrLen;x++)); do
let z=0x$(echo -n ${InStr:x:1} | od -h | awk '{ print $2 }')
echo -n $z...
done
if [ ${InStr:0:6} = $'\x80\x80\x80\x03\x01\x01' ]; then
let a=0x$(echo -n ${InStr:6:1} | od -h | awk '{ print $2 }')
let b=0x$(echo -n ${InStr:7:1} | od -h | awk '{ print $2 }')
let c=0x$(echo -n ${InStr:8:1} | od -h | awk '{ print $2 }')
WattsTotal=$[(($a*256)+$b)*10**$c]
fi
echo TOTAL: $WattsTotal
 
Old 06-03-2009, 03:45 PM   #2
harry edwards
Member
 
Registered: Nov 2007
Location: Lincolnshire, UK
Distribution: CentOS, Fedora, and Suse
Posts: 365

Rep: Reputation: 48
Do you get the response with a simple test i.e.
Code:
stty -F /dev/ttyS0 raw ispeed 2400 ospeed 2400 cs8 -ignpar -cstopb -echo
cat < /dev/ttyS0 &
echo $'\x80\x80\x80\x01\x01\x01\x11\x14' > /dev/ttyS0
 
Old 06-04-2009, 07:23 AM   #3
01000111
LQ Newbie
 
Registered: Jun 2009
Posts: 3

Original Poster
Rep: Reputation: 0
Quote:
Originally Posted by harry edwards View Post
Do you get the response with a simple test i.e.
Code:
stty -F /dev/ttyS0 raw ispeed 2400 ospeed 2400 cs8 -ignpar -cstopb -echo
cat < /dev/ttyS0 &
echo $'\x80\x80\x80\x01\x01\x01\x11\x14' > /dev/ttyS0
I tried:
Code:
cat < /dev/ttyS0 `echo $'\x80\x80\x80\x01\x01\x01\x11\x14' > /dev/ttyS0`
but that hangs too.
 
Old 06-04-2009, 08:24 AM   #4
jlinkels
Senior Member
 
Registered: Oct 2003
Location: Bonaire
Distribution: Debian Lenny/Squeeze/Wheezy/Sid
Posts: 4,164

Rep: Reputation: 506Reputation: 506Reputation: 506Reputation: 506Reputation: 506Reputation: 506
I am not really familiar with reading and writing thru /dev/ttyS0, but I assume you simple echo to it and read from it and everything else is handled on a lower level by the device driver.

First question is of course if the serial port is configured correctly at works at all. You can connect pin 2 and 3 of the serial connector on the PC as to make a loopback plug. Everything you write to the port should be echoed and read again by your script.

If this does not happen, it is useless to try to talk to the inverter.

If this works, are you sure that there is no additional protocol being used to talk to the inverter? Often it is something like STX at the beginning, some DLE's and EOT's at the end of the transmission, often with checksums etc.

Also a great help is a device called break-out box or Interfaker which has LED's for all important serial signals, and you can force signals like DTR and DSR active or inactive. With the LED's you can see if anything is transmitted ar all and if the status of the handshake lines is satisfactory.

jlinkels
 
Old 06-04-2009, 11:09 AM   #5
01000111
LQ Newbie
 
Registered: Jun 2009
Posts: 3

Original Poster
Rep: Reputation: 0
Lightbulb

I've made some progress. I'm getting data back from the inverter now. Turns out that one of my \x01 needed to be \x00. This caused a problem with null characters, but printf solved that.... I think. The problem I'm having now is that I appear to be getting 'random' responses from the inverter. I get different length responses (anywhere between 1 and 5 bytes) and almost never the same response twice. The fact that I'm getting anything at all indicates that my message TO the inverter is working. If I change it to a badly formatted message (such as changing the last byte to a incorrect checksum) I get nothing. So, here's what I have (the commented line is what I expect):

Code:
#!/bin/bash
stty -F /dev/ttyS0 raw ispeed 2400 ospeed 2400 cs8 -ignpar -cstopb eol 255 eof 255

#Get total watt-hours generated
printf "\x80\x80\x80\x00\x01\x01\x11\x13" > /dev/ttyS0
eol=0
ff=$'\xff'
until [ $eol -eq 1 ]; do
    echo -n .
    read -r -d $ff -n 1 -t 2 OneByte < /dev/ttyS0
    eol=$?
    InStr=$InStr$OneByte
done
echo $InStr
######InStr=$'\x80\x80\x80\x03\x01\x01\x11\x01\x02\x03\x18'       
InStrLen=${#InStr}
for ((x=0;x<$InStrLen;x++)); do
    let z=0x$(echo -n ${InStr:x:1} | od -h | awk '{ print $2 }')
    echo -n $z...
done
if [ $InStrLen -gt 8 ]; then
    if [ ${InStr:0:7} = $'\x80\x80\x80\x03\x01\x01\x11' ]; then
        let a=0x$(echo -n ${InStr:7:1} | od -h | awk '{ print $2 }')
        let b=0x$(echo -n ${InStr:8:1} | od -h | awk '{ print $2 }')
        let c=0x$(echo -n ${InStr:9:1} | od -h | awk '{ print $2 }')
        let WattsTotal=$[ (($a*256)+$b)*10**$c ]
    fi
fi
echo TOTAL: $WattsTotal
 
Old 06-05-2009, 10:31 AM   #6
Wim Sturkenboom
Senior Member
 
Registered: Jan 2005
Location: Roodepoort, South Africa
Distribution: Slackware 10.1/10.2/12, Ubuntu 12.04, Crunchbang Statler
Posts: 3,786

Rep: Reputation: 282Reputation: 282Reputation: 282
If I understand your code (I'm not a bash scripter),you stop when there's nothing to read (eol=$? and test $eol).

This however does not mean that you have received a complete message (you might be reading to early). So if you know that a message has a fixed length or a specific terminator, I would read till you have the full message (count bytes or set n to 8 or OneByte equals whatever) and ignore $eol for that purpose.

What probably happens now:
the second time you run the program, you still receive data from the previous run.

Hope this helps

Last edited by Wim Sturkenboom; 06-05-2009 at 10:42 AM.
 
Old 07-23-2012, 12:05 PM   #7
wollik
LQ Newbie
 
Registered: Jul 2011
Posts: 1

Rep: Reputation: Disabled
Smile Reading binary data via tty

Hi 01000111,
I got a similar situation in reading binary data with my embedded Linux environment. Since this sytem is ARM based I can't do the reading wit a C-program because of the missing cross toolchain for mipsel.

So I try to read via the shell but can't get any succsess.

My Inverter sends every 4,8 seconds the PV data without beeing polled like in your example. In the other times there are fill bytes send. My problem is that my inverter sends binary data and no linefeed or CR. I have to check every byte to see if this is the start of a PV-Record but can't get any byte read in via my shell.

My version of the read also don't supports the -d command so I can't use the startbyte as a line delimiter.
I just want to continious read from the tty-port one byte, but can't get any of it.

Did you get your environment to run ?

I there just someone here in the forum that can help me on this ?

Doing a:

cat /dev/ttyS0 | hd -c

(assuming there is permanent binary data with no LF or CR)


Regards
WolliK
 
Old 10-29-2012, 11:05 AM   #8
pcpostar
LQ Newbie
 
Registered: Sep 2010
Posts: 4

Rep: Reputation: 0
Quote:
I just want to continious read from the tty-port one byte, but can't get any of it.
Did you make any progress on this subject. I have the same difficult. I used command:
READ -n 1 character < /dev/tts/1
The READ command reply with illegal option -n.
 
Old 10-29-2012, 12:07 PM   #9
sundialsvcs
Guru
 
Registered: Feb 2004
Location: SE Tennessee, USA
Distribution: Gentoo, LFS
Posts: 5,401

Rep: Reputation: 1119Reputation: 1119Reputation: 1119Reputation: 1119Reputation: 1119Reputation: 1119Reputation: 1119Reputation: 1119Reputation: 1119
Have no idea under the sun why you are using Bash for this. Use a real programming language. Even on DamnSmall, you have literally a dozen or more to choose from. . .
 
Old 10-29-2012, 07:50 PM   #10
theNbomr
LQ 5k Club
 
Registered: Aug 2005
Distribution: OpenSuse, Fedora, Redhat, Debian
Posts: 5,395
Blog Entries: 2

Rep: Reputation: 903Reputation: 903Reputation: 903Reputation: 903Reputation: 903Reputation: 903Reputation: 903Reputation: 903
sundialsvcs is correct. Serial IO invariably requires the use of the termios API, and shells lack that capability. Some things just shouldn't be done with shell scripts.

--- rod.
 
Old 10-29-2012, 11:39 PM   #11
Wim Sturkenboom
Senior Member
 
Registered: Jan 2005
Location: Roodepoort, South Africa
Distribution: Slackware 10.1/10.2/12, Ubuntu 12.04, Crunchbang Statler
Posts: 3,786

Rep: Reputation: 282Reputation: 282Reputation: 282
Please realize that this thread is old (and revived in june 2012 by wollik).

@wollik
have you tried a standard program like minicom just to see if you get something in?
 
Old 10-31-2012, 04:56 PM   #12
pcpostar
LQ Newbie
 
Registered: Sep 2010
Posts: 4

Rep: Reputation: 0
Thank you for your answers. OK, i know that with some other programing languages it could be done more easily.

But I'm not a programer, and I'm not very familiar with Linux programing.

So what would you suggest me to use? i need really a simple program, that would continuously read from serial byte by byte and write to text file. That's all.

all other work is already done.

I'm doing my thesis at faculty and this is just some part. I'm doing something completely different and this reading from serial is just a small sub-problem...

Would anyone help me with that?
 
Old 10-31-2012, 06:14 PM   #13
pcpostar
LQ Newbie
 
Registered: Sep 2010
Posts: 4

Rep: Reputation: 0
Quote:
Originally Posted by Wim Sturkenboom View Post
@wollik
have you tried a standard program like minicom just to see if you get something in?
I've tried reading from serial. I'm getting data in. The thing is, that all the commands are waitng for carriage-return. But for protocol that i use, it shouldn't wait for CR. It should read every byte by byte.

Programs such as minicom, microcm, picocom... can they read byte by byte? I tried to play arround with them, but i couldn't get any data to be read from serial?
 
Old 11-01-2012, 08:39 AM   #14
theNbomr
LQ 5k Club
 
Registered: Aug 2005
Distribution: OpenSuse, Fedora, Redhat, Debian
Posts: 5,395
Blog Entries: 2

Rep: Reputation: 903Reputation: 903Reputation: 903Reputation: 903Reputation: 903Reputation: 903Reputation: 903Reputation: 903
With the port in raw mode, the port should not wait for line terminators. In that case, I think read will get however many bytes are waiting in the receive buffer. How are the replies from your device delimited? Generally, these kinds of devices either send some kind of terminator, or send chunks of fixed-size data. If I understand your code correctly, you terminate reading data byte-at-time and appending to $InStr as soon as read times out once. Are you sure that your timeout is not too short? Would it make more sense to compose your $InStr until it of the length you require?

--- rod.

EDIT: Crap! I just replied to the OP, which probably doesn't apply to the person who first necroposted to this thread.
The answer to his/her question cannot be given without more information, whihc should be provide by starting a new thread, with more details.

Last edited by theNbomr; 11-01-2012 at 08:45 AM.
 
  


Reply

Tags
bash, read, serial port, write


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Creating a bash script with serial port input Elv13 Linux - Hardware 10 06-08-2010 07:01 AM
Should be dead simple - read/write serial port from bash ericcarlson Linux - Software 3 10-21-2006 08:35 PM
Bash Sleep vs crontab and bash serial port nutthick Programming 4 06-01-2006 02:42 AM
Using serial port card(PCMCIA) with IPAQ running Linux, can't find ttyS0 port d2army Linux - Laptop and Netbook 0 11-12-2005 08:07 PM
Why can't I read in data from the serial port using a bash script? tjt Linux - Newbie 1 06-17-2004 12:21 AM


All times are GMT -5. The time now is 08:40 AM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration