# PDI-2025: Practice 4 SKEL ## epd_pus_mission.h ```c= #ifndef EPD_PUS_MISSION_H #define EPD_PUS_MISSION_H /** * \brief Assigned Application Process ID */ #define EPD_APID 0x32C /** * \brief Destination ID to be used on the TM packets */ #define EPD_DESTINATION_ID 0x78 /** * \brief Source ID to be used on the TC packets */ #define EPD_SOURCE_ID 25 /** * \brief CRC ERROR code */ #define CRC_ERROR_CODE 1 /** * \brief TC Service unknown ERROR */ #define SERVICE_UNKNOWN_ERROR_CODE 2 #endif /* EPD_PUS_MISSION_H */ ``` ## 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); 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; uint8_t tc_buffer[TC_FIFO_TAM_TC]; uint32_t receiver_state = IDLE; void uart_rx_irq_handler(void){ uint8_t data; data = (uint8_t)riscv_getchar(); switch (receiver_state) { case IDLE: // TO COMPLETE: Wait for TC HEADER start (0x1B) break; case READING_CCSDS_HEADER: // TO COMPLETE: Read TC HEADER break; case READING_PACKET_DF: // TO COMPLETE: Read packet data field and checksum // TO COMPLETE: When TC complete PUSH tc_buffer into FIFO break; } //switch } /* 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 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 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 return 6+4+4+2; // packet header + pus header + tc_packet_id + 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 } } ``` <!-- 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 } --> ## main.c ```c= #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 ) { 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 } */ printf("TC(17,1) ---> TM(17,2)\n"); // build TM(17,2) and sendTM /* if (TM1,7) required { printf("TM(1,7)\n"); build TM(1,7) and sendTM } */ } else { 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 ); } } } 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 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 enable_irq(); // Global interrupt enable while(1) { /* * if FIFO is not empty * POP TC in mutual exclusion to avoid UART IRQ * Process TC */ } return 0; } ```