1KUNS-PF image decoder

A week ago, Mike Rupprecht DK3WN told me that he had discovered JPEG images in the packets transmitted by 1KUNS-PF. I’ve had some time now to take a look at the information he sent me (including KISS dumps of the packets) and add an image decoder to gr-satellites.

JPEG images are not so difficult to spot amongst binary data, since they contain JFIF in ASCII in their header (4a 46 49 46 in hex). Another telltale sign of JPEG is the ff d8 ff that marks the start of the file. Presumably this is how Mike first noticed the images.

Mike has published some information about the image packets transmitted by 1KUNS-PF and he has been posting some of the images he receives.

Below there is the hex dump of the first and second packet CSP packet of a JPEG image (note the JFIF and ff d8 ff inside the packet payload).

pdu_length = 138
contents = 
0000: 00 e2 92 42 00 00 ff d8 ff e0 00 10 4a 46 49 46 
0010: 00 01 01 01 00 00 00 00 00 00 ff db 00 43 00 0c 
0020: 08 09 0b 09 08 0c 0b 0a 0b 0e 0d 0c 0e 12 1e 14
0030: 12 11 11 12 25 1a 1c 16 1e 2c 26 2e 2d 2b 26 2a
0040: 29 30 36 45 3b 30 33 41 34 29 2a 3c 52 3d 41 47
0050: 4a 4d 4e 4d 2f 3a 55 5b 54 4b 5a 45 4c 4d 4a ff
0060: db 00 43 01 0d 0e 0e 12 10 12 23 14 14 23 4a 32
0070: 2a 32 4a 4a 4a 4a 4a 4a 4a 4a 4a 4a 4a 4a 4a 4a
0080: 4a 4a 4a 4a 4a 4a fa 14 dc 9e

pdu_length = 138
contents = 
0000: 00 e2 92 42 00 01 4a 4a 4a 4a 4a 4a 4a 4a 4a 4a 
0010: 4a 4a 4a 4a 4a 4a 4a 4a 4a 4a 4a 4a 4a 4a 4a 4a 
0020: 4a 4a 4a 4a ff c4 00 1f 00 00 01 05 01 01 01 01 
0030: 01 01 00 00 00 00 00 00 00 00 01 02 03 04 05 06 
0040: 07 08 09 0a 0b ff c4 00 b5 10 00 02 01 03 03 02 
0050: 04 03 05 05 04 04 00 00 01 7d 01 02 03 00 04 11 
0060: 05 12 21 31 41 06 13 51 61 07 22 71 14 32 81 91 
0070: a1 08 23 42 b1 c1 15 52 d1 f0 24 33 62 72 82 09 
0080: 0a 16 17 18 19 1a 95 64 b7 7e

It seems that all the image packets are 138 bytes long. The first four bytes are the CSP header. Then we have 16bit big-endian field which counts the number of chunk, starting by 00. The last four bytes of the packet are most likely a checksum, and the remaining bytes are the corresponding chunk of the JPEG file.

I don’t know how to detect the end of one image other than by taking note of the beginning of the next image. In fact, this is the last packet of this image:

pdu_length = 138
contents = 
0000: 00 e2 92 42 00 47 8a 00 5a 28 00 a2 81 05 14 00 
0010: 51 40 05 14 00 51 40 05 14 00 51 40 05 14 00 51 
0020: 40 c2 8a 00 28 a0 02 8a 00 28 a0 04 a2 80 0a 28 
0030: 18 51 40 05 14 00 51 40 05 14 00 51 40 05 14 c6 
0040: 14 50 01 45 00 14 50 01 45 00 14 50 01 45 00 14 
0050: 50 01 45 00 14 50 01 45 00 7f ff d9 00 00 00 00 
0060: 00 00 00 00 00 11 41 42 00 48 00 00 04 58 00 00 
0070: 00 10 00 00 00 51 d0 38 c9 54 05 ac 8f d7 00 00 
0080: bc 24 00 00 bc 24 dc bd 44 b0 

The ff d9 that occurs mid-packet is the end-of-file of the JPEG file. I don’t know what to make of the rest of the data following it. Since not all of it is zero, it doesn’t look as deliberate padding. It might be the case that the satellite is sending information left over in a buffer.

The image below is the whole JPEG file contained in the packets received by Mike. It was sent using 72 chunks, for a total of 9216 bytes (at 128 bytes per chunk) and its resolution is 640×480. Most of the other images sent by 1KUNS-PF are smaller.

JPEG image downlinked by 1KUNS-PF

1KUNS-PF decoded

A few days ago, I spoke about my tries to decode telemetry from 1KUNS-PF. Since then, Mike Rupprecht DK3WN has managed to get in contact with Lorenzo Frezza, from the satellite team in La Sapienza, who has given us very valuable and detailed information regarding the telemetry. This has allowed me to include a fully working decoder for 1KUNS-PF in gr-satellites. Many thanks to Lorenzo for his collaboration.

Just after reading Lorenzo’s description of the coding, where he mentions Golay and Reed Solomon, I noticed that 1KUNS-PF was using the NanoCom AX100 transceiver in ASM+Golay mode. This is the same mode that the Chinese TY-2 and TY-6 satellites use, and I’ve already spoken about ASM+Golay mode in a post about TY-2. The only difference between these Chinese satellites and 1KUNS-PF is that 1KUNS-PF is currently using 1k2 (but perhaps might change to 9k6 in the future), whereas the Chinese satellites use 9k6. With this in mind, it is very easy to adapt the decoder for TY-2 to obtain a decoder for 1KUNS-PF.

Regarding my previous tries, note that I had tried to identify the syncword as 11011001111010010101110001000011, whereas the correct syncword is 10010011000010110101000111011110. My syncword candidate was inverted (this might be a problem with sideband inversion in the recording by Mike that I used) and off by one bit (due to the difficulty of deciding where the preamble ends).

After reading Lorenzo’s email, it has been a very easy and fast task to add a fully working decoder to gr-satellites, while before I wasn’t optimistic at all about the difficulty of decoding this satellite. This makes me think about two things:

  • We should really check the usual suspects (i.e., popular modems) when trying to reverse-engineer some new satellite. I could have found this out by myself just by trying the AX100 ASM+Golay decoder.
  • Some advice IARU Satcoord: if a satellite uses some popular hardware (for instance the U482C or the AX100) or some popular standard (CCSDS), please list that in the frequency coordination sheet. Lorenzo’s email could have been well summarised in the sentence “1KUNS-PF uses a NanoCom AX100 in the ASM+Golay mode”, and then we would have been able to decode this satellite without any effort.

Lorenzo has also sent us the telemetry format, which is rather simple. Using that, I’ve been able to add a telemetry decoder also. The new decoder for 1KUNS-PF can be found as sat_1kuns_pf.grc in gr-satellites. I have also added a sample recording to satellite-recordings. The telemetry in one of the packets in the sample recording is as follows:

CSP header:
        Priority:		2
        Source:			1
        Destination:		9
        Destination port:	10
        Source port:		37
        Reserved field:		0
        HMAC:			0
        XTEA:			0
        RDP:			0
        CRC:			0
Container: 
    beacon_counter = 4274
    solar_panel_voltage = ListContainer: 
        2448.0
        2448.0
        2432.0
    eps_temp = ListContainer: 
        1.0
        3.0
        2.0
        2.0
    eps_boot_cause = 7
    eps_batt_mode = 3
    solar_panel_current = 0.0
    system_input_current = 80.0
    battery_voltage = 8262.0
    radio_PA_temp = 4.0
    tx_count = 45584
    rx_count = 0
    obc_temp = ListContainer: 
        1.0
        1.0
    ang_velocity_mag = 10
    magnetometer = ListContainer: 
        288.0
        0.0
        0.0
    main_axis_of_rot = 89

A first look at 1KUNS-PF telemetry

Last Friday, three Amateur cubesats were deployed from the ISS as part of the KiboCUBE program. These were Irazú, a 1U cubesat from Costa Rica which is the first satellite in orbit from a Central American country; UBAKUSAT, a 3U cubesat from Istanbul Technical University, Turkey; and 1KUNS-PF, a 1U cubesat from University of Nairobi, Kenya, developed jointly with University of Rome La Sapienza, Italy.

Irazú and UBAKUSAT both use standard 9k6 FSK packet radio (AX.25 with G3RUH scrambler), so they can be decoded with direwolf and many other packet radio decoders. However, no one has been able to decode 1KUNS-PF yet, due to the lack of information about the modulation and coding used. Mike Rupprecht DK3WN has some information about 1KUNS-PF, including a recording of some packets. I’ve taken a look at Mike’s recording and here are my findings.

S-NET telemetry parser

Recently I have added a telemetry parser to the S-NET decoder in gr-satellites. Recall that I have talked about S-NET and its decoder in a previous post. To implement this telemetry parser I have used the information in Mike Rupprecht DK3WN’s web, some additional information shared by the S-NET team, as well as some recordings done by Mike. Many thanks to Mike and the S-NET team for all their help. Here I describe a few details about the telemetry.

Soft Viterbi decoder for AO-40 FEC

A year ago, I made a decoder for the AO-40 FEC. While AO-40 has been dead for many years, the same FEC system is used in AO-73 and the rest of the FUNcube satellites. This decoder was later included in gr-satellites and it is currently used in the decoders for AO-73, UKube-1 and Nayif-1.

When I implemented this FEC decoder, for simplicity I used a hard decision Viterbi decoder, since my main concern was to get all the system working. I always intended to replace this by a soft decision Viterbi decoder, but it seems that I forgot completely about it.

Now, while thinking about integrating gr-aausat (my AAUSAT-4 decoder OOT module) into gr-satellites and adding a soft Viterbi decoder for AAUSAT-4, I have remembered about this. While the decoder for AAUSAT-4 will have to wait, since I have found a bug in the GNU Radio Viterbi decoder that makes it segfault, I have already added a soft Viterbi AO-40 FEC decoder to the FUNcube decoders in gr-satellites.

Decoder for PolyITAN-2-SAU

PolyITAN-2-SAU, or QB50 UA01, is a cubesat from National Technical University of Ukraine, that was launched on May 2017 as part of the QB50 proyect. When it was launched, I made a recording of several QB50 satellites, including PolyITAN-2-SAU. Presumably, the modulation and coding used by this satellite is 9k6 BPSK AX.25, with G3RUH scrambling. Back then, I commented that although the signal was strong and I could get a clean constellation plot, I was unable to get valid AX.25 packets.

I had completely forgotten this satellite, but the other day I saw that Andy UZ7HO had added support for PolyITAN-2-SAU to his SoundModem. I asked Andy for some help, since I suspected that the coding wasn’t exactly standard G3RUH AX.25.

The trick is that this satellite uses two “layers” of NRZI encoding. The relevant part of the decoder is shown below. The BPSK symbols come in from the left of the figure and the AX.25 packets exit by the right. A standard G3RUH AX.25 decoder wouldn’t have the extra NRZI decoder on the right.

PolyITAN-2-SAU decoder

Note that NRZI decoding and G3RUH descrambling commute, since the G3RUH polynomial has an odd number of terms. Therefore, the decoder can also be organized in a different way, with both NRZI decoders at one side (either the input or output) of the descrambler.

Having two NRZI decoders in chain is a really funny concept, so it almost seems as some kind of mistake from the satellite team (most QB50 satellites use standard BPSK or FSK AX.25 packet radio for compatibility). In fact, if we write an NRZI decoder as \(y_n = 1 + x_n + x_{n-1}\), where \(x_n\) is the input sequence, \(y_n\) is the output sequence and the operations are performed on the finite field \(GF(2)\), then the effect of two NRZI decoders in chain can be written as\[z_n = 1 + y_n + y_{n-1} = 1 + x_n + x_{n-2},\] which is a rather strange form of differential decoder.

Thanks to Andy for giving me the clue about the extra NRZI decoder, as I would have had a hard time in finding it by myself (although, in retrospective, it is not that difficult to guess it by looking at the descrambled stream and seeing how HDLC 0x7e flags can be obtained from it). I have now added a decoder for PolyITAN-2-SAU to gr-satellites.

Decoding S-NET

S-NET is a swarm of 4 cubesats from TU-Berlin. Their mission is to test SLink, an S-band transceiver for inter-satellite communications. They were launched on February 1 this year and they use use Amateur frequencies for their telemetry downlink on the 70cm band. Several weeks ago, Mike Rupprecht DK3WN raised my attention towards these satellites. Since they use a rather particular coding, custom software would be needed to decode the telemetry. Then, I set to add support for S-NET to gr-satellites

After some really helpful communication with the S-NET team, in particular with Walter Frese, and some exchanges of ideas with Andrei Kopanchuk UZ7HO, who was also working to add an S-NET decoder to his soundmodem, I have finally added a basic S-NET decoder to gr-satellites.

TY-2 decoded

In January, I took a look at TY-2 telemetry. This is a Chinese cubesat that transmits 9k6 FSK telemetry in the 70cm Amateur band. In my previous post I tried to reverse engineer the packets from TY-2 and got as far as recognizing the syncword, and noting that the syncword is the same as the one sent by the GOMspace NanoCom AX100 transceiver. However, in all AX100 transceivers I had seen, the syncword was sent scrambled with a G3RUH scrambler, and TY-2 sent it unscrambled. This left me a bit puzzled. The payload seemed to be scrambled and I was unable to descramble it, preventing any further progress.

Since then, I have tried to get in contact with the satellite team to see if they could give me any additional information about TY-2 and its companion TY-6 (which uses the same format). Finally, the satellite team have answered me, giving me some details and confirming me that they use the AX100. This has allowed me to finish the decoder. An updated decoder is now available in gr-satellites. Thanks to BI1AEM for his help. Here I look at the specific details of the format used by TY-2.

Outernet LDPC code revisited

I have been preparing the slides for my future talk about reverse-engineering Outernet at FAQin 2018. While doing this, I have been re-reading some of the material about the work done on LDPC code and FEC in Outernet by George Hopkins in January 2017. One of the things I didn’t do back then was to read carefully the LDPC decoding function implemented by George.

In my post I explained that the LDPC code used in Outernet followed RFC5170, and I wondered whether it used the staircase scheme or the triangle scheme. I also commented that erasure decoding with an LDPC code (or any other linear code, actually) was mathematically equivalent to solving a linear system where the unknowns correspond to the erased symbols. I observed that the decoding function looked very different from this mathematical procedure, but should do more or less the same thing. Now I have read the decoder implementation carefully and I have the answer to both questions.