# PDI-2025: P4 Solution ## tm_tc_handling.h ```c= #ifndef TM_TC_HANDLING_H #define TM_TC_HANDLING_H #include "riscv_types.h" #define IDLE 0 #define READING_CCSDS_HEADER 1 #define READING_PACKET_DF 2 #define TC_HEADER_SIZE 6 void uart_rx_irq_handler(void); void timer_handler(void); uint32_t build_response_tm_17_2(uint8_t tm_bytes[], uint16_t tm_seq_count, uint16_t tc_packet_id, uint16_t tc_packet_seq_ctrl); uint32_t build_response_tm_1_1 (uint8_t tm_bytes[], uint16_t tm_seq_count, uint16_t tc_packet_id, uint16_t tc_packet_seq_ctrl); uint32_t build_response_tm_1_2 (uint8_t tm_bytes[], uint16_t tm_seq_count, uint16_t tc_packet_id, uint16_t tc_packet_seq_ctrl, uint8_t error); uint32_t build_response_tm_1_7 (uint8_t tm_bytes[], uint16_t tm_seq_count, uint16_t tc_packet_id, uint16_t tc_packet_seq_ctrl); uint32_t build_response_tm_1_8 (uint8_t tm_bytes[], uint16_t tm_seq_count, uint16_t tc_packet_id, uint16_t tc_packet_seq_ctrl, uint8_t error); void sendTM( uint8_t tm_bytes[], uint32_t n ); #endif /* TM_TC_HANDLING_H */ ``` ## tm_tc_handling.c ```c= #include "ccsds_pus_format.h" #include "riscv_uart.h" #include "serialize.h" #include "crc.h" #include "epd_pus_mission.h" #include "tc_fifo.h" #include "tm_tc_handling.h" #include "log.h" uint32_t idx=0; uint32_t bytes_to_read=0; // Total bytes to read uint8_t tc_buffer[TC_FIFO_TAM_TC]; uint32_t receiver_state = IDLE; uint32_t counter = 0; //---------- // PHASE 5 void timer_handler(void) { if ( counter != 0 ) { counter--; if ( counter == 0 ) { receiver_state = IDLE; idx=0; } } } //---------- // PHASE 1 void uart_rx_irq_handler(void) { uint8_t data; data = riscv_getchar(); switch (receiver_state) { case IDLE: // TO COMPLETE: Wait for TC HEADER start (0x1B) //------- if ( data == 0x1B ) { tc_buffer[idx] = data; idx++; receiver_state = READING_CCSDS_HEADER; //---------- // PHASE 5 counter = 10; // esperamos 10 ticks de una decima } //------- break; case READING_CCSDS_HEADER: // TO COMPLETE: Read TC HEADER //------- tc_buffer[idx] = data; idx++; if ( idx == TC_HEADER_SIZE ) { bytes_to_read = deserialize_uint16( &tc_buffer[4] ) + TC_HEADER_SIZE + 1; receiver_state = READING_PACKET_DF; } //------- break; case READING_PACKET_DF: // TO COMPLETE: Read packet data field and checksum // TO COMPLETE: When TC complete PUSH tc_buffer into FIFO //------- tc_buffer[idx] = data; idx++; if ( idx == bytes_to_read ) { tc_fifo_push( &tc_fifo, tc_buffer, idx ); receiver_state = IDLE; idx=0; bytes_to_read = 0; //---------- // PHASE 5 counter = 0; // Se ha recibido el TC completo, desactivamos el contador } //------- break; } } /* Build TM 17.2 example */ uint32_t build_response_tm_17_2(uint8_t tm_bytes[], uint16_t tm_seq_count, uint16_t tc_packet_id, uint16_t tc_packet_seq_ctrl) { struct ccds_pus_tmtc_packet_header tm_packet_header; struct ccds_pus_tm_df_header df_header; tm_packet_header.packet_id = ccsds_pus_tm_build_packet_id(EPD_APID); tm_packet_header.packet_seq_ctrl = ccsds_pus_tm_build_packet_seq_ctrl(0x3, tm_seq_count); // verify packet sequence (0x3) tm_packet_header.packet_length = 4+2 - 1; // pus header + checksum - 1 df_header.version = 0x10; // 0001 0000 df_header.type = 17; df_header.subtype = 2; df_header.destinationID = EPD_DESTINATION_ID; serialize_uint16(tm_packet_header.packet_id, &tm_bytes[0]); serialize_uint16(tm_packet_header.packet_seq_ctrl, &tm_bytes[2]); serialize_uint16(tm_packet_header.packet_length, &tm_bytes[4]); // Store version field into the corresponding byte tm_bytes[6] = df_header.version; // Store the remaining fields into their respective locations tm_bytes[7] = df_header.type; tm_bytes[8] = df_header.subtype; tm_bytes[9] = df_header.destinationID; // This TM has no data uint16_t crc_value = cal_crc_16(tm_bytes, 6+4); // 6 bytes CCSDS header, 4 bytes PUS header serialize_uint16(crc_value, &tm_bytes[10]); return 6+4+2; // packet header + pus header + checksum } uint32_t build_response_tm_1_1(uint8_t tm_bytes[], uint16_t tm_seq_count, uint16_t tc_packet_id, uint16_t tc_packet_seq_ctrl) { // TO COMPLETE: This TM has app data before checksum //---------- struct ccds_pus_tmtc_packet_header tm_packet_header; struct ccds_pus_tm_df_header df_header; tm_packet_header.packet_id = ccsds_pus_tm_build_packet_id(EPD_APID); tm_packet_header.packet_seq_ctrl = ccsds_pus_tm_build_packet_seq_ctrl(0x3, tm_seq_count); // verify packet sequence (0x3) tm_packet_header.packet_length = 4+4+2 - 1; // pus header + APP id (4 bytes) + errorCode (1 byte) + checksum - 1 df_header.version = 0x10; // 0001 0000 df_header.type = 1; df_header.subtype = 1; df_header.destinationID = EPD_DESTINATION_ID; serialize_uint16(tm_packet_header.packet_id, &tm_bytes[0]); serialize_uint16(tm_packet_header.packet_seq_ctrl, &tm_bytes[2]); serialize_uint16(tm_packet_header.packet_length, &tm_bytes[4]); // Store version field into the corresponding byte tm_bytes[6] = df_header.version; // Store the remaining fields into their respective locations tm_bytes[7] = df_header.type; tm_bytes[8] = df_header.subtype; tm_bytes[9] = df_header.destinationID; // This TM has data: TC Packet ID (4 bytes) serialize_uint32( (uint32_t)tc_packet_id, &tm_bytes[10] ); uint16_t crc_value = cal_crc_16(tm_bytes, 6+4+4); // 6 bytes CCSDS header, 4 bytes PUS header, 4 bytes APP ID serialize_uint16(crc_value, &tm_bytes[14]); //---------- return 6+4+4+2; // packet header + pus header + tc_packet_id + checksum } uint32_t build_response_tm_1_2(uint8_t tm_bytes[], uint16_t tm_seq_count, uint16_t tc_packet_id, uint16_t tc_packet_seq_ctrl, uint8_t error_code) { // TO COMPLETE: This TM has app data and error code before checksum //---------- struct ccds_pus_tmtc_packet_header tm_packet_header; struct ccds_pus_tm_df_header df_header; tm_packet_header.packet_id = ccsds_pus_tm_build_packet_id(EPD_APID); tm_packet_header.packet_seq_ctrl = ccsds_pus_tm_build_packet_seq_ctrl(0x3, tm_seq_count); // verify packet sequence (0x3) tm_packet_header.packet_length = 4+4+1+2 - 1; // pus header + APP id (4 bytes) + errorCode (1 byte) + checksum - 1 df_header.version = 0x10; // 0001 0000 df_header.type = 1; df_header.subtype = 2; df_header.destinationID = EPD_DESTINATION_ID; serialize_uint16(tm_packet_header.packet_id, &tm_bytes[0]); serialize_uint16(tm_packet_header.packet_seq_ctrl, &tm_bytes[2]); serialize_uint16(tm_packet_header.packet_length, &tm_bytes[4]); // Store version field into the corresponding byte tm_bytes[6] = df_header.version; // Store the remaining fields into their respective locations tm_bytes[7] = df_header.type; tm_bytes[8] = df_header.subtype; tm_bytes[9] = df_header.destinationID; // This TM has data: TC Packet ID (4 bytes) + ERROR CODE (1 byte) serialize_uint32( (uint32_t)tc_packet_id, &tm_bytes[10] ); tm_bytes[14] = error_code; uint16_t crc_value = cal_crc_16(tm_bytes, 6+4+4+1); // 6 bytes CCSDS header, 4 bytes PUS header, 4 bytes APP ID, 1 byte error serialize_uint16(crc_value, &tm_bytes[15]); //---------- return 6+4+4+1+2; // packet header + pus header + tc_packet_id + error code + checksum } uint32_t build_response_tm_1_7(uint8_t tm_bytes[], uint16_t tm_seq_count, uint16_t tc_packet_id, uint16_t tc_packet_seq_ctrl) { // TO COMPLETE: This TM has app data before checksum //---------- struct ccds_pus_tmtc_packet_header tm_packet_header; struct ccds_pus_tm_df_header df_header; tm_packet_header.packet_id = ccsds_pus_tm_build_packet_id(EPD_APID); tm_packet_header.packet_seq_ctrl = ccsds_pus_tm_build_packet_seq_ctrl(0x3, tm_seq_count); // verify packet sequence (0x3) tm_packet_header.packet_length = 4+4+2 - 1; // pus header + APP id (4 bytes) + errorCode (1 byte) + checksum - 1 df_header.version = 0x10; // 0001 0000 df_header.type = 1; df_header.subtype = 7; df_header.destinationID = EPD_DESTINATION_ID; serialize_uint16(tm_packet_header.packet_id, &tm_bytes[0]); serialize_uint16(tm_packet_header.packet_seq_ctrl, &tm_bytes[2]); serialize_uint16(tm_packet_header.packet_length, &tm_bytes[4]); // Store version field into the corresponding byte tm_bytes[6] = df_header.version; // Store the remaining fields into their respective locations tm_bytes[7] = df_header.type; tm_bytes[8] = df_header.subtype; tm_bytes[9] = df_header.destinationID; // This TM has data: TC Packet ID (4 bytes) serialize_uint32( (uint32_t)tc_packet_id, &tm_bytes[10] ); uint16_t crc_value = cal_crc_16(tm_bytes, 6+4+4); // 6 bytes CCSDS header, 4 bytes PUS header, 4 bytes APP ID serialize_uint16(crc_value, &tm_bytes[14]); return 6+4+4+2; // packet header + pus header + tc_packet_id + checksum } uint32_t build_response_tm_1_8(uint8_t tm_bytes[], uint16_t tm_seq_count, uint16_t tc_packet_id, uint16_t tc_packet_seq_ctrl, uint8_t error) { // TO COMPLETE: This TM has app data and error code before checksum return 6+4+4+1+2; // packet header + pus header + tc_packet_id + error code + checksum } void sendTM( uint8_t tm_bytes[], uint32_t tm_len ) { for (int i=0;i<tm_len;i++) { uint8_t error = riscv_putchar( tm_bytes[i]); if ( error ) break; // discard response } } ``` ## main.c ```c= #include "riscv_types.h" #include "log.h" #include "riscv_uart.h" #include "tc_fifo.h" #include "tm_tc_handling.h" #include "serialize.h" #include "dispatch.h" #include "crc.h" #include "epd_pus_mission.h" void processTC(uint8_t tc_bytes[], uint32_t tc_len ) { uint8_t tm_bytes[TC_FIFO_TAM_TC]; uint32_t tm_len; uint16_t tm_seq_counter = 1; uint16_t tc_packet_id = deserialize_uint16( &tc_bytes[0] ); uint16_t tc_packet_seq_ctrl = deserialize_uint16( &tc_bytes[2] ); uint16_t crc_received = deserialize_uint16( &tc_bytes[tc_len-2] ); uint16_t crc_calculated = cal_crc_16(tc_bytes, tc_len - 2); printf("PacketID: %04X\n", tc_packet_id ); printf("PacketSeqCtrl: %04X\n", tc_packet_seq_ctrl ); printf("[CRCs] Rec: 0x%04X Calc: 0x%04X\n", crc_received, crc_calculated ); if ( crc_received != crc_calculated ) { //-------- // PHASE 3 printf("ERROR: CRC Error: TM(1,2)\n"); // CRC ERROR: Generate TM (1,2) - Reject tm_len = build_response_tm_1_2(tm_bytes, tm_seq_counter++, tc_packet_id, tc_packet_seq_ctrl, CRC_ERROR_CODE ); sendTM( tm_bytes, tm_len ); } else { // TC response uint8_t service_type = tc_bytes[7]; uint8_t service_subtype = tc_bytes[8]; if ( (service_type == 17) && (service_subtype == 1 ) ) { // TO COMPLETE: Test ACK field // Bit 3: ack of successful acceptance. 1=TM(1,1) required; 0=TM(1,1) not required // Bit 2: 0, not used. // Bit 1: 0, not used. // Bit 0: 1=TM(1,7) is required; 0=TM(1,7) not required /* if TM(1,1) required { printf("TM(1,1)\n"); build TM(1,1) and sendTM } */ //-------- // PHASE 4 : Processing ACK field (bit 3) if ( tc_bytes[6] & 0x08 ) { printf("TM(1,1)\n"); tm_len = build_response_tm_1_1(tm_bytes, tm_seq_counter++, tc_packet_id, tc_packet_seq_ctrl ); sendTM( tm_bytes, tm_len ); } //-------- //-------- // PHASE 2 printf("TC(17,1) ---> TM(17,2)\n"); // build TM(17,2) and sendTM tm_len = build_response_tm_17_2(tm_bytes, tm_seq_counter++, tc_packet_id, tc_packet_seq_ctrl ); sendTM( tm_bytes, tm_len ); //-------- /* if TM1,7) required { printf("TM(1,7)\n"); build TM(1,7) and sendTM } */ //-------- // PHASE 4 : Processing ACK field (bit 0) if ( tc_bytes[6] & 0x01 ) { printf("TM(1,7)\n"); tm_len = build_response_tm_1_7(tm_bytes, tm_seq_counter++, tc_packet_id, tc_packet_seq_ctrl ); sendTM( tm_bytes, tm_len ); } } else { //-------- // PHASE 3 printf("ERROR: Service not supported: TM(1,2)\n"); // Error: service nor supported TM(1,2) - Reject tm_len = build_response_tm_1_2(tm_bytes, tm_seq_counter++, tc_packet_id, tc_packet_seq_ctrl, SERVICE_UNKNOWN_ERROR_CODE); sendTM( tm_bytes, tm_len ); } } // else CRC } // processTC int main() { uint8_t tc_bytes[TC_FIFO_TAM_TC]; uint32_t tc_len; tc_fifo_init( &tc_fifo ); // tc_fifo is declared in tm_tc_handling.c printf("TM/TC RISCV Handler\n"); // TX/RX enable riscv_uart_enable_TX(); riscv_uart_enable_RX(); // E/S por interrupción con mapeo socket install_irq_handler( UART_IRQ, uart_rx_irq_handler ); // Install uart handler riscv_uart_enable_RI(); // Enable RX irq plic_irq_unmask( UART_IRQ ); // PLIC UART irq unmask enable_ext_irq(); // Enable MIE.MEI install_local_timer_handler( timer_handler ); local_timer_set_gap( 1000000 ); // CLINT timer clock is 10Mhz enable_timer_clinc_irq(); enable_irq(); // Global interrupt enable while(1) { /* * if FIFO is not empty * POP TC in mutual exclusion to avoid UART IRQ * Process TC */ //---------- if ( tc_fifo_not_empty( &tc_fifo) ) { plic_irq_mask( UART_IRQ ); // PLIC UART irq mask tc_fifo_pop( &tc_fifo, tc_bytes, &tc_len ); plic_irq_unmask( UART_IRQ ); // PLIC UART irq unmask // print_buffer( tc_bytes, tc_len ); processTC( tc_bytes, tc_len ); } //---------- } return 0; } ```