SPOT Hacking
by Alexei Karpenko (natrium42)

Disclaimer

The information provided here might be completely wrong. Use at your own risk.
This site has no affiliation with SPOT, Axonn or Globalstar.

Introduction

SPOT is a nice little satellite transmitter using Globalstar Simplex data (uplink only). The SPOT tracking service is available for a flat rate. If you were to use a STX2 module directly (which SPOT is based on), each message would be at a cost. Unfortunately SPOT suffers from two things:

By encoding altitude and misc sensor data though lat/lon and by using our own GPS module we can remove these limitations.

Update (2011-12-04)

Travis Goodspeed has reverse engineered the SPOT Connect and published a great article of how he accomplished it. What's neat about SPOT Connect is that you can send positions and short messages via Bluetooth.

1.1 SPOT PCB

Test Points

Name Pad Direction Description
SEL0 TP22 Input SEL0 high, SEL1 low - selects STX2 module
SEL1 TP23 Input SEL0 low, SEL1 high - selects GPS module
TX TP20 Input Serial data from microcontroller to selected module
RX TP24 Output Serial data from selected module to microcontroller
RTS TP21 Input Request To Send (from microcontroller to STX2 when it's selected)
CTS TP13 Output Clear To Send (from STX2 when it's selected to microcontroller)
VSAT TP25 Power Connect to V3.3 to turn on STX2 module
V3.3 - Power 3.3V from the onboard DC/DC converter
VBAT TP36 Power Positive battery terminal (3V)
GND TP37 Ground System ground

1.2 Hacking SPOT to control the STX2-based satellite transmitter directly

SPOT Hacking

First desolder the MSP430F2252 microcontroller using a hot air rework station. Alternatively you can cut the VCC lines of the microcontroller. We don't want the microcontroller to interfere with our communications to the STX2.

Now connect VSAT to V3.3 so that the STX2 module receives 3.3V.

Connect SEL0 to V3.3 and SEL1 to GND. This is to select the STX2 module. The original MSP430 microcontrollers uses those to switch between the STX2 and GPS on a single UART port.

Connect RX to the RX of your microcontroller and connect the TX to the TX. Also connect the RTS and CTS lines. Microcontroller should pull RTS low to start transmission and wait for CTS to be pulled low by the STX2 within 20-30ms.

Use the VBAT battery terminal to supply 3V as provided by original battery. 3.3V also seems to work without problems. Current seems to be 0.1 mA when module is inactive and 150 mA for a second or so when transmitting.

2.1 STX2 Protocol

2.1.1 STX2 Message Format

STX2 messages have the same format in either direction:

Preamble
(1 byte)
Length
(1 byte)
Cmd
(1 byte)
Data
(variable)
CRC
(2 bytes)

Preamble Fixed pattern 0xAA
Length Total number of bytes in the serial packet including the preamble and CRC
Cmd Command type
Responses to commands carry the same command type as the command that initiated the answer
Data Data associated with the command or answer
CRC 16 Bit CRC

2.1.2 Available STX2 Commands

Cmd Description
0x00 Transmit following data bytes via the air interface.
If number of data bytes > 9, then message is split into multiple messages.
Up to 144 data bytes can be sent via this command.
(Although we must only send messages in SPOT format in our case, see below.)
0x01 Request modem's unit ID.
Response contains four data bytes (MSB first) representing unit ID.
0x03 Request modem to abort current transmission.
0x04 Checks if there is a pending transmission.
Response contains one data byte:
    0x00 (no pending transmissions)
    0xXX (XX remaining transmission attempts)
0x05 Request firmware and interface ID.
Response contains two data bytes: major revision and minor revision
0x06 Setup message.
Four deprecated data bytes (don't care)
One byte to specify the RF channel: 00 (A), 01 (B), 02 (C), 03 (D)
One byte to define the number of tries (1-20)
One byte to define the minimum interval between tries (seconds/5)
One byte to define the maximum interval between tries (seconds/5)
One byte to define the transmit power level: 0 (20dBm fixed)
0x07 Query setup.
Returns settings specified by above command.
0x10 SET/CLR GPS FLAG
OEM command used to set/clear the GPS flag in the on-air message header.
One data byte (0 or 1)
Deprecated, but seems to be sent by SPOT on cold start.
0x11 GET GPS FLAG STATUS
Response contains one byte of data representing GPS FLAG.
0xFF This value is only used for an answer and corresponds to a negative acknowledgement.

2.1.3 SPOT Message Format

I have captured three message types: 0x01 (OK), 0x04 (HELP), 0x40 (TRACK). There's also the SOS message type, which I didn't capture since it should never be sent anyway.

Example:
  AA 0E 00 00 3D DD 85 C6 C5 5D 01 00 EC 78

AA          preamble
0E          total length of message (14 bytes)
00          command: transmit message
3D DD 85    encoded latitude  (MSB - LSB)
C6 C5 5D    encoded longitude (MSB - LSB)
01          message type: 0x01 (OK), 0x04 (HELP), 0x40 (TRACK)
EC 78       CRC16

Response:
  AA 05 00 D9 C4

AA          preamble
05          total length of message
00          acknowledge transmit command
D9 C4       CRC16

2.1.4 Latitude Format

DEGREES_PER_COUNT_LAT = 90.0 / 2^23
decimal_latitude = encoded_latitude * DEGREES_PER_COUNT_LAT
If result is greater than or equal to 90 degrees, 180 must be subtracted.

Example:
    encoded_latitude = 0x3DDD85 = 4054405
    decimal_latitude = 4054405 * 90.0 / 2^23 = 43.4990
    Result is less than 90, so this is correct form.

2.1.4 Longitude Format

DEGREES_PER_COUNT_LONG = 180.0 / 2^23
decimal_longitude = encode_longitude * DEGREES_PER_COUNT_LONG
If result is greater than or equal to 180 degrees, 360 must be subtracted.

Example:
    encoded_longitude = 0xC6C55D = 13026653
    decimal_longitude = 13026653 * 180.0 / 2^23 = 279.5216
    Result is greater than 180, so subtract 360 to get:
    decimal_longitude = -80.4784

2.1.5 Calculating CRC16

/*******************************************************************************
* COMPONENT NAME:
* crc16
*
* DESCRIPTION:
* This function computes a 16 bit CRC value for an array of bytes. The value
* that is returned by this function needs to be inverted before it gets placed
* into the packet. The CRC goes at the end of the packet, low byte first.
* For example:
*
* crc = ~crc16(0xFFFF, msgbuf, length);
*
* msgbuf[length] = (uint8_t)(crc & 0xFF);
* msgbuf[length + 1] = (uint8_t)(crc >> 8);
*
* When calling this function to check the validity of a packet received from
* the STX2, the caller should expect the value 0xF0B8 (#defined as CRC_OK) to
* be returned if the packet is valid.
*
* INPUTS:
* crc - the value to start computing the CRC with. This allows for chaining
* together of CRC values computed for multiple arrays of data. The
* initial value should be FFFFh (#defined as CRC_INIT).
* ptr - the pointer to the array of bytes to compute the CRC for
* length - the length of the data array
*
* OUTPUTS:
* returns - the computed 16 bit crc value
*******************************************************************************/
uint16_t crc16(uint16_t crc, uint8_t *ptr, int length)
{
  auto uint16_t i;
  while(length--)
  {
    crc = crc ^ (uint16_t) *ptr++;
    for(i=0;i<8;i++)
    {
      if(crc & 0x0001)
      crc = (crc >> 1) ^ 0x8408;
      else
      crc >>= 1;
      }
  }
  return crc;
}

2.2 Serial Port

STX2 serial port runs at 9600 baud with CTS and RTS flow control. Microcontroller should lower RTS and wait for CTS to be lowered by STX2. If this does not occur within 20-30ms, STX2 is busy and cannot accept any commands.

Once the microcontroller has transmitted the packet, it should return RTS back to high and STX2 will consequently also return CTS back to high.

3.1 Pictures

Desoldered MSP430 MCU

Satellite Antenna

3.2 Schematic

This schematic was determined by many hours of probing, tracing and scoping.

SPOT Schematic

3.3 Sending custom data

To transmit custom data like altitude or sensor data, we need a way to encode it as Lat/Lon and then decode it back to the original data. This is because we do not have access to raw message on the findmespot site, but only to position. We have 6 bytes to work with (3 for Lat and 3 for Lon). Through tests, it was determined how the findmespot servers round off Lat and Lon fields and it turns out that 4 lower bits are wasted on each field, if we want to ensure that we get the upper bits correctly for every possible combination. The trick is to set the lower 4 bits to 0111, then the upper 20 bits are not mangled. This means that we can transfer custom 20 bits with the Lat field and 20 custom bits with the Lon field, for a total of 40 bits (5 bytes). See spot-encode.c and spot-decode.c below for sample code.

3.4 Sample code

stx2.h - STX2 functions for AVR
stx2.c - STX2 functions for AVR
spot.php - Code to grab XML with positions from SPOT page

spot-encode.c - Code to encode 5 bytes and transmit them to SPOT
spot-decode.c, Makefile.spot-decode - Utility to decode Lat/Lon to 5 original bytes that were sent

3.5 Captured data

"0:" is data to MCU
"1:" is data from MCU

(1) Initialization
0: $PNMRX600,0,NemeriX NS1030A, SW Release Version 4.0.14_PROD, Welcome On Board! *01
0: $GPGGA,095133.000,0000.0000,S,00000.0000,W,0,00,00.0,0.0,M,0.0,M,,*5F
1: AA 0E 06 00 00 00 00 00 03 3C 78 00 32 74
0: AA 05 06 EF A1
0: $PNMRX600,0,NemeriX NS1030A, SW Release Version 4.0.14_PROD, Welcome On Board! *01
0: $GPGGA,095144.000,0000.0000,S,00000.0000,W,0,00,00.0,0.0,M,0.0,M,,*5F
0: $GPGSA,A,1,,,,,,,,,,,,,0.0,0.0,0.0*30
1: $PNMRX103,GGA,1,GLL,0,GSA,1,GSV,0,RMC,0,VTG,0,ZDA,0*10
0: $GPGGA,095144.000,0000.0000,S,00000.0000,W,0,00,00.0,0.0,M,0.0,M,,*5F
0: $GPGSA,A,1,,,,,,,,,,,,,0.0,0.0,0.0*30
0: $GPGGA,095144.000,0000.0000,S,00000.0000,W,0,00,00.0,0.0,M,0.0,M,,*5F
0: $GPGSA,A,1,,,,,,,,,,,,,0.0,0.0,0.0*30
0: $GPGGA,095144.000,0000.0000,S,00000.0000,W,0,00,00.0,0.0,M,0.0,M,,*5F
0: $GPGSA,A,1,,,,,,,,,,,,,0.0,0.0,0.0*30
...

This contains setup message:
  AA 0E 06 00 00 00 00 00 03 3C 78 00 32 74

  AA            preamble
  0E            total length of message (14 bytes)
  06            command: setup message
  00 00 00 00   deprecated
  00            RF channel: A
  03            number of tries: 3
  3C            minimum interval between tries: 5 minutes
  78            maximum interval between tries: 10 minutes
  00            power level: 20dBm
  32 74         CRC16

  Response:
  AA 05 06 EF A1

  AA            preamble
  05            total length of message
  06            acknowledge setup command
  EF A1         CRC16

(2) OK message #1 (after cold start)
0: $GPGGA,033032.172,4329.9448,N,08028.7018,W,1,05,05.0,279.2,M,-36.8,M,,*54
0: $GPGSA,A,3,03,20,23,31,32,,,,,,,,14.6,5.0,13.8*3D
0: $GPGGA,033033.172,4329.9448,N,08028.7018,W,1,05,05.0,279.0,M,-36.8,M,,*57
0: $GPGSA,A,3,03,20,23,31,32,,,,,,,,14.6,5.0,13.8*3D
0: $GPGGA,033034.172,4329.9433,N,08028.7011,W,1,06,01.6,286.5,M,-36.8,M,,*51
1: AA 0E 06 00 00 00 00 00 03 3C 78 00 32 74
0: AA 05 06 EF A1
1: AA 06 10 01 8C D0
0: AA 05 10 58 D4
1: AA 0E 00 00 3D DD 85 C6 C5 5D 01 00 EC 78
0: AA 05 00 D9 C4

Received message:
  Latitude: 43.4990
  Longitude: -80.4784
  Time: 03/04/2009 03:31:09 (GMT)

(3) OK message #2
0: $GPGGA,041135.846,4329.9453,N,08028.7036,W,1,05,02.0,302.6,M,-36.8,M,,*51
0: $GPGSA,A,3,06,16,20,23,31,,,,,,,,2.9,2.0,2.2*3B
0: $GPGGA,041136.845,4329.9449,N,08028.7036,W,1,05,02.0,302.6,M,-36.8,M,,*5A
0: $GPGSA,A,3,06,16,20,23,31,,,,,,,,2.9,2.0,2.2*3B
0: $GPGGA,041137.845,4329.9445,N,08028.7034,W,1,06,01.6,302.6,M,-36.8,M,,*53
1: AA 0E 06 00 00 00 00 00 03 3C 78 00 32 74
0: AA 05 06 EF A1
1: AA 0E 00 00 3D DD 88 C6 C5 5B 01 00 EA 9B
0: AA 05 00 D9 C4

Received message:
  Latitude: 43.4991
  Longitude: -80.4784
  Time: 03/04/2009 04:12:12 (GMT)

(4) HELP message
0: $GPGGA,035111.934,4329.9459,N,08028.7055,W,1,05,02.1,285.0,M,-36.8,M,,*56
0: $GPGSA,A,3,03,06,16,23,31,,,,,,,,4.3,2.1,3.7*33
0: $GPGGA,035112.934,4329.9458,N,08028.7054,W,1,05,02.1,285.0,M,-36.8,M,,*55
0: $GPGSA,A,3,03,06,16,23,31,,,,,,,,4.3,2.1,3.7*33
0: $GPGGA,035113.933,4329.9458,N,08028.7055,W,1,05,02.1,285.0,M,-36.8,M,,*52
1: AA 0E 06 00 00 00 00 00 01 3C 78 00 44 4D
0: AA 05 06 EF A1
1: AA 0E 00 00 3D DD 89 C6 C5 5A 04 00 A5 BB
0: AA 05 00 D9 C4

Received message:
  Latitude: 43.4991
  Longitude: -80.4784
  Time: 03/04/2009 03:51:49 (GMT)

break, ~5 minutes

0: $PNMRX600,0,NemeriX NS1030A, SW Release Version 4.0.14_PROD, Welcome On Board! *01
0: $GPGGA,035523.999,4329.9458,N,08028.7055,W,0,00,00.0,285.0,M,-36.8,M,,*52
0: $GPGSA,A,1,,,,,,,,,,,,,0.0,0.0,0.0*30
1: $PNMRX103,GGA,1,GLL,0,GSA,1,GSV,0,RMC,0,VTG,0,ZDA,0*10
0: $GPGGA,035523.999,4329.9458,N,08028.7055,W,0,00,00.0,285.0,M,-36.8,M,,*52
0: $GPGSA,A,1,,,,,,,,,,,,,0.0,0.0,0.0*30
0: $GPGGA,035523.999,4329.9458,N,08028.7055,W,0,00,00.0,285.0,M,-36.8,M,,*52
0: $GPGSA,A,1,,,,,,,,,,,,,0.0,0.0,0.0*30
...
0: $GPGGA,035546.934,4329.9414,N,08028.7028,W,1,05,02.2,292.8,M,-36.8,M,,*5E
0: $GPGSA,A,3,03,06,16,23,31,,,,,,,,4.5,2.2,3.9*38
0: $GPGGA,035547.933,4329.9414,N,08028.7029,W,1,05,02.2,292.9,M,-36.8,M,,*58
1: AA 0E 00 00 3D DD 83 C6 C5 5C 04 00 72 44
0: AA 05 00 D9 C4

Received message:
  Latitude: 43.4990
  Longitude: -80.4784
  Time: 03/04/2009 03:56:22 (GMT)

(5) TRACK message
0: $GPGGA,035921.905,4329.9279,N,08028.6731,W,1,04,03.5,314.6,M,-36.8,M,,*54
0: $GPGSA,A,3,03,06,20,31,,,,,,,,,13.3,3.5,12.9*3A
0: $GPGGA,035922.905,4329.9280,N,08028.6730,W,1,04,03.5,314.4,M,-36.8,M,,*52
0: $GPGSA,A,3,03,06,20,31,,,,,,,,,13.3,3.5,12.9*3A
0: $GPGGA,035923.904,4329.9301,N,08028.6749,W,1,05,01.7,324.9,M,-36.8,M,,*5B
1: AA 0E 00 00 3D DD 71 C6 C5 72 40 00 A1 BE
0: AA 05 00 D9 C4

Received message:
  Latitude: 43.4988
  Longitude: -80.4779
  Time: 03/04/2009 3:59:59 (GMT)

break, ~8 minutes

0: $PNMRX600,0,NemeriX NS1030A, SW Release Version 4.0.14_PROD, Welcome On Board! *01
0: $GPGGA,040838.999,4329.9301,N,08028.6749,W,0,00,00.0,324.9,M,-36.8,M,,*54
0: $GPGSA,A,1,,,,,,,,,,,,,0.0,0.0,0.0*30
1: $PNMRX103,GGA,1,GLL,0,GSA,1,GSV,0,RMC,0,VTG,0,ZDA,0*10
0: $GPGGA,040838.999,4329.9301,N,08028.6749,W,0,00,00.0,324.9,M,-36.8,M,,*54
0: $GPGSA,A,1,,,,,,,,,,,,,0.0,0.0,0.0*30
0: $GPGGA,040838.999,4329.9301,N,08028.6749,W,0,00,00.0,324.9,M,-36.8,M,,*54
0: $GPGSA,A,1,,,,,,,,,,,,,0.0,0.0,0.0*30
...
0: $GPGGA,040907.899,4329.9394,N,08028.7013,W,1,04,06.1,304.3,M,-36.8,M,,*57
0: $GPGSA,A,3,03,06,16,31,,,,,,,,,9.6,6.1,7.4*39
0: $GPGGA,040908.899,4329.9395,N,08028.7013,W,1,04,06.1,304.3,M,-36.8,M,,*59
0: $GPGSA,A,3,03,06,16,31,,,,,,,,,9.6,6.1,7.4*39
0: $GPGGA,040909.899,4329.9396,N,08028.7014,W,1,05,02.5,304.2,M,-36.8,M,,*5C
1: AA 0E 00 00 3D DD 80 C6 C5 5D 40 00 D5 33
0: AA 05 00 D9 C4

Received message:
  Message lost