// $RCSfile: mem_serv.c,v $Revision: 1.45 $Date: 2005/03/11 15:08:57 /*! Contains functions for implementing the memory managment commands. The functions are excuted within different tasks but most of them within the hs_hdl task. Several functions are simply interfaces towards lower level functions of the MM (memory managment) library */ #include "allnodes.h" #include "node1.h" #include #include "configura.h" #include "pubfuncs.h" #include "err_hdl.h" #include "hk_ask.h" #include "hs_lib.h" #include "hs_hdl.h" #include "cmd_seq.h" #include "hs0.h" #include "hs1.h" #include "data_hdl.h" #include "ls.h" #include "MM_lib.h" #include "MM_crc.h" #include "mem_serv.h" #include "Eprm.h" #include "time_tsk.h" #include "mem_serv.dox" /*------------------------- local defines -----------------------------------------------*/ // ids of the HIFI mem segments #define MEM_ID_PM 0 #define MEM_ID_DM 1 #define MEM_ID_1553 2 #define MEM_ID_EEPROM 3 #define MEM_ID_LCU 4 /*------------------------- local functions -----------------------------------------------*/ int check_memory_header(memory_header header, int check_TC); void check_memory_load_returned_value(int error_value, unsigned int check_sum); int generate_check_report (TC_packet * p_tc, unsigned int crc); int generate_dump_report(int RAM_type, int mem_id, int start, int *data, unsigned int check_sum); int map_HIFI_id_to_LIB_id(unsigned int *id); unsigned int translate_eeprom_write_retval (int); int generate_sim_science_data( void ); int exec_mem_dump_LCU(LS_HDL_MSG *msg); int exec_mem_dump_RAM(HS_HDL_MSG *message); int exec_mem_load_LCU(int *); void exec_mem_load_RAM (TC_packet * packet); /*------------------------- local variables -----------------------------------------------*/ START_FRAME_DATA dummy_TS; //!< time stamps for the last TS /*------------------------- init_memory_manager -----------------------------------------------*/ /*! This function is called at program startup in order to initialize the MM library static data. */ void init_memory_manager(void) { // reset the IDs delete_memory_segments(); // load IDs for HIFI: add_memory_segment(ID, Offset, lenght, is_writable) // lpdeb: shall test the error generation in the init phase if ( ! add_memory_segment(MEM_ID_PM, 0x0, 0x7ffff, 1) ) generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_MEM_DATA_OVFL, 0, NULL); if ( ! add_memory_segment(MEM_ID_DM, 0x0, 0x7ffff, 1) ) generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_MEM_DATA_OVFL, 0, NULL); if ( ! add_memory_segment(MEM_ID_1553, BUS_IF_MIL_AND_ANALOG_INP, 0x4000, 0) ) generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_MEM_DATA_OVFL, 0, NULL); if ( ! add_memory_segment(MEM_ID_EEPROM, EEPROM_MEMORY_BASE_ADDRESS, 0x40000, 0) ) generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_MEM_DATA_OVFL, 0, NULL); } //------------------------- map_HIFI_id_to_LIB_id ------------------------------ /*! This function converts the HIFI memory ID into a MM lib memory ID */ int map_HIFI_id_to_LIB_id(unsigned int *id) { int mem_id; // Add the info about the mem type (PM or DM) since the library does not infers that from the ID // and delete the first three bits (useless in HIFI) mem_id = (id[0] >> 8) & 0x000F; switch( mem_id ) { case MEM_ID_DM: case MEM_ID_1553: case MEM_ID_EEPROM: id[0] &= 0x0FFF; // set to zero the first four bits id[0] |= 0x1000; // set to one the fourth bit return 1; break; case MEM_ID_PM: id[0] &= 0x0FFF; // set to zero the first four bits return 1; break; case MEM_ID_LCU: // LCU load/dump is to be handled differently: here we simply detect the id return 2; default: // id is not recognized return 0; } } //------------------------- start_memory_check --------------------------------- //! Implements the first (and only) step of a memory check command. Executed within the hs_hdl task int start_memory_check(HS_HDL_MSG *message) { int check_TC; memory_header header; TC_packet * packet; unsigned int crc; int id_map_output; // init auxiliary pointer to the TC packet packet = (TC_packet *) message->block.pointer_to_data; // check the HS systems status if ( ! bring_to_safe( message ) ) return RC_OK; // now HS is safe, we can initialize and start // HK production is compatible with memory managment AID_spectroscopy = REQUIRING_HK; // Map HIFI ID to MM_lib ID. id_map_output = map_HIFI_id_to_LIB_id(packet->data); switch( id_map_output ) { case 1: /* the id is a normal memory id, was recognised and was mapped to the library id: simply go on */ break; case 2: /* the id refers to a LCU mem operation: no check LCU exists, kill the command */ case 0: /* the id was not recognised */ default: enqueue_exec_fail(EXF_MEM_INVALID_MEMID, 1, packet->data); release_block(&(message->block)); return RC_FAIL; } // if we are here the memory id was all right, was not LCU and has been mapped to the library id: go on with normal mem operation // create header check_TC = create_memory_header(packet->data, &header, 0); if ( check_memory_header( header, check_TC ) == RC_FAIL ) { release_block(&(message->block)); return RC_FAIL; } // check crc = memory_check(&header, 0xFFFFFFFF); // send_report if ( generate_check_report (packet, crc) == RC_OK ) enqueue_exec_compl(); // function that handles execution completion ack else enqueue_exec_fail(ERR_MEM_FIFOPUT_HK_TM_QUEUE, 0, NULL); // function that handles execution completion nack // here I can free the TC block release_block(&(message->block)); // here we can free the TC block return RC_OK; } /*------------------------- exec_memory_load -----------------------------------------------*/ //! Implements a memory load command. Executed within the cmd_seq task void exec_memory_load (TC_packet * packet) { int id_map_output; // Map HIFI ID to MM_lib ID. id_map_output = map_HIFI_id_to_LIB_id(packet->data); switch( id_map_output ) { case 2: /* the id refers to a LCU mem operation: process it differently and return */ exec_mem_load_LCU( (int*) packet); break; case 1: /* the id is a normal memory id, was recognised and was mapped to the library id */ exec_mem_load_RAM(packet); break; case 0: /* the id was not recognised: exit */ default: enqueue_exec_fail(EXF_MEM_INVALID_MEMID, 1, packet->data); break; } } /*------------------------- exec_mem_load_RAM -----------------------------------------------*/ //! Implements a memory load command. Executed within the cmd_seq task void exec_mem_load_RAM (TC_packet * packet) { int error_value, check_TC; unsigned int check_sum; memory_header header; // if we are here the memory id was all right, was not LCU and has been mapped to the library id // create header check_TC = create_memory_header(packet->data, &header, (packet->packet_length - 13) ); if ( check_memory_header( header, check_TC ) == RC_FAIL ) { enqueue_exec_fail(ERR_MEM_INTERNAL, 0, NULL); return ; } // protect boot software area if ( header.start_address < 0x4000 && header.RAM_type == 0) { enqueue_exec_fail(EXF_MEM_BOOT_OVERWRITE, 0, NULL); return ; } // load check_sum = memory_load(packet->data+3,&header,&error_value); if (error_value != MEM_LOAD_OK) check_memory_load_returned_value(error_value, check_sum); else enqueue_exec_compl(); // function that handles execution completion ack } /*------------------------- variables used by memory dumping-----------------------------------------------*/ static int number_of_packets_to_dump; //! number of packets still to be dumped static int new_address; //! starting address of the packet to dump in the current step static memory_header dump_header; //! static header for memory dumping static int SAU; //! number of bytes in the smallest addressable unit (6 for PM, 4 for DM) /*------------------------- start_memory_dump -----------------------------------------------*/ /*! Implements the first step of a memory dump command, that is the selection if the memory is RAM or LCU (in addition to normal start actions, i.e. the stoppoing of a possibly running command. Executed within the hs_hdl task */ int start_memory_dump(HS_HDL_MSG *message) { TC_packet * packet; int id_map_output; // init auxiliary pointer to the TC packet packet = (TC_packet *) message->block.pointer_to_data; // check the HS systems status if ( ! bring_to_safe( message ) ) return RC_OK; // now HS is safe, we can initialize and start // Map HIFI ID to MM_lib ID. id_map_output = map_HIFI_id_to_LIB_id(packet->data); switch( id_map_output ) { case 2: /* the id refers to a LCU mem operation: process it differently and return */ // HK production is NOT compatible with LCU memory managment. AID_spectroscopy = LCU_MEM_DUMP_ID; exec_mem_dump_LCU(message); return RC_OK; case 1: /* the id is a normal memory id, was recognised and was mapped to the library id */ // HK production is compatible with memory managment AID_spectroscopy = REQUIRING_HK; exec_mem_dump_RAM(message); return RC_OK; case 0: /* the id was not recognised: exit */ default: enqueue_exec_fail(EXF_MEM_INVALID_MEMID, 1, packet->data); release_block(&(message->block)); AID_spectroscopy = REQUIRING_HK; return RC_FAIL; } } /*------------------------- exec_mem_dump_RAM -----------------------------------------------*/ /*! Implements the first step of a memory dump command for the RAM, that is the initialization of the related static variables */ int exec_mem_dump_RAM(HS_HDL_MSG *message) { TC_packet * packet; int check_TC; HS_HDL_MSG cmd_queue; // if we are here the memory id was all right, was not LCU and has been mapped to the library id: go on with normal mem operation // init auxiliary pointer to the TC packet packet = (TC_packet *) message->block.pointer_to_data; // create header check_TC = create_memory_header(packet->data, &dump_header, 0); // here I can free the TC block release_block(&(message->block)); // check header if ( check_memory_header( dump_header, check_TC ) == RC_FAIL ) return RC_FAIL; // set the Smallest Addressable units. if ( dump_header.RAM_type == 0 ) SAU = 6; else SAU = 4; // init other static data new_address = dump_header.start_address; number_of_packets_to_dump = memory_dump(&dump_header, NULL, &new_address); // prepare and send to hs_hdl task a message to start the first step of memory dumping cmd_queue.operation_id = MKSTEP_MEM_DUMP; cmd_queue.command_number = message->command_number; cmd_queue.block_loaded = 0; if (KS_FIFOPut(HS_HDL_QUEUE, (void *) &cmd_queue) == RC_FAIL) { enqueue_exec_fail(EXF_MEM_HS_HDL_QUEUE, 0, NULL); // execution failure return RC_FAIL; } else return RC_OK; } //------------------------- mkstep_memory_dump --------------------------------- /*! Implements a step of a memory dump command. I.e. gets the contents of a part of the memory, put them into a HK packet and pass the packet to TMTC. Before doing that it checks the HK pool occupation level and, if full, the step is skipped, some time is waited and the step is reenqueued. */ int mkstep_memory_dump (int command_number) { HS_HDL_MSG cmd_queue; unsigned int check_sum; unsigned int last_dump_address; int hk_cnt; int data_store[1026]; // safe. Could be optimised (e.g. use: MAX_NUMBER_DM_WORDS_TM) // check if we are over (useless but safer) if ( number_of_packets_to_dump <= 0 ) { enqueue_exec_compl(); // function that handles execution completion ack return RC_OK; } // flood control, if the pool is almost full wait and retry hk_cnt = Memory_Pool_Occupation[3]; // HK_POOL if ( hk_cnt > 5 ) // pools used too heavily. Pause. { // wait a while KS_TaskSleep(SAFE_STATUS_WT); // resend the command and exit cmd_queue.operation_id = MKSTEP_MEM_DUMP; cmd_queue.command_number = command_number; cmd_queue.block_loaded = 0; if (KS_FIFOPut(HS_HDL_QUEUE, (void *) &cmd_queue) == RC_FAIL) { enqueue_exec_fail(EXF_MEM_HS_HDL_QUEUE, 0, NULL); // execution failure return RC_FAIL; } return RC_OK; } // write the memory contents in data in data_store. At the output // data_store[0] = number of SAU written, followed by the SAUs // a PM sau (6 bytes) is written in three vector elements // a DM sau (4 bytes) is written in two vector elements last_dump_address = new_address; // store the starting address of the data of the current packet check_sum = memory_dump(&dump_header, data_store, &new_address); // send a packet generate_dump_report(dump_header.RAM_type, dump_header.memory_ID, last_dump_address, data_store, check_sum); // decrease packets to send number_of_packets_to_dump--; // prepare and send to hs_hdl task a message to make the next step cmd_queue.operation_id = MKSTEP_MEM_DUMP; cmd_queue.command_number = command_number; cmd_queue.block_loaded = 0; if (KS_FIFOPut(HS_HDL_QUEUE, (void *) &cmd_queue) == RC_FAIL) { enqueue_exec_fail(EXF_MEM_HS_HDL_QUEUE, 0, NULL); // execution failure return RC_FAIL; } return RC_OK; } //------------ generate_dump_report -------------------------------------------- //! Writes the report packet then enqueues it towards tmtc_if task in order to be sent to ground. int generate_dump_report (int RAM_type, int mem_id, int start_add, int *data, unsigned int check_sum) { K_BLOCK block; HK_TM_MSG tm_msg; int *tm_data; int position; int pkt_len, data_len; int i; // compute len of mem data. data_len = data[0]; switch( RAM_type ) { case 1: data_len = data_len * 2; /* DM words (32 bits) */ break; case 0: data_len = data_len * 3; /* PM words (48 bits) */ break; case 2: /* LCU words (48 bits) */ break; default: /* unknown ram type */ generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_MEM_INTERNAL, 0, NULL); return RC_FAIL; break; } // add mem_id, start_add, length and checksum pkt_len = data_len + 4; // get a memory block from the HK_POOL pool if (get_block(&block, HK_POOL, SIZEOFUNIT_TO_OCTET(HK_BLOCK_LEN_WORDS)) == RC_FAIL) return RC_FAIL; init_block(&(block), HK_BLOCK_LEN_WORDS); // initialize the block prepare_TM_packet(&block, TM_DFHF_REGULAR, APID1024, 11 + 2*pkt_len, TM_MEM_DUMP_TYPE, TM_MEM_DUMP_SUBT); // copy the data tm_data = block.pointer_to_data; position = 8; // first byte of the data part tm_data[position++] = ( (mem_id & 0x000000FF) << 8) | ( (start_add & 0x00FF0000) >> 16 ) ; tm_data[position++] = start_add & 0x0000FFFF; tm_data[position++] = data[0]; for (i = 0; i < data_len; i++) tm_data[position++] = data[1+i]; tm_data[position++] = check_sum; tm_msg.block = block; tm_msg.packing = PACKING_16; // set the packetization flag to 16 bit tm_msg.packing |= SDH_HK_WLEN << 8; // set the length of data header tm_msg.packing |= HKP << 16; tm_msg.offset = HK_TM_HEADER; // no offset tm_msg.count = 0; // downcount of the packet tm_msg.length = 0; // useless // send message to tm_tc if (KS_FIFOPut(HK_TM_QUEUE, (void *) &tm_msg) == RC_FAIL) { release_block(&block); // if the fifo_put fails, we must deallocate the memory block generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_MEM_FIFOPUT_HK_TM_QUEUE, 0, NULL); return RC_FAIL; } return RC_OK; } /*------------------------- check_memory_header -----------------------------------------------*/ /*! Decodes the value returned by the function crate_memory_header. If an error was detected the relative message is enqueued towards ground with data taken from the header to specify the error. */ int check_memory_header(memory_header header, int check_TC) { unsigned int data[2]; if (check_TC == INVALID_MEMLENGTH ) { enqueue_exec_fail(EXF_MEM_INVALID_MEMLENGTH, 0, NULL); return RC_FAIL; } if (check_TC == INVALID_ADDRESS ) { data[0] = (header.start_address & 0xFF0000) >> 16; data[1] = (header.start_address & 0xFFFF); enqueue_exec_fail(EXF_MEM_INVALID_ADDRESS, 2, data); return RC_FAIL; } if (check_TC == INVALID_MEMID) { data[0] = header.memory_ID; enqueue_exec_fail(EXF_MEM_INVALID_MEMID, 1, data); return RC_FAIL; } if (header.length_SAU == 0) { enqueue_exec_fail(EXF_MEM_INVALID_MEMLENGTH, 0, NULL); return RC_FAIL; } return RC_OK; } //-- check_memory_load_returned_value ------------------------------------------------------------------------------------ /*! Decodes the value returned by the function memory_load. If an error was detected the relative message is enqueued towards ground with data taken from the header to specify the error. */ void check_memory_load_returned_value(int error_value, unsigned int check_sum) { unsigned int cks; cks = check_sum; switch (error_value) { case INVALID_MEMID: /* read only segment */ enqueue_exec_fail(EXF_MEM_INVALID_MEMID, 0, NULL); break; case INVALID_CRC_1ST_CHK: enqueue_exec_fail(EXF_MEM_INVALID_CRC1, 1, &cks); break; case INVALID_CRC_2ND_CHK: enqueue_exec_fail(EXF_MEM_INVALID_CRC2, 1, &cks); break; default: enqueue_exec_fail(EXF_MEM_UNKNOWN_RET_CODE, 0, NULL); break; } } //-- generate_check_report ------------------------------------------------------------------------------------ //! Writes the report packet then enqueues it towards tmtc_if task in order to be sent to ground. int generate_check_report (TC_packet * p_tc, unsigned int crc) { TM_MEM_CHK *tm_chkrep; K_BLOCK block; HK_TM_MSG message; // queue to tm_tc // Get a new free block from pool to put TM data if (get_block((K_BLOCK *)&block, HK_POOL, SHORT_BLOCK_SIZE) == RC_FAIL) return RC_FAIL; // Write a TC_verify structure into the block tm_chkrep = (TM_MEM_CHK *) block.pointer_to_data; // equate pointers // Write TM data tm_chkrep->data_1 = p_tc->data[0] & 0xFF; tm_chkrep->data_2 = p_tc->data[1]; tm_chkrep->data_3 = p_tc->data[2]; tm_chkrep->data_4 = crc; prepare_TM_packet((K_BLOCK *)&block, TM_DFHF_REGULAR, APID1024, TM_MCHK_LEN, TM_TYPE_MCHK, TM_SUBTY_MCHK); // Now prepare the message for the queue message.block = block; message.offset = TM_HEADER_NWORDS + TM_DATAHEADER_NWORDS; // offset to data message.length = 4; message.count = 0; message.packing = PACKING_16; // 16 bit data // send message to tm_tc if (KS_FIFOPut(HK_TM_QUEUE, (void *) &message) == RC_FAIL) { release_block(&block); // if the fifo_put fails, we must deallocate the memory block return RC_FAIL; } else return RC_OK; } //************************************************************************************************** //************************************************************************************************** // simulated science //************************************************************************************************** //************************************************************************************************** int deliver_sd_sim_packet(int fifo_id, K_BLOCK *sd_block); int generate_sim_science_data (void); //----- start_sim_sci----------------------------------------------------------- /*! Executed within the hs_hdl task. Implemets the start step of the simulated science command. The HS system is stopped and a message is posted into hs_hdl queue to trigger the first step of simulated science */ int start_sim_sci (HS_HDL_MSG *message) { HS_HDL_MSG cmd_queue; // check the HS systems status if ( ! bring_to_safe( message ) ) return RC_OK; // now HS is safe, we can initialize and start // here I can free the TC block release_block(&(message->block)); // init static data and launch first step AID_spectroscopy = TC_FUNMAN_SPCTRSM_AID; init_spec_table(); init_science_data(); // prepare and send to tuning task a message to start the first step of memory dumping cmd_queue.operation_id = MKSTEP_SIM_SCI; cmd_queue.command_number = message->command_number; cmd_queue.block_loaded = 0; if (KS_FIFOPut(HS_HDL_QUEUE, (void *) &cmd_queue) == RC_FAIL) { enqueue_exec_fail(EXF_MEM_HS_HDL_QUEUE, 0, NULL); // execution failure return RC_FAIL; } else { enqueue_exec_compl(); // simulated science has started return RC_OK; } } //----- mkstep_sim_sci---------------------------------------------------------- /*! Executed within the hs_hdl task. Implements the generic step of the simulated science command and triggers the next step */ int mkstep_sim_sci(int command_number) { HS_HDL_MSG cmd_queue; // send the simulated data generate_sim_science_data(); // wait 3205 msecs task_hs_hdl_sleep(3205); // prepare the next step cmd_queue.operation_id = MKSTEP_SIM_SCI; cmd_queue.command_number = command_number; cmd_queue.block_loaded = 0; if (KS_FIFOPut(HS_HDL_QUEUE, (void *) &cmd_queue) == RC_FAIL) { enqueue_exec_fail(EXF_MEM_HS_HDL_QUEUE, 0, NULL); // execution failure return RC_FAIL; } else return RC_OK; } //------ generate_sim_science_data --------------------------------------------- //! produces simulated science data and sends it towards data_hdl int generate_sim_science_data (void) { int i, j, m, problems; static K_BLOCK sim_sci_block[4]; // request from memory pool one block for each FIFO for (i=0;i<4;i++) get_block(&sim_sci_block[i], SD_POOL, SD_BLOCK_MAX_BYTES); // fill the blocks with increasing numbers for (i=0; i<4; i++) { int * p_aux; p_aux = (int*) (sim_sci_block[i].pointer_to_data + SD_TM_HEADER); for (m=0; m<32 ; m++) { for (j=0; j < HRS_SUBBLOCK_DATA_LEN; j++) { if ( j + (m*HRS_SUBBLOCK_DATA_LEN) < SD_BLOCK_MAX_WORDS - SD_TM_HEADER ) p_aux[j + (m*HRS_SUBBLOCK_DATA_LEN)] = j; } } } // increase pending frames fifo_0_pending_frames++; fifo_1_pending_frames++; fifo_2_pending_frames++; fifo_3_pending_frames++; // pass the packets to data_hdl problems = 0; if ( RC_FAIL == deliver_sd_sim_packet(HRS_V_ID, &sim_sci_block[HRS_V_ID]) ) { release_block(&sim_sci_block[HRS_V_ID]); problems = 1;} if ( RC_FAIL == deliver_sd_sim_packet(HRS_H_ID, &sim_sci_block[HRS_H_ID]) ) { release_block(&sim_sci_block[HRS_H_ID]); problems = 1;} if ( RC_FAIL == deliver_sd_sim_packet(WBS_V_ID, &sim_sci_block[WBS_V_ID]) ) { release_block(&sim_sci_block[WBS_V_ID]); problems = 1;} if ( RC_FAIL == deliver_sd_sim_packet(WBS_H_ID, &sim_sci_block[WBS_H_ID]) ) { release_block(&sim_sci_block[WBS_H_ID]); problems = 1;} // pass the pakcets reset fifo counters when over if ( RC_FAIL == deliver_frame_completed_pkt(WBS_H_ID) ) problems =1; if ( RC_FAIL == deliver_frame_completed_pkt(WBS_V_ID) ) problems =1; if ( RC_FAIL == deliver_frame_completed_pkt(HRS_H_ID) ) problems =1; if ( RC_FAIL == deliver_frame_completed_pkt(HRS_V_ID) ) problems =1; // return if ( problems ) return RC_FAIL; else return RC_OK; } //----------------- deliver_sd_sim_packet -------------------------------------- //! sends simulated science data towards data_hdl int deliver_sd_sim_packet (int fifo_id, K_BLOCK *sd_block) { static SD_PKT_MSG sd_out_msg; // structure which holds the message to data pkt task // Prepare message sd_out_msg.int_scan_cnt = 1; sd_out_msg.subsysID = fifo_id; sd_out_msg.measID = AID_spectroscopy; sd_out_msg.phase = 0; // values: 0 for buffer 1, 1 for buffer 2 sd_out_msg.block = *sd_block; sd_out_msg.transfer_cnt = 1; get_TS( &(dummy_TS.time_stamp)); // get a dummy time stamp: should be useless but is safer sd_out_msg.time_position = put_TS_in_pool( dummy_TS ); // put the TS in the TSD pool and store the addres to pass it to data_hdl // send a message in the Science Data Packet queue if (KS_FIFOPut(SD_PKT_QUEUE, (void *) &sd_out_msg) == RC_FAIL) { release_block(&sd_out_msg.block); // if the fifo_put fails, we must deallocate the memory block generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_MEM_FIFOPUT_SD_PKT_QUEUE, 0, NULL); return RC_FAIL; } else return RC_OK; } //************************************************************************************************** //************************************************************************************************** // more mem managment: check_pm and copy_obs //************************************************************************************************** //************************************************************************************************** //------------------------- start_copy_obs --------------------------------- /*! Implements the first and only step of a OBS_copy command. It copies num_of_words memory cells of the program memory from 0 to start_offset if direction = 1, and in the other direction if direction is 2 (in addition to normal start actions, i.e. the stopping of a possibly running command) Executed within the hs_hdl task */ int start_copy_obs(HS_HDL_MSG *message) { unsigned int direction, start_offset, num_of_words; TC_packet * packet; int result; // check the HS systems status this could be avoided in principle: we keep it for safeness and standardization if ( ! bring_to_safe( message ) ) return RC_OK; // now HS is safe, we can initialize and start // HK production is compatible with memory managment AID_spectroscopy = REQUIRING_HK; // init auxiliary pointer to the TC packet packet = (TC_packet *) message->block.pointer_to_data; // init parameters direction = (packet->data)[2]; start_offset = ((packet->data[3]&0x0000FFFF)<<16) + (packet->data[4]&0x0000FFFF); num_of_words = ((packet->data[5]&0x0000FFFF)<<16) + (packet->data[6]&0x0000FFFF); // here we can release the block release_block(&(message->block)); // execute command result = copy_OBSW_image(direction, start_offset, num_of_words); /* check results: if result is zero the function has been executed */ if (result != COPY_OBSW_IMAGE_OK) enqueue_exec_fail(EXF_MEM_COPY_OBS, 1, &result); // execution failure: send to ground the reurn code else enqueue_exec_compl(); // function that handles execution completion ack return RC_OK; } /*------------------------- variables and defines used by check_pm -----------------------------------------------*/ #define CHECK_PM_WORDS_PER_STEP 0xFFFF /* maximum number of words to check in every step */ static unsigned int ckpm_start_address; //!< start address of PM part to check static unsigned int ckpm_end_address; //!< end address of PM part to check static unsigned int ckpm_next_start; //!< start address for next step static unsigned int ckpm_current_crc; //!< crc as computed from start_address to last_addres static unsigned int ckpm_expected_crc; //!< expected value for the crc /*------------------------- start_check_pm -----------------------------------------------*/ /*! Implements the first step of a check PM command i.e. initialize its static variables. (in addition to normal start actions, i.e. the stopping of a possibly running command) Executed within the hs_hdl task */ int start_check_pm(HS_HDL_MSG *message) { HS_HDL_MSG cmd_queue; TC_packet * packet; // init auxiliary pointer to the TC packet packet = (TC_packet *) message->block.pointer_to_data; // check the HS systems status this could be avoided in principle: we keep it for safeness and standardization if ( ! bring_to_safe( message ) ) return RC_OK; // now HS is safe, we can initialize and start // HK production is compatible with memory managment AID_spectroscopy = REQUIRING_HK; // init parameters ckpm_start_address = ((packet->data[2]&0x0000FFFF)<<16) + (packet->data[3]&0x0000FFFF); ckpm_end_address = ((packet->data[4]&0x0000FFFF)<<16) + (packet->data[5]&0x0000FFFF); ckpm_expected_crc = packet->data[6]; ckpm_next_start = ckpm_start_address; ckpm_current_crc = 0xFFFFFFFF; // here we can release the block release_block(&(message->block)); // check consistency of input data......... // prepare and send to hs_hdl task a message to start the first step of memory dumping cmd_queue.operation_id = MKSTEP_CHECK_PM; cmd_queue.command_number = message->command_number; cmd_queue.block_loaded = 0; if (KS_FIFOPut(HS_HDL_QUEUE, (void *) &cmd_queue) == RC_FAIL) { enqueue_exec_fail(EXF_MEM_HS_HDL_QUEUE, 0, NULL); // execution failure return RC_FAIL; } else return RC_OK; } //------------------------- mkstep_check_pm--------------------------------- /*! Implements the generic step of a check PM command. It checks an additional section of the PM and updates the crc computed on the previous sections. Executed within the hs_hdl task */ int mkstep_check_pm (int command_number) { HS_HDL_MSG cmd_queue; unsigned int end_address; memory_header header; // check if we are over if ( ckpm_next_start > ckpm_end_address ) { // let's compare the crc if ( ckpm_current_crc == ckpm_expected_crc ) enqueue_exec_compl(); // the check was all right else enqueue_exec_fail(EXF_MEM_CHECK_PM_CRC, 1, &ckpm_current_crc); // the check failed // we are over return RC_OK; } // compute the address of the last word to check in this step end_address = ckpm_next_start + CHECK_PM_WORDS_PER_STEP; if ( end_address > ckpm_end_address ) end_address = ckpm_end_address; // prepare header header.subsystem = 0; /* DPU */ header.RAM_type = 0; /* 0 PRAM, 1 DRAM */ header.memory_ID = 1; //= MEMORY_RAM_ID in MM_lib.c header.start_address = ckpm_next_start; header.length_SAU = end_address - header.start_address + 1; header.length_bytes = header.length_SAU * 6; // update the crc ckpm_current_crc = memory_check(&header, ckpm_current_crc); // prepare address for next step ckpm_next_start = end_address + 1; // sleep 1 msec to allow other tasks to take control KS_TaskSleep(1); // prepare and send to hs_hdl task a message to make the next step cmd_queue.operation_id = MKSTEP_CHECK_PM; cmd_queue.command_number = command_number; cmd_queue.block_loaded = 0; if (KS_FIFOPut(HS_HDL_QUEUE, (void *) &cmd_queue) == RC_FAIL) { enqueue_exec_fail(EXF_MEM_HS_HDL_QUEUE, 0, NULL); // execution failure return RC_FAIL; } return RC_OK; } //************************************************************************************************** //************************************************************************************************** // EEPROM R/W //************************************************************************************************** //************************************************************************************************** //-------- defines used by start_write_in_eeprom() ----------------------------- #define MAX_NUMBER_EEPROM_BAD_PAGES 20 // maximum number of bad pages that can be handled //------------ start_write_in_eeprom ------------------------------------------- int start_write_in_eeprom (HS_HDL_MSG * message) { TC_packet * packet; unsigned char result; unsigned int start_addr, end_addr, which_partition, number_of_pages_to_avoid; unsigned int j_FcsTotal, i, obs_err_code; unsigned int page_for_EEPROM[MAX_NUMBER_EEPROM_BAD_PAGES + 2]; // array to hold the list of // pages to be avoided (+2 because the list always starts with 0 and ends with 256) // check the HS systems status if ( ! bring_to_safe( message ) ) return RC_OK; // now HS is safe, we can initialize and start // requests of frames from spectrometers for hk purposes is NOT compatible with memory management AID_spectroscopy = START_EEPROM_WRITE; // init auxiliary pointer to the TC packet packet = (TC_packet *) message->block.pointer_to_data; // extract parameters from TC packet and check their correctness start_addr = PACK(packet->data[2], packet->data[3]); // start address end_addr = PACK(packet->data[4], packet->data[5]); // end address which_partition = packet->data[6]; // partition to write into (1 - primary, 2 - secondary) // which_partition must be either 1 or 2 (this should be consistent with the force boot TC convention) if ((which_partition != 1) && (which_partition != 2)) { release_block(&(message->block)); AID_spectroscopy = REQUIRING_HK; return enqueue_exec_fail(EXF_MEM_EEPROM_WRONG_PARTITION, 1, &which_partition); } number_of_pages_to_avoid = packet->data[7]; // we are assuming a maximum length for the list of bad pages if (number_of_pages_to_avoid > MAX_NUMBER_EEPROM_BAD_PAGES) { release_block(&(message->block)); AID_spectroscopy = REQUIRING_HK; return enqueue_exec_fail(EXF_MEM_EEPROM_WRONG_NUM_BAD_PAGES, 1, &number_of_pages_to_avoid); } // the Eeprom write TC has variable length; we can do the following consistency check if ((number_of_pages_to_avoid*2 + 21) != packet->packet_length) { release_block(&(message->block)); AID_spectroscopy = REQUIRING_HK; return enqueue_exec_fail(EXF_MEM_EEPROM_WRONG_NUM_BAD_PAGES, 0, NULL); } // now set up the list of bad pages in array page_for_EEPROM[] page_for_EEPROM[0] = 0; // first element in the list is always 0 for (i = 0; i < number_of_pages_to_avoid; i++) { // check that the list of bad pages does not contain uncorrect values (ie greater than 256) if (packet->data[8 + i] > 256) { release_block(&(message->block)); AID_spectroscopy = REQUIRING_HK; return enqueue_exec_fail(EXF_MEM_EEPROM_WRONG_BAD_PAGE_ID, 0, NULL); } else page_for_EEPROM[i + 1] = packet->data[8 + i]; } page_for_EEPROM[number_of_pages_to_avoid + 1] = 256; // last element in the list is always 256 // here we can free the block release_block(&(message->block)); // compute Frame Check Sequence table ComputeFCSTable(); // compute the FCS on the program memory overall j_FcsTotal = ComputeFcsOverall(start_addr, end_addr); // perform the copy result = CopyProgramInEEPROM(start_addr, end_addr, which_partition, page_for_EEPROM, j_FcsTotal); if (result == DM_EEPROM_ERROR_COPY_SUCCESS) { enqueue_exec_compl(); // execution completion ack AID_spectroscopy = REQUIRING_HK; return RC_OK; } else { obs_err_code = translate_eeprom_write_retval(result); AID_spectroscopy = REQUIRING_HK; return enqueue_exec_fail(obs_err_code, 0, NULL); // execution failure } } //-------- translate_eeprom_write_retval --------------------------------------- // maps to obs error codes the return error value of function CopyProgramInEEPROM() of the eeprom library unsigned int translate_eeprom_write_retval (int error_code) { switch (error_code) { case DM_EEPROM_ERROR_OVERFLOW: return EXF_MEM_EEPROM_WRITE_OVERFLOW; case DM_EEPROM_ERROR_COPY_FAILED: return EXF_MEM_EEPROM_COPY_FAILED; default: return EXF_MEM_UNKNOWN_RET_CODE; } } /******************************************************************************************/ /******************************************************************************************/ // LCU MEMORY DUMP and LOAD /******************************************************************************************/ /******************************************************************************************/ // The following functions implement the mem dump LCU command #define MEM_LCU_PARS_LEN 499 /* max number of hk to issue */ // TC packet datas static int start_address; static int words_num; // TM packet data static unsigned int mem_LCU_data[MEM_LCU_PARS_LEN+1]; // +1 because later we will add the total lenght as first element //------- exec_mem_load_LCU ---------------------------------------------------- //! Start and only step for a mem load LCU request: enqueues the HK requestes towards the LCU by posting the corresponding messages towards ls() int exec_mem_load_LCU(int *paux) { int i; int load_address, words_to_load; static unsigned int LS_cmd[MEM_LCU_PARS_LEN+1]; unsigned int checksum; // store the data into variables load_address = paux[6] & 0xFFFF; words_to_load = paux[7] & 0x00FF; // some consistency checks if ( load_address + 2*words_to_load > 0xffff) return enqueue_exec_fail(EXF_MEM_LCU_INVALID_DATA, 0, NULL); // data crc check checksum = memcrc16( &paux[8], words_to_load, 0xFFFF); if ( checksum != paux[8 + words_to_load] ) return enqueue_exec_fail(EXF_MEM_INVALID_CRC1, 0, NULL); // check if LCU is on, otherwise abort if ((SubsysStatus & LCU_MASK) == 0) return enqueue_exec_fail(EXF_MEM_LCU_OFF, 0, NULL); // Now construct and send the cmds to LS for (i = 0; i < words_to_load; i++) { // construct the command that tells LCU where to write LS_cmd[i] = 0xF3000000 | (load_address + 2*i); // issue the command if (ls_put_msg_hp(&LS_cmd[i], NULL, 0, NULL) == RC_FAIL) return enqueue_exec_fail(EXF_MEM_ERROR_LS_HP_QUEUE, 0, NULL); // construct the command that tells LCU what to write mem_LCU_data[i] = 0xF3210000 | (paux[8+i] & 0x0000FFFF); // issue the command if (ls_put_msg_hp(&mem_LCU_data[i], NULL, 0, NULL) == RC_FAIL) return enqueue_exec_fail(EXF_MEM_ERROR_LS_HP_QUEUE, 0, NULL); } // finished enqueue_exec_compl(); // function that handles execution completion ack return RC_OK; } //------- exec_mem_dump_LCU ---------------------------------------------------- //! Start step for a mem dump LCU request: enqueues the HK requestes towards the LCU by posting the corresponding messages towards ls() int exec_mem_dump_LCU(HS_HDL_MSG *msg) { int *paux, i; unsigned int max_num, yy; static unsigned int LCU_mem_LScmd_current[MEM_LCU_PARS_LEN]; static unsigned int mem_LCU_current_request[MEM_LCU_PARS_LEN]; // prepare an auxiliary pointer paux = (int *) (msg->block).pointer_to_data; // store the data into static top level variables start_address = paux[6]; words_num = paux[7]; // we can free the block from the TC_POOL release_block((K_BLOCK *) &(msg->block)); // some consistency checks max_num = start_address + 2*(words_num-1); if ( max_num > 0xffff) { AID_spectroscopy = REQUIRING_HK; return enqueue_exec_fail(EXF_MEM_LCU_INVALID_DATA, 0, NULL); } // max length of a TM packet = 1024 bytes. Header and fixed data for mem_dump = 26 byte. Max number of dumpable 16bit words = (1024-26)/2 = 499. if ( words_num > 499) { AID_spectroscopy = REQUIRING_HK; return enqueue_exec_fail(EXF_MEM_LCU_INVALID_DATA, 0, NULL); } // check if LCU is on, otherwise abort if ((SubsysStatus & LCU_MASK) == 0) { AID_spectroscopy = REQUIRING_HK; return enqueue_exec_fail(EXF_MEM_LCU_OFF, 0, NULL); } // Now construct and send the hk reqs to LS yy = start_address; for (i = 0; i < words_num; yy+=2, i++) { // construct the cmd LCU_mem_LScmd_current[i] = 0xF30ACC00 | ( (yy & 0xFF00) >> 8 ); // issue the command only if different from the last one (it is useless to set the page twice) if ( i == 0 ) { if (ls_put_msg_hp(&LCU_mem_LScmd_current[i], NULL, 0, NULL) == RC_FAIL) { AID_spectroscopy = REQUIRING_HK; return enqueue_exec_fail(EXF_MEM_ERROR_LS_HP_QUEUE, 0, NULL); } // wait 3 msec for the cmd to be executed in order prevent ls_hp_queue flooding KS_TaskSleep(3); } else if( LCU_mem_LScmd_current[i] != LCU_mem_LScmd_current[i-1] ) { if (ls_put_msg_hp(&LCU_mem_LScmd_current[i], NULL, 0, NULL) == RC_FAIL) { AID_spectroscopy = REQUIRING_HK; return enqueue_exec_fail(EXF_MEM_ERROR_LS_HP_QUEUE, 0, NULL); } // wait 3 msec for the cmd to be executed in order prevent ls_hp_queue flooding KS_TaskSleep(3); } // construct the HK req mem_LCU_current_request[i] = ((0xB300 | (yy&0xFF) ) << 16) | 0xffff; // issue the HK req if (ls_put_msg_hp(&mem_LCU_current_request[i], &mem_LCU_data[i], 0, NULL) == RC_FAIL) { AID_spectroscopy = REQUIRING_HK; return enqueue_exec_fail(EXF_MEM_ERROR_LS_HP_QUEUE, 0, NULL); } // wait 3 msec for HK in order prevent ls_hp_queue flooding KS_TaskSleep(3); // check if the command is still the last: if not kill command if (msg->command_number != current_command_number) { AID_spectroscopy = REQUIRING_HK; return RC_FAIL; } } // push in ls queue the request for signalling upon termination if (ls_put_msg_hp(NULL, (unsigned int *) msg->command_number, SEND_MEM_DUMP_LCU_REPORT, NULL) == RC_FAIL) { AID_spectroscopy = REQUIRING_HK; return enqueue_exec_fail(EXF_MEM_ERROR_LS_HP_QUEUE, 0, NULL); } // finished return RC_OK; } //---- send_mem_dump_LCU_report ------------------------------------------------- //! Second and last step for a mem dump LCU request: sends a report containing the data gathered by the first step int send_mem_dump_LCU_report(void) { unsigned int i; unsigned int checksum; int ram_type; int mem_id; // We now format the data as required by generate_dump_report // shift HK results one position up to make space for the number of data for (i = words_num; i > 0; i--) mem_LCU_data[i] = mem_LCU_data[i-1]; // store the number of words as first parameter mem_LCU_data[0] = words_num; // set other parameters checksum = 0; mem_id = MEM_ID_LCU; ram_type = 2; // we now produce and try to send the dump report if ( RC_OK == generate_dump_report(ram_type, mem_id, start_address, mem_LCU_data, checksum) ) { // all right enqueue_exec_compl(); // function that handles execution completion ack AID_spectroscopy = REQUIRING_HK; // restarts HK return RC_OK; } else { // problems enqueue_exec_fail(ERR_MEM_FIFOPUT_HK_TM_QUEUE, 0, NULL); // execution failure AID_spectroscopy = REQUIRING_HK; // restarts HK return RC_FAIL; } }