ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
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.
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.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
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.
Distribution: Debian /Jessie/Stretch/Sid, Linux Mint DE
Posts: 5,194
Rep:
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.
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
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.
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)
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.
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. . .
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.
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...
@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?
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.
Newbie here at using Serial or Parallel communication, but, I've seen 01000111 post and thought of posting my question here.
I have a need to generate either a bash script or a c executable to energize the coin on a relay to drop power to my remote DSL modem when TCP/IP communication is lost.
I have the code working well to detect loss of TCP/IP communication, but have no idea how to write a script or c executable to cause the DTR or CTS lines (RS232) to go high and trigger a low current low voltage coil via a call from my bash script.
Could a kind soul assist me as to what I could modify on 01000111 script to cause my desired effect for say 2-5 sec interval so that the DSL modem would reboot?
Many thanks for any advise, examples or ideas on how I can do this.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.