TracNav
- Home
- Research Overview
- MPhil Information
Research Projects
- Wireless Comms
- Bat System
- Broadband Phone
Visual tags
- Sentient Vehicles
- Task Assignment
- NLMaP
- Computing for the Future of the Planet
- SESAME
- Active Floor
- Open-Source CSK Energy
Development Info
DTG Local Pages
- Cambridge Weather
- Contact Details
Sending SMS using Vodafone 3G datacard
Author: Tom Craig
This page describes how to send SMS (i.e. text messages) programmatically using a Vodafone 3G datacard, and chronicles some pitfalls to avoid.
If you're in a hurry, jump to the bottom of the page for the Perl.
Note: SMSs are not normally included in your data allowance. Vodafone's current charge is £0.102 per SMS.
Required AT commands
To get the card to send SMS, you need to issue AT commands to it. I recommend you check they work using a modem control program such as Minicom (for Linux) or HyperTerminal (for Windows) before you try to call them programmatically (which I describe below).
The following sequence of commands worked for me:
AT&F # reset card to factory settings ATE1 # (optional) echo commands locally AT+CPMS="SM" # (optional) store message on the SIM card AT+CMGF=1 # use text format (much friendlier than the alternative format, PDU) AT+CSCA="+447785016005" # SMS centre number (my card defaulted to none) AT+CMGS="+441234567890" # recipient's number
In general,
- an AT attribute (e.g. AT+CPMS) followed by ? gives the current setting for that attribute;
- an AT attribute followed by =? gives all possible settings for that attribute;
- an AT attribute followed by =foo sets that attribute to foo.
Points that tripped me up:
- You need to get your device and baud rate right!
- When sending SMS programmatically, I experienced problems when sending messages above 80 characters. I'm guessing this is something to do with terminal width, and possibly just a bug in the Perl library I was using. Whatever the cause, I circumvented this by splitting the message into 79-character blocks, as in the Perl code below.
- My card defaulted to no SMS centre number - i.e. no number to dial in order to relay SMS to the recipient. Googling for "Vodafone SMSC" soon revealed it. (N.B. Wikipedia's SMSC article links to a long list of these numbers, but I found the Vodafone UK number to be wrong/out-of-date.)
- I'd sometimes accidentally lock the datacard. To unlock it, from the command line issue cardctl status and cardctl ident to identify which card to reset, and then cardctl eject n and cardctl insert n, with the socket number you identified for n, to reset it.
If you want to use PDU format, this page is helpful, or this page if you speak German (!). You'll need to issue AT+CMGF=0 rather than =1 as above. Beware the 7-bit alphabet!
Sending AT Commands using Perl
You'll need some means of interfacing with the datacard from Perl. I used the Device::Modem library from CPAN (for which I first needed to install Device::SerialPort).
I then used the following code to send SMS:
#!/usr/bin/perl
#
# Function for sending an SMS.
#
use strict;
use Device::Modem;
sub sendSMS
{
my $message = $_[0];
my $PORT = "/dev/vodafone2";
my $BAUDRATE = 9600;
my $SMSC = "+447785016005";
my %RECIPIENTS = (
tom => "+440123456789",
dick => "+440123456789",
harry => "+440123456789"
);
my $modem = new Device::Modem( port => $PORT );
$modem->connect( baudrate => $BAUDRATE ) || die "Could not connect to $PORT\n";
foreach my $phone_number (values %RECIPIENTS) {
# send messages to modem to prepare to send a message
$modem->atsend("AT&F\r\n");
print $modem->answer();
$modem->atsend("ATE1\r\n");
print $modem->answer();
$modem->atsend("AT+CPMS=\"SM\"\r\n");
print $modem->answer();
$modem->atsend("AT+CMGF=1\r\n");
print $modem->answer();
$modem->atsend("AT+CSCA=\"" . $SMSC . "\"\r\n");
print $modem->answer();
$modem->atsend("AT+CMGS=\"" . $phone_number . "\"\r\n");
print $modem->answer();
# split message into blocks of $BLOCK_SIZE characters
my $BLOCK_SIZE = 79;
my $tmpmsg = $message;
my $block;
my @splitmsg;
while (length($tmpmsg) > 0) {
$block = substr($tmpmsg, 0, $BLOCK_SIZE, "");
push @splitmsg, $block;
}
# send each block
for (@splitmsg) {
$modem->atsend($_);
if ($modem->answer() =~ /ERROR/) {
sendSMS($message);
goto STOP;
}
}
# end the message with a Ctrl+Z character
my $ctrlz = chr(26);
$modem->atsend("\r\n$ctrlz");
if ($modem->answer() =~ /ERROR/) {
sendSMS($message);
}
STOP:
}
}
What I don't know
I'd be interested to know the answers to the following (although evidently not so interested that I've found out for myself!):
- I issue AT+CPMS="SM", but is the message saved by default or do I have to issue a command to save it?
