// $RCSfile: hs_lib.c,v $Revision: 1.102 $Date: 2005/03/11 15:08:57 #include "allnodes.h" #include "node1.h" #include #include "configura.h" #include "pubfuncs.h" #include "time_tsk.h" #include "cmd_seq.h" #include "data_hdl.h" #include "hs0.h" #include "main.h" #include "tables.h" #include "conf_tab.h" #include "cmd_exec.h" #include "hs_hdl.h" #include "err_hdl.h" #include "hs_lib.h" #include "hk_ask.h" #include "ls.h" #include "vm_lib.h" #include "hs0.h" #include "res_chk.h" #include "MM_misc.h" #include #include "hs_lib.dox" //------------------------- Global variables ----------------------------------- static unsigned int target_in_percents; //------------------------- Local functions ------------------------------------ void init_tuni_table (unsigned int spectr_id); void reset_fifo (void); unsigned int median_idx (int * Vettore, int lunghezza); void siftdown (int array[], int lower, int upper); void heapsort (int array[], int len); int HS_safe_status (void); void mix_mag_optimise_and_store(unsigned int fifo_id, unsigned int * nl, unsigned int average_power, int position); int peakup_integrate_hrs (int instrument_id, int command_number); int peakup_integrate_wbs (int instrument_id, int command_number); int peakup_find_best_direction (int * microrotation_z, int * microrotation_y); int step_1_new_cal(void); int step_2_new_cal(int); int step_3_new_cal(void); int step_4_new_cal(int); int step_5_new_cal(void); int step_6_new_cal(void); //------------------------- init_tuni_table ------------------------------------ //! Inits SD_hdl and Spectroscopy_table for several OBS operations void init_tuni_table (unsigned int spectr_id) { int fifo; // set coaddition to 1 for (fifo = 0; fifo < 4; fifo++) Sd_hdl[fifo].int_num = 1; // init_science data init_spec_table(); switch (spectr_id) { case HRS_ATTSETT_ID : case PEAKUP_ACQUIRE_HRS : //Number of WBS starts during the whole measurement Spectroscopy_table[HIF_N_WBS_START_IDX] = 0; //Number of HRS-accumulations during one WBS accumulation Spectroscopy_table[HIF_R_HRS_IDX] = 1; // 1 accumulation per each cicle Spectroscopy_table[HIF_T_ACC_HRS_IDX] = 1000; break; case WBS_ATTSETT_ID : case WBS_COMB_STEP1_ID : case SPECTROSCOPY_WBS_ZERO_ID : //Number of WBS starts during the whole measurement Spectroscopy_table[HIF_N_WBS_START_IDX] = 1; //Number of HRS-accumulations during one WBS accumulation Spectroscopy_table[HIF_R_HRS_IDX] = 0; //set wbs data packing to 24 bits Spectroscopy_table[HIF_WBS_packing_IDX] = PACKING_24; break; case TUNE_HMIXMAG_ID : case DIP_SCAN_IF_ID : //Number of WBS starts during the whole measurement Spectroscopy_table[HIF_N_WBS_START_IDX] = 0; //Number of HRS-accumulations during one WBS accumulation Spectroscopy_table[HIF_R_HRS_IDX] = 1; // 1 accumulation per each cicle break; case TUNE_WMIXMAG_ID : case PEAKUP_ACQUIRE_WBS : //Number of WBS starts during the whole measurement Spectroscopy_table[HIF_N_WBS_START_IDX] = 1; //Number of HRS-accumulations during one WBS accumulation Spectroscopy_table[HIF_R_HRS_IDX] = 0; break; default : generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_INVALID_SPECTR_ID, 1, &spectr_id); break; } init_science_data(); } //------------------------- reset_fifo ----------------------------------------- //! Resets the HS subsystem (HW and SW) void reset_fifo (void) { KS_ISRDisable(IRQ0_N); // disable IRQ0 reset_FIFO(); // Empties FIFOs reset_HS(); // Restarts hs reset_data_hdl(); // Inits static data for data_hdl KS_ISREnable(IRQ0_N); // Reenable hs } //------------------------- LS_activity_preparation ---------------------------- //! Prepare a new command execution by the ls_hdl task. Similar to hs_safe_status void LS_activity_preparation (void) { switch (AID_spectroscopy) { case REQUIRING_HK: // HK status { // in this case nothing has to be done since frame requests to spectrometers // for HK purpose are compatible with the activities carried out by task ls_hdl break; } case TC_FUNMAN_SPCTRTP_AID: // total power case TC_FUNMAN_SPCTRSC_AID: // slow chop case TC_FUNMAN_SPCTRFC_AID: // fast chop case TC_FUNMAN_SPCTRFS_AID: // frequency switch case NEW_CALIB_RUN_AID: // new wbs comb case NEW_CALIB_CLOSE_AID: // new wbs comb { // stop virtual machine if running stop_VM(); // change AID_spectroscopy so that, if the VM has already given the flush // event, the data frame will not arrive up to task data_hdl AID_spectroscopy = STOPPING_VM; // wait 1100 msecs; enough for a possibly ongoing data transfer to end KS_TaskSleep(1100); // check that AID_spectroscopy has not been changed by some other task during the sleep period; // in fact it is possible (but not too propable) that data_hdl receives the last frames of // a measurement that were put in its input fifo before AID_spectroscopy was changed to STOPPING_VM, // so with the right value of the field measID: data_hdl will set AID_spectroscopy to // REQUIRING_HK: in this case is correct to return and avoid the call to reset_fifo(), // because the situation is safe for a ls activity to start (but note: the exec compl will be wrong) if (AID_spectroscopy != STOPPING_VM) { generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_AID_SPECTR_CHANGED, 1, &AID_spectroscopy); return; } // reset HW fifos to clear any remaining data reset_fifo(); // reset the pending frames counters fifo_0_pending_frames = 0; fifo_1_pending_frames = 0; fifo_2_pending_frames = 0; fifo_3_pending_frames = 0; // set AID_spectroscopy to REQUIRING_HK (i.e. reenable Hk acquisition from spectrometers) AID_spectroscopy = REQUIRING_HK; break; } case STOPPING_HK: { // set AID_spectroscopy to REQUIRING_HK (i.e. reenable Hk acquisition from spectrometers) AID_spectroscopy = REQUIRING_HK; break; } case STOPPING_VM: { // this case is just for debug: it should never be executed generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_AID_STOPPING_VM, 0, NULL); break; } // the default case is for all OBS activities involving the HS links default: { // change AID_spectroscopy so that data_hdl will no more receive frames // from the interrupted activity and so it should be impossible (or less // probable) that data_hdl sets AID_spectroscopy to REQUIRING_HK AID_spectroscopy = STOPPING_OBS; // wait 1100 msecs; enough for a possibly ongoing data transfer to end; // NOTE: here we don't exploit the fifo_X_pending_frames variables as we // could; we decide, eventually as a first rough solution, to force a // constant sleep of 1100 msecs (but it should be safer to replace the // fixed duration sleep above with a more reliable re-enqueuinq mechanism // as that used in hs_hdl) KS_TaskSleep(1100); // check that AID_spectroscopy has not been changed by some other task during the sleep period; // in fact it is possible (but not too propable) that data_hdl receives the last frames of // a measurement that were put in its input fifo before AID_spectroscopy was changed to STOPPING_OBS, // so with the right value of the field measID: data_hdl will set AID_spectroscopy to // REQUIRING_HK: in this case is correct to return and avoid the call reset_fifo(), because // the situation is safe for a ls activity to start; but there may be more difficult cases: // for example if a TC of a hs_hdl activity arrives during the previous 1100 ms sleep: that // TC execution could start and change AID_spectroscopy before this task wakes up... // this problem is avoided by checking the current_command_number after the execution of this // function LS_activity_preparation() if (AID_spectroscopy != STOPPING_OBS) { generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_AID_SPECTR_CHANGED, 1, &AID_spectroscopy); return; } // reset HW fifos to clear any remaining data reset_fifo(); // reset the pending frames counters fifo_0_pending_frames = 0; fifo_1_pending_frames = 0; fifo_2_pending_frames = 0; fifo_3_pending_frames = 0; // set AID_spectroscopy to REQUIRING_HK (i.e. reenable Hk acquisition from spectrometers) AID_spectroscopy = REQUIRING_HK; break; } } } //------------------------- check_and_flush_pending_frames ------------------------------------- //! Checks if there are pending frames and issues a flush if needed int check_and_flush_pending_frames( int really_flush ) { int frames_pending; // check if there are pending frames frames_pending = 0; if ( SubsysStatus & WBS_H_MASK ) if ( fifo_0_pending_frames > 0 ) frames_pending = 1; if ( SubsysStatus & WBS_V_MASK ) if ( fifo_1_pending_frames > 0 ) frames_pending = 1; if ( SubsysStatus & HRS_H_MASK ) if ( fifo_2_pending_frames > 0 ) frames_pending = 1; if ( SubsysStatus & HRS_V_MASK ) if ( fifo_3_pending_frames > 0 ) frames_pending = 1; // if no frames are pending we are safe // otherwise if a flush is not running issue a flush request if ( !frames_pending ) return 1; else { if ( really_flush ) ls_put_msg_hp(NULL, NULL, FLUSH_REQUEST, NULL); return 0; // we are not safe yet } } //------------------------- HS_safe_status ------------------------------------- //! Checks if the HS is in a safe status (i.e. no frames pending); if not performs //! actions to bring it towards a safe status; returns 1 if the HS status is safe int HS_safe_status (void) { switch (AID_spectroscopy) { case REQUIRING_HK: // HK status { // change AID_spectroscopy so that task hk_ask will stop requesting frames AID_spectroscopy = STOPPING_HK; // check whether there are pending frames or if HK is about to request frames if ( HK_is_asking_spectrometry ) return 0; else return check_and_flush_pending_frames(0); // we need no flush in case of HK break; } // VM status case TC_FUNMAN_SPCTRTP_AID: // total power case TC_FUNMAN_SPCTRSC_AID: // slow chop case TC_FUNMAN_SPCTRFC_AID: // fast chop case TC_FUNMAN_SPCTRFS_AID: // frequency switch case NEW_CALIB_RUN_AID: // new wbs comb case NEW_CALIB_CLOSE_AID: // new wbs comb { // stop virtual machine if running stop_VM(); // change AID_spectroscopy so that, if the VM has already given the flush // event, the data frame will not arrive up to task data_hdl AID_spectroscopy = STOPPING_VM; // check if there are pending frames return check_and_flush_pending_frames(1); break; } case STOPPING_HK: case STOPPING_VM: case STOPPING_OBS: { // check if there are pending frames if ( SubsysStatus & WBS_H_MASK ) if ( fifo_0_pending_frames > 0 ) return 0; if ( SubsysStatus & WBS_V_MASK ) if ( fifo_1_pending_frames > 0 ) return 0; if ( SubsysStatus & HRS_H_MASK ) if ( fifo_2_pending_frames > 0 ) return 0; if ( SubsysStatus & HRS_V_MASK ) if ( fifo_3_pending_frames > 0 ) return 0; // there are no pending frames for active subsystems: we can return 1, but // before let's reset the counters (actually it could be useless, apart from // the case of non active subsystems) fifo_0_pending_frames = 0; fifo_1_pending_frames = 0; fifo_2_pending_frames = 0; fifo_3_pending_frames = 0; return 1; // no more pending frames now, we can return 1 break; } // the default case is for all OBS activities involving HS links default: { // change AID_spectroscopy so that data_hdl will no more receive frames // from the interrupted activity and so it should be impossible (or less // probable) that data_hdl sets AID_spectroscopy to REQUIRING_HK AID_spectroscopy = STOPPING_OBS; // check if there are pending frames return check_and_flush_pending_frames(1); break; } } } //------------------------- bring_to_safe -------------------------------------- //! Checks if the HS is in a safe status (i.e. no frames pending); if not performs //! actions to bring it towards a safe status; returns 1 if the HS status is safe int bring_to_safe (HS_HDL_MSG *message) { // check the HS systems status if ( ! HS_safe_status() ) { if ( message->exec_attempts < SAFE_STATUS_N_ATTEMPTS ) { // the HS system is not in a safe state: we have to wait KS_TaskSleep(SAFE_STATUS_WT); // send command back to tuning task message->exec_attempts++; if (KS_FIFOPut(HS_HDL_QUEUE, (void *) message) == RC_FAIL) generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_QUEUE_FAIL, 0, NULL); return 0; } else { // the HS system is not in a safe state: we cannot wait anymore, reset and return ok fifo_0_pending_frames = 0; fifo_1_pending_frames = 0; fifo_2_pending_frames = 0; fifo_3_pending_frames = 0; // restart checks in res_chk rc_restart_checks(); // issue a warning generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_BRING_SAFE_TIMEOUT, 0, NULL); return 1; } } else { // restart checks in res_chk rc_restart_checks(); return 1; // we are safe } } //---------- start_abort ------------------------------------------------------- //! Aborts any pending spectroscopy, putting hs in a well defined state, stopping FIFOs IRQ and VM (IRQ3); // always returns RC_OK int start_abort (HS_HDL_MSG *message) { SD_TM_MSG sd_tm_msg; // check the HS systems status if ( ! bring_to_safe( message ) ) return RC_OK; // signal that abort is done - note that it is important to reset this flag before force_HIFI_goto_safe where perform_goto_safe_after_abort is resetted too // otherwise we could miss the goto safe abort_is_running = 0; // goto safe, or simply reset fifo if (perform_goto_safe_after_abort) force_HIFI_goto_safe(); else reset_fifo(); AID_spectroscopy = REQUIRING_HK; // restart HK reqs // flush TM Science Data packets fifos and pools while (KS_FIFOGet(SD_TM_QUEUE, &sd_tm_msg) == RC_OK) if (sd_tm_msg.count == 0) release_block(&sd_tm_msg.block); return RC_OK; } //************************************************************************************************** //************************************************************************************************** // spectroscopy //************************************************************************************************** //************************************************************************************************** //-------- start_total_power --------------------------------------------------- //! First (and only step) of a total power measurement. Checks the HS status. //! When safe resets static variables and start VM. int start_total_power (HS_HDL_MSG *message) { TC_packet * packet; unsigned int fifo, i; // 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 the HS systems and static data, and start // copy configured spectroscopy tables to the working spec table for (i = 0; i < WNUM_Spectroscopy_table; i++) Spectroscopy_table[i] = Conf_Spectroscopy_table[i]; VM_init_spec_table(Conf_Spectroscopy_table, WNUM_Spectroscopy_table); // copy spectroscopy table into sd_hdl and other inits. if (init_science_data() == 0) // the return is the mask of the instruments involved { release_block(&(message->block)); return enqueue_exec_fail(EXF_HS_LIB_NO_INSTRU_INVOLVED, 0, NULL); } // check consistency of input data for (fifo = 0; fifo < 4; fifo++) if (IFSI_MOD(Sd_hdl[fifo].duration,Sd_hdl[fifo].int_num) != 0) { release_block(&(message->block)); return enqueue_exec_fail(NOK_HS_LIB_WRONG_INPUT_PARAM, 0, NULL); } if ( (IFSI_MOD(Spectroscopy_table[HIF_T_ACC_WBS_IDX], 10)!= 5) || (Spectroscopy_table[HIF_T_ACC_WBS_IDX] < ((12+ Spectroscopy_table[HIF_DEL_HRS_IDX]+Spectroscopy_table[HIF_T_ACC_HRS_IDX])*Spectroscopy_table[HIF_R_HRS_IDX]+2)) ) { release_block(&(message->block)); return enqueue_exec_fail(EXF_HS_LIB_WRONG_WBS_ACCTIME, 1,&Spectroscopy_table[HIF_T_ACC_WBS_IDX]); } // reset HS subsystem and other inits AID_spectroscopy = TC_FUNMAN_SPCTRTP_AID; // set AID_spectroscopy Meas_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX + 1]); Cur_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX + 1]); reset_fifo(); fifo_0_command_number = fifo_1_command_number = fifo_2_command_number = fifo_3_command_number = current_command_number; release_block(&(message->block)); // here the block can be released // prepare vm data and start program prepare_VM_total_power(TC_FUNMAN_SPCTRTP_AID, HS_FLUSH_EVENT, VM_REQ_EVENT); start_VM(VMPROG_TOTAL_POWER); // start the VM return RC_OK; } //-------------- start_freq_switch ---------------------------------------- //! First (and only step) of a freq switch. Checks the HS status. //! When safe resets static variables and start VM. int start_freq_switch (HS_HDL_MSG *message) { TC_packet * packet; unsigned int fifo, i, freq1, freq2; // il LCU has problems abort if ( LCU_non_interaction == TRUE) { release_block(&(message->block)); return enqueue_exec_fail(EXF_HS_LIB_LCU_NON_INTERACTION, 0, NULL); } // init the 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 the HS systems and static data, and prepare obs for measurement // copy configured spectroscopy tables to the working spec table for (i = 0; i < WNUM_Spectroscopy_table; i++) Spectroscopy_table[i] = Conf_Spectroscopy_table[i]; VM_init_spec_table(Conf_Spectroscopy_table, WNUM_Spectroscopy_table); // copy spectroscopy table into sd_hdl and other inits. if (init_science_data() == 0) // the return is the mask of the instruments involved { release_block(&(message->block)); return enqueue_exec_fail(EXF_HS_LIB_NO_INSTRU_INVOLVED, 0, NULL); } // check consistency of input data for (fifo = 0; fifo < 4; fifo++) if (IFSI_MOD(Sd_hdl[fifo].duration, (2*Sd_hdl[fifo].int_num)) != 0) { release_block(&(message->block)); return enqueue_exec_fail(NOK_HS_LIB_WRONG_INPUT_PARAM, 0, NULL); } if ( (IFSI_MOD(Spectroscopy_table[HIF_T_ACC_WBS_IDX], 10)!= 5) || (Spectroscopy_table[HIF_T_ACC_WBS_IDX] < ((12+ Spectroscopy_table[HIF_DEL_HRS_IDX]+Spectroscopy_table[HIF_T_ACC_HRS_IDX])*Spectroscopy_table[HIF_R_HRS_IDX]+2)) ) { release_block(&(message->block)); return enqueue_exec_fail(EXF_HS_LIB_WRONG_WBS_ACCTIME, 1, &Spectroscopy_table[HIF_T_ACC_WBS_IDX]); } // reset HS subsystem and other inits AID_spectroscopy = TC_FUNMAN_SPCTRFS_AID; // set AID_spectroscopy Meas_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX + 1]); Cur_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX + 1]); reset_fifo(); fifo_0_command_number = fifo_1_command_number = fifo_2_command_number = fifo_3_command_number = current_command_number; // prepare vm data freq1 = ((packet->data[TC_SPECFS_FREQ1_IDX] & 0xFFFF) << 16) + (packet->data[TC_SPECFS_FREQ1_IDX+1] & 0xFFFF); freq2 = ((packet->data[TC_SPECFS_FREQ2_IDX] & 0xFFFF) << 16) + (packet->data[TC_SPECFS_FREQ2_IDX+1] & 0xFFFF); prepare_VM_freq_switch(TC_FUNMAN_SPCTRFS_AID, HS_FLUSH_EVENT, VM_REQ_EVENT, freq1, freq2); // here I can free the block release_block(&(message->block)); // start the VM start_VM(VMPROG_FREQ_SWITCH); return RC_OK; } //------- start_slow_chop ------------------------------------------------------ //! First (and only step) of a slow chop measurement. Checks the HS status. //! When safe resets static variables and start VM. int start_slow_chop (HS_HDL_MSG *message) { TC_packet * packet; unsigned int fifo, i, rot1, rot2; // init the 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 the HS systems and static data, and prepare obs for measurement // check that wbs is on: otherwise stop the measurement if ( ( SubsysStatus & WBS_H_MASK == 0 ) && (SubsysStatus & WBS_V_MASK == 0) ) { release_block(&(message->block)); return enqueue_exec_fail(EXF_HS_LIB_WBS_SUB_OFF, 0, NULL); } // copy configured spectroscopy tables to the working spec table for (i = 0; i < WNUM_Spectroscopy_table; i++) Spectroscopy_table[i] = Conf_Spectroscopy_table[i]; VM_init_spec_table(Conf_Spectroscopy_table, WNUM_Spectroscopy_table); // copy spectroscopy table into sd_hdl and other inits. if (init_science_data() == 0) // the return is the mask of the instruments involved { release_block(&(message->block)); return enqueue_exec_fail(EXF_HS_LIB_NO_INSTRU_INVOLVED, 0, NULL); } // check consistency of input data for (fifo = 0; fifo < 4; fifo++) if (IFSI_MOD(Sd_hdl[fifo].duration, (2*Sd_hdl[fifo].int_num)) != 0) { release_block(&(message->block)); return enqueue_exec_fail(NOK_HS_LIB_WRONG_INPUT_PARAM, 0, NULL); } if ( (IFSI_MOD(Spectroscopy_table[HIF_T_ACC_WBS_IDX], 10)!= 5) || (Spectroscopy_table[HIF_T_ACC_WBS_IDX] < ((12+ Spectroscopy_table[HIF_DEL_HRS_IDX]+Spectroscopy_table[HIF_T_ACC_HRS_IDX])*Spectroscopy_table[HIF_R_HRS_IDX]+2)) ) { release_block(&(message->block)); return enqueue_exec_fail(EXF_HS_LIB_WRONG_WBS_ACCTIME, 1, &Spectroscopy_table[HIF_T_ACC_WBS_IDX]); } // reset HS subsystem and other inits AID_spectroscopy = TC_FUNMAN_SPCTRSC_AID; // set AID_spectroscopy Meas_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX + 1]); Cur_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX + 1]); reset_fifo(); fifo_0_command_number = fifo_1_command_number = fifo_2_command_number = fifo_3_command_number = current_command_number; // prepare vm data rot1 = ((packet->data[TC_SPECSC_ROT1_IDX] & 0xFFFF) << 16) + (packet->data[TC_SPECSC_ROT1_IDX+1] & 0xFFFF); rot2 = ((packet->data[TC_SPECSC_ROT2_IDX] & 0xFFFF) << 16) + (packet->data[TC_SPECSC_ROT2_IDX+1] & 0xFFFF); prepare_VM_slow_chop(TC_FUNMAN_SPCTRSC_AID, HS_FLUSH_EVENT, VM_REQ_EVENT, rot1, rot2); // here I can free the block release_block(&(message->block)); // start the VM start_VM(VMPROG_SLOW_CHOP); return RC_OK; } //------- start_fast_chop ------------------------------------------------------ //! First (and only step) of a fast chop measurement. Checks the HS status. //! When safe resets static variables and start VM. int start_fast_chop (HS_HDL_MSG *message) { TC_packet * packet; unsigned int fifo, i, rot1, rot2, n_wbs1, hrs_trans; // init the 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 the HS systems and static data, and prepare obs for measurement // check that at least one instrument is active if ((SubsysStatus & HRS_H_MASK == 0) && (SubsysStatus & HRS_V_MASK == 0) && (SubsysStatus & WBS_H_MASK == 0) && (SubsysStatus & WBS_V_MASK == 0)) { release_block(&(message->block)); return enqueue_exec_fail(EXF_HS_LIB_NO_INSTRU_INVOLVED, 0, NULL); } // copy configured spectroscopy tables to the working spec table for (i = 0; i < WNUM_Spectroscopy_table; i++) Spectroscopy_table[i] = Conf_Spectroscopy_table[i]; VM_init_spec_table(Conf_Spectroscopy_table, WNUM_Spectroscopy_table); // next parameter always 1 for fast chop Spectroscopy_table[HIF_R_HRS_IDX] = 1; // init SD_hdl for (i = 0; i < 4; i++) { Sd_hdl[i].duration = 0; // reset number of frames expected for the instrument Sd_hdl[i].coadded = 0; // number of frames coadded for this fifo Sd_hdl[i].isn = 0; } // compute the duration (number of frames) for each fifo if ( (SubsysStatus & WBS_H_MASK) != 0 ) Sd_hdl[WBS_H_ID].duration = 2 * Spectroscopy_table[HIF_N_WBS_START_IDX]; // set number of frames expected for the instrument if ( (SubsysStatus & WBS_V_MASK) != 0 ) Sd_hdl[WBS_V_ID].duration = 2 * Spectroscopy_table[HIF_N_WBS_START_IDX]; // set number of frames expected for the instrument if ( (SubsysStatus & HRS_H_MASK) != 0 ) Sd_hdl[HRS_H_ID].duration = Spectroscopy_table[HIF_N_WBS_START_IDX] * ( (packet->data[TC_SPECSC_N_WBS1_IDX] & 0xFFFF) + 2*(packet->data[TC_SPECSC_N_HRS_TRANS_IDX] & 0xFFFF) ); if ( (SubsysStatus & HRS_V_MASK) != 0 ) Sd_hdl[HRS_V_ID].duration = Spectroscopy_table[HIF_N_WBS_START_IDX] * ( (packet->data[TC_SPECSC_N_WBS1_IDX] & 0xFFFF) + 2*(packet->data[TC_SPECSC_N_HRS_TRANS_IDX] & 0xFFFF) ); // set integration number (coadditions) Sd_hdl[WBS_H_ID].int_num = Sd_hdl[WBS_V_ID].int_num = Spectroscopy_table[HIF_N_WBS_INTEGR_IDX]; // number of frames to coadd Sd_hdl[HRS_H_ID].int_num = Sd_hdl[HRS_V_ID].int_num = Spectroscopy_table[HIF_N_HRS_INTEGR_IDX]; // number of frames to coadd // init range sel Sd_hdl[WBS_H_ID].range_sel = HIF_WBSH_OFFSET1_IDX; Sd_hdl[WBS_V_ID].range_sel = HIF_WBSV_OFFSET1_IDX; Sd_hdl[HRS_H_ID].range_sel = HIF_HRSH_SEL_IDX; Sd_hdl[HRS_V_ID].range_sel = HIF_HRSV_SEL_IDX; // check consistency of input data for (fifo = 0; fifo < 4; fifo++) if (IFSI_MOD(Sd_hdl[fifo].duration, (2*Sd_hdl[fifo].int_num)) != 0) { release_block(&(message->block)); return enqueue_exec_fail(NOK_HS_LIB_WRONG_INPUT_PARAM, 0, NULL); // execution failure } if ((Sd_hdl[WBS_H_ID].duration == 0) && (Sd_hdl[WBS_V_ID].duration == 0)) { release_block(&(message->block)); return enqueue_exec_fail(NOK_HS_LIB_WRONG_INPUT_PARAM, 0, NULL); } if ( (IFSI_MOD(Spectroscopy_table[HIF_T_ACC_WBS_IDX], 10)!= 5) || (Spectroscopy_table[HIF_T_ACC_WBS_IDX] < ((12+ Spectroscopy_table[HIF_DEL_HRS_IDX]+Spectroscopy_table[HIF_T_ACC_HRS_IDX])*Spectroscopy_table[HIF_R_HRS_IDX]+2)) ) { release_block(&(message->block)); return enqueue_exec_fail(EXF_HS_LIB_WRONG_WBS_ACCTIME, 1, &Spectroscopy_table[HIF_T_ACC_WBS_IDX]); } // reset HS subsystem and other inits AID_spectroscopy = TC_FUNMAN_SPCTRFC_AID; // set AID_spectroscopy Meas_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX + 1]); Cur_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX + 1]); reset_fifo(); fifo_0_command_number = fifo_1_command_number = fifo_2_command_number = fifo_3_command_number = current_command_number; // prepare vm data rot1 = ((packet->data[TC_SPECSC_ROT1_IDX] & 0xFFFF) << 16) + (packet->data[TC_SPECSC_ROT1_IDX+1] & 0xFFFF); rot2 = ((packet->data[TC_SPECSC_ROT2_IDX] & 0xFFFF) << 16) + (packet->data[TC_SPECSC_ROT2_IDX+1] & 0xFFFF); n_wbs1 = (packet->data[TC_SPECSC_N_WBS1_IDX] & 0xFFFF); hrs_trans = (packet->data[TC_SPECSC_N_HRS_TRANS_IDX] & 0xFFFF); reset_vm_mon ( n_wbs1 ); prepare_VM_fast_chop(TC_FUNMAN_SPCTRFC_AID, HS_FLUSH_EVENT, VM_REQ_EVENT, rot1, rot2, n_wbs1, hrs_trans, HIF_R_HRS_IDX); // here I can free the block release_block(&(message->block)); // check consistency of input data if (IFSI_MOD( n_wbs1, 2 ) != 0) return enqueue_exec_fail(NOK_HS_LIB_WRONG_INPUT_PARAM, 0, NULL); // execution failure // start the VM start_VM(VMPROG_FAST_CHOP); return RC_OK; } // ---------- upload_VM_code --------------------------------------------------- //! Copy a new program, received by means of a TC, into the VM memory int upload_VM_code (HS_HDL_MSG *message) { TC_packet * packet; unsigned int i, par_type, length, offset, err_code; // check the HS systems status if ( ! bring_to_safe(message) ) return RC_OK; // now HS is safe, we can initialize the HS systems and static data, and start // init this auxiliary pointer to the TC packet packet = (TC_packet *) message->block.pointer_to_data; // update BBID variable Meas_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX + 1]); Cur_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX + 1]); // extraction of parameter type from TC par_type = (packet->data[4]) >> 8; // check that parameter type is equal to 3 (we want only 32-bit fields) if (par_type != 3) { release_block(&(message->block)); return enqueue_exec_fail(EXF_HS_LIB_UPLOAD_VM_PARAM_TYPE, 0, NULL); } // extraction of length (i.e. number of 32-bit fields) from TC length = (packet->data[4]) & 0x0FF; // check that "length" (i.e. number of 32-bit fields in the TC) is consistent // with the length of the TC packet if ((4*length + 17) != packet->packet_length) { release_block(&(message->block)); return enqueue_exec_fail(EXF_HS_LIB_UPLOAD_VM_INCONSISTENT_TC, 0, NULL); } // extraction of offset from TC: it is the index in array Code[] at which the // copy of the code coming with the TC will start offset = packet->data[5]; // now check that the protected areas of Code[] will not be overwritten err_code = 1; // if everything is ok, err_code is set to zero if ((offset >= 3) && (offset <= 7)) { if ((offset + length - 1) < 8) err_code = 0; // set to zero because it is ok } else { if ((offset >= 2048) && (offset <= 8063)) { if ((offset + length - 1) < 8064) err_code = 0; // set to zero because it is ok } } // if now err_code is 1, the upload execution is rejected if (err_code == 1) { release_block(&(message->block)); return enqueue_exec_fail(EXF_HS_LIB_UPLOAD_VM_CODE_AREA, 0, NULL); } // now copy, in the area of array Code[] given by offset, the vm code (32-bit // parameters in number given by length) contained in the TC packet for (i = 0; i < length; i++) Code[offset + i] = PACK(packet->data[6 + 2*i], packet->data[6 + 2*i + 1]); enqueue_exec_compl(); // completion ack return RC_OK; } //-------- start_VM_prog ------------------------------------------------------- //! Start the VM setting the program counter to the value specified by the TC packet carried by the input message int start_VM_prog (HS_HDL_MSG *message) { TC_packet * packet; unsigned int index_entry, i; // check the HS systems status if ( ! bring_to_safe(message) ) return RC_OK; // now HS is safe, we can initialize the HS systems and static data, and start // init this auxiliary pointer to the TC packet packet = (TC_packet *) message->block.pointer_to_data; // extraction of offset from TC: it is the index in array Code[] at which the // vm program to be executed starts index_entry = packet->data[4]; // check that index_entry is a valid index in the entry point area of Code[] if (index_entry > 7) { release_block(&(message->block)); return enqueue_exec_fail(EXF_HS_LIB_START_VM_INVALID_INDEX, 0, NULL); } // copy configured spectroscopy tables to the working spec table for (i = 0; i < WNUM_Spectroscopy_table; i++) { VM_Spectroscopy_table[i] = Conf_Spectroscopy_table[i]; Spectroscopy_table[i] = Conf_Spectroscopy_table[i]; } // copy spectroscopy table into sd_hdl and other inits. if (init_science_data() == 0) // the return is the mask of the instruments involved { release_block(&(message->block)); return enqueue_exec_fail(EXF_HS_LIB_NO_INSTRU_INVOLVED, 0, NULL); } // reset HS subsystem and other inits AID_spectroscopy = TC_FUNMAN_SPCTRTP_AID; // set AID_spectroscopy Meas_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX + 1]); Cur_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX + 1]); reset_fifo(); fifo_0_command_number = fifo_1_command_number = fifo_2_command_number = fifo_3_command_number = current_command_number; release_block(&(message->block)); // here the block can be released // prepare vm data VM_AID_spectroscopy = TC_FUNMAN_SPCTRTP_AID; VM_Spectroscopy_table[HIF_EVENT_CODE_IDX] = HS_FLUSH_EVENT; start_VM(index_entry); // start the VM return RC_OK; } //****************************************************************************** //****************************************************************************** // new wbs calibrate //****************************************************************************** //****************************************************************************** int new_cal_pending_wbs_h_frames = 0; int new_cal_pending_wbs_v_frames = 0; int new_cal_init_loops = 0; int new_cal_command_number; static int new_cal_current_step = 0; //------------------------- start_new_calib_init ------------------------------------- //! this function performs the initial operations of a new calibrate init , then triggers //! the real start by putting a message into the hs_hdl fifo int start_new_calib_init (HS_HDL_MSG *message) { HS_HDL_MSG cmd_queue; TC_packet * packet; // check that at least one wbs is on if ((SubsysStatus & WBS_H_MASK) == 0 && (SubsysStatus & WBS_V_MASK) == 0) { release_block(&(message->block)); return enqueue_exec_fail(EXF_HS_LIB_WBS_SUB_OFF, 0, NULL); } // check that at least one hrs is on, if not return execution failure if ( (SubsysStatus & HRS_H_MASK) == 0 && (SubsysStatus & HRS_V_MASK) == 0 ) { release_block(&(message->block)); return enqueue_exec_fail(EXF_HS_LIB_HRS_SUB_OFF, 0, NULL); } // check the HS systems status if ( ! bring_to_safe( message ) ) return RC_OK; // now HS is safe, we can initialize the HS systems and static data, and start // init this auxiliary pointer to the TC packet packet = (TC_packet *) message->block.pointer_to_data; // read from TC the building block id Meas_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX + 1]); Cur_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX + 1]); // copy into WBS_H_CMD[ATT_COMB_MEAS_IDX] and WBS_V_CMD[ATT_COMB_MEAS_IDX] // the attenuator setting contained in the TC (two 32-bit ls command) WBS_H_CMD[ATT_COMB_MEAS_IDX] = PACK(packet->data[4], packet->data[5]); // prepare the commands we need to restore the previous wbs attenuator // setting, which is stored into the global variable wbs_att_setting[] WBS_H_CMD[ATT_RESTORE_COMB_IDX] = ((wbs_att_setting[0] << 5) | 0xE400000F); WBS_H_CMD[ATT_RESTORE_ZERO_IDX] = ((zero_switch_setting[0] << 5) | 0xE400000A); WBS_V_CMD[ATT_RESTORE_ZERO_IDX] = ((zero_switch_setting[1] << 5) | 0xE800000A); // free block release_block(&(message->block)); // here the block can be released // compute the number of wbs frames to expect and other inits new_cal_current_step = 0; new_cal_pending_wbs_h_frames = 0; if ( (SubsysStatus & WBS_H_MASK) != 0 ) new_cal_pending_wbs_h_frames = 3; new_cal_pending_wbs_v_frames = 0; if ( (SubsysStatus & WBS_V_MASK) != 0 ) new_cal_pending_wbs_v_frames = 3; // compute the number of init loops new_cal_init_loops = 0; if ( (SubsysStatus & HRS_H_MASK) != 0 ) new_cal_init_loops++; if ( (SubsysStatus & HRS_V_MASK) != 0 ) new_cal_init_loops++; // set working spectrometers mask and other inits and resets AID_spectroscopy = NEW_CALIB_INIT_AID; // set AID_spectroscopy init_tuni_table(HRS_ATTSETT_ID); // init tables and other stuff reset_fifo(); // write the operation ID for the next step and other inits cmd_queue.operation_id = MKSTEP_NEW_CALIB_INIT; cmd_queue.command_number = message->command_number; new_cal_command_number = message->command_number; cmd_queue.block_loaded = 0; // trigger next step if (KS_FIFOPut(HS_HDL_QUEUE, (void *) &cmd_queue) == RC_FAIL) return enqueue_exec_fail(EXF_HS_LIB_QUEUE, 0, NULL); // execution failure else return RC_OK; } //---------------------- mkstep_new_calib_init -------------------------------------- int mkstep_new_calib_init (int command_number) //! Implements the initialization step of new calibrate: simply issue a data transfer on both polarisations to gather the HRS status { // check the activity ID if (AID_spectroscopy != NEW_CALIB_INIT_AID ) return enqueue_exec_fail(EXF_HS_HDL_WRONG_SPECT_AID, 1, &AID_spectroscopy); // HRS integration if (hrs_integrate(0, 1, command_number) != RC_OK) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); return RC_OK; } //---------------------- start_new_calib_run -------------------------------------- //! Implements the initialization step of new calibrate run phase. When we are here the fifos should be empty and in a safe status. int start_new_calib_run (int command_number) { int i; // set aid_spectroscopy AID_spectroscopy = NEW_CALIB_RUN_AID; // here we initialise the spectroscopy table for the new calibrate operation. We command one integration of 1005 sec for each wbs for (i = 0; i < WNUM_Spectroscopy_table; i++) Spectroscopy_table[i] = WBS_Calibrate_Spectroscopy_table_init[i]; // copy spectroscopy table into sd_hdl and other inits. if (init_science_data() == 0) // the return is the mask of the instruments involved return enqueue_exec_fail(EXF_HS_LIB_NO_INSTRU_INVOLVED, 0, NULL); // here we set the HRS and the LO for (i=0; iblock.pointer_to_data; // check that hrs is on, if not return execution failure if ( (SubsysStatus & HRS_H_MASK) == 0 && (SubsysStatus & HRS_V_MASK) == 0 ) { release_block(&(message->block)); return enqueue_exec_fail(EXF_HS_LIB_HRS_SUB_OFF, 0, NULL); } // compute the number of init loops hrs_total_init_loops = 0; if ( (SubsysStatus & HRS_H_MASK) != 0 ) hrs_total_init_loops++; if ( (SubsysStatus & HRS_V_MASK) != 0 ) hrs_total_init_loops++; // check the HS systems status if ( ! bring_to_safe( message ) ) return RC_OK; // now HS is safe, we can initialize the HS systems and static data, and start // set working spectrometers mask and other inits and resets Meas_spectr = Active_spectr & 0x60; // only HRS working AID_spectroscopy = HRS_TUNE_INIT; // set AID_spectroscopy reset_fifo(); init_tuni_table(HRS_ATTSETT_ID); // init tables and other stuff Meas_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX + 1]); Cur_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX + 1]); release_block(&(message->block)); // here we can free the TC block // prepare and send to hs_hdl task a message for the first step of hrs tune cmd_queue.operation_id = HRS_TUNE_INIT; cmd_queue.command_number = message->command_number; cmd_queue.block_loaded = 0; if (KS_FIFOPut(HS_HDL_QUEUE, (void *) &cmd_queue) == RC_FAIL) return enqueue_exec_fail(EXF_HS_LIB_QUEUE, 0, NULL); // execution failure else return RC_OK; } //---------------------- hrs_tune_init -------------------------------------- int hrs_tune_init (int command_number) //! Implements the initialization step of hrs tuning: simply issue a data transfer on both polarisations to gather the HRS status { // check the activity ID if (AID_spectroscopy != HRS_TUNE_INIT) return enqueue_exec_fail(EXF_HS_HDL_WRONG_SPECT_AID, 0, NULL); // HRS integration if (hrs_integrate(0, 1, command_number) != RC_OK) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); return RC_OK; } //---------------------- save_hrs_status -------------------------------------- //! Reads and stores the status of the HRS #define HRS_SUB_BLOCK_DIM 258 void save_hrs_status(unsigned int * hrs_data, unsigned int hrs_unit) { int block, subblock, i; // save the hrs status by reading it from the hrs data switch(hrs_unit) { case HRS_V_ID: for ( i=0; i<16; i++) // cycle over the subblocks { block = 7 - i/2; subblock = IFSI_MOD(i,2); HRSV_mode[block][subblock] = hrs_data[i*HRS_SUB_BLOCK_DIM + SD_TM_HEADER]; } break; case HRS_H_ID: for ( i=0; i<16; i++) // cycle over the subblocks { block = 7 - i/2; subblock = IFSI_MOD(i,2); HRSH_mode[block][subblock] = hrs_data[i*HRS_SUB_BLOCK_DIM + SD_TM_HEADER]; } break; default: generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_SUBSYSID, 0, NULL); break; } } //---------------------- restore_hrs_status -------------------------------------- //! Restores the status of the HRS void restore_hrs_status(void) { static unsigned int commands_to_send[16]; // 8 commands for each polarization unsigned int command_counter, i; // init command count command_counter = 0; // process hrsh if ( (SubsysStatus & HRS_H_MASK) != 0 ) for (i=0; i<8; i++) { // build command commands_to_send[command_counter] = 0xD6000000 | ( i << 20 ) | ((HRSH_mode[i][1] & 0x1FF) << 9) | (HRSH_mode[i][0] & 0x1FF); // send command if (ls_put_msg_hp(&commands_to_send[command_counter], NULL, 0, NULL) == RC_FAIL) generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_FAILED_TO_RESTORE, 0, NULL); // increas counter command_counter++; } // process hrsv if ( (SubsysStatus & HRS_V_MASK) != 0 ) for (i=0; i<8; i++) { // build command commands_to_send[command_counter] = 0xDA000000 | ( i << 20 ) | ((HRSH_mode[i][1] & 0x1FF) << 9) | (HRSH_mode[i][0] & 0x1FF); // send command if (ls_put_msg_hp(&commands_to_send[command_counter], NULL, 0, NULL) == RC_FAIL) generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_FAILED_TO_RESTORE, 0, NULL); // increas counter command_counter++; } } //---------------------- mkstep1_hrs_tune -------------------------------------- int mkstep1_hrs_tune (int command_number) //! Implements step1 of an hrs tuning procedure { unsigned int j; // check the activity ID if (AID_spectroscopy != HRS_ATTSETT_ID) return enqueue_exec_fail(EXF_HS_HDL_WRONG_SPECT_AID, 0, NULL); // init hrs if((SubsysStatus & HRS_H_MASK) != 0) // only if SS is ON { // prepare instruments for (j = 0; j < hrs_defset_len; j++) if (ls_put_msg_hp(&HRS_H_defset[j], NULL, 0, NULL) == RC_FAIL) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); // configure UWB mode for (j = 0; j < hrs_UWBset_len; j++) if (ls_put_msg_hp(&HRS_H_UWBset[j], NULL, 0, NULL) == RC_FAIL) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); for (j = RESET_A_IDX; j < (RESET_A_IDX+3); j++) if (ls_put_msg_hp(&HRS_H_CMD[j], NULL, 0, NULL) == RC_FAIL) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); } if((SubsysStatus & HRS_V_MASK) != 0) // only if SS is ON { // prepare instruments for (j = 0; j < hrs_defset_len; j++) if (RC_FAIL == ls_put_msg_hp(&HRS_V_defset[j], NULL, 0, NULL)) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); // configure UWB mode for (j = 0; j < hrs_UWBset_len; j++) if (RC_FAIL == ls_put_msg_hp(&HRS_V_UWBset[j], NULL, 0, NULL)) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); for (j = RESET_A_IDX; j < (RESET_A_IDX+3); j++) if (RC_FAIL == ls_put_msg_hp(&HRS_V_CMD[j], NULL, 0, NULL)) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); } // HRS integration if (hrs_integrate(1000, 1, command_number) != RC_OK) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); return RC_OK; } //----------------------- mkstep2_hrs_tune ------------------------------------- int mkstep2_hrs_tune (int command_number) //! Implements step2 of an hrs tuning procedure { unsigned int j; // check the activity ID if (AID_spectroscopy != HRS_ATTSETT2_ID) return enqueue_exec_fail(EXF_HS_HDL_WRONG_SPECT_AID, 0, NULL); // init hrs if ((SubsysStatus & HRS_H_MASK) != 0) for (j = RESET_A_IDX; j < (RESET_A_IDX + 3); j++) if (ls_put_msg_hp(&HRS_H_CMD[j], NULL, 0, NULL) == RC_FAIL) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); if ((SubsysStatus & HRS_V_MASK) != 0) for (j = RESET_A_IDX; j < (RESET_A_IDX + 3); j++) if (ls_put_msg_hp(&HRS_V_CMD[j], NULL, 0, NULL) == RC_FAIL) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); // HRS integration if (hrs_integrate(1000, 1, command_number) != RC_OK) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); return RC_OK; } //----------------------- packetize_ATTHRS ------------------------------------- //! Process the science data of the first step of an hrs tuning command. //! Sends a tune report TM(21,3) to the HK_TM_QUEUE. void packetize_ATTHRS (unsigned int fifo_id) { K_BLOCK block; HK_TM_MSG hk_msg; TM_ST3_HEADER *st3_header; int k,n, m, * p_aux; unsigned int offset, head_chan[16*4]; unsigned int cstar[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; fifo_id &= 3; for (k = 0; k < 8;k++) // span the datablock_id vector (k) and the range selection (l) { // K is the block index within the pool block, not the absolute data block // extract the first 4 channels of each subblock necessary to calculate the ifpower for (m = 0; m < 2; m++) // index of the subblock (chip number) { for (n = 0; n < 4; n++) // span the first 4 data of each subblock { offset= SD_TM_HEADER + m*HRS_SUBBLOCK_DATA_LEN + k*HRS_BLOCK_DATA_LEN + n; head_chan[n] = *(int *)(sd_msg.block.pointer_to_data + offset); } if ((head_chan[1])!= 0) { cstar[m + k*2] = ((head_chan[3]*2048)/head_chan[1])*2; } else { cstar[m + k*2] = ((head_chan[3]*2048))*2; generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_HRS_DURATION_NULL, 0, NULL); } } // end for over m if (cstar[k*2 + 1] < HRS_ATT_LIM1[0]) // cstar(CCD2) < limit { ATT_value[fifo_id][k] = 0x0A; // attenuator set to 5db ATT_status[fifo_id][k] = 1; } else // cstar > limit { ATT_value[fifo_id][k] = 0x1A; // attenuator set to 13db ATT_status[fifo_id][k] = 0; } // configure the attenuators if (fifo_id == HRS_H_ID) ATT_cmd[fifo_id-2][k] = ((HRS_H_defset[k] & 0xffffff00) | (ATT_value[fifo_id][k] & 0x000000ff)); else ATT_cmd[fifo_id-2][k] = ((HRS_V_defset[k] & 0xffffff00) | (ATT_value[fifo_id][k] & 0x000000ff)); if (ls_put_msg_hp(&ATT_cmd[fifo_id-2][k], NULL, 0, NULL) == RC_FAIL) { generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); return; } } // end for k // prepare a tune report // require a block from the pool if (get_block(&block, HK_POOL, HK_BLOCK_LEN_BYTES) == RC_FAIL) { generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_GET_HK_POOL_BLOCK, 0, NULL); return; } // initialize the block just requested init_block(&(block), HK_BLOCK_LEN_WORDS); p_aux = block.pointer_to_data + HK_TM_HEADER; // prepare auxiliary pointer for (k = 0; k < HRS_BLOCK_NUM; k++) { p_aux[k] = (int)cstar[k*2 + 1]; p_aux[k + HRS_BLOCK_NUM] = ATT_value[fifo_id][k]; } prepare_TM_packet(&block, TM_DFHF_REGULAR, TM_APID_HK, (((DFH_WLEN + SDH_HK_WLEN + (HRS_BLOCK_NUM*2) + 1) << 1)- 1), TM_HK_TYPE, TM_HK_SUBT); // prepare the pointer to header st3_header = (TM_ST3_HEADER *) block.pointer_to_data; // write Source Data Header if (fifo_id == HRS_H_ID) st3_header->structure_ID = HRSH_TUNE_SID; else st3_header->structure_ID = HRSV_TUNE_SID; UNPACK(st3_header->obs_ID, Observation_ID); UNPACK(st3_header->bb_ID, Meas_BuildingBlock_ID); hk_msg.block = block; // prepare the block to be sent in various messages hk_msg.packing = PACKING_16; // set the packetization flag to 16 bit hk_msg.packing |= SDH_HK_WLEN << 8; // set the length of data header hk_msg.packing |= HKP << 16; hk_msg.offset = HK_TM_HEADER; // no offset hk_msg.count = 0; // downcount of the packet hk_msg.length = (((DFH_WLEN + SDH_HK_WLEN + (HRS_BLOCK_NUM*2) + 1) << 1) + 6) ; // number of octets (not relevant for packing 16) // send message to tm_tc if (KS_FIFOPut(HK_TM_QUEUE, (void *) &hk_msg) == RC_FAIL) { release_block(&block); generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_FIFOPUT_HK_TM_QUEUE, 0, NULL); } } //---------------------- packetize_ATTHRS2 ------------------------------------- //! Process the science data of the second step of an hrs tuning command. //! Sends a tune report TM(21,3) to the HK_TM_QUEUE. void packetize_ATTHRS2 (unsigned int fifo_id) { K_BLOCK block; HK_TM_MSG hk_msg; TM_ST3_HEADER *st3_header; int l, k, n, m, * p_aux; unsigned int select, lim, offset; unsigned int head_chan[16*4]; unsigned int cstar[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; select = Spectroscopy_table[Sd_hdl[fifo_id].range_sel]; // span the datablock_id vector (k) and the range selection (l) for ( k = 0; k < 8; k++) { // K is the block index within the pool block, not in the absolute data block // extract the first 4 channels of each subblock necessary to calculate the ifpower for (m = 0; m < 2; m++) // index of the subblock (chip number) { for (n = 0; n < 4; n++) // span the first 4 data of each subblock { offset = SD_TM_HEADER + m*HRS_SUBBLOCK_DATA_LEN + k*HRS_BLOCK_DATA_LEN + n; head_chan[n] = *(unsigned int *)(sd_msg.block.pointer_to_data + offset); } if ((head_chan[1])!= 0) { cstar[m + k*2] = ((head_chan[3]*2048)/head_chan[1])*2; } else { cstar[m + k*2] = ((head_chan[3]*2048))*2; generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_HRS_DURATION_NULL, 0, NULL); } } // end for over m if (ATT_status[fifo_id][k] == 1) // attenuator set to 5db in the previous loop { lim = 1; while (lim) { for (l = 0; l < hrs_attlim2_len; l++) if (cstar[2*k + 1] < HRS_ATT_LIM2[l]) { ATT_value[fifo_id][k] = HRS_ATT_VAL2[l]; lim = 0; break; } if (lim == 1) { ATT_value[fifo_id][k] = HRS_ATT_VAL2[HRS_ATTVAL2_LEN - 1]; // c* > all limits Att= last value in att table lim = 0; } } // end while on lim ATT_status[fifo_id][k] = 0; } else // att status 0 { lim = 1; while (lim) { for (l = 1; l < hrs_attlim1_len; l++) // first element = limit if (cstar[k*2 + 1] < HRS_ATT_LIM1[l]) { ATT_value[fifo_id][k] = HRS_ATT_VAL1[l]; lim = 0; break; } if (lim == 1) { ATT_value[fifo_id][k] = HRS_ATT_VAL1[HRS_ATTVAL1_LEN - 1]; //c* > all limits Att= last value in att table lim = 0; } } // end while on lim ATT_status[fifo_id][k] = 0; } // end else atten status if (fifo_id == HRS_H_ID) ATT_cmd[fifo_id-2][k] = ((HRS_H_defset[k] & 0xffffff00)|(ATT_value[fifo_id][k] & 0x000000ff)); else ATT_cmd[fifo_id-2][k] = ((HRS_V_defset[k] & 0xffffff00)|(ATT_value[fifo_id][k] & 0x000000ff)); if (ls_put_msg_hp(&ATT_cmd[fifo_id-2][k], NULL, 0, NULL) == RC_FAIL) { generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); return; } } // end for k // prepare a tune report // require a block from the pool if (get_block(&block, HK_POOL, HK_BLOCK_LEN_BYTES) == RC_FAIL) { generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_GET_HK_POOL_BLOCK, 0, NULL); return; } // initialize the block just requested init_block(&(block), HK_BLOCK_LEN_WORDS); p_aux = block.pointer_to_data + HK_TM_HEADER; // prepare auxiliary pointer for (k = 0; k < HRS_BLOCK_NUM; k++) { p_aux[k] = (int)cstar[k*2 + 1]; p_aux[k + HRS_BLOCK_NUM] = ATT_value[fifo_id][k]; } prepare_TM_packet(&block, TM_DFHF_REGULAR, TM_APID_HK, (((DFH_WLEN+SDH_HK_WLEN+(HRS_BLOCK_NUM*2)+1)<<1 )- 1), TM_HK_TYPE, TM_HK_SUBT); // prepare the pointer to header st3_header = (TM_ST3_HEADER * ) block.pointer_to_data; // write Source Data Header if (fifo_id == HRS_H_ID) st3_header->structure_ID = HRSH_TUNE_SID; else st3_header->structure_ID = HRSV_TUNE_SID; UNPACK(st3_header->obs_ID, Observation_ID); UNPACK(st3_header->bb_ID, Meas_BuildingBlock_ID); hk_msg.block = block; // prepare the block to be sent in various messages hk_msg.packing = PACKING_16; // set the packetization flag to 16 bit hk_msg.packing |= SDH_HK_WLEN << 8; // set the length of data header hk_msg.packing |= HKP << 16; hk_msg.offset = HK_TM_HEADER; // no offset hk_msg.count = 0; // downcount of the packet hk_msg.length =(((DFH_WLEN+SDH_HK_WLEN+(HRS_BLOCK_NUM*2)+1)<<1 ) + 6) ; // number of octets (not relevant for packing 16) // send message to tm_tc if (KS_FIFOPut(HK_TM_QUEUE, (void *) &hk_msg) == RC_FAIL) { release_block(&block); generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_FIFOPUT_HK_TM_QUEUE, 0, NULL); } } //************************************************************************************************** //************************************************************************************************** // hrs_functest //************************************************************************************************** //************************************************************************************************** //------------------------- start_hrs_functest ------------------------------------- //! this function performs the start and only step of hrs functional test int start_hrs_functest (HS_HDL_MSG *message) { static unsigned int HRH_Mreset = 0xD7700003; static unsigned int HRV_Mreset = 0xDB700003; unsigned int request_flush; START_FRAME_DATA time_stamp; TC_packet * packet; unsigned int hrs_functest_id, hrs_selected_unit; // init this 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 the HS systems and static data, and start // set working spectrometers mask and other inits and resets Meas_spectr = Active_spectr & 0x60; // only HRS working AID_spectroscopy = HRS_FUNCTEST; // set AID_spectroscopy reset_fifo(); init_tuni_table(HRS_ATTSETT_ID); // we use the same inits as a hrs tuning hrs_functest_id = packet->data[4]; // hrs_functest_id hrs_selected_unit = packet->data[5]; // hrs_selected_unit Meas_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX + 1]); Cur_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX + 1]); // free the TC block release_block(&(message->block)); // here we can free the TC block // consistency checks switch(hrs_functest_id) { case 0: case 1: break; default: enqueue_exec_fail(EXF_HS_LIB_INVALID_DATA, 0, NULL); return RC_FAIL; break; } // consistency and instrument status checks switch(hrs_selected_unit) { case 1: // hrsr h if ((SubsysStatus & HRS_H_MASK) == 0) { enqueue_exec_fail(EXF_HS_LIB_HRS_SUB_OFF, 0, NULL); return RC_FAIL; } break; case 2: // hrsr v if ((SubsysStatus & HRS_V_MASK) == 0) { enqueue_exec_fail(EXF_HS_LIB_HRS_SUB_OFF, 0, NULL); return RC_FAIL; } break; case 3: // hrsr h and v if (((SubsysStatus & HRS_H_MASK) == 0) && ((SubsysStatus & HRS_V_MASK) == 0)) { enqueue_exec_fail(EXF_HS_LIB_HRS_SUB_OFF, 0, NULL); return RC_FAIL; } break; default: enqueue_exec_fail(EXF_HS_LIB_INVALID_DATA, 0, NULL); return RC_FAIL; break; } // now execute command request_flush = 0; // no data requested already get_TS(&(time_stamp.time_stamp)); // store the time when the command starts // perform master reset if ( hrs_functest_id == 1 ) { if ( hrs_selected_unit == 1 || hrs_selected_unit == 3) if (ls_put_msg_hp(&HRH_Mreset, NULL, 0, NULL) == RC_FAIL) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); if ( hrs_selected_unit == 2 || hrs_selected_unit == 3) if (ls_put_msg_hp(&HRV_Mreset, NULL, 0, NULL) == RC_FAIL) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); } // perform readout if ( hrs_selected_unit == 1 || hrs_selected_unit == 3) { if ( ls_put_msg_hp(&HRS_H_CMD[DATA_TRANS_IDX], NULL, 0, NULL) == RC_FAIL ) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); else { // a frame was requested fifo_2_pending_frames++; push_TS( time_stamp, HRS_H_ID, DO_NOT_ATTACH_HK); fifo_2_command_number = message->command_number; request_flush = 1; } } if ( hrs_selected_unit == 2 || hrs_selected_unit == 3) { if ( ls_put_msg_hp(&HRS_V_CMD[DATA_TRANS_IDX], NULL, 0, NULL) == RC_FAIL ) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); else { // a frame was requested fifo_3_pending_frames++; push_TS( time_stamp, HRS_V_ID, DO_NOT_ATTACH_HK); fifo_3_command_number = message->command_number; request_flush = 1; } } // check if we need a flush if ( request_flush ) ls_put_msg_hp(NULL, NULL, FLUSH_REQUEST, NULL); // command executed return RC_OK; } //************************************************************************************************** //************************************************************************************************** // wbs_tuning //************************************************************************************************** //************************************************************************************************** static float Bands_att[2][4]; static unsigned int LsCommand[2] = {0,0}; static unsigned int Main_att_cmd[2]; static float Main_att[2]; static unsigned int Bands_att_cmd[2][4]; static float zscan[2][WBS_BLOCK_DATA_LEN*4]; // element 0,1,2,3 mean HW FIFO 0,1,2,3 static float zscan_corr[2][WBS_BLOCK_DATA_LEN*4]; // element 0,1,2,3 mean HW FIFO 0,1,2,3 //------------------------- start_wbs_tune ------------------------------------- //! this function performs the initial operations of a wbs tuning, then triggers //! the real start by putting a message into the hs_hdl fifo int start_wbs_tune (HS_HDL_MSG *message) { TC_packet * packet; HS_HDL_MSG cmd_queue; // init this auxiliary pointer to the TC packet packet = (TC_packet *) message->block.pointer_to_data; // check that wbs is on, if not return with execution failure if (((SubsysStatus & WBS_H_MASK) == 0) && ((SubsysStatus & WBS_V_MASK) == 0)) { enqueue_exec_fail(EXF_HS_LIB_WBS_SUB_OFF, 0, NULL); release_block(&(message->block)); return RC_FAIL; } // check the HS systems status if ( ! bring_to_safe( message ) ) return RC_OK; // now HS is safe, we can initialize the HS systems and static data, and start // set working spectrometers mask and other inits and resets Meas_spectr = Active_spectr & 0x18; // only WBS working AID_spectroscopy = ZSCAN_ID; // set AID_spectroscopy reset_fifo(); init_tuni_table(WBS_ATTSETT_ID); // init tables and other stuff target_in_percents = packet->data[TC_ATTF_IDX]; if (target_in_percents == 0) { enqueue_exec_fail(NOK_HS_LIB_WRONG_INPUT_PARAM, 0, NULL); release_block(&(message->block)); return RC_FAIL; } Meas_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX + 1]); Cur_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX + 1]); release_block(&(message->block)); // here we can free the TC block // prepare and send command for the first step of hrs tune to hs_hdl task cmd_queue.operation_id = WBS_ATTSETT_ID; 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_HS_LIB_QUEUE, 0, NULL); // execution failure return RC_FAIL; } else return RC_OK; } //----------------------- packetize_ATTWBS2 ------------------------------------ //! Process the science data of the first and second step of an wbs tuning command. //! Sends a tune report TM(21,3) to the HK_TM_QUEUE. void packetize_ATTWBS2 (unsigned int wbs_id, int scan_count) { K_BLOCK block; HK_TM_MSG hk_msg; TM_ST3_HEADER *st3_header; int * p_aux, * p_data, k, n,i; float ATT_corr[2][4]; unsigned int dark_pix; float lookupValue; unsigned int offset, value, median_index, meas_type; static float Current_bands_att[2][4]; // element 0,1,2,3 mean HW FIFO 0,1,2,3 static float Current_main_att[2][4]; unsigned int index_max[4], val_max[4]; unsigned int index_main, index_strong,index_weak; unsigned int sat_flag[4]; int dmax = 300; float hot_corr[4], zsc_avg[4], zsc_corr_avg[4]; float atten, att2_corr, corr_factor[4]; float strong =-10; float weak = 150; p_data = sd_msg.block.pointer_to_data + SD_TM_HEADER; meas_type = AID_spectroscopy; att2_corr = (float)(target_in_percents) /100; for (n=0;n val_max[n]) { val_max[n] = value; index_max[n] = k + n*WBS_BLOCK_DATA_LEN + median_index; } } } // step #1a: check for saturated dark pixels for (n=0;n (dmax*scan_count) ) { sat_flag[n]++; } } if (sat_flag[n]>0) generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_DARK_OVFL, 0, NULL); } // step #2: calculate correction factor wrt current setting: for (n = 0; n < WBS_BLOCK_NUM; n++) { if ((index_max[n]&1) == 1) // odd index { offset = SD_TM_HEADER + n*WBS_BLOCK_DATA_LEN + 1; } else { offset = SD_TM_HEADER + n*WBS_BLOCK_DATA_LEN ; } dark_pix = *(unsigned int *)(sd_msg.block.pointer_to_data + offset); if (scan_count != 0) { hot_corr[n] = (((float)(val_max[n]) - (float)(dark_pix) )/scan_count); if ( ((float)(val_max[n]) - (float)(dark_pix) ) <= 0. ) generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_DARK_OVFL, 0, NULL); } else { generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_ZERO_DIV, 0, NULL); hot_corr[n] = ((float)(val_max[n]) - (float)(dark_pix)); } zsc_corr_avg[n] = zscan_corr[wbs_id][index_max[n]]; zsc_avg[n] = zscan[wbs_id][index_max[n]]; atten = (hot_corr[n] - zsc_corr_avg[n]); if (meas_type == WBS_ATTSETT2_ID) { corr_factor[n] = (0.3*1024) - zsc_avg[n]; } else { corr_factor[n] = (att2_corr*1024) - zsc_avg[n]; } if (atten > 10) { corr_factor[n] = corr_factor[n]/(atten); } else { corr_factor[n] = corr_factor[n]/10; // commented after scr 1769 (and scr 1518): generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_ATTEN_LOW, 0, NULL); } if (corr_factor[n] > 0) corr_factor[n] = 10.0*log10f(corr_factor[n]); else { // when corr_factor[n] <= 0, the result of log10f() would be - infinity generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_NUMERICAL_OVFL, 0, NULL); // corr_factor[n] is set to 10.0*log10f(2^(-126)) = -379.298, because 2^(-126) is the // least positive floating point number representable on the DSP corr_factor[n] = -379.298; } } //Step #3 // Calculate necessary attenuations for (n = 0; n < WBS_BLOCK_NUM; n++) { ATT_corr[wbs_id][n] = (Current_main_att[wbs_id][n]+Current_bands_att[wbs_id][n]) - corr_factor[n]; } // search for the weakest and strongest subband for (n = 0; n < WBS_BLOCK_NUM; n++) { if (strong < ATT_corr[wbs_id][n] ) { strong = ATT_corr[wbs_id][n]; index_strong=n; } if (weak > ATT_corr[wbs_id][n] ) { weak = ATT_corr[wbs_id][n]; index_weak=n; } if (sat_flag[n]>0) { strong = 22; index_strong=n; } } // setting Main attenuator: /* make sure that weakest subband attn is 0 and strongest line is not saturated */ if (strong - weak < 7) { Main_att[wbs_id] = weak; /* optimum setting, weakest subband @ 0dB */ index_main = index_weak; } else { Main_att[wbs_id] = strong - 7; /* fallback setting: do not saturate strongest band */ index_main= index_strong; } /* Max allowed value of common att is 15 */ if (Main_att[wbs_id] > 15) Main_att[wbs_id] = 15; /* Main_att contains the optimum value for the common main-attenuator */ //this block is for setting the common attenuator value and for //inserting the corresponding bits into the command ATT_wbs lookupValue = Main_att[wbs_id]; k = WBS_MAIN_ATT_STEPS - 1; while (k-->0) { Main_att_cmd[wbs_id] = k; Main_att[wbs_id] = WBS_main[wbs_id][k][index_main]; if (lookupValue >= WBS_main[wbs_id][k][index_main]) { Main_att_cmd[wbs_id] = k+1; Main_att[wbs_id] = WBS_main[wbs_id][k+1][index_main]; break; } } for (n = 0; n < WBS_BLOCK_NUM; n++) Current_main_att[wbs_id][n]=WBS_main[wbs_id][Main_att_cmd[wbs_id]][n]; // setting bands attenuators for (n = 0; n < WBS_BLOCK_NUM; n++) { if ((ATT_corr[wbs_id][n] - Current_main_att[wbs_id][n]) <= WBS_BANDS_ATT[wbs_id][7][n]) { Bands_att[wbs_id][n] = ATT_corr[wbs_id][n] - Current_main_att[wbs_id][n]; if ( Bands_att[wbs_id][n] >= 0) { k = WBS_BANDS_ATT_STEPS-1; lookupValue = Bands_att[wbs_id][n]; while (k-->0) { Bands_att_cmd[wbs_id][n] = k; Bands_att[wbs_id][n] = WBS_BANDS_ATT[wbs_id][k][n]; if (lookupValue >= WBS_BANDS_ATT[wbs_id][k][n]) { Bands_att_cmd[wbs_id][n] = k + 1; Bands_att[wbs_id][n] = WBS_BANDS_ATT[wbs_id][k+1][n]; break; } } } else { Bands_att[wbs_id][n]=0; Bands_att_cmd[wbs_id][n] = 0; } } else { Bands_att_cmd[wbs_id][n] = 7; Bands_att[wbs_id][n] = WBS_BANDS_ATT[wbs_id][WBS_BANDS_ATT_STEPS-1][n]; } if (sat_flag[n]>0) { Bands_att_cmd[wbs_id][n] = 7; Bands_att[wbs_id][n] = WBS_BANDS_ATT[wbs_id][WBS_BANDS_ATT_STEPS-1][n]; } Current_bands_att[wbs_id][n] = Bands_att[wbs_id][n]; } // # step #6 build LS-command if (wbs_id == WBS_H_ID) LsCommand[wbs_id] = WBS_H_CMD[ATT_ZERO_IDX]; else LsCommand[wbs_id] = WBS_V_CMD[ATT_ZERO_IDX]; LsCommand[wbs_id] = LsCommand[wbs_id] | (Main_att_cmd[wbs_id] << 5); for (n = 0; n < WBS_BLOCK_NUM; n++) { offset = 9 + 3*n; // 5 bits + 4 (Ain bits) + 3bits per each atten LsCommand[wbs_id] = LsCommand[wbs_id] | (Bands_att_cmd[wbs_id][n] << (offset)); } if (ls_put_msg_hp(&LsCommand[wbs_id], NULL, 0, NULL) == RC_FAIL) { generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); return; } // report // prepare a tune report // require a block from the pool if (get_block(&block, HK_POOL, HK_BLOCK_LEN_BYTES) == RC_FAIL) { generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_GET_HK_POOL_BLOCK, 0, NULL); return; } // initialize the block just requested init_block(&(block), HK_BLOCK_LEN_WORDS); p_aux = block.pointer_to_data + HK_TM_HEADER; // prepare auxiliary pointer n=0; for (k = 0; k < (WBS_BLOCK_NUM*2); n++, k+=2) { p_aux[k] = ( val_max[n] >>16); p_aux[k+1] = ( val_max[n] & 0xffff); } p_aux[8] = (LsCommand[wbs_id]>>16); p_aux[9] = (LsCommand[wbs_id]& 0xffff); prepare_TM_packet(&block, TM_DFHF_REGULAR, TM_APID_HK, (((DFH_WLEN+SDH_HK_WLEN+(WBS_BLOCK_NUM+1)*2+1)<<1)-1), TM_HK_TYPE, TM_HK_SUBT); // prepare the pointer to header st3_header = (TM_ST3_HEADER * ) block.pointer_to_data; // write Source Data Header if (wbs_id == WBS_H_ID) st3_header->structure_ID = WBSH_TUNE_SID; else st3_header->structure_ID = WBSV_TUNE_SID; UNPACK(st3_header->obs_ID, Observation_ID); UNPACK(st3_header->bb_ID, Meas_BuildingBlock_ID); hk_msg.block = block; // prepare the block to be sent in various messages hk_msg.packing = PACKING_16; // set the packetization flag to 16 bit hk_msg.packing |= SDH_HK_WLEN << 8; // set the length of data header hk_msg.packing |= HKP << 16; hk_msg.offset = HK_TM_HEADER; // no offset hk_msg.count = 0; // downcount of the packet hk_msg.length = (WBS_BLOCK_NUM + 1)*2; // with packing 32 here is the number of parameters // send message to tm_tc if (KS_FIFOPut(HK_TM_QUEUE, (void *) &hk_msg) == RC_FAIL) { release_block(&block); generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_FIFOPUT_HK_TM_QUEUE, 0, NULL); } } //----------------------- zscan_WBS -------------------------------------------- //! Process the science data of the zero scan step of an wbs tuning command. void zscan_WBS (unsigned int i, int scan_count) { int * p_data; int k, n, l; unsigned int offset; unsigned int dark_pix[16]; p_data = sd_msg.block.pointer_to_data + SD_TM_HEADER; // prepare the zscan array for (n = 0; n < WBS_BLOCK_NUM; n++) // span the 4 data blocks of 2048 words { for (l = 0; l < 4; l++) { offset = SD_TM_HEADER + n*WBS_BLOCK_DATA_LEN + l; dark_pix[n*4 + l] = *(unsigned int *)(sd_msg.block.pointer_to_data + offset); } for (k = 0; k < WBS_BLOCK_DATA_LEN ; k += 2) { // even and odd pixels have different dark currents zscan[i][k+n*WBS_BLOCK_DATA_LEN] = ((float)(p_data[k+n*WBS_BLOCK_DATA_LEN])/scan_count); zscan[i][k+n*WBS_BLOCK_DATA_LEN+1] = ((float)(p_data[k+n*WBS_BLOCK_DATA_LEN+1])/scan_count); zscan_corr[i][k+n*WBS_BLOCK_DATA_LEN] = ((float)p_data[k+n*WBS_BLOCK_DATA_LEN]-(float)dark_pix[n*4])/scan_count; zscan_corr[i][k+n*WBS_BLOCK_DATA_LEN+1] = ((float)p_data[k+n*WBS_BLOCK_DATA_LEN+1]-(float)dark_pix[n*4+1])/scan_count; //even channels } } } //****************************************************************************** //****************************************************************************** // engineering scan //****************************************************************************** //****************************************************************************** // defines of indexes in the TC #define TC_ENGSCAN_SID_IDX 1 #define TC_ENGSCAN_INTERVAL_IDX 2 #define TC_ENGSCAN_HK_ADDR1_IDX 3 #define TC_ENGSCAN_HK_ADDR2_IDX 4 #define TC_ENGSCAN_HK_ADDR3_IDX 5 #define TC_ENGSCAN_COMMAND_IDX 6 #define TC_ENGSCAN_NSAMPLES_1_IDX 8 #define TC_ENGSCAN_NSAMPLES_2_IDX 9 // defines #define ENGSCAN_MIN_INTERVAL 3 // expressed in ms #define ENGSCAN_MAX_INTERVAL 10 // expressed in ms; to be confirmed #define ENGSCAN_MAX_NSAMP_1 150 // to be confirmed #define ENGSCAN_MAX_NSAMP_2 1000 // to be confirmed #define ENGSCAN_MAX_COLLECTED_DATA (3*ENGSCAN_MAX_NSAMP_1 + 3*ENGSCAN_MAX_NSAMP_2) // dimension of the array used to collect hk values #define MAX_HK_BYTE_NUM_ENGSCAN_REP (1024 - 48) // maximum number of bytes of hk values that can fit into a report packet; 48 = 46 (including HIF_N_samples_2) + 2 (pec) #define MAX_HK_WORDS_NUM_ENGSCAN_REP (MAX_HK_BYTE_NUM_ENGSCAN_REP / 2) // maximum number of hk values that can fit into a report packet #define ENGSCAN_REP_ARRAY_DIM ((1024 - 18) / 2) // 1024 is the max number of bytes in a packet; 18 = 16 (up to data field header) + 2 (pec) #define ENGSCAN_REPORT_SID 271 // variables for the engineering scan routine static unsigned int eng_scan_interval, eng_scan_command; static unsigned int eng_scan_Nsampl_1, eng_scan_Nsampl_2; static unsigned int hk_address[3]; // to store the 3 hk addresses coming with the TC static unsigned int hk_request_word[3]; // to store the 3 32-bit words to be transmitted to ss as hk requests static unsigned int valid_addr_number; // to hold the number of valid hk addresses in the TC (can be 1, 2 or 3) static unsigned int eng_scan_collected_data[ENGSCAN_MAX_COLLECTED_DATA]; // array used to collect hk values static unsigned int eng_scan_report_data[ENGSCAN_REP_ARRAY_DIM]; // array used to build each packet of the report static unsigned int collected_hk_value_num; // to hold the number of 16-bit HK values collected during the scan static unsigned int eng_scan_sid; //---------------------- start_eng_scan ---------------------------------------- int start_eng_scan (HS_HDL_MSG * message) { TC_packet * packet; int k; // init this auxiliary pointer to the TC packet packet = (TC_packet *) message->block.pointer_to_data; // check that fcu is on, if not return execution failure if ((SubsysStatus & FCU_MASK) == 0) { enqueue_exec_fail(EXF_HS_LIB_FCU_SUB_OFF, 0, NULL); release_block(&(message->block)); return RC_FAIL; } // check that the sampling interval is between ENGSCAN_MIN_INTERVAL and ENGSCAN_MAX_INTERVAL if ((packet->data[TC_ENGSCAN_INTERVAL_IDX] > ENGSCAN_MAX_INTERVAL) || (packet->data[TC_ENGSCAN_INTERVAL_IDX] < ENGSCAN_MIN_INTERVAL)) { enqueue_exec_fail(EXF_HS_LIB_ENGSCAN_INVALID_INTERVAL, 1, &(packet->data[TC_ENGSCAN_INTERVAL_IDX])); release_block(&(message->block)); return RC_FAIL; } // check that parameter HIF_NSAMPLES_1 is not zero and is not greater than the maximum allowed value ENGSCAN_MAX_NSAMP_1 if ((packet->data[TC_ENGSCAN_NSAMPLES_1_IDX] > ENGSCAN_MAX_NSAMP_1) || (packet->data[TC_ENGSCAN_NSAMPLES_1_IDX] == 0)) { enqueue_exec_fail(EXF_HS_LIB_ENGSCAN_INVALID_NSAMP_1, 1, &(packet->data[TC_ENGSCAN_NSAMPLES_1_IDX])); release_block(&(message->block)); return RC_FAIL; } // check that parameter HIF_NSAMPLES_2 is not zero and is not greater than the maximum allowed value ENGSCAN_MAX_NSAMP_2 if ((packet->data[TC_ENGSCAN_NSAMPLES_2_IDX] > ENGSCAN_MAX_NSAMP_2) || (packet->data[TC_ENGSCAN_NSAMPLES_2_IDX] == 0)) { enqueue_exec_fail(EXF_HS_LIB_ENGSCAN_INVALID_NSAMP_2, 1, &(packet->data[TC_ENGSCAN_NSAMPLES_2_IDX])); release_block(&(message->block)); return RC_FAIL; } // set variable valid_addr_number and check that it is not zero; // check also the correctness of the start and mode bits of each hk_address valid_addr_number = 0; for (k = 0; k < 3; k++) { if (packet->data[TC_ENGSCAN_HK_ADDR1_IDX + k] != 0x0FFF) { valid_addr_number++; // now check also the correctness of the start and mode bits if ((packet->data[TC_ENGSCAN_HK_ADDR1_IDX + k] & 0xC000) != 0x8000) { enqueue_exec_fail(EXF_HS_LIB_ENGSCAN_WRONG_ADDR, 0, NULL); release_block(&(message->block)); return RC_FAIL; } } } if (valid_addr_number == 0) { enqueue_exec_fail(EXF_HS_LIB_ENGSCAN_NO_VALID_ADDR, 0, NULL); release_block(&(message->block)); return RC_FAIL; } // check the correctness of the start and mode bits of TC parameter HIF_command if ((packet->data[TC_ENGSCAN_COMMAND_IDX] & 0xC000) != 0xC000) { // if it is not a dummy command: abort if ( PACK(packet->data[TC_ENGSCAN_COMMAND_IDX], packet->data[TC_ENGSCAN_COMMAND_IDX + 1]) != 0x0FFFFFFF ) { enqueue_exec_fail(EXF_HS_LIB_ENGSCAN_WRONG_CMD, 0, NULL); release_block(&(message->block)); return RC_FAIL; } } // check the HS systems status if ( ! bring_to_safe( message ) ) return RC_OK; // now that HS is safe we can start // initialization AID_spectroscopy = ENG_SCAN_ID; // set AID_spectroscopy reset_fifo(); collected_hk_value_num = 0; // reset the number of collected hk values // extract parameters from the TC and store them in appropriate variables eng_scan_sid = packet->data[TC_ENGSCAN_SID_IDX]; eng_scan_interval = packet->data[TC_ENGSCAN_INTERVAL_IDX]; eng_scan_command = PACK(packet->data[TC_ENGSCAN_COMMAND_IDX], packet->data[TC_ENGSCAN_COMMAND_IDX + 1]); eng_scan_Nsampl_1 = packet->data[TC_ENGSCAN_NSAMPLES_1_IDX]; eng_scan_Nsampl_2 = packet->data[TC_ENGSCAN_NSAMPLES_2_IDX]; hk_address[0] = packet->data[TC_ENGSCAN_HK_ADDR1_IDX]; hk_address[1] = packet->data[TC_ENGSCAN_HK_ADDR2_IDX]; hk_address[2] = packet->data[TC_ENGSCAN_HK_ADDR3_IDX]; // build the 32-bit words that will be transmitted on the ls bus to request hk values: // the MS 16 bits are those provided by TC (hk address) and the LS 16 bits are 0xFFFF hk_request_word[0] = PACK(hk_address[0], 0xFFFF); hk_request_word[1] = PACK(hk_address[1], 0xFFFF); hk_request_word[2] = PACK(hk_address[2], 0xFFFF); // now we can free the block containing the TC release_block(&(message->block)); // note: before starting issuing hk requests, we must make sure that fifos LS_HP_QUEUE, // LS_LP_QUEUE are empty: this is done by sending a special message into the low // priority input fifo of task ls; this message will trigger the next step // this message will be recognized by ls, which will then send a message to task hs_hdl asking for the next step if (ls_put_msg_hp(NULL, (unsigned int *) message->command_number, ENGSCAN_ROUTINE, NULL) == RC_FAIL) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_LP_QUEUE, 0, NULL); return RC_OK; } //---------------------- perform_eng_scan -------------------------------------- int perform_eng_scan (int command_number) { int i, k; // first phase of hk acquisition (before the single command) for (i = 0; i < eng_scan_Nsampl_1; i++) { for (k = 0; k < 3; k++) { if (hk_address[k] != 0x0FFF) { if (ls_put_msg_hp(&hk_request_word[k], &eng_scan_collected_data[collected_hk_value_num], 0, NULL) == RC_FAIL) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); KS_TaskSleep(eng_scan_interval); // wait eng_scan_interval ms collected_hk_value_num++; // increment the number of collected hk values if ( command_number != current_command_number ) return RC_OK; // a new command was issued: stop immediately; } } } // send the single command (if not dummy) if ( eng_scan_command != 0x0FFFFFFF ) { if (ls_put_msg_hp(&eng_scan_command, NULL, 0, NULL) == RC_FAIL) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); } // wait eng_scan_interval ms KS_TaskSleep(eng_scan_interval); // second phase of hk acquisition (after the single command) for (i = 0; i < eng_scan_Nsampl_2; i++) { for (k = 0; k < 3; k++) { if (hk_address[k] != 0x0FFF) { if (ls_put_msg_hp(&hk_request_word[k], &eng_scan_collected_data[collected_hk_value_num], 0, NULL) == RC_FAIL) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); KS_TaskSleep(eng_scan_interval); // wait eng_scan_interval ms collected_hk_value_num++; // increment the number of collected hk values if ( command_number != current_command_number ) return RC_OK; // a new command was issued: stop immediately; } } } // this message will be recognized by ls, which will then send a message to // task hs_hdl asking for the report generation if (ls_put_msg_hp(NULL, (unsigned int *) command_number, ENGSCAN_REPORT, NULL) == RC_FAIL) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_LP_QUEUE, 0, NULL); return RC_OK; } //---------------------- send_eng_scan_report ---------------------------------- // note: this function has been written considering that the maximum allowed value // for TC parameter HIF_N_samples_1 is such that the first group of hk values always // fits in the first packet int send_eng_scan_report (void) { int collected_hk_groups_num, max_hk_groups_num_in_pkt, num_pkts_in_scan; int i, k, groups_to_copy, write_index, read_index = 0; int group_2_samples_in_the_packet; // set the variable which tells us how many groups of hk values we must packetize // (a group can be made of 1, 2 or 3 hk values, depending on valid_addr_number) collected_hk_groups_num = eng_scan_Nsampl_1 + eng_scan_Nsampl_2; // set the variable which tells us the max number of groups of hk values that can fit into one packet max_hk_groups_num_in_pkt = MAX_HK_WORDS_NUM_ENGSCAN_REP / valid_addr_number; // truncation may occur: it's ok // compute the number of packets needed to download all the acquired hk values num_pkts_in_scan = collected_hk_groups_num / max_hk_groups_num_in_pkt; // division between integers (truncation may occur) if (IFSI_MOD(collected_hk_groups_num, max_hk_groups_num_in_pkt) != 0) num_pkts_in_scan++; // prepare the first part of report packets: it is essentially the same for all packets eng_scan_report_data[0] = eng_scan_sid; // structure id UNPACK(&eng_scan_report_data[1], Observation_ID); // obsid UNPACK(&eng_scan_report_data[3], Meas_BuildingBlock_ID); // bbid eng_scan_report_data[5] = num_pkts_in_scan; // number of report packets in scan eng_scan_report_data[7] = eng_scan_interval; eng_scan_report_data[8] = hk_address[0]; eng_scan_report_data[9] = hk_address[1]; eng_scan_report_data[10] = hk_address[2]; UNPACK(&eng_scan_report_data[11], eng_scan_command); for (i = 0; i < num_pkts_in_scan; i++) { eng_scan_report_data[6] = i; // packet number in scan // determine how many hk groups will be copied into this packet if (i == (num_pkts_in_scan - 1)) groups_to_copy = IFSI_MOD(collected_hk_groups_num, max_hk_groups_num_in_pkt); // last packet else groups_to_copy = max_hk_groups_num_in_pkt; // every other packet // copy from array eng_scan_collected_data[] into array eng_scan_report_data[] the // hk data that will form the current packet; this must be done differently depending // on whether we are at the first packet or not if (i == 0) { eng_scan_report_data[13] = eng_scan_Nsampl_1; // first packet write_index = 14; for (k = 0; k < valid_addr_number*eng_scan_Nsampl_1; k++) eng_scan_report_data[write_index++] = eng_scan_collected_data[read_index++]; if (num_pkts_in_scan > 1) group_2_samples_in_the_packet = max_hk_groups_num_in_pkt - eng_scan_Nsampl_1; // the data does not all fit into one packet else group_2_samples_in_the_packet = eng_scan_Nsampl_2; // the data all fit into one packet eng_scan_report_data[write_index++] = group_2_samples_in_the_packet; for (k = 0; k < (valid_addr_number * group_2_samples_in_the_packet); k++) eng_scan_report_data[write_index++] = eng_scan_collected_data[read_index++]; } else // not first packet { eng_scan_report_data[13] = 0; // every other packet (we assume that the first set of hk always fits in 1 packet) eng_scan_report_data[14] = groups_to_copy; write_index = 15; for (k = 0; k < valid_addr_number*groups_to_copy; k++) eng_scan_report_data[write_index++] = eng_scan_collected_data[read_index++]; } // call function generate_report() to produce the report packet generate_report(APID1026, TM_HK_TYPE, TM_HK_SUBT, (15 + valid_addr_number*groups_to_copy), eng_scan_report_data); } // end of for // set AID_spectroscopy AID_spectroscopy = REQUIRING_HK; // completion ack enqueue_exec_compl(); return RC_OK; } //************************************************************************************************** //************************************************************************************************** // diplexer scan //************************************************************************************************** //************************************************************************************************** //---------------------- start_dip_scan_ifp ------------------------------------ //! this function starts a diplexer scan with if power by performing some preparatory //! operations and putting a message into the hs_hdl queue. int start_dip_scan_ifp (HS_HDL_MSG * message) { TC_packet * packet; HS_HDL_MSG cmd_queue; // message to be sent to the hs_hdl task int i; // init this auxiliary pointer to the TC packet packet = (TC_packet *) message->block.pointer_to_data; // check that hrs is on, if not return execution failure if ( (SubsysStatus & HRS_H_MASK) == 0 && (SubsysStatus & HRS_V_MASK) == 0 ) { enqueue_exec_fail(EXF_HS_LIB_HRS_SUB_OFF, 0, NULL); release_block(&(message->block)); return RC_FAIL; } // check that fcu is on, if not return execution failure if ((SubsysStatus & FCU_MASK) == 0) { enqueue_exec_fail(EXF_HS_LIB_FCU_SUB_OFF, 0, NULL); release_block(&(message->block)); return RC_FAIL; } // check on the number of steps requested if (packet->data[TC_N_DIPLEXER_IDX] > MAX_NSTEP_DIPSCAN_IF) { enqueue_exec_fail(EXF_HS_LIB_DIPSCAN_NUM_STEP, 0, NULL); release_block(&(message->block)); return RC_FAIL; } // check the HS systems status if ( ! bring_to_safe( message ) ) return RC_OK; // now that HS is safe we can start // set working spectrometers mask and other inits and resets Meas_spectr = Active_spectr & 0x60; // only HRS working AID_spectroscopy = DIP_SCAN_IF_ID; // set AID_spectroscopy reset_fifo(); init_tuni_table(DIP_SCAN_IF_ID); // init tables and other stuff // set the building block id Meas_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX+1]); Cur_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX+1]); dip_scan_if_cur_step = 0; // reset this global variable (a counter) // reset the array dip_scan_if_data[], where we store the data for the report for (i = 0; i < MAX_DIPSCAN_DATA; i++) dip_scan_if_data[i] = 0; // now write the initial words of array dip_scan_if_data[] dip_scan_if_data[0] = DIP_SCAN_IF_REP_SID; // sid is 258 UNPACK(&dip_scan_if_data[1], Observation_ID); // obsid UNPACK(&dip_scan_if_data[3], Meas_BuildingBlock_ID); // bbid dip_scan_if_data[TM_DP_STEP_TIME_IDX] = packet->data[5]; // step time dip_scan_if_data[TM_CH1_DP_POS0_IDX] = packet->data[6]; // ch1 dp pos0 dip_scan_if_data[TM_CH2_DP_POS0_IDX] = packet->data[7]; // ch2 dp pos0 dip_scan_if_data[TM_DP_STEP_IDX] = packet->data[8]; // diplexer step dip_scan_if_data[TM_N_DIPLEXER_IDX] = packet->data[TC_N_DIPLEXER_IDX]; // HIF_Ndiplexer // Correct the sign of the step: extend with 1 if negative (2complement representation) if ( dip_scan_if_data[TM_DP_STEP_IDX] & 0x8000 ) dip_scan_if_data[TM_DP_STEP_IDX] = dip_scan_if_data[TM_DP_STEP_IDX] | 0xFFFF0000; release_block(&(message->block)); // now we can free the block containing the TC // we get once for all two values that must be put into the report if (ls_put_msg_hp(&FCU_PS_HK[HF_DH1_MXBAND_IDX], &dip_scan_if_data[9], 0, NULL) == RC_FAIL) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); if (ls_put_msg_hp(&FCU_PS_HK[HF_DV1_MXBAND_IDX], &dip_scan_if_data[10], 0, NULL) == RC_FAIL) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); // prepare and send the command for the first step of diplexer scan cmd_queue.operation_id = DIP_SCAN_IF_ID; cmd_queue.command_number = message->command_number; cmd_queue.block_loaded = 0; // no memory blocks have been allocated for this message if (KS_FIFOPut(HS_HDL_QUEUE, (void *) &cmd_queue) == RC_FAIL) { enqueue_exec_fail(EXF_HS_LIB_QUEUE, 0, NULL); // execution failure return RC_FAIL; } else return RC_OK; } //----------------------- dipscan_compute_ifpower ------------------------------ //! Process the science data of a diplexer scan with IF power. void dipscan_compute_ifpower (unsigned int fifo_id, unsigned int step) { unsigned int k, l, n, aux, select; unsigned int offset = 0; unsigned int head_chan[4]; int ifpower_chip1[8]; float ifpo_r[16]; // read 2 configuration parameters from the Spectroscopy_table select = Spectroscopy_table[Sd_hdl[fifo_id].range_sel]; // index k (running from 0 to 7) is for data blocks contained into the hrs frame for (k = 0, l = 0x1; k < 8; l <<= 1, k++) { if (select & l) // go on with processing only if block k is in the range selected { // extract the first 4 words of chip 2 subblock: these words, stored into // head_chan[], are needed for ifpower computation for (n = 0; n < 4; n++) { offset = SD_TM_HEADER + k*HRS_BLOCK_DATA_LEN + n; head_chan[n] = *(unsigned int *)(sd_msg.block.pointer_to_data + offset); } // use the following formula for if power ifpo_r[k] = (((float)(2*head_chan[3])-(float)(head_chan[1]))*65535.); if ((head_chan[1])!= 0) { ifpo_r[k] = ifpo_r[k]/(float)(head_chan[1]); } else { ifpo_r[k] =0; generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_HRS_DURATION_NULL, 0, NULL); } if (ifpo_r[k] < 0) ifpo_r[k] =0; ifpower_chip1[k] = (int)ifpo_r[k]; // HK packet ICD 1.4 } } // now array ifpower_chip1[] contains the 8 values that must be copied into the // array dip_scan_if_data[], where we are building the diplexer scan report. // prepare offset aux, which depends on polarization if (fifo_id == HRS_H_ID) aux = 0; else aux = 8; // case (fifo_id == HRS_V_ID) // now copy for (k = 0; k < 8; k++) dip_scan_if_data[12 + step*DIP_SCAN_DATA + DIP_SCAN_HKOFFSET + aux + k] = ifpower_chip1[k]; } //****************************************************************************** //****************************************************************************** // wbs calibration //****************************************************************************** //****************************************************************************** //------------- start_wbs_calibrate -------------------------------------------- //! this function can start both a spectroscopy wbs comb and a spectroscopy wbs zero, //! depending on the operation code contained into the structure pointed by message int start_wbs_calibrate (HS_HDL_MSG * message) { HS_HDL_MSG cmd_queue; TC_packet * packet; // check that wbs on if ((SubsysStatus & WBS_H_MASK) == 0 && (SubsysStatus & WBS_V_MASK) == 0) { release_block(&(message->block)); return enqueue_exec_fail(EXF_HS_LIB_WBS_SUB_OFF, 0, NULL); } // check the HS systems status if ( ! bring_to_safe( message ) ) return RC_OK; // now HS is safe, we can initialize the HS systems and static data, and start // inits Meas_spectr = Active_spectr & 0x18; // only WBS working // init this auxiliary pointer to the TC packet packet = (TC_packet *) message->block.pointer_to_data; // read from TC the building block id Meas_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX + 1]); Cur_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX + 1]); // the following switch sets AID_spectroscopy and the next step's operation id switch (message->operation_id) { case START_SPECTR_WBS_COMB_ID: // WBS calibration AID_spectroscopy = WBS_COMB_STEP1_ID; // set AID_spectroscopy // copy into WBS_H_CMD[ATT_COMB_MEAS_IDX] and WBS_V_CMD[ATT_COMB_MEAS_IDX] // the attenuator setting contained in the TC (two 32-bit ls command) WBS_H_CMD[ATT_COMB_MEAS_IDX] = PACK(packet->data[4], packet->data[5]); WBS_V_CMD[ATT_COMB_MEAS_IDX] = PACK(packet->data[6], packet->data[7]); // prepare the commands we need to restore the previous wbs attenuator // setting, which is stored into the global variable wbs_att_setting[] WBS_H_CMD[ATT_RESTORE_COMB_IDX] = ((wbs_att_setting[0] << 5) | 0xE400000F); WBS_V_CMD[ATT_RESTORE_COMB_IDX] = ((wbs_att_setting[1] << 5) | 0xE800000F); WBS_H_CMD[ATT_RESTORE_ZERO_IDX] = ((zero_switch_setting[0] << 5) | 0xE400000A); WBS_V_CMD[ATT_RESTORE_ZERO_IDX] = ((zero_switch_setting[1] << 5) | 0xE800000A); // write the operation ID for the next step cmd_queue.operation_id = WBS_COMB_STEP1_ID; break; case START_SPECTR_WBS_ZERO_ID: // WBS zero measurement AID_spectroscopy = SPECTROSCOPY_WBS_ZERO_ID; // set AID_spectroscopy cmd_queue.operation_id = SPECTROSCOPY_WBS_ZERO_ID; break; } reset_fifo(); init_tuni_table(AID_spectroscopy); release_block(&(message->block)); // here the block can be released // prepare and send a message for the next step to be performed cmd_queue.command_number = message->command_number; cmd_queue.block_loaded = 0; if (KS_FIFOPut(HS_HDL_QUEUE, (void *) &cmd_queue) == RC_FAIL) return enqueue_exec_fail(EXF_HS_LIB_QUEUE, 0, NULL); // execution failure else return RC_OK; } //************************************************************************************************** //************************************************************************************************** // tune_mixer_magnet //************************************************************************************************** //************************************************************************************************** // the following two variables are for mixer magnet current tuning static unsigned int ifpower_min[4]; // to hold the min power for each of the four spectrometers (index 0=wbsh ..) during a mixer magnet tuning procedure static unsigned int nmagnet_min[4]; // to hold the iteration index which has given the minimum power //--------------------- start_tune_mixer_magnet ---------------------------- //! First step of a mixer magnet tuning. Checks the HS status. //! When safe resets static variables and enqueue a packet that will trigger the actual tuning. int start_tune_mixer_magnet (HS_HDL_MSG *message, int AID_sp) { TC_packet * packet; HS_HDL_MSG cmd_queue; int i; // init an auxiliary pointer to the TC packet packet = (TC_packet *) message->block.pointer_to_data; // check that AID_sp is either TUNE_HMIXMAG_ID or TUNE_WMIXMAG_ID if ( ( AID_sp != TUNE_HMIXMAG_ID ) && ( AID_sp != TUNE_WMIXMAG_ID ) ) { enqueue_exec_fail(ERR_HS_LIB_INVALID_SPECTR_ID, 0, NULL); // execution failure release_block(&(message->block)); return RC_FAIL; } // if mixmag for hrs check that hrs is on, if not return if ( AID_sp == TUNE_HMIXMAG_ID ) { if ( (SubsysStatus & HRS_H_MASK) == 0 && (SubsysStatus & HRS_V_MASK) == 0 ) { enqueue_exec_fail(EXF_HS_LIB_HRS_SUB_OFF, 0, NULL); // execution failure release_block(&(message->block)); return RC_FAIL; } } else { // if mixmag for wbs check that wbs is on, if not return if ( (SubsysStatus & WBS_H_MASK) == 0 && (SubsysStatus & WBS_V_MASK) == 0 ) { enqueue_exec_fail(EXF_HS_LIB_WBS_SUB_OFF, 0, NULL); // execution failure release_block(&(message->block)); return RC_FAIL; } } // check that fcu is on if ((SubsysStatus & FCU_MASK) == 0) { enqueue_exec_fail(EXF_HS_LIB_FCU_SUB_OFF, 0, NULL); // execution failure release_block(&(message->block)); return RC_FAIL; } // check on the number of steps requested if (packet->data[TC_NMAGNET_IDX] > MAX_NUMB_MAG_CUR_STEP) { enqueue_exec_fail(EXF_HS_LIB_MIXMAG_DATA, 0, NULL); // execution failure release_block(&(message->block)); return RC_FAIL; } // check the HS systems status if ( ! bring_to_safe( message ) ) return RC_OK; // now HS is safe, we can initialize the HS systems and static data, and start // set working spectrometers mask and other inits and resets if ( AID_sp == TUNE_HMIXMAG_ID ) Meas_spectr = Active_spectr & 0x60; // only HRS working else Meas_spectr = Active_spectr & 0x18; // only WBS working AID_spectroscopy = AID_sp; // set AID_spectroscopy reset_fifo(); Meas_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX + 1]); Cur_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX + 1]); // reset the array mixer_magnet_data[] and other inits mixer_mag_steps_performed = 0; // a global variable (a counter) init_tuni_table(AID_sp); for (i = 0; i < MAX_MIXMAG_DATA; i++) mixer_magnet_data[i] = 0; // now copy some parameters from the tc packet to the vector mixer_magnet_data mixer_magnet_data[STEPTIME_IDX] = packet->data[TC_STEPTIME_IDX]; mixer_magnet_data[NMAGNET_IDX] = packet->data[TC_NMAGNET_IDX]; mixer_magnet_data[CH1_C0_IDX] = packet->data[TC_CH1_C0_IDX]; mixer_magnet_data[CV1_C0_IDX] = packet->data[TC_CV1_C0_IDX]; mixer_magnet_data[STEPSIZE_IDX] = packet->data[TC_STEPSIZE_IDX]; release_block(&(message->block)); // here we can free the TC block // Correct the sign of the step: extend with 1 if negative (2complement representation) if ( mixer_magnet_data[STEPSIZE_IDX] & 0x8000 ) mixer_magnet_data[STEPSIZE_IDX] = mixer_magnet_data[STEPSIZE_IDX] | 0xFFFF0000; // prepare and send command for the first step of hrs tune to hs_hdl task cmd_queue.operation_id = AID_sp; 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_HS_LIB_QUEUE, 0, NULL); // execution failure return RC_FAIL; } else return RC_OK; } //----------------------- tune_hmixmag ----------------------------------------- //! for a single step of a hrs mixer magnet tuning, this function computes the average //! power from the frame received and, if necessary, updates the variables used for //! the minimum average power search. void tune_hmixmag (unsigned int fifo_id, unsigned int * nl) { int k, l, n, counter = 0; unsigned int select, average_power = 0; unsigned int offset = 0; unsigned int head_chan[4]; int ifpower[16]; float ifpo_r[16]; select = Spectroscopy_table[Sd_hdl[fifo_id].range_sel]; // span the datablock_id vector (k) and the range selection (l) for (k = 0, l = 0x1; k < 8; l <<= 1, k++) { if (select & l) // check the range selected { for (n = 0; n < 4; n++) // span the first 4 data of each subblock { offset= SD_TM_HEADER + k*HRS_BLOCK_DATA_LEN + n; head_chan[n] = *(unsigned int *)(sd_msg.block.pointer_to_data + offset); } ifpo_r[k] = (((float)(2*head_chan[3])-(float)(head_chan[1]))*65535.); if ((head_chan[1])!= 0) { ifpo_r[k] = ifpo_r[k]/(float)(head_chan[1]); } else { ifpo_r[k] =0; generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_HRS_DURATION_NULL, 0, NULL); } if (ifpo_r[k] < 0) ifpo_r[k] =0; ifpower[k] = (int)ifpo_r[k]; // HK packet ICD 1.4 average_power += (unsigned int) ifpower[k]; // accumulate to compute the average power over the entire hrs frame counter++; // count the number of blocks used for the average } else { ifpower[k] = 0; // HK packet ICD 1.4 } } average_power /= counter; // compute the average power mix_mag_optimise_and_store(fifo_id, nl, average_power, fifo_id-2); } //----------------------- tune_wmixmag ----------------------------------------- //! for a single step of a wbs mixer magnet tuning, this function computes the average //! power from the frame received and, if necessary, updates the variables used for //! the minimum average power search. //! arguments: fifo_id = subsysID (it should be 0 for wbsh, 1 for wbsv); nl = nloop array void tune_wmixmag (unsigned int fifo_id, unsigned int * nl, unsigned int scan_count) { int * p_data, k, n; unsigned int start_pix, stop_pix, npixels; unsigned int totp_data = 0, average_power = 0; unsigned int ifpower_wbs[WBS_BLOCK_NUM]; float ifpo_r; wbs_right_shift(); p_data = sd_msg.block.pointer_to_data + SD_TM_HEADER; for (n = 0; n < WBS_BLOCK_NUM; n++) { start_pix = Spectroscopy_table[Sd_hdl[fifo_id].range_sel + (n*2)]; npixels = Spectroscopy_table[Sd_hdl[fifo_id].range_sel + (n*2) + 1]; stop_pix = start_pix + npixels; if (stop_pix != 0) { for (k = start_pix; k < stop_pix ; k++) totp_data = totp_data + p_data[k]; // if power estimate as the average of the output of the subband if (npixels != 0) { ifpo_r = (float)(totp_data)/(float)npixels; if (scan_count != 0) ifpo_r = ifpo_r/scan_count; else generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_ZERO_DIV, 0, NULL); // scale by 2^6 the IF power to exploit the 16 bit allowable and make it integer ifpo_r = ifpo_r * 64.; ifpower_wbs[n] = (int)(ifpo_r + .5); } else { ifpo_r = 0; ifpower_wbs[n] = 0; } average_power += ifpower_wbs[n]; // accumulating to compute the average power over the four elements of ifpower_wbs[] totp_data = 0; // reset } } // end of for loop on n average_power /= WBS_BLOCK_NUM; // compute the average power mix_mag_optimise_and_store(fifo_id, nl, average_power, fifo_id); } //------------- mix_mag_optimise_and_store ------------------------------------------------ void mix_mag_optimise_and_store(unsigned int fifo_id, unsigned int * nl, unsigned int average_power, int position) { // if it's the first step, we have to initialize ifpower_min[] and nmagnet_min[] if (nl[fifo_id] == 1) // it's the first frame from the spectrometer identified by fifo_id { ifpower_min[fifo_id] = average_power; nmagnet_min[fifo_id] = nl[fifo_id]; } // looking for the minimum power: if (average_power < ifpower_min[fifo_id]) { ifpower_min[fifo_id] = average_power; // update the variable that holds the minimum nmagnet_min[fifo_id] = nl[fifo_id]; // save the index of the loop which has given the minimum } // store the average power of the frame just processed into mixer_magnet_data[] for the tune report mixer_magnet_data[MIX_MAG_HKOFFSET + MIX_MAG_DATA*(nl[fifo_id] - 1) + MIX_MAG_HKDATA + position] = average_power; } //------------- send_mixmag_rep ------------------------------------------------ //! it prepares and sends the report at the end of a mixer magnet tuning; //! this function receives a tuni_id to distinguish between wbs and hrs. void send_mixmag_rep (unsigned int tuni_id) { K_BLOCK block; TM_ST3_HEADER *st3_header; HK_TM_MSG hk_msg; int tot_data, k, * p_aux, fifo_id, struct_id; // get and init a block from the hk pool if (get_block(&block, HK_POOL, HK_BLOCK_LEN_BYTES) == RC_FAIL) { generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_GET_HK_POOL_BLOCK, 0, NULL); return; } init_block(&(block), HK_BLOCK_LEN_WORDS); // prepare auxiliary pointer p_aux = block.pointer_to_data + HK_TM_HEADER; // it points immediately after the bbid of the tm packet tot_data = MIX_MAG_HKOFFSET + MIX_MAG_DATA*mixer_magnet_data[NMAGNET_IDX]; // total number of 16-bit words to be written into the report for (k = 0; k < tot_data; k++) // copy the entire array mixer_magnet_data[] into the tm packet p_aux[k] = mixer_magnet_data[k]; // set fifo_id and struct_id depending on the tuni_id if (tuni_id == TUNE_WMIXMAG_ID) { fifo_id = WBS_H_ID; struct_id = MXMAGW_TUNE_SID; } else { fifo_id = HRS_H_ID; struct_id = MXMAGH_TUNE_SID; } // write optimized magnet current H and V into the appropriate locations of the tm packet: // notice: we write the commanded current value which gave the optimum, and not the corresponding hk-returned value. p_aux[MIX_MAG_HKOFFSET - 3] = mixer_magnet_data[CH1_C0_IDX] + (nmagnet_min[fifo_id] - 1)*mixer_magnet_data[STEPSIZE_IDX]; p_aux[MIX_MAG_HKOFFSET - 2] = mixer_magnet_data[CV1_C0_IDX] + (nmagnet_min[fifo_id + 1] - 1)*mixer_magnet_data[STEPSIZE_IDX]; prepare_TM_packet(&block, TM_DFHF_REGULAR, TM_APID_HK, 39 + 20*mixer_magnet_data[NMAGNET_IDX], TM_HK_TYPE, TM_HK_SUBT); // prepare the pointer to header st3_header = (TM_ST3_HEADER * ) block.pointer_to_data; // write Source Data Header st3_header->structure_ID = struct_id; UNPACK(st3_header->obs_ID, Observation_ID); UNPACK(st3_header->bb_ID, Meas_BuildingBlock_ID); // prepare the block to be sent into the HK_TM_QUEUE hk_msg.block = block; hk_msg.packing = PACKING_16; // set the packetization flag to 16 bit hk_msg.packing |= SDH_HK_WLEN << 8; // set the length of data header hk_msg.packing |= HKP << 16; hk_msg.offset = HK_TM_HEADER; hk_msg.count = 0; // downcount of the packet hk_msg.length = tot_data + 5; // length in words of the application data field without crc (actually it is useless for non-science packets) // send message to tm_tc task if (KS_FIFOPut(HK_TM_QUEUE, (void *) &hk_msg) == RC_FAIL) { release_block(&block); generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_FIFOPUT_HK_TM_QUEUE, 0, NULL); } } //------------------ set_magnet_opt_current ------------------------------------ //! this function is called at the end of a mixer magnet tuning in order to set //! the magnet currents to the optimum values. void set_magnet_opt_current (unsigned int tuni_id) { static unsigned int FCU_CMD1, FCU_CMD2; // these are static so that the pointers passed to task ls should be meaningful int fifo_id; // set fifo_id depending on the tuni_id if (tuni_id == TUNE_WMIXMAG_ID) fifo_id = WBS_H_ID; else fifo_id = HRS_H_ID; // Due to histeresys set the current to tyhe inital value before setting it to the optimum value (SCR 1045) // set the magnet current h FCU_CMD1 = FCU_PS_CMD[HF_CH1_MX_MG_C_IDX] | ((mixer_magnet_data[CH1_C0_IDX] ) & 0x0FFFF); if (ls_put_msg_hp(&FCU_CMD1, NULL, 0, NULL) == RC_FAIL) generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); // set the magnet current v FCU_CMD2 = FCU_PS_CMD[HF_CV1_MX_MG_C_IDX] | ((mixer_magnet_data[CV1_C0_IDX] ) & 0x0FFFF); if (ls_put_msg_hp(&FCU_CMD2, NULL, 0, NULL) == RC_FAIL) generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); // wait one second to allow current to stabilise task_hs_hdl_sleep(1000); // wait the specified time // now set the current to the optimum value // notice: we consider the commanded current value which gave the optimum, and not the corresponding hk-returned value. // set the magnet current h FCU_CMD1 = FCU_PS_CMD[HF_CH1_MX_MG_C_IDX] | ((mixer_magnet_data[CH1_C0_IDX] + (nmagnet_min[fifo_id] - 1)*mixer_magnet_data[STEPSIZE_IDX]) & 0x0FFFF); if (ls_put_msg_hp(&FCU_CMD1, NULL, 0, NULL) == RC_FAIL) generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); // set the magnet current v FCU_CMD2 = FCU_PS_CMD[HF_CV1_MX_MG_C_IDX] | ((mixer_magnet_data[CV1_C0_IDX] + (nmagnet_min[fifo_id + 1] - 1)*mixer_magnet_data[STEPSIZE_IDX]) & 0x0FFFF); if (ls_put_msg_hp(&FCU_CMD2, NULL, 0, NULL) == RC_FAIL) generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); } //************************************************************************************************** //************************************************************************************************** // goto safe //************************************************************************************************** //************************************************************************************************** //------- start_HIFI_goto_safe ---------------------------------------------- //! Stops spectroscopy and issues commands to bring the systems into a safe status int start_HIFI_goto_safe(HS_HDL_MSG *message) { TC_packet * packet; int i; // 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 the HS systems and static data, and start // release the TC block release_block(&(message->block)); // reset HS subsystem and restart HK acquisition AID_spectroscopy = REQUIRING_HK; // set AID_spectroscopy reset_fifo(); fifo_0_command_number = fifo_1_command_number = fifo_2_command_number = fifo_3_command_number = current_command_number; // now send the commands to the subsystems for ( i=0; i< goto_safe_commands_len; i++) if (ls_put_msg_hp(&goto_safe_commands[i], NULL, 0, NULL) == RC_FAIL) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); enqueue_exec_compl(); return RC_OK; } //------- force_HIFI_goto_safe ---------------------------------------------- //! This is a goto_safe command issued at system startup. Stops spectroscopy and issues commands to bring the systems into a safe status void force_HIFI_goto_safe(void) { int i; // reset HS subsystem reset_fifo(); // now send the commands to the subsystems for ( i=0; i< goto_safe_commands_len; i++) if (ls_put_msg_hp(&goto_safe_commands[i], NULL, 0, NULL) == RC_FAIL) return; // reset the flag perform_goto_safe_after_abort = 0; } //************************************************************************************************** //************************************************************************************************** // peak up //************************************************************************************************** //************************************************************************************************** int peakup_acquired_ifpowers[9]; //! to store the if powers we acquire with the 9 measurements of a peakup procedure int peakup_acquired_instrument[9] = {-1, -1, -1, -1, -1, -1, -1, -1, -1}; //! contains ID indicating the instrument: -1 if not acquired int peakup_meas_seq_number; //! to store the peakup_seqnr parameter received with the last acquire_peakup TC int peakup_current_spectrometer; //! to store the ID of the spectrometer being acquired int peakup_scale_fact_y, peakup_scale_fact_z, peakup_offset_y, peakup_offset_z; //! store the parameter values coming with the configure peakup TC //---------------------- configure_peakup_function ----------------------------- //! Start (and only) of a configure peak up - performs the peakup configuration int configure_peakup_function (TC_packet * packet) { // Executed within cmd_seq. No need to free the packet, done in cmd_seq. int i; // store peakup data peakup_scale_fact_y = packet->data[4]; peakup_scale_fact_z = packet->data[5]; peakup_offset_y = packet->data[6]; peakup_offset_z = packet->data[7]; // set BB id Cur_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX+1]); // reset static data for (i = 0; i < 9; i++) peakup_acquired_instrument[i] = -1; // Correct the sign of the offset values: extend with 1 if negative (2complement representation) if ( peakup_offset_y & 0x08000 ) peakup_offset_y = peakup_offset_y | 0xFFFF0000; if ( peakup_offset_z & 0x08000 ) peakup_offset_z = peakup_offset_z | 0xFFFF0000; // done enqueue_ok(packet, TC_EXEC_COMPLETED); // completion ack return RC_OK; } //---------------------- start_peakup_acquire_hrs ------------------------------ //! first (and only) step of a hrs peakup acquisition int start_peakup_acquire_hrs (HS_HDL_MSG * message) { TC_packet * packet; // init this auxiliary pointer to the TC packet packet = (TC_packet *) message->block.pointer_to_data; // set the building block id Meas_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX+1]); Cur_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX+1]); // check instrument polarization, check that instrument is on and set current spectrometer: only two possible values: 0 = H, 1 = V switch(packet->data[4]) { case 0: peakup_current_spectrometer = HRS_H_ID; if (SubsysStatus & HRS_H_MASK == 0) { enqueue_exec_fail(EXF_HS_LIB_HRS_SUB_OFF, 0, NULL); release_block(&(message->block)); return RC_FAIL; } break; case 1: peakup_current_spectrometer = HRS_V_ID; if (SubsysStatus & HRS_H_MASK == 0) { enqueue_exec_fail(EXF_HS_LIB_HRS_SUB_OFF, 0, NULL); release_block(&(message->block)); return RC_FAIL; } break; default: enqueue_exec_fail(EXF_HS_LIB_PEAKUP_POLAR_TYPE_PAR, 0, NULL); release_block(&(message->block)); return RC_FAIL; } // check and store sequence number: it must belong to interval 1, .. 9 peakup_meas_seq_number =packet->data[5]; if ( (peakup_meas_seq_number < 1) || (peakup_meas_seq_number > 9) ) { enqueue_exec_fail(EXF_HS_LIB_PEAKUP_SEQ_NUMBER_PAR, 0, NULL); release_block(&(message->block)); return RC_FAIL; } // check the HS systems status if ( ! bring_to_safe( message ) ) return RC_OK; // now that HS is safe we can start // we can free the block containing the TC release_block(&(message->block)); // other inits and resets AID_spectroscopy = PEAKUP_ACQUIRE_HRS; // set AID_spectroscopy reset_fifo(); init_tuni_table(PEAKUP_ACQUIRE_HRS); // init tables ---> ANNA // integrate and return result return peakup_integrate_hrs(peakup_current_spectrometer, message->command_number); } //---------------------- peakup_integrate_hrs ------------------------------ //! performs hrs integration and final flush for the peakup procedure int peakup_integrate_hrs (int instrument_id, int command_number) { START_FRAME_DATA time_stamp; unsigned int * commands; unsigned int * fifo_pending_frames; unsigned int * fifo_command_number; switch(instrument_id) { case HRS_H_ID: commands = HRS_H_CMD; fifo_pending_frames = &fifo_2_pending_frames; fifo_command_number = &fifo_2_command_number; break; case HRS_V_ID: commands = HRS_V_CMD; fifo_pending_frames = &fifo_3_pending_frames; fifo_command_number = &fifo_3_command_number; break; default: break; } // select buffer A if (ls_put_msg_hp(&commands[SEL_A_IDX], NULL, 0, NULL) == RC_FAIL) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); // reset buffer A if (ls_put_msg_hp(&commands[RESET_A_IDX], NULL, 0, NULL) == RC_FAIL) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); // integrate if (ls_put_msg_hp(&commands[START_INT_IDX], NULL, 0, NULL) == RC_FAIL) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); get_TS(&(time_stamp.time_stamp)); //store the time when the integration was started task_hs_hdl_sleep(1000); // assumption: integration time 1000 ms ---> ANNA if (ls_put_msg_hp(&commands[STOP_INT_IDX], NULL, 0, NULL) == RC_FAIL) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); KS_TaskSleep(7); // select buffer B if (ls_put_msg_hp(&commands[SEL_B_IDX], NULL, 0, NULL) == RC_FAIL) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); // now ask for the data transfer, but only if the current_command_number has not been incremented by a new incoming TC if (command_number == current_command_number) { if (ls_put_msg_hp(&commands[DATA_TRANS_IDX], NULL, HS_FLUSH_EVENT, NULL) == RC_FAIL) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); // now update the global variables used to control hs state (*fifo_pending_frames)++; push_TS(time_stamp, instrument_id, DO_NOT_ATTACH_HK); (*fifo_command_number) = command_number; } return RC_OK; } //---------------------- start_peakup_acquire_wbs ------------------------------ //! first (and only) step of a wbs peakup acquisition int start_peakup_acquire_wbs (HS_HDL_MSG * message) { TC_packet * packet; // init this auxiliary pointer to the TC packet packet = (TC_packet *) message->block.pointer_to_data; // set the building block id Meas_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX+1]); Cur_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX+1]); // check instrument polarization, check that instrument is on and set current spectrometer: only two possible values: 0 = H, 1 = V switch(packet->data[4]) { case 0: peakup_current_spectrometer = WBS_H_ID; if (SubsysStatus & WBS_H_MASK == 0) { enqueue_exec_fail(EXF_HS_LIB_WBS_SUB_OFF, 0, NULL); release_block(&(message->block)); return RC_FAIL; } break; case 1: peakup_current_spectrometer = WBS_V_ID; if (SubsysStatus & WBS_H_MASK == 0) { enqueue_exec_fail(EXF_HS_LIB_WBS_SUB_OFF, 0, NULL); release_block(&(message->block)); return RC_FAIL; } break; default: enqueue_exec_fail(EXF_HS_LIB_PEAKUP_POLAR_TYPE_PAR, 0, NULL); release_block(&(message->block)); return RC_FAIL; } // check and store sequence number: it must belong to interval 1, .. 9 peakup_meas_seq_number =packet->data[5]; if ( (peakup_meas_seq_number < 1) || (peakup_meas_seq_number > 9) ) { enqueue_exec_fail(EXF_HS_LIB_PEAKUP_SEQ_NUMBER_PAR, 0, NULL); release_block(&(message->block)); return RC_FAIL; } // check the HS systems status if ( ! bring_to_safe( message ) ) return RC_OK; // now that HS is safe we can start // we can free the block containing the TC release_block(&(message->block)); // other inits and resets AID_spectroscopy = PEAKUP_ACQUIRE_WBS; // set AID_spectroscopy reset_fifo(); init_tuni_table(PEAKUP_ACQUIRE_WBS); // init tables ---> ANNA // integrate and return result return peakup_integrate_wbs (peakup_current_spectrometer, message->command_number); } //---------------------- peakup_integrate_wbs ------------------------------ //! performs hrs integration and final flush for the peakup procedure int peakup_integrate_wbs (int instrument_id, int command_number) { START_FRAME_DATA time_stamp; // now start int, stop int, data transfer: temporary solution // better solution: put a call to xxx_integrate() after we've modified it deleting // argument flush_at_end and adding a control parameter with 3 possible values to // indicate if we want to use v, h, or both // the following while loop is essential since we must be sure that, before // commanding the start integration, the previous tuning commands sent to task // ls through the high priority fifo have already been processed by this task. while (KS_FIFOStatus(LS_HP_QUEUE) != 0) KS_TaskSleep(1); // wait 1 ms Irq3_flag = TRUE; // set this flag to reserve the ls port KS_TaskSleep(WAIT_LS_END_TIME); // wait for possible task ls to end using ls port (3 ms is the worst case) SendLss(&WBS_H_CMD[START_INT_IDX]); // writes start integration command directly into trx register get_TS(&(time_stamp.time_stamp)); // stroe the time when the integration was requested KS_TaskSleep(COMMAND_TRANSMIT_TIME); // time needed to transmit properly Irq3_flag = FALSE; // reset the flag to free the ls port task_hs_hdl_sleep(1005 - COMMAND_TRANSMIT_TIME - WAIT_LS_END_TIME); // wait integration // time -( COMMAND_TRANSMIT_TIME + WAIT_LS_END_TIME) because the overall time between the two calls // to SendLss (ie between start and stop int) must be equal to integ_time. Irq3_flag = TRUE; // set this flag to reserve the ls port KS_TaskSleep(WAIT_LS_END_TIME); // wait for possible task ls to end using ls port (3 ms is the worst case) SendLss(&WBS_H_CMD[STOP_INT_IDX]); // writes stop integration command directly into trx register KS_TaskSleep(COMMAND_TRANSMIT_TIME); // time needed to transmit properly Irq3_flag = FALSE; // reset the flag to free the ls port KS_TaskSleep(12); // now ask for the data transfer, but only if the current_command_number // has not been incremented by a new incoming TC if (command_number == current_command_number) { if (instrument_id == WBS_H_ID) // we use H { if ( SubsysStatus & WBS_H_MASK ) { if (ls_put_msg_hp(&WBS_H_CMD[DATA_TRANS_IDX], NULL, HS_FLUSH_EVENT, NULL) == RC_FAIL) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); // now update the global variables used to control hs state fifo_0_pending_frames++; push_TS(time_stamp, WBS_H_ID, DO_NOT_ATTACH_HK); fifo_0_command_number = command_number; } } else // we use V { if ( SubsysStatus & WBS_V_MASK ) { if (ls_put_msg_hp(&WBS_V_CMD[DATA_TRANS_IDX], NULL, HS_FLUSH_EVENT, NULL) == RC_FAIL) return enqueue_exec_fail(EXF_HS_LIB_ERROR_LS_HP_QUEUE, 0, NULL); // now update the global variables used to control hs state fifo_1_pending_frames++; push_TS(time_stamp, WBS_V_ID, DO_NOT_ATTACH_HK); fifo_1_command_number = command_number; } } } return RC_OK; } //----------------------- peakup_hrs_compute_ifpower --------------------------- //! process the science data received within a hrs peakup void peakup_hrs_compute_ifpower (unsigned int fifo_id) { unsigned int k, l, n, select, average_power = 0,counter = 0; unsigned int offset = 0; unsigned int head_chan[4]; int ifpower_chip1[8]; float ifpo_r[16]; // read 2 configuration parameters from the Spectroscopy_table select = Spectroscopy_table[Sd_hdl[fifo_id].range_sel]; // now do some operations about the right shift hrs_right_shift(); // index k (running from 0 to 7) is for data blocks contained into the hrs frame for (k = 0, l = 0x1; k < 8; l <<= 1, k++) { if (select & l) // go on with processing only if block k is in the range selected { // extract the first 4 words of chip 2 subblock: these words, stored into // head_chan[], are needed for ifpower computation for (n = 0; n < 4; n++) { offset = SD_TM_HEADER + k*HRS_BLOCK_DATA_LEN + n; head_chan[n] = *(unsigned int *)(sd_msg.block.pointer_to_data + offset); } // use the following formula for if power ifpo_r[k] = (((float)(2*head_chan[3])-(float)(head_chan[1]))*65535.); if ((head_chan[1])!= 0) { ifpo_r[k] = ifpo_r[k]/(float)(head_chan[1]); } else { ifpo_r[k] =0; generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_HRS_DURATION_NULL, 0, NULL); } if (ifpo_r[k] < 0) ifpo_r[k] =0; ifpower_chip1[k] = (int)ifpo_r[k]; // HK packet ICD 1.4 average_power += (unsigned int)ifpower_chip1[k]; // accumulate to compute the average power counter++; // count the number of blocks used for the average } } // now array ifpower_chip1[] contains 8 ifpower values average_power /= counter; // average power peakup_acquired_ifpowers[peakup_meas_seq_number - 1] = average_power; // store the value peakup_acquired_instrument[peakup_meas_seq_number - 1] = fifo_id; // set the flag to signal that one of the 9 values has been acquired } //----------------------- peakup_wbs_compute_ifpower --------------------------- //! process the science data received within a wbs peakup void peakup_wbs_compute_ifpower (unsigned int fifo_id, unsigned int scan_count) { int * p_data, k, n; unsigned int start_pix, stop_pix, npixels; unsigned int totp_data = 0, average_power = 0; unsigned int ifpower_wbs[WBS_BLOCK_NUM]; float ifpo_r; wbs_right_shift(); p_data = sd_msg.block.pointer_to_data + SD_TM_HEADER; for (n = 0; n < WBS_BLOCK_NUM; n++) { start_pix = Spectroscopy_table[Sd_hdl[fifo_id].range_sel + (n*2)]; npixels = Spectroscopy_table[Sd_hdl[fifo_id].range_sel + (n*2) + 1]; stop_pix = start_pix + npixels; if (stop_pix != 0) { for (k = start_pix; k < stop_pix ; k++) totp_data = totp_data + p_data[k]; // if power estimate as the average of the output of the subband if (npixels != 0) { ifpo_r = (float)(totp_data)/(float)npixels; if (scan_count != 0) ifpo_r = ifpo_r/scan_count; else generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_ZERO_DIV, 0, NULL); // scale by 2^6 the IF power to exploit the 16 bit allowable and make it integer ifpo_r = ifpo_r * 64.; ifpower_wbs[n] = (int)(ifpo_r + .5); } else { generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS_LIB_ZERO_DIV, 0, NULL); ifpo_r = 0; ifpower_wbs[n] = 0; } average_power += ifpower_wbs[n]; // accumulating to compute the average power over the four elements of ifpower_wbs[] totp_data = 0; // reset } } // end of for loop on n average_power /= WBS_BLOCK_NUM; // average power peakup_acquired_ifpowers[peakup_meas_seq_number - 1] = average_power; // store the value peakup_acquired_instrument[peakup_meas_seq_number - 1] = fifo_id; // set the flag to signal that one of the 9 values has been acquired } // ----------- peakup_report --------------------------------------------------- //! prepares and sends the report at the end of a peakup acquire (both hrs and wbs) void peakup_report (unsigned int fifo_id) { int rep_data_array[8]; rep_data_array[0] = PEAKUP_ACQUIRE_REP_SID; // SID UNPACK(&rep_data_array[1], Observation_ID); // obsid UNPACK(&rep_data_array[3], Meas_BuildingBlock_ID); // bbid rep_data_array[5] = fifo_id; // spectrometer id rep_data_array[6] = peakup_meas_seq_number; // measurement number rep_data_array[7] = peakup_acquired_ifpowers[peakup_meas_seq_number - 1]; // ifpower generate_report(APID1026, TM_HK_TYPE, TM_HK_SUBT, 8, rep_data_array); } // ----------- peakup_aocs_correction ------------------------------------------ //! first(start) step of a Correction AOCS Telecommand void peakup_aocs_correction (TC_packet * packet) { int i = 0, report_data[20]; int acquisition_is_incomplete; int microrotation_z = 0, microrotation_y = 0; // check on flags in array peakup_acquired_instrument[]: 9 acquisitions on the same instr must have been executed since last configure peakup TC acquisition_is_incomplete = 0; if ( peakup_acquired_instrument[0] == -1 ) acquisition_is_incomplete = 1; for (i = 1; i < 9; i++) if ( peakup_acquired_instrument[i] != peakup_acquired_instrument[0] ) acquisition_is_incomplete = 1; if ( acquisition_is_incomplete ) { enqueue_exec_fail(EXF_HS_LIB_PEAKUP_INCOMPLETE, 0, NULL); // incomplete acquisition generate_peak_up_event(0, 0); // peakup event must always be generated return; } // set the building block id Cur_BuildingBlock_ID = PACK(packet->data[TC_BBID_IDX], packet->data[TC_BBID_IDX+1]); // find best pointing position if ( peakup_find_best_direction(µrotation_z, µrotation_y) != RC_OK ) { // the procedure peakup_find_best_direction issued an execution failure. we stop. generate_peak_up_event(0, 0); // peakup event must always be generated return; } // now prepare the report report_data[0] = PEAKUP_AOCS_COR_REP_SID; // SID UNPACK(&report_data[1], Observation_ID); // obsid UNPACK(&report_data[3], Cur_BuildingBlock_ID); // bbid for (i = 0; i < 9; i++) report_data[5 + i] = peakup_acquired_ifpowers[i]; // nine measured ifpowers report_data[14] = microrotation_y; // microrotation y report_data[15] = microrotation_z; // microrotation z report_data[16] = peakup_scale_fact_y; // scale y report_data[17] = peakup_scale_fact_z; // scale z report_data[18] = peakup_offset_y; // offset y report_data[19] = peakup_offset_z; // offset z // produce the report packet generate_report(APID1026, TM_HK_TYPE, TM_HK_SUBT, 20, report_data); // send the peakup event generate_peak_up_event(microrotation_y, microrotation_z); // completion ack enqueue_ok(packet, TC_EXEC_COMPLETED); } // ----------- peakup_find_best_direction --------------------------------------- int peakup_find_best_direction (int * microrotation_z, int *microrotation_y) { int i; float d[9], p[4], b[4], x0, y0; // we follow the notation of Do Kester's algorithm: see his mail of 20/09/2007 // consistency check on the input: positive for (i=0; i<9; i++) if (peakup_acquired_ifpowers[i] < 0) return enqueue_exec_fail(EXF_HS_LIB_PEAKUP_NEGATIVE_POWER, 0, NULL); // convert data to float and take logarithm for (i=0; i<9; i++) d[i] = log( (float) peakup_acquired_ifpowers[i] ); // compute vector b b[0] = 2*d[0] + d[1] + 2*d[2] + d[3] + d[5] + 2*d[6] + d[7] + 2*d[8]; b[1] = -d[0] + d[2] - d[3] + d[5] - d[6] + d[8]; b[2] = -d[0] - d[1] - d[2] + d[6] + d[7] + d[8]; b[3] = d[0] + d[1] + d[2] + d[3] + d[4] + d[5] + d[6] + d[7] + d[8]; // compute vector p p[0] = b[0] / 4 - b[3] / 3; p[1] = b[1] / 6; p[2] = b[2] / 6; p[3] = - b[0] / 3 + 5 * b[3] / 9; // compute best pointing x0 = - p[1] / (2 * p[0]); y0 = - p[2] / (2 * p[0]); // perform some consistency checks if ( p[0] >= 0 ) return enqueue_exec_fail(EXF_HS_LIB_PEAKUP_FOUND_MINIMUM, 0, NULL); // we peaked a minimum and not a maximum - data are crap if ( x0 < -1 || x0 > 1 || y0 < -1 || y0 > 1 ) return enqueue_exec_fail(EXF_HS_LIB_PEAKUP_OUT_OF_GRID, 0, NULL); // optimum pointing is outside the grid if ( p[3] - p[1] * x0 - p[2] * y0 < 0 ) return enqueue_exec_fail(EXF_HS_LIB_PEAKUP_FOUND_NEGATIVE_PEAK, 0, NULL); // the peak is negative // now scale and add the offset *microrotation_z = (int) (x0 * peakup_scale_fact_z) + peakup_offset_z; *microrotation_y = (int) (y0 * peakup_scale_fact_y) + peakup_offset_y; // check for overflow: 2^16 -1 = 65535 if ( (*microrotation_z > 65535 ) || (*microrotation_z < -65535 ) ) return enqueue_exec_fail(EXF_HS_LIB_PEAKUP_Z_OVERFLOW, 0, NULL); // microrotation does not fit into 16 bits if ( (*microrotation_y > 65535 ) || (*microrotation_y < -65535 ) ) return enqueue_exec_fail(EXF_HS_LIB_PEAKUP_Y_OVERFLOW, 0, NULL); // microrotation does not fit into 16 bits // all went well return RC_OK; } // ----------- peakup_simulate_aocs_corr --------------------------------------- void peakup_simulate_aocs_corr (TC_packet * packet) { // send a peakup event with microrotations copied from the TC generate_peak_up_event(packet->data[2], packet->data[3]); // completion ack enqueue_ok(packet, TC_EXEC_COMPLETED); } /************************************************************************************************** ********************************* MEDIAN AND UTILITY FUNCTIONS ******************************************* ***************************************************************************************************/ //------------------- shift_right ---------------------------------------------- //! Purpose: To perform the division required by the coadding mechanism. //! Description: This function right shifts the words of the frame just processed. //! Input: Pointer and length of the data buffer and amount of shift. void shift_right (int *p_data, int length, int shift) { // 1 us per cycle if (shift) while(length--) (*p_data++) >>= shift; } //----------------------- siftdown --------------------------------------------- //! tool for the heapsort routine void siftdown (int array[], int lower, int upper) { register int i = lower, c = lower; register int lastindex = upper/2; register int temp; temp = array[i]; while (c <= lastindex) { c = 2 * i; /* c = 2i is the left-child of i */ if (c + 1 <= upper && (array[c + 1] > array[c]) ) c++; /* c is the greatest child of i */ if (temp >= array[c]) break; array[i] = array[c]; i = c; } array[i] = temp; } //----------------------- heapsort --------------------------------------------- #define SWAP(x, y) temp = (x); (x) = (y); (y) = temp //! Sorting routine void heapsort (int array[], int len) { register int i, temp, *sa = array - 1; /* | 'sa[]' is 'array[]' "shifted" one position to the left | i.e. sa[i] == array[i - 1] (in particular: sa[1] == array[0]) | 'sa' has "Pascalish" indices and is thus more convenient | for heap-sorting. An index i obeys the law: | left_child (i) == 2i, right_child (i) == 2i + 1 | Note: we don't use a[-1] which is outside our range, we just | fake an array that starts one address lower, so we can refer | to its first element as a[1] (rather than as a[0]) */ /* first step: make 'sa[]' a heap using siftdown len/2 times */ for (i = len / 2; i >= 1; i--) { siftdown (sa, i, len); } /* heapify N more times, to reach complete order */ for (i = len; i >= 2; i--) { SWAP(sa[1], sa[i]); siftdown (sa, 1, i - 1); } } #undef SWAP //--------------------- median_idx --------------------------------------------- //! finds the position of the median element of input vectror (invec) unsigned int median_idx (int * invec, int inlen) { int vec[256]; int len = inlen >> 1; int i = inlen; unsigned int j; while(i-->0) { vec[i] = invec[i]; } heapsort(vec,inlen); j = 0; while (invec[j] != vec[len]) j++; return j; }