Sending an SMS from your Arduino

Posted 2015/01/01. Last updated 2015/01/03.

Getting started

While I was back home for the holidays, I decided to try and put to use one of our old Nokia phones. The idea was to fit it into an overall home security/automation project, the first step of which would be to automate sending an SMS. Though I have ordered a shield with the SIM900 chip, it has not yet arrived, and I wanted to see what I can get done with the tools already at my disposal.

While doing my research on the Internet, I came across a post detailing how you can use the TRS headphone plug of a Motorola C168i to issue Hayes AT commands, but unfortunately old Nokia phones do not support this. They instead use the FBus protocol, which is considerably more complicated, and there is surprisingly little information on using an Arduino to control Nokia phones, with the exception of this post using a Nokia 6150, and this post using a Nokia 3310.

Though both are great starting points, the phone that I had available, the Nokia 6310i, unfortunately uses different FBus "frames", despite having the same pinout as the Nokia 6150. Moreover, I only discovered the second reference while doing this write-up, but I decided to include it as it has gathered together a lot of the relevant documentation, though, again, for a phone with a different protocol. In practice, what this meant is that I would have to implement the portion of the FBus protocol that I was interested in, as the reference code did not work.

Making connections

The first step to connecting the phone to the Arduino is figuring out the connector pins. Thankfully, this page explains precisely what each one corresponds to. After soldering wires to pins 7-9 of the Nokia, you should end up with something like the picture below, where the blue wire corresponds to RX, the red wire to TX, and the brown wire to GND.

Nokia 6310i Soldered Wires

What we need to do is connect GND to GND, and cross RX and TX between the Arduino and the phone (as one should Receive what the other Transmits), but we need to be somewhat careful with the Arduino's TX pin, as it outputs 5V, while the phone operates at 3.6V. Both blog posts mentioned above create the same voltage divider by using two 330Ω resistors to reduce the output to 2.5V, but the reasoning is not particularly clear to me (UPDATE: According to Hans Peter Haastrup on Hackaday, this is because 2.5V is still considered a logical HIGH from the phone's perspective.). I instead used a 470Ω and a 240Ω resistor to output approximately 3.3V, as shown in the schematic below.

Schematic to connect Nokia 6310i to Arduino Mega

You might have noticed that the pinouts in the schematic correspond to Mega's Serial1 interface. While using the Mega is not necessary, it is better to use a hardware rather than a software serial for this project, and I wanted to maintain the Serial interface for debugging.

Making contact

With these connections in place, we are now ready to start communicating with the phone through the FBus protocol. Luckily for us, there is an excellent open-source tool, called gnokii that has been built for controlling Nokia phones through your computer. If you want to follow along, please download the latest version of the source code, and the Windows binaries if you are not on a *nix platform.

As a first step, what we are going to do is essentially use the Arduino as an intermediary since we don't have a USB-to-Serial adapter. For this, we are going to modify the standard MultiSerialMega sketch (also found in the Arduino IDE under File > Examples > 04. Communication) to use baud rates of 115,200 instead of 9,600.

The Gnokii binary also complains if the config file is missing. This can be placed in multiple standard locations (one of which is %userprofile%\gnokii.ini in Windows) or it can be specified with the --config option directly for the gnokii binary. For the Nokia 6310i, we want our config file to contain the following:

[global]
model = 6310i
port = COM3:
connection = serial

[logging]
debug = on

Two things are worth pointing out. First, the port corresponds to the port the Arduino is on (plus the colon for Windows. For *nix, it would probably look like /dev/serial/tty*). And second, it is important to turn debugging on to see how the FBus protocol works, and to help port the code to Arduino.

Now, we can finally issue our first command: gnokii.exe --identify. If all goes according to plan, the command will execute very quickly and you will see the messages exchanged, accompanied by identifying information, such as the phone's IMEI and Revision. However, you may get output that says Command failed or Command timed out. If that's the case, don't panic! The first instance is likely to be preceded by lines saying Couldn't open FBUS device: Result too large. In that case, verify that you Arduino is connected to your computer, that you have uploaded the modified MultiSerialMega sketch mentioned above, and that you have identified the correct serial port. In the second case, you may get output that says SM_Block: exiting the retry loop, or The fbus stream is out of sync. If so, verify that your connections correspond to the schematic presented above, and, if needed, hard-reset your Arduino.

Exploring the FBus

Now that we know that the connection is working, we should try to understand the protocol used to communicate these messages. The 6310i uses the same driver as the 6510, and they both use FBus version 2, which according to gnokii-0.6.31\Docs\protocol\nokia.txt is as follows (with some modifications for readability):

{FrameID, Dst, Src, MsgType, 0x00, FrmLen, {block}, FramesToGo, SeqNo, Padding?, ChkSum1, ChkSum2}
FrameID:     0x1c: IR / FBUS
             0x1e: Serial / FBUS
Dst, Src:    0x00: mobile phone
             0x0c: other end point
MsgType:     Depends on function and phone
FrmLen:      {block} + 2 (+ 1 if Padding)
FramesToGo:  0x01 means the last frame
SeqNo:       [0xXY]
                X: 4: first block
                   0: continuing block
                 Y: sequence number
Padding?:    0x00 if FrmLen odd, else doesn't exist
ChkSum1:     XOR on frame's odd positions
ChkSum2:     XOR on frame's even positions

Thus, in order to ask the phone over Serial to send an SMS (MsgType=0x02), the first 4 bytes to be sent are 0x1E, 0x00, 0x0C, 0x02. The fbus_send_message and the fbus_tx_send_frame functions in gnokii-0.6.31\common\links\fbus.c take care of the FBus header/footer, by setting everything except the message type and the actual blocks. Incidentally, these bytes are also not shown in the debug output by gnokii, so we ignore them for now. The code for sending an SMS from our phone is found at gnokii-0.6.31\common\phones\nk6510.c and specifically at the NK6510_SendSMS function (which sets up a further SMS header) and the sms_encode function which contains the meat of creating the frame blocks.

After some further header set-up (which in reality corresponds to data structures which are already populated elsewhere and are hard to track), the data comes in 4 blocks, all of which have some header and/or footer bytes, but I will refer you to my code instead of discussing them in detail for the sake of brevity. The first block is the number you want to send a message to, packed in "semi-octet" representation, which means that each digit is represented in 4 bits, and 2 digits are packed together in one byte (the order is flipped). The second block is the SMS Center number, a unique number corresponding to the carrier associated with the particular SIM card. Though for the most up-to-date number you should contact your provider (or search their forums), you can try this page as a backup. In reality you can obtain this number through further FBus commands, but this would get slightly out of hand for such an introductory project. The third block contains the actual text message, though it uses a 7-bit alphabet, and packs values together. What this means is that the most significant bit (MSB) is ignored (for ASCII this is always 0), and the missing high-order bits are replaced by the next character's low-order bits (see below). Finally, the fourth block contains information regarding the validity period of the message.

The (redacted) screenshot below shows the gnokii output for a sample SMS message. It is missing the header bytes 1E 00 0C 02 00 38 (where 02 is the SMS message type and 38 is the frame length) and the footer bytes 01 60 9D EC, indicating that FramesToGo=0x01, SeqNo=0x60 corresponds to a first block, there is no padding, and that the two checksum values are 0x9D and 0xEC.

Test message output by Gnokii

The first 9 bytes of the message shown above are also header information and should always be the same. The 01 02 bytes indicate that this will be one big block of type submit. They are followed by the message length, as well as 6 fixed bytes, the last of which (04) is the number of blocks as explained above.

The next 12 bytes (between the two 82 bytes) represent the recipient number. 82 indicates that this is a number, 0c is a length field that may change but usually stays fixed, 01 indicates that this is the first number, and is followed by two more length fields. The 91 indicates that this is an international number, and is followed by the country code for Greece, which is +30 (note how the order of the semi-octets is reversed to 03). This is followed by the actual number in the same representation.

The 12 bytes after it (from the 82 up to the last 00 before 80) are similar, but for the SMSC number. The third byte is 02 (as it is the second number), and the bytes after 91 correspond to Cosmote's +3097100000 SMSC number.

The 80 byte indicates the beginning of the user data, followed by 3 length bytes. The D4 F2 9C 0E corresponds to the word "Test". Specifically, the ASCII values for the word are 54 65 73 74, which correspond to 7-bit binary 1010100 1100101 1110011 1110100. Each one is turned into 8 bits by turning the low order bits of the next byte into the high order bits of this byte, as illustrated in color (with the last one using all 0s): 11010100 111100101 1001110011 00001110100. The resulting 11010100 11110010 10011100 00001110 correspond to 54 65 73 74 as expected.

Finally, the 08 04 01 A9 bytes correspond to the validity period information and are fixed.

Putting it all together

My code can be accessed on GitHub, and should hopefully work out of the box provided you set up the SMSC and recipient numbers correctly. Note that once you upload the code, a connection to the computer is not necessary (i.e. you can run it off a battery without the USB cable) as neither gnokii nor the Serial connection are used, so the SMS is truly sent by the Arduino itself. As is explained in the comments, there are a couple of places where my porting made some assumptions based on gnokii's command line output, so if you find that the code does not work, try sending the same SMS through the command line and compare the values byte-by-byte. And if you find out how to fix the code/make it more general, please let me know! It is worth pointing out that for more robust code, we would need to send ACKs back to the phone, so I don't recommend using this in security-sensitive projects as-is, where you are probably better-off using phones or shields that understand AT commands.

I hope this post was helpful, but even if you didn't follow it completely, maybe this video of the code in action will make up for it: