LinuxQuestions.org
Support LQ: Use code LQCO20 and save 20% on CrossOver Office
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
 
LinkBack 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: 360

Rep: Reputation: 47
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 Etch/Lenny/Squeeze
Posts: 3,485

Rep: Reputation: 308Reputation: 308Reputation: 308Reputation: 308
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 10.04, Crunchbang Statler
Posts: 3,325

Rep: Reputation: 168Reputation: 168
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.
 
  


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
Trackbacks are Off
Pingbacks are On
Refbacks are 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 03:53 PM.

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
Open Source Consulting | Domain Registration