Useful info I learned from playing with GSM
NOTE: This has been sat in my unfinished folder
for a few years. It uses an OpenMoko Freerunner, which I’ve now mostly
replaced with a PinePhone.
General Setup
The following assumes serial access to a GSM modem. My phone runs Debian (QtMoko) and starts an OpenSSH server at boot, so I’ve been accessing the modem directly from Bash running on the phone. It’s probably possible to do something similar from a PC via a USB cable or Bluetooth, but I don’t know how since I’ve not needed to. Likewise I don’t know whether serial access can be shared through non-standard Linux setups (e.g. Android). I don’t know or care about proprietary systems (e.g. iOS).
Once you’ve got serial access, write down the relevant device name
somewhere handy, since we’ll be using it a lot. In my case this was
/dev/ttySAC0.
GSM Basics
GSM modems can be controlled by sending so-called “AT
commands” over a serial line.
Many programs can communicate over serial; I was happy piping
echo commands into socat (Debian package name
socat). I also played with the more specialised
gsmctl program (Debian package name
gsm-utils).
Note: One reason I was happy with echo
and socat is that I use shell-mode in Emacs to
run my terminals. This integrates well with TRAMP for SSH
(tab-completion, opening remote files, etc.) and makes it easy to edit,
search, find/replace, etc. my previous commands and their output. I
imagine that a normal terminal would be more painful to use, in which
case you might want to look for something more than echo
;)
Since we’re using serial, we might as well set the sending and receiving baud rate to a conservative 9600, to rule out a potential source of problems. The command I’ve been piping into is the following:
socat - file:/dev/ttySAC0,crtscts,crnl,ispeed=9600,ospeed=9600
As well as setting the baud rates, this ends each line with a
carriage return and newline (AKA “carriage return linefeed”, or CRLF).
This is unlike the default Unix/Linux convention of just using newline
(AKA linefeed). The - tells socat to read from
its standard input.
To avoid spurious errors I’ve been turning the GSM modem off and on
before sending commands, and waiting 2 seconds between commands. The
general script I’ve been using looks like the following (I call it
go), although this /sys path is specific to
the OpenMoko FreeRunner, yours will probably differ:
#!/bin/sh
set -e
echo "OFF"
echo 0 > /sys/bus/platform/devices/gta02-pm-gsm.0/power_on
sleep 2
echo "ON"
echo 1 > /sys/bus/platform/devices/gta02-pm-gsm.0/power_on
sleep 2
{
for C in "$@"
do
sleep 2
echo "SENDING $C" 1>&2
echo "$C"
done
sleep 4
} | socat - file:/dev/ttySAC0,crtscts,crnl,ispeed=9600,ospeed=9600
Here for C in "$@"; do ...; done will loop through each
argument of the script and send them as AT commands to the
modem.
AT Commands
AT commands get their name from the characters
AT that they begin with. Later extensions begin with
AT+. This prefix must be included when sending
commands!
Note: Some sites/listings (e.g. developershome.com) leave
off the prefix, saying things like “Syntax of the +CMGD
AT Command”. In this case the bytes we should send over the
serial line are not +CMGD, they are
AT+CMGD.
Some useful things to know, that may not be immediately obvious:
Commands can be given in upper or lowercase. I stick to uppercase.
Sending the command
ATon its own acts like a test; the modem should respondOK:
# ./go 'AT'
OFF
ON
^@^@^@AT-Command Interpreter ready
SENDING AT
AT
OK
Some commands require parameters. These are separated from the command using
=and (if there are multiple parameters) from each other using,.Parameters can often take the special value
?which queries for the available values. For example, theAT+CPMScommand tells the modem which “storage area” to use for SMS reading, writing and sending. We can query for the possible areas like this:
# ./go 'AT+CPMS=?'
OFF
ON
^@^@AT-Command Interpreter ready
SENDING AT+CPMS=?
AT+CPMS=?
+CPMS: ("ME","SM"),("ME","SM"),("ME","SM")
OK
Here we see (...),(...),(...) which tells us that there
are three parameters. Each parameter can either be "ME" or
"SM" (including the quotes!). In this case these represent
the modem’s storage and the SIM card, respectively.
We can choose between multiple levels of error verbosity using the
AT+CMEEcommand. This can take values0(just sayERROR),1(give a numeric error code) or2(give a meaningful error message). We might as well set this to2every time, by editing our script to always sendAT+CMEE=2SMS can be set to text mode or “PDU” (data) mode. Text mode is usually easier to understand, so we can have our script set that by default using
AT+CMGF=1
Now try sending some commands, good luck!