Światowid is an Earth observation 2U cubesat built by the Polish company SatRevolution. It carriers a camera with a resolution of 4 metres per pixel and an Amateur radio U/V FM transponder that was never activated due to power budget constraints. The cubesat was launched to the ISS on April 17 this year and released in orbit on July 3. It transmits on the 70cm Amateur satellite band, using 1k2 AFSK AX.25 APRS plaintext for telemetry and 9k6 FSK with a custom protocol for downlinking the camera images. According to the IARU frequency coordination sheet and SatRevolution, it can also transmit images in the 13cm Amateur satellite band at 500kbps.
During June, I worked under a contract with SatRevolution to adapt gr-satellites for their use with Światowid and KRAKsat. Since I am well aware of the problem of private companies using the Amateur satellite bands as “free spectrum” for their satellites, when I was first contacted by SatRevolution regarding this project I did a small background check and saw that Światowid and KRAKsat had obtained an IARU frequency coordination successfully.
I also showed my IARU R1 proposal to SatRevolution and told them that, even though I was signing an NDA for the project, according to ITU regulations they had to publish all the details for the protocols they used on Amateur bands. Formally, these details were not covered by the NDA, and we also agreed that the modified version of gr-satellites would be publicly released under the GPLv3. The decoder was released here on July 4, and this was also announced by SatRevolution on Twitter.
Some Amateurs were not at all happy with the news that the FM transponder was not going to be activated, and accused SatRevolution of adding only the FM transponder to get through the IARU coordination, without having any real intention to activate it, of possibly causing interference to SO-50 and of not giving back anything to the community. However, all of this happened by the time I was already finishing my project with SatRevolution.
After finishing this project, I didn’t merge back to the main version of gr-satellites any of the modifications I did for SatRevolution, and I am not aware of SatRevolution having published any technical information about the 9k6 custom protocol used by Światowid. I didn’t see any reports of people receiving the 9k6 signal (only the APRS telemetry beacon was often seen), so I didn’t consider sorting this out as a priority, since I wasn’t even sure if the 9k6 protocol was actually being used (maybe they were only using S-band to download the images).
A couple days ago, I saw that Piotr Kuligowski SQ4NOW, Maciej Nowak and Tomek SP9TMQ, from the PW-Sat2 team managed to decode one of the images transmitted by Światowid using the 9k6 custom protocol. Talking with Piotr, I learned that they had used my modified gr-satellites version, but as it didn’t provide a complete solution to decode images (below I explain what was missing), they had to do some reverse engineering of the custom protocol.
Now that I’ve learned about the effort of Piotr, Maciej and Tomek, I have decided to add a complete decoder solution for the Światowid 9k6 custom protocol to the main gr-satellites version and to write this post to document completely the protocol.
The Światowid 9k6 protocol is used to transmit JPEG files from the camera. From the point of view of the transmitter, the protocol can be described with these steps:
- The JPEG file is split into chunks of 48 bytes. The last chunk is padded with zeros at the end in case the file size is not a multiple of 48 bytes.
- A Reed-Solomon (58, 48) code is used to encode each 48 byte chunk by adding 10 parity check bytes.
- The 58 byte Reed-Solomon blocks are organized in packets of 141 blocks. The last packet may be shorter if the number of blocks is not a multiple of 141.
- A CRC-16CCITT zero (see this post about ESEO) of the packet is appended to the packet in big-endian byte format.
- The length of the packet (including the CRC) in bytes, minus 8, is prepended to the packet as a little-endian 16bit integer.
- The following data is prepended to the packet, a preamble 0xAAAA, a syncword 0xDADA, and a packet ID 0xBBBB (in this respective order an big-endian format).
- The packet is sent, with each byte in a least significant bit first fashion, in 9k6 FSK.
I stress that bytes are sent least-significant bit first, which is quite uncommon.
The Reed-Solomon code used corresponds to the following parameters when using Phil Karn KA9Q’s libfec:
- Finite field generator polynomial: 0x11d
- First consecutive root index: 0
- Primitive element index: 1
- Number of roots: 10
This Reed-Solomon code is implemented in many open source libraries which are based in this Wikiversity article, including mersinvald’s Reed-Solomon, Arduino-FEC, and the Python implementation reedsolo, which is what the PW-Sat2 team has used in their reverse engineering effort.
There are a number of drawbacks to the Światowid custom protocol, which make decoding unreliable and likely to fail. First of all, the preamble is very short, making clock recovery difficult for the receiver. Second, the packets are very large. A full packet is 8188 bytes long. This takes 6.8 seconds to transmit at 9k6. Therefore, a lot of data is lost if the packet start is not detected correctly or if a problem such as a clock slip happens mid-packet. The packet length field is not protected by any checksum or FEC, so a bit error in this field will potentially cause a lot of data to be lost as well.
The CRC-16 is somewhat useless, since it is computed on the Reed-Solomon blocks rather than on the data before applying FEC, which is the usual approach. The only way I can think of to use the CRC in this manner is to run Reed-Solomon decoding for each block, recompute the parity check bytes, and check the CRC over this data to see if all the blocks inside the packet were FEC decoded correctly.
The data in each Reed-Solomon block doesn’t have any kind of checksum. Therefore, it is not possible to check if a Reed-Solomon block was decoded without errors. Note that, even though Reed-Solomon is an error correcting code, some blocks at the output of the decoder may still have errors. It is only possible to check if all the 141 blocks inside a packet have been correctly decoded, in the manner remarked above. However, it is not possible to check each block individually.
The packets have no sequence number and there is no indication about the start or end of a file. Therefore, it is difficult or impossible to detect lost packets.
All these problems make it rather difficult to decode an image successfully. For correct decoding, the operator must know where the image starts, maybe by finding the JPEG 0xFFD8FF magic number within the data, and either manage not to lose any packet, or detect packet loss and leave the appropriate gap in the file (although it is difficult to repair a JPEG file with gaps, as some experiments with BY70-1 and other satellites sending images using JPEG instead of SSDV have shown).
There is also a bug in the onboard implementation of this protocol in Światowid, whereby the CRC is omitted from some packets. Presumably this happens whenever a packet doesn’t have 141 Reed-Solomon blocks. Probably it’s possible to detect if a packet is buggy by checking if the length of its payload modulo 58 is either 0 or 2.
The Światowid decoder now available in gr-satellites is not designed to run automatically to reassemble images as other image decoders do, owing to these potential problems in the protocol. It is expected to be run under the supervision of the user, who will then try to reassemble the image manually with the data obtained. It is shown in the figure below.
It works in the following manner. The start of the packet is detected by using 0x5B5BDDDD as a syncword. This is just 0xDADABBBB in least-significant-bit first format. A threshold of zero is used in syncword detection because it is easy to missdetect this syncword, as it has large self-correlation sidelobes.
After detecting the syncword and extracting the 8200 bytes following the syncword, the bytes are reflected to handle the least-significant-bit first format, the packet length is read and the packet is cropped to its correct size. The CRC-16 is checked, but this is only done for informative purposes. The packet is processed regardless of whether the CRC is correct or not.
Each packet is split into FEC blocks and the blocks are then sent to the libfec Reed-Solomon decoder, which prints out whether FEC decoding succeeded or not for each block. The output is then sent into two files. The first,
swiatowid_img.jpg, is a concatenation of all the FEC decoded blocks. If the recording processed contains a single image and all the FEC block could be decoded successfully, then this file will contain the JPEG image transmitted by Światowid.
The second file,
swiatowid.kss, contains all the decoded FEC blocks in KISS format. This file can be used by an operator that wishes to try to reassemble the JPEG file by hand.
The FEC decoder was not available in the gr-satellites modification I did for SatRevolution, since they intended to do FEC decoding using their own tools, so it wasn’t covered by the contract. Therefore, the PW-Sat2 team have needed to reverse engineer the FEC without any information. Apparently they managed to detect the 58 byte structure somehow.
A sample recording is included in my satellite-recordings repository. This file is an extract from one of the recordings done by the PW-Sat2 team and can be processed by the gr-satellites decoder to yield many correct FEC blocks. However, I haven’t been able to extract the image from the full recording, since none of the FEC blocks in the first packet (which presumably contains the JPEG header) decode successfully. This shows that it is not easy to successfully extract an image from the Światowid signal, making even more remarkable the feat achieved by the PW-Sat2 team.