PicSat telemetry parser added to gr-satellites

PicSat is a recently launched cubesat from the Observatoire de Paris. It is designed to observe the Beta Pictoris star system, using a telescope based on an optical fibre. It transmits telemetry in the 70cm Amateur satellite band and it also carries a V/U FM Amateur transponder as a secondary payload. In my previous post, I decoded the 1k2 BPSK + G3RUH AX.25 packets from PicSat, and added a decoder to gr-satellites. Now I have added a telemetry parser to the gr-satellites decoder.

The PicSat team has written up a very nice description of the packet formats used by PicSat. PicSat's packets are based on the CCSDS Space Packet Protocol. The Space Packet Protocol is very general, so other than the primary header, the packet format is all specific to PicSat. The PicSat webpage allows sending received packets to their server, for inclusion in their database. The webpage also shows the decoded telemetry from the packets, so I've been able to use this feature to check that my telemetry parser is producing the correct results.

This is the same packet as this one, decoded with gr-satellites:

Container: 
    primary_header = Container: 
        ccsds_version = 0
        packet_type = False
        secondary_header_flag = True
        process_id = 2
        level_flag = False
        payload_flag = False
        packet_category = 1
        sequence_flag = 3
        packet_id = 4822
        data_length = 108
    secondary_header = 2030-01-01 04:53:40.676000
    beacon = Container: 
        solar_panel_error_flags = ListContainer: 
            False
            False
            False
            False
            False
        i_adcs_get_attitude_error = False
        i_adcs_get_status_register_error = False
        fram_enable_error_flag = False
        ants_error_flag = ListContainer: 
            False
            False
        trxvu_tx_error_flag = False
        trxvu_rx_error_flag = False
        obc_supervisor_error_flag = False
        gom_eps_error_flag = False
        ant1_status_b = Container: 
            undeployed = False
            timeout = False
            deploying = False
        ant2_status_b = Container: 
            undeployed = False
            timeout = False
            deploying = False
        ignore_flag_ants_b_status = False
        ant3_status_b = Container: 
            undeployed = False
            timeout = False
            deploying = False
        ant4_status_b = Container: 
            undeployed = False
            timeout = False
            deploying = False
        armed_ants_b_status = False
        ant1_status_a = Container: 
            undeployed = False
            timeout = False
            deploying = False
        ant2_status_a = Container: 
            undeployed = False
            timeout = False
            deploying = False
        ignore_flag_ants_a_status = False
        ant3_status_a = Container: 
            undeployed = False
            timeout = False
            deploying = False
        ant4_status_a = Container: 
            undeployed = False
            timeout = False
            deploying = False
        armed_ants_a_status = False
        solar_panel_temps = ListContainer: 
            0
            0
            0
            2
            30210
        ants_temperature = ListContainer: 
            30472
            49926
        tx_trxvu_hk_current = 33029
        tx_trxvu_hk_forwardpower = 5389
        tx_trxvu_tx_reflectedpower = 1029
        tx_trxvu_hk_pa_temp = 30473
        rx_trxvu_hk_pa_temp = 49152
        rx_trxvu_hk_board_temp = 768
        eps_hk_temp_batts = 771
        eps_hk_batt_mode = 32
        eps_h_kv_batt = 33
        eps_hk_boot_cause = 3
        n_reboots_eps = 131864
        n_reboots_obc = 0
        quaternions = ListContainer: 
            0.0
            0.0
            0.0
            0.0
        angular_rates = ListContainer: 
            0.00333024328575
            -0.0162032786757
            0.110771499574
        adcs_stat_flag_hl_op_tgt_cap = False
        adcs_stat_flag_hl_op_tgt_track_fix_wgs84 = False
        adcs_stat_flag_hl_op_tgt_track_nadir = False
        adcs_stat_flag_hl_op_tgt_track = False
        adcs_stat_flag_hl_op_tgt_track_const_v = False
        adcs_stat_flag_hl_op_spin = False
        adcs_stat_flag_hl_op_sunp = False
        adcs_stat_flag_hl_op_detumbling = False
        adcs_stat_flag_hl_op_measure = False
        adcs_stat_flag_datetime_valid = False
        adcs_stat_flag_hl_op_safe = False
        adcs_stat_flag_hl_op_idle = False
        up_time = 104017
        last_fram_log_fun_err_code = 0
        last_fram_log_line_code = 381
        last_fram_log_file_crc_code = 1366333782
        last_fram_log_counter = 64
        average_photon_count = 0
        sat_mode = 0
        tc_sequence_count = 10768

When implementing the telemetry parser, I've encountered a few small pitfalls with the documentation. The first is that the primary header seems to be 6 byte long, rather than 8 bytes as stated. The beacon data doesn't start immediately after the 6 byte secondary telemetry header. There are 3 bytes of padding between them. This isn't mentioned anywhere in the docs. Finally, I don't know how to decide if the secondary header is for telemetry or for telecommand. This might be mentioned somewhere, so perhaps I need to read the documentation more closely.

As I final remark, it seems that the timestamp in the secondary header was invalid in all the packets of the pass I recorded in my previous post. The interesting thing is that my parser shows 2030-01-01 04:53:40, while the webpage shows 2000-01-02 04:53:40. Note that both agree that the number of days since 2000-01-01 is 10958, so my calculation is actually the correct one.

Leave a Reply

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