How to use satellite data communication (with code)

One of my current projects needs to send and receive data from remote locations, so I have been working with satellite communication. This post will explain the Iridium Short Burst Data system and provide a simple Perl driver you can customize for your own project. I am using a Raspberry Pi with Raspbian Linux for this project, but any Linux PC works.

The unit I’m using is the RockBLOCK+ available here:
http://www.rock7.com/products-rockblock-plus
This device contains an Iridium 9602 Short Burst Data satellite modem, an antenna, a power regulator, and an RS-232 level converter in a 13cm weatherproof enclosure. Smaller units are available if you want to package them yourself.

Rock7.com is an intermediary between Iridium and your application. You can sign up with a credit card, much like a prepaid mobile phone. Other satellite services require contracts and fairly expensive up-front work, but Rock7 is very quick to set up. This device is the easiest way to send and receive data anywhere on the planet.

Iridium Short Burst Data is much like SMS text messaging, with one big conceptual difference: there is no recipient address in the mobile-originated message. Each message will be sent to the recipient addresses configured at the Rock7 website for your device. The messages are delivered to you by email or HTTPS POST.

The service is charged by the 50-byte unit, so a message up to 50 bytes, uplink or downlink, costs one credit. From 51 to 100 bytes costs two, up to a maximum message length of 340 bytes up and 270 bytes down.

The cost is GBP 10 per month per device, and GBP 0.11 to 0.04 per credit depending on the number of credits you buy. As a developer you have a strong incentive to keep these messages short. The protocol is binary, so you can use all 256 byte values. Binary or BCD rather than ASCII makes sense here.

You can send a message to the mobile unit either by typing it into the website, or by initiating an HTTPS POST to Rock7’s infrastructure. You can have multiple devices registered to one account sharing one set of delivery addresses and one pool of credits. Each unit is addressed by a 15-digit decimal IMEI number, and a password is required to send.

Iridium SBD devices like the RockBLOCK+ cannot communicate with each other. They can only send to and receive from a server on the Internet. If you want to communicate between mobile nodes, your server must relay messages. I have built simple text relay communication into my project, but this costs two credits per 50-byte mobile-to-mobile message.

The mobile unit must register with the satellite, which my code handles for you. When you send a mobile-terminated message, the satellite sends a one-way SBD RING broadcast. If your unit is turned on and pointed at the sky at that moment, it will receive the RING and my code will fetch the message and act on it.

The modem only has continuous coverage if you are outdoors with a clear view of the sky and the modem pointed straight up. Indoors with only a non-metallic roof overhead, the signal comes and goes as the satellites pass overhead. My code handles this and waits for a signal before attempting to communicate.

However, if the RING message is missed, the mobile will only discover it has a message waiting the next time it sends an outgoing message. You can also send the mobile another message to send another RING, but the satellite does not resend the RING on its own. This means you cannot count on the mobile being immediately reachable at all times. Your project should probably report in periodically, although this costs credits.

The modem comes with a long cable ending in bare wires. You will need to attach a DB9 female connector and a power source. If you have a power supply from a defunct laptop, those are usually 18 or 19 volts, and will work fine. Check voltage and polarity with a meter.

The unit requires 9-30 volts DC. Maximum current is 225 mA, because the device has a capacitor for momentary transmit power. Idle current (listening for incoming messages) is about 16 mA, and low power sleep is possible but not implemented in this project.

Wire as follows:

GREY – GROUND – DB9 pin 5 and power negative
BROWN – POWER – power positive
YELLOW – RX OUT – DB9 pin 2
BLUE – TX IN – DB9 pin 3

The rest of the wires can just be insulated. For the RockBLOCK+ you need a RS-232 type USB to serial adapter with a DB9 male connector. Some of the smaller non-packaged modems use TTL/CMOS levels, but the RB+ has a level converter.

You need the serial driver (sudo cpan install Device::SerialPort) installed. You should also install cu (sudo apt-get install cu).

To test the RockBLOCK+, power it up and run (assuming no other serial ports
are attached):

pi@raspberrypi:~ $ cu -l /dev/ttyUSB0 -s 19200
Connected.
AT
OK
~.

Disconnected.

If you get the OK, the RockBLOCK+ is connected properly. The satcom_p.pl program is a simple, single-file Perl driver that lets you send and receive text or binary data and define your own commands. There is a command already defined that runs shell command lines over the satellite.

Run it like this:

perl satcom_p.pl /dev/ttyUSB0

You will see a series of AT commands and responses, and the program will display the IMEI number. The program is now listening for commands over the satellite. Messages like +CIEV:0,4 indicate the signal strength (in this case 4 out of 5). At least 2 is required to send, in my experience.

Once you have a signal, go to the rockblock.rock7.com admin page, choose Send a Message, choose your Rockblock from the list, and in the Plain Text box type: sh uptime
and press Send.

Within a few seconds you should see SBDRING and then some activity on the Pi. The program waits for a signal of 2 or better, initiates a session with the satellite, fetches the incoming message from the downlink buffer, clears the downlink buffer, runs the command, puts the response in the uplink buffer, initiates another session with the satellite, and clears the uplink buffer. The modem does not automatically clear buffers, so my code checks this in a paranoid manner. If you fail to clear buffers, you will infinite loop and spend all your credits.

The shell command “uptime” will be run on the Pi, and the first 50 bytes of the output are sent back. You can click on Messages to see the reply. If you use sx (“shell expensive”) instead of sh it will return the first 340 bytes.

To add your own commands, find “sub process_message” in the program and add more patterns to the if-else structure. The incoming message will be in $msg (this can be binary) and you transmit using the satsend() function. More than one message can be queued for transmission. There is also a “sub periodic_poll” function where you can add timed operations such as reporting in at regular intervals.

It is normal to see occasional AT commands and signal strength updates. The driver polls the modem regularly even if nothing is happening. It is normal for send and receive attempts to fail, in which case the program waits 30 seconds before trying again.

My driver has a few file-based functions. If you touch the file nosend.flag, outgoing messages will not be sent to the satellite, but only displayed on the screen. You can fake an incoming satellite message by putting it into the file command.txt, which will be read and deleted. This combination lets you test commands without spending money.

The file satcom_status.txt contains, on separate lines, the IMEI number, signal strength, number of pending outgoing messages, last downlink time, and last uplink time. In my project, this information is displayed to the user.

The files txcommand0.dat and txcommand1.dat are polled for and, if found, the contents are immediately queued for transmission and the file deleted. The user interface uses this to send messages. To make sure the program does not read an empty file, you should create the file with a different name, write it, close it, and rename it into place.

Here are a few other problems I had to deal with:

The project has a GPS receiver as well as the RockBLOCK+. They look identical to Linux, and get randomly assigned at boot to ttyUSB0 and ttyUSB1. I needed to assign gpsd and satcom to the proper port at boot. The program identify_port.pl will interrogate the port and output gps, rockblock, or unknown as well as the baud rate of the GPS.

$ perl identify_port.pl /dev/ttyUSB0
rockblock 19200
$ perl identify_port.pl /dev/ttyUSB1
gps 115200
[ script then parses and runs the processes ]
$ stty 115200 < /dev/ttyUSB1
$ gpsd -n /dev/ttyUSB1
[ in screen session ]
$ perl satcom.pl /dev/ttyUSB0

On the server side, here is a simple CGI script that will serialize the incoming RockBLOCK messages and write them to a file:

#!/usr/bin/perl

use CGI qw( );
use Fcntl qw(:flock SEEK_END);

my $cgi = CGI->new();

open(OUT,'>>/tmp/rockblock.log');
flock(OUT,LOCK_EX) || die $!;
seek(OUT, 0, SEEK_END) || die $!;
$date=`/bin/date "+%Y-%m-%d %H:%M:%S"`;
chomp($date);
print OUT "=====================================\n";
print OUT $date."\n";

print OUT "====================== ENV\n";
for my $param (keys %ENV) {
print OUT $param .'='.$ENV{$param}."\n";
}
print OUT "====================== POST\n";
for my $param ($cgi->param()) {
print OUT $param .'='.$cgi->param($param)."\n";
}
print OUT "\n";
flock(OUT,LOCK_UN) || die $!;
close(OUT);
print "Content-Type: text/plain\r\n\r\n\nnot much to say\r\n";

# EOF

A background process on the server watches the file date and processes these messages. To decode hex messages from the file:
$data =~ s/((?:[0-9a-fA-F]{2})+)/pack ‘H*’, $1/ge;

To send outgoing satellite messages:

my $browser=LWP::UserAgent->new;
$browser->timeout(30);
my $hexmessage = unpack "H*", $message;
print "Sending message (".length($message)." bytes) ".$hexmessage." to ".$imei."\n";
#print "Pause 10 sec\n"; sleep(10); # DEBUG
my $response=$browser->post('https://core.rock7.com/rockblock/MT',
[ 'imei' => $imei,
'data' => $hexmessage,
'username' => $rb_username,
'password' => $rb_password ],
'Accept-Language' => 'en-us',
'User-Agent' => 'perl/lwp',
);
print $response->status_line."\n"; # expecting 200 OK

To make sure your remote device does not hang and stop responding to commands, you should have a keepalive script. The keepalive script can check the file date, last downlink time, and last uplink time in satcom_status.txt. Since your application should report in periodically, if those times don’t change within the expected interval, assume something is broken and reboot.

My project needed to send timestamps, GPS data, and other numeric fields. I wanted to keep a character string format rather than using binary, especially for the GPS decimal fields, so I used four-bit BCD with some delimiter characters. The bcdencode and bcddecode functions support the digits, space, decimal point, minus sign, and slash. An ASCII list of numbers can be converted to BCD, using half as many bytes over the air, and then converted back to ASCII at the server.

satcom_p.pl

identify_port.pl

Leave a Reply

Your email address will not be published. Required fields are marked *