// $RCSfile: res_chk.c,v $Revision: 1.85 $Date: 2005/03/11 15:08:57 #include "allnodes.h" #include "node1.h" #include #include "configura.h" #include "pubfuncs.h" #include "err_hdl.h" #include "cmd_exec.h" #include "data_hdl.h" #include "cmd_seq.h" #include "hk_ask.h" #include "main.h" #include "hs0.h" #include "MM_crc.h" #include "hs_hdl.h" #include "res_chk.h" #include "vm_lib.h" #include "res_chk.dox" #include "init1553.h" //------ Local Defines --------------------------------------------------------- // OBS Version and ID #define OBS_VERS 0x0106 #define OBS_REV 0x4 #define OBS_VERS_REV (OBS_VERS << 8) + (OBS_REV & 0xFF) // OBS housekeeping vector indexes names #define OBS_VERS_IDX 0 #define NUM_IDLE_RUN_IDX 1 #define CPU_LOAD_MIN_IDX 2 #define CPU_LOAD_AVER_IDX 3 #define CPU_LOAD_MAX_IDX 4 #define EV_POOL_MAX_BLOCKS_IDX 5 #define HK_POOL_MAX_BLOCKS_IDX 6 #define SD_POOL_MAX_BLOCKS_IDX 7 #define TC_POOL_MAX_BLOCKS_IDX 8 #define LS_LP_QUEUE_MAX_IDX 9 #define HK_TM_QUEUE_MAX_IDX 10 #define SD_TM_QUEUE_MAX_IDX 11 #define EVENT_TM_QUEUE_MAX_IDX 12 #define TC_QUEUE_MAX_IDX 13 #define SD_PKT_QUEUE_MAX_IDX 14 #define VM_RUNNING_FLAG_IDX 15 #define PLUS_2_5_V_MONITOR_IDX 16 #define PLUS_5_V_MONITOR_IDX 17 #define PLUS_15_V_MONITOR_IDX 18 #define MINUS_15_V_MONITOR_IDX 19 #define TEMPERATURE_MONITOR_IDX 20 #define SUBSYSTEM_STATUS_IDX 21 #define LS_HP_QUEUE_MAX_IDX 22 #define SPECTR_HK_VALID_IDX 23 #define AID_SPECTR_IDX 24 //------ Local functions ------------------------------------------------------- void rc_check_DM(void); void rc_check_subframe_counter(void); //------ Local Variables ------------------------------------------------------- // OBS housekeeping vector (only partially initialized); this array is continuously // written by task res_chk, then it is read by task hk_ask to prepare the ICU section // of the hk packet. static unsigned int Obs_HK[MAX_ICU_HK] = {OBS_VERS_REV, 0, 0xFFFFFFFF, 0, 0, 0, 0, 0}; static unsigned int check_pending_frames = 1; // if 0 the check on the pending frames is disabled (prevents event overflow) //------ Task resource check --------------------------------------------------- // Task resource check, prepares the OBS house keeping void res_chk (void) { static unsigned int * P_sel, * P_data; static unsigned int OLd_ticks = 0; unsigned int new_ticks; unsigned int ticks_delta = 0; // to hold the difference between two subsequent run of the task unsigned int ev_cnt, hk_cnt, sd_cnt, tc_cnt; static unsigned int ev_tccnt = 0, ev_sdcnt = 0, ev_hkcnt = 0; unsigned int ls_lp_fifo_cnt, ls_hp_fifo_cnt, hk_tm_fifo_cnt, sd_tm_fifo_cnt, event_tm_fifo_cnt, tc_fifo_cnt; unsigned int sd_pkt_fifo_cnt; unsigned int i, value, start_count, wait_count; // auxiliary pointers initialization P_sel = ICU_HK_SEL_REG; // points to ICU HK select register P_data = ICU_HK_DATA_REG; // points to ICU HK data register while (1) { Obs_HK[NUM_IDLE_RUN_IDX]++; // increment counter, used to count how many times // this task passes over this instruction between two consecutive hk packet generations // (in fact this counter is reset after a hk packet delivery: see function rc_write_obs_hk) new_ticks = KS_HighTimerRead(); // read High Resolution Timer // verify if there has been a wrap around since the last call, and perform difference // WARNING: we make the assumption that at most one wrap around has occurred (this means that this task must run // at least once every 215 seconds, that is a reasonable assumption) if (new_ticks > OLd_ticks) ticks_delta = new_ticks - OLd_ticks; else ticks_delta = 0xFFFFFFFF - OLd_ticks + new_ticks; OLd_ticks = new_ticks; // update old ticks value // update CPU_LOAD_MIN and CPU_LOAD_MAX if (ticks_delta < Obs_HK[CPU_LOAD_MIN_IDX]) Obs_HK[CPU_LOAD_MIN_IDX] = ticks_delta; // Obs_HK[CPU_LOAD_MIN_IDX] represents the minimum (over the hk generation period) time interval between // two consecutive loop iterations of this task (it should be > 15 ms, but may be corrupted by first iteration) if (ticks_delta > Obs_HK[CPU_LOAD_MAX_IDX]) Obs_HK[CPU_LOAD_MAX_IDX] = ticks_delta; // Obs_HK[CPU_LOAD_MAX_IDX] represents the maximum (over the hk generation period) time interval between // two consecutive loop iterations of this task (certainly > 15 ms) Obs_HK[CPU_LOAD_AVER_IDX] += ticks_delta; // cumulate amount of ticks into CPU_LOAD_AVER //Obs_HK[CPU_KSLOAD_IDX] = KS_WorkloadRead(); // virtuoso service to read the processor workload // see also the call to KS_WorkloadSetPeriod() in main.c Obs_HK[VM_RUNNING_FLAG_IDX] = ! EndProg; // virtual machine state // note: when EndProg is TRUE the virtual machine isn't running, so the hk parameter must be FALSE // now collect parameter HI_2P5_V *P_sel = 7; // set the value of the register pointed by P_sel // before reading the result in the register pointed by P_data, we have // to wait at least 100 microseconds ( = 2000 high resolution timer periods) start_count = KS_HighTimerRead(); wait_count = start_count; while ((wait_count - start_count) < 2000) wait_count = KS_HighTimerRead(); value = *P_data; if (value >= 0x1000) Obs_HK[PLUS_2_5_V_MONITOR_IDX] = value & 0xFFF; // now in the same way: 3 voltages (HI_5P_V, HI_15P_V, HI_15M_V) and the CPU temperature for (i = 1; i < 5; i++) { *P_sel = i; start_count = KS_HighTimerRead(); wait_count = start_count; while ((wait_count - start_count) < 2000) wait_count = KS_HighTimerRead(); value = *P_data; if (value >= 0x1000) Obs_HK[PLUS_2_5_V_MONITOR_IDX + i] = value & 0xFFF; } // gather memory pool occupation information from the global array sd_cnt = Memory_Pool_Occupation[0]; // SD_POOL tc_cnt = Memory_Pool_Occupation[1]; // TC_POOL ev_cnt = Memory_Pool_Occupation[2]; // EV_POOL hk_cnt = Memory_Pool_Occupation[3]; // HK_POOL // if necessary, update the Obs_HK vector if (ev_cnt > Obs_HK[EV_POOL_MAX_BLOCKS_IDX]) Obs_HK[EV_POOL_MAX_BLOCKS_IDX] = ev_cnt; if (hk_cnt > Obs_HK[HK_POOL_MAX_BLOCKS_IDX]) Obs_HK[HK_POOL_MAX_BLOCKS_IDX] = hk_cnt; if (sd_cnt > Obs_HK[SD_POOL_MAX_BLOCKS_IDX]) Obs_HK[SD_POOL_MAX_BLOCKS_IDX] = sd_cnt; if (tc_cnt > Obs_HK[TC_POOL_MAX_BLOCKS_IDX]) Obs_HK[TC_POOL_MAX_BLOCKS_IDX] = tc_cnt; // SD pool occupation monitoring: if ((ev_sdcnt >= 1) && (sd_cnt < 30)) ev_sdcnt = 0; // reset event counter if (sd_cnt >= 30) // pool occupation >= (30/32)*100 = 94% of pool capacity { if (ev_sdcnt == 0) { SD_TM_MSG sd_tm_msg; // flush TM Science Data packets fifos and pools while (RC_OK == KS_FIFOGet(SD_TM_QUEUE, &sd_tm_msg)) if (sd_tm_msg.count == 0) release_block(&sd_tm_msg.block); abort_measurement(); // Stops all activities on board, VM included generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_RESCK_SD_POOL_OVERFLOW_WARN, 1, &sd_cnt); } ev_sdcnt++; } // HK pool occupation monitoring: if ((ev_hkcnt >= 1) && (hk_cnt < 22)) { ev_hkcnt = 0; // reset event counter Hk_enable = TRUE; } if (hk_cnt >= 22) // pool occupation >= (22/24)*100 = 91% of pool capacity { if (ev_hkcnt == 0) { HK_TM_MSG hk_tm_msg; Hk_enable = FALSE; abort_measurement(); // Stops all activities on board, VM included generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_RESCK_HK_POOL_OVERFLOW_WARN, 1, &hk_cnt); // flush HK fifos and pools while (RC_OK == KS_FIFOGet(HK_TM_QUEUE, &hk_tm_msg)) release_block(&hk_tm_msg.block); } ev_hkcnt++; } // TC pool occupation monitoring: if ((ev_tccnt >= 1) && (tc_cnt < 28)) ev_tccnt = 0; // reset event counter if (tc_cnt >= 28) // pool occupation >= (28/32)*100 = 87,5% of pool capacity { if (ev_tccnt == 0) generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_RESCK_TC_POOL_OVERFLOW_WARN, 1, &tc_cnt); ev_tccnt++; } // read Virtuoso fifos occupation status ls_lp_fifo_cnt = KS_FIFOStatus(LS_LP_QUEUE); // LS_LP_QUEUE ls_hp_fifo_cnt = KS_FIFOStatus(LS_HP_QUEUE); // LS_HP_QUEUE hk_tm_fifo_cnt = KS_FIFOStatus(HK_TM_QUEUE); // HK_TM_QUEUE sd_tm_fifo_cnt = KS_FIFOStatus(SD_TM_QUEUE); // SD_TM_QUEUE sd_pkt_fifo_cnt = KS_FIFOStatus(SD_PKT_QUEUE); // SD_TM_QUEUE event_tm_fifo_cnt = KS_FIFOStatus(EVENT_TM_QUEUE); // EVENT_TM_QUEUE tc_fifo_cnt = KS_FIFOStatus(TC_QUEUE); // TC_QUEUE // store FIFOs status in Obs_HK array only if greater than previously // stored values (we want the max during two consecutive hk packets) if (ls_lp_fifo_cnt > Obs_HK[LS_LP_QUEUE_MAX_IDX]) Obs_HK[LS_LP_QUEUE_MAX_IDX] = ls_lp_fifo_cnt; // idx 9 if (ls_hp_fifo_cnt > Obs_HK[LS_HP_QUEUE_MAX_IDX]) Obs_HK[LS_HP_QUEUE_MAX_IDX] = ls_hp_fifo_cnt; // idx 22 if (hk_tm_fifo_cnt > Obs_HK[HK_TM_QUEUE_MAX_IDX]) Obs_HK[HK_TM_QUEUE_MAX_IDX] = hk_tm_fifo_cnt; // idx 10 if (sd_tm_fifo_cnt > Obs_HK[SD_TM_QUEUE_MAX_IDX]) Obs_HK[SD_TM_QUEUE_MAX_IDX] = sd_tm_fifo_cnt; // idx 11 if (sd_pkt_fifo_cnt > Obs_HK[SD_PKT_QUEUE_MAX_IDX]) Obs_HK[SD_PKT_QUEUE_MAX_IDX] = sd_pkt_fifo_cnt; // idx 14 if (event_tm_fifo_cnt > Obs_HK[EVENT_TM_QUEUE_MAX_IDX]) Obs_HK[EVENT_TM_QUEUE_MAX_IDX] = event_tm_fifo_cnt; // idx 12 if (tc_fifo_cnt > Obs_HK[TC_QUEUE_MAX_IDX]) Obs_HK[TC_QUEUE_MAX_IDX] = tc_fifo_cnt; // idx 13 Obs_HK[SUBSYSTEM_STATUS_IDX] = SubsysStatus; // current subsystem status Obs_HK[AID_SPECTR_IDX] = AID_spectroscopy; // current subsystem status // check data memory integrity rc_check_DM(); // check _pending_frames if ( check_pending_frames == 1 ) check_pending_frames = check_fifo_pending_frames(); // the function returns 0 if an error was issued, thereby stopping the check } } //----------- rc_write_obs_hk -------------------------------------------------- // this function, to be called by the HK task, copies the OBS HK data, stored into // array Obs_HK[], into the memory block where the hk packet is being built, in a // position pointed by argument pdata_obs; after that, the array Obs_HK[] is // appropriately reinitialized. void rc_write_obs_hk (int * pdata_obs) { static unsigned int duration_of_res_chk = 0xFFFFFFFF; // store the estimated duration of one run of the idle task (in high res thiks) static unsigned int last_check_time = 0; unsigned int delta_check_time, this_check_time; float f_perc; int i, j; // improve the estimate of the duration of one res_chk round if ( duration_of_res_chk > Obs_HK[CPU_LOAD_MIN_IDX] ) duration_of_res_chk = Obs_HK[CPU_LOAD_MIN_IDX]; // compute the time since last access to ICU HK an store this check time this_check_time = KS_HighTimerRead(); // read High Resolution Timer // verify if there has been a wrap around since the last call, and perform difference // WARNING: we make the assumption that at most one wrap around has occurred (this means that this task must run // at least once every 215 seconds, that is a reasonable assumption) if (this_check_time > last_check_time ) delta_check_time = this_check_time - last_check_time; else delta_check_time = 0xFFFFFFFF - last_check_time + this_check_time ; last_check_time = this_check_time ; // update old ticks value // compute the average cpu load f_perc = (float)Obs_HK[CPU_LOAD_AVER_IDX]-((float)(Obs_HK[NUM_IDLE_RUN_IDX] * (float) duration_of_res_chk)); f_perc = (float)((f_perc/(float)(delta_check_time))*100.); Obs_HK[CPU_LOAD_AVER_IDX] = (unsigned int) (f_perc); // this loop is for copying from Obs_HK[] to memory pointed by pdata_obs; // note: every element in Obs_HK[] is split into two elements in pdata_obs[] // note: j goes from 0 to 22, then i from 0 to 45: we mustn't overwrite // position 46 and 47 of pdata_obs[] because there task hs1 has written the // validity flags (see functions hk_process_hrs, hk_process_wbs) for (j = 0, i = 0; j < 23; j++, i++) { pdata_obs[i] = Obs_HK[j] >> 16; pdata_obs[++i] = Obs_HK[j]; } // the following two lines copy the AID_spectroscopy value stored at index // AID_SPECTR_IDX of array Obs_HK[] pdata_obs[48] = Obs_HK[AID_SPECTR_IDX] >> 16; pdata_obs[49] = Obs_HK[AID_SPECTR_IDX]; // note: positions at indexes 50-53 (extremes included) in pdata_obs[] are // occupied by the transfer counters written by task hs1 (see functions // hk_process_hrs, hk_process_wbs) in order to link hk to science; // note: positions from index 54 on are still spare. // therefore here we use position 55 (that is the lower 16 bits of 32-bit word 27) to send the status word on the autonomous functions pdata_obs[55] = hk_limit_check_status(); // and position 56 (that is the upper 16 bits of 32-bit word 28) to send the status of the HK_SubsysStatus pdata_obs[56] = HK_SubsysStatus; // and position 57 (that is the lower 16 bits of 32-bit word 28) to send the status of the LCU_non_interaction_flag pdata_obs[57] = LCU_non_interaction; // and position 58 (that is uppe 16 bits of word 29) to send the crc of dummy_check_mem (to spot memory corruption problems) pdata_obs[58] = memcrc32 (dummy_chk_mem, 400, 0xFFFFFFFF); // and position 59 (that is lower 16 bits of word 29) to send the subframe delta counters (to spot interrupts problems) if ( Counter_Flag ) { pdata_obs[59] = Delta_0_SubFrame_Counter; pdata_obs[60] = Delta_1_SubFrame_Counter; } else { pdata_obs[59] = 64; pdata_obs[60] = 1; } // now reinitialize some elements in Obs_HK[] Obs_HK[NUM_IDLE_RUN_IDX] = 0; Obs_HK[CPU_LOAD_MIN_IDX] = 0xFFFFFFFF; Obs_HK[CPU_LOAD_AVER_IDX] = 0; Obs_HK[CPU_LOAD_MAX_IDX] = 0; Obs_HK[EV_POOL_MAX_BLOCKS_IDX] = 0; Obs_HK[HK_POOL_MAX_BLOCKS_IDX] = 0; Obs_HK[SD_POOL_MAX_BLOCKS_IDX] = 0; Obs_HK[TC_POOL_MAX_BLOCKS_IDX] = 0; Obs_HK[LS_LP_QUEUE_MAX_IDX] = 0; Obs_HK[LS_HP_QUEUE_MAX_IDX] = 0; Obs_HK[HK_TM_QUEUE_MAX_IDX] = 0; Obs_HK[SD_TM_QUEUE_MAX_IDX] = 0; Obs_HK[EVENT_TM_QUEUE_MAX_IDX] = 0; Obs_HK[TC_QUEUE_MAX_IDX] = 0; Obs_HK[SD_PKT_QUEUE_MAX_IDX] = 0; Obs_HK[SUBSYSTEM_STATUS_IDX] = SubsysStatus; Obs_HK[AID_SPECTR_IDX] = AID_spectroscopy; } //----------- rc_check_DM -------------------------------------------------- //! checks one word of the DM by reading and writing its content. // The address of the checked word (check_address) is increased in order to check the whole memory in some time #define DM_LAST_WORD 0x7ffff #define MAX_BROKEN_DM_CELL 100 void rc_check_DM() { // allocate variables in the Program memory static unsigned int check_address = 0; // address of current cell to check static unsigned int * pm check_pointer; static unsigned int pm dm_copy; static unsigned int dm_check; static unsigned int check_ok, cell_marked; int i; static unsigned int broken_cell_table[MAX_BROKEN_DM_CELL]; static int number_of_broken_cells = 0; // check if we overflowed if ( number_of_broken_cells >= MAX_BROKEN_DM_CELL ) return; // check if the cell is marked cell_marked = 0; for( i=0; i< number_of_broken_cells; i++ ) if ( broken_cell_table[i] == check_address ) cell_marked = 1; // check memory if ( !cell_marked ) { check_ok = 1; check_pointer = (unsigned int *) check_address; // cast the address and set a pointer to the word to check __asm("bit clr mode1 0x1000;NOP;NOP;"); // disables all interrupts dm_copy = (*check_pointer); // store value dm_check = ~(*check_pointer); // read and negate (*check_pointer) = dm_check; // write dm_check = ~(*check_pointer); // read and negate if ( dm_check != dm_copy ) check_ok = 0; // check (*check_pointer) = dm_copy; // restore value __asm("bit set mode1 0x1000;NOP;NOP;"); // enables all interrupts // check results and issue a report in case of error if ( ! check_ok ) { unsigned int report_data[2]; report_data[0] = ( check_address & 0xFFFF0000) >> 16; report_data[1] = ( check_address & 0x0000FFFF); generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_RESCK_DM_FAIL, 2, report_data); // mark the cell as broken broken_cell_table[number_of_broken_cells] = check_address; number_of_broken_cells++; if ( number_of_broken_cells >= MAX_BROKEN_DM_CELL ) generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_RESCK_DM_CK_STOPPED, 0, NULL); } } // check if wrap check_address++; if ( check_address > DM_LAST_WORD ) check_address = 0; // uncomment the following line to get a feedback from the DM check //if ( check_address == 0 ) generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_RESCK_DM_WRAP, 0, NULL); } //----------- rc_restart_checks -------------------------------------------------- //! called by hk_ask: reenables checks void rc_restart_checks(void) { check_pending_frames = 1; } /******************************* some important ICU HK: position as 16 bit word (byte = word*2 + 26) 42-43 subsys status 44-45 ls hp queue 46-47 HK validity flag 48-49 Aid spectroscopy 50-51 wbs transf count 52-53 hrs transf count 54 spare 55 007f autonomous function status 56 003f HK_subsysstatus 57 0000 LCU_non_interaction 58 fbbc crc of dummy mem ************************************/