Hi @bali & everyone in the community,
I’ve been working through a large archive of SatNOGS frames for Nayif-1 (EO-88) and managed to fully reverse-engineer and verify the FUNcube Whole-Orbit (WO) telemetry format. Since gr-satellites currently treats Nayif-1 WO as 23-byte raw blobs and the High-Resolution parser does not match the satellite’s own decoder, I thought this would be useful to share.
Method. The reference is the official FUNcube Nayif-1 Dashboard for Windows (http://download.funcube.org.uk/Nayif-1_Dashboard_1040_Installer.msi). I decompiled it (WholeOrbitSample.cs, WholeOrbitDataStore.cs, HighResolutionSample.cs, HighResolutionDataStore.cs, Telemetry.cs, BKSystem.IO/BitStream.cs) and extracted the exact bit layout. I then wrote a pure-Python + Kaitai (.ksy) decoder and verified it against real frames (733 complete orbits = 70,368 WO records), including a 100% match of the freshest WO record against the realtime block of the same cycle (see below).
Whole-Orbit record = 25 bytes (200 bits), read MSB-first sequentially:
| bits | width | field | conversion |
|---|---|---|---|
| 0-11 | 12 | WOTempMcu | v=raw*0.00078753; v>=0.7012 ? 25-(v-0.7012)/0.001646 : 25-(v-0.7012)/0.001749 |
| 12-23 | 12 | WOTempRf | °C = -0.3465*(raw&0x3FF)+266.70646 (top 2 bits const “11”) |
| 24-35 | 12 | WOTempPa | piecewise-linear 31-anchor table on (raw&0x3FF) (see ksy) |
| 36-45 | 10 | WOPanelTempXp | °C = -0.208*raw+158.792 |
| 46-55 | 10 | WOPanelTempXm | °C = -0.208*raw+158.792 |
| 56-65 | 10 | WOPanelTempYp | °C = -0.208*raw+158.792 |
| 66-75 | 10 | WOPanelTempYm | °C = -0.208*raw+158.792 |
| 76-85 | 10 | WOPanelTempZp | °C = -0.208*raw+158.792 |
| 86-95 | 10 | WOPanelTempZm | °C = -0.208*raw+158.792 |
| 96-155 | 10x6 | WOSunSensorXp/Xm/Yp/Ym/Zp/Zm | raw |
| 156-163 | 8 | WOBatteryTemp | raw |
| 164-173 | 10 | WOPanelCurrent | raw (= RT totalphotocurrent) |
| 174-187 | 14 | WOBatteryVoltage | raw (mV) |
| 188-199 | 12 | WOSystemCurrent | raw (= RT systemcurrent) |
Reassembly. Each WO frame (ft 0-11) carries 8 x 25-byte records in its 200-byte payload; a cycle is the 12 WO frames sharing the same 24-bit in-frame sequence number (bytes 50-52). Record sampleNumber = 96 - frame_id*8 - sample_in_frame; WO1 holds the oldest samples (96..89), WO12 the freshest (8..1). Time anchor from the Dashboard: sample_time = receive_time - sampleNumber minutes - frame_id*5 s.
Cross-check with the realtime block (341 cycles where all 24 frame types present; realtime block lives in bytes 2-56 of every frame):
-
battery voltage, battery temp, panel current, all 6 sun sensors: WO freshest record == RT, 100%
-
(WO temp_rf & 0x3FF)>>2 == RT rftemp, 100% (top 2 bits of the 12-bit fields are a constant 0xC00)
-
(WO temp_pa & 0x3FF)>>2 == RT paboardtemp, 100%
-
WO system_current == RT systemcurrent, 100%
High-Resolution frames (ft 12-16) are not what gr-satellites parses. The Dashboard decodes 132-bit samples: 6x10-bit sun sensors, then per axis a 22-bit signed magnetometer (x4), plus iMTQ IVA / coil-active / error flags — packed continuously across the five 200-byte HR frames (samples wrap across frame boundaries via the offset lookup in HighResolutionDataStore.cs; 60 samples per cycle).
About JY1SAT (JO-97). JY1SAT is a different satellite (NORAD 43803, launched on the same PSLV-C43 mission as Nayif-1) but carries the same FUNcube payload, so it uses the same protocol and the same extended frame path in gr-satellites (its header ext-ID byte is 0x10 vs Nayif-1’s 0x08). That means JY1SAT is affected by the same 23-byte WO bug and the same HR parser issue — and it also has the ft 32/33 SSDV frames that gr-satellites still reports as unknown. I’ve only validated the layout against Nayif-1 data, so if anyone has JY1SAT (or FUNcube-1) WO/HR archives I’d love to confirm the 25-byte format carries over. Note FUNcube-1 (AO-73) uses the same protocol but a different WO layout (WholeOrbitFC1), so it is not affected.
Artifacts: nayif1.ksy (Kaitai Struct, compiles with kaitai-struct-compiler 0.11, verified 0 mismatches on 32,736 records) and a pure-Python decoder. Happy to share anything or submit the corrected decoder as a PR to gr-satellites.
Thank you!
73!