Thursday, October 20, 2011

Sending SMS via GPRS modem using Perl Device::SerialPort

Sometimes ago, I posted a script to send SMS using Gammu. Now, I would like to deep dive on the underlying communication to GPRS modem using AT command to send SMS.

The sequence of AT commands to use are:
  • ATZ : Reset modem 
  • ATE0 : Disable echo (not necessary)
  • AT+CMGF : Setting the SMS mode (Text or PDU) 
  • AT+CSCA : Query or set the SMS center number 
  • AT+CMGS: Send SMS 
To cut the story short, here is the example of Perl script I use to send SMS using a GPRS modem.Note that checks have been omitted for brevity.

#!/usr/bin/perl
use POSIX;
use Device::SerialPort;

$modem_dev="/dev/ttyS1";
# change it to your mobile network SMSC number.

$smsc="+62811000000";

# to read modem response
sub readModem
{
    if (!defined $_[0])
    {
        return;
    } else {
        my $tmout = 2;
        my $ret = "";
        while ($tmout>0)
        {
            my ($cnt,$saw) = $_[0]->read(255);
            if ($cnt>0)
            {
                $ret.=$saw;
            } else {
                $tmout--;
            }

            select(undef,undef,undef,0.2);
        }
        return $ret;
    }
}


$modem = Device::SerialPort->new($modem_dev);
if (defined $modem)
{
    $modem->databits(8);
    $modem->baudrate(115200);
    $modem->parity("none");
    $modem->stopbits(1);
    $modem->stty_echo(0);
    $modem->read_char_time(0); # don't wait each char
    $modem->read_const_time(500); # spend 500ms to read data from serial line
} else {
    print "Modem ".$modem_dev." is not available.\n";
    exit();
}
 

$phone = $ARGV[0];
$msg = $ARGV[1];

$modem->write("ATZ\r\n");

$str = &readModem($modem);

$modem->write("ATE0\r\n");
$str = &readModem($modem);
 

$modem->write("AT+CMGF=1\r\n");
$str = &readModem($modem);
 

$modem->write("AT+CSCA=\"$smsc\",145\r\n");
$str = &readModem($modem);
 

# Some modems requires \r\n  for this command
$modem->write("AT+CMGS=\"".$phone."\"\n");
#$modem->write("AT+CMGS=\"".$phone."\"\r\n");
$str = &readModem($modem);
# wait for 2 second for the prompt to appear
select(undef,undef,undef,2);\" : ".$str."\n";

$modem->write($msg.pack('c',26));

sleep(2);
$str = &readModem($modem);

$modem->close();


To use this script, you need to pass 2 arguments which are phone number as the first argument and the message as the second argument.
e.g:
# ./sendSMS "+62812344556" "Test SMS via Perl"

I hope this could help.

No comments: