How do I capture responses from the chat command?

Unfortunately googling the word 'chat' gives you zebedee billion responses that relate to everything and few of them refer to the linux chat command. I've read the man page and found a couple of examples but can't see how to do this.

I want to query the modem for it's manufacturer, product id and firmware version using AT commands. I can get the modem to respond as expected to the commands if initiated using chat, however I can't see how to get the response into a bash variable for me to work on it.

for example

chat -V -s '' 'AT+CGMI' 'OK' '' > $COMPORT < $COMPORT 

gives me the onscreen response I am looking for, however using a RESPONSEVALUE=`chat....` just gives me an empty variable.

Any ideas anyone?

Google chat.c, there is a bsd version with a -r option for a report file, or you can add it. There is an inactive sourceforge file. Some versions send the dialog to syslog.

1 Like

What function does 'chat' serve in this? You should just be able to talk to the modem.

#!/bin/sh
# set up modem device to translate outgoing \n into \r\n
stty -F /dev/ttyS0 9600 -echo igncr icanon onlcr
# Open modem for reading and writing
exec 5</dev/ttyS0
exec 6>/dev/ttyS0

echo "AT+CGMI" >&6

# Eat the echo, then eat the blank line
read <&5 ; read <&5
# Read the actual response
read RESPONSE <&5

echo "Response was $RESPONSE"

# close the files
exec 5<&-
exec 6>&-
$ ./modem.sh
Response was ERROR
$

...mine returns 'ERROR' because it's not a cellphone so AT+CGMI means nothing to it. It responds 'OK' to plain 'AT'. Works in BASH, KSH, and ASH. If you have trouble, try 'cat <&5' to see what it's printing.

The version I'm using is supposed to support the REPORT file, however I'll be darned if I can get it to work.....

If I could find any working examples I could at least try to see if my syntax is correct.....

for example..

chat -Vs ' ' 'AT+CGMI' 'OK' ' ' > $COMPORT < $COMPORT

gives me the response

Ericsson

OK

However

chat -Vsr /path/to/outputfile REPORT ' ' 'AT+CGMI' 'OK' ' ' > $COMPORT < $COMPORT

gives me

Failed

I've tried variations on where to place the word REPORT without success.....it's annoying to be honest.

---------- Post updated at 01:29 PM ---------- Previous update was at 01:25 PM ----------

I had thought about going this way but the problem is that if the modem throws anything other then what's expected I could miss the error...for example (understandably) the normal response requires dropping the first two lines from read <&5 however if there's an error state I may never get to see it.

What I really want to do is capture all the response from the modem and then start to code the analysis of said response.

Thanks for the idea but hopefully you can see my concern.

You don't have to throw the output away, you know. I just did so to make the example small... As for capturing 'all' the output of the modem, it really doesn't tell you when it ends, so chat's not doing anything you can't. I still think common utilities are preferred over something so ossified it's undocumented and/or dropped by half the UNIX world..

If you want it to show up as whole whacks of text at once you can do this:

$ cat modem.sh
#!/bin/bash
function get_response
{
        local ECHO
        # cat will read the response, then die on timeout
        cat <&5 >$TMP &
        echo "$1" >&5
        # wait for cat to die
        wait $!
        # Check if the modem echoed our command
        read ECHO <$TMP
        [ "$ECHO" != "$1" ] && return 1
        return 0
}

TMP="./response"

# Clear out old response
: > $TMP

# Set modem with timeout of 5/10 a second.  Things reading will read until
# data stops, wait 1/2 second, then quit.
stty -F /dev/ttyS0 9600 -echo igncr -icanon onlcr ixon min 0 time 5

# Open modem on FD 5
exec 5<>/dev/ttyS0

get_response "AT+CGMI" || echo "Bad response"
echo "Response was:"    ;       cat $TMP

get_response "AT" || echo "Bad response"
echo "Response was:"    ;       cat $TMP

exec 5<&-

$ ./modem.sh
Response was:
AT+CGMI

ERROR
Response was:
AT

OK
$

I simplified it a lot using features from ksh/zsh/bash, particularly functions and the exec 5<>/dev/ttyS0 which lets you read and write to the same FD.

---------- Post updated at 10:26 AM ---------- Previous update was at 10:00 AM ----------

this is kind of fun

#!/bin/bash

function get_response
{
        local ECHO
        # cat will read the response, then die on timeout
        cat <&5 >$TMP &
        echo "$1" >&5
        # wait for cat to die
        wait $!

        exec 6<$TMP
        read ECHO <&6
        if [ "$ECHO" != "$1" ]
        then
                exec 6<&-
                return 1
        fi

        read ECHO <&6
        read RESPONSE <&6
        exec 6<&-
        return 0
}

TMP="./response"

# Clear out old response
: > $TMP

# Set modem with timeout of 5/10 a second
stty -F /dev/ttyS0 9600 -echo igncr -icanon onlcr ixon min 0 time 5

# Open modem on FD 5
exec 5<>/dev/ttyS0

get_response "AT+CGMI" || echo "Bad response"
echo "Response was '${RESPONSE}'"       ;       cat $TMP

echo

get_response "AT" || echo "Bad response"
echo "Response was '${RESPONSE}'"       ;       cat $TMP

exec 5<&-

$ ./modem.sh
Response was 'ERROR'
AT+CGMI

ERROR

Response was 'OK'
AT

OK
$
1 Like

Corona688

Thanks for the ideas but I'm afraid the way you're suggesting doesn't work, not because of your code but instead the 'inconsistency' of the way the modem(s) outputs the data. Some insert line feeds or carriage returns at different places and it requires too much 'pre management' to account for all the variables.

I have found a sort of way to do it with chat, I cannot get REPORT to work and suspect it's the same problem as above, however by using the -v option the output gets pushed to the /var/log/messages logfile and I can pick up what I want from there.

So my last step is how to do the following....

The modem gets reset and as a result the 'timing' of when it comes back stable is variable. The only way I've identified to be certain it's back is an entry in the var/log/messages file that reads "now managed".

So what I wanted to do was something like....

while [ ` tail -f /var/log/messages | read -r LINE | echo "$LINE" | grep "now managed" ` ]; do

echo got here

done

I realise the above line won't work but has anyone previously written a bit of code that keeps reading /var/log/messages till a specific message comes up and then continue running the script?

Thanks in advance.

Maybe you need a pseudo-terminal to capture /dev/tty writes/reads, like expect, rsh, ssh sessions.

1 Like

I managed to get it all working by pulling the data from /var/log/messages.

Even though my version of chat is supposed to support REPORT I couldn't get it working properly and there's little if any working examples out there that I could find.

The intrinsic problem with serial comms is that the handshaking is never very reliable and using anything other then chat too often leads to a 'hanging' state in the script which is waiting for something to happen or didn't receive an ACK properly.

Thanks for everyone's suggestions and help.

In case you didn't read it too closely, my last couple versions of my serial comms script included -- and relied on -- TTY timeouts. If any serial read hung it would just die after a configurable number of tenths of a second.

Reading from /var/log/messages sounds like a very poor solution. For one thing, it could break from changing the configuration of your system logger and isn't likely to work on a system where it differs even slightly. For another thing this means your serial communications program probably needs root access to work!