// $RCSfile: ls.c,v $Revision: 1.33 $Date: 2005/03/11 15:08:57 #include "allnodes.h" #include "node1.h" #include #include "configura.h" #include "tables.h" #include "ls_hdl.h" #include "hs_hdl.h" #include "cmd_exec.h" #include "pubfuncs.h" #include "err_hdl.h" #include "cmd_seq.h" #include "main.h" #include "vm_lib.h" #include "hs0.h" #include "hk_ask.h" #include "ls.h" //---- local functions --------------------------------------------------------- int GetLss(unsigned int *); int send ( unsigned int * datum ); int push_hp_queue(void *); int push_lp_queue(void *); //---- local variables --------------------------------------------------------- static unsigned int ls_tx_reg_content; static unsigned int ls_tx_busy_flag = FALSE; //--------- ls_init ------------------------------------------------------------ void ls_init (void) { KS_SemaReset(LS_SEMA); KS_FIFOPurge(LS_HP_QUEUE); KS_FIFOPurge(LS_LP_QUEUE); } //---------- task ls ----------------------------------------------------------- void ls (void) { LS_CMD_MSG cmd_queue; // command data structure of the queue unsigned int result, was_event; unsigned int N_LS_event = 0; // used as a counter for a particular error condition unsigned int event_par[MAX_N_REP_PAR]; // to hold parameters for possible error messages unsigned int it_is_LCU_req; // to signal LCU Hk reqs while (1) { KS_SemaTestW(LS_SEMA); // waits for the semaphore to be signalled // get the cmd from the queues if (KS_FIFOGet(LS_HP_QUEUE, &cmd_queue) != RC_OK) // first read high priority queue { if (KS_FIFOGet(LS_LP_QUEUE, &cmd_queue) != RC_OK) // then check low priority queue { generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_LS_QUEUES_EMPTY, 0, NULL); continue; // error handlig is still TBD } } // trap events or queues requests and send Signal to the proper task was_event = 1; switch (cmd_queue.event_number) { case BLOCK_LCU_REQUEST: LCU_non_interaction = 1; break; case FLUSH_REQUEST: if( ! hs_flush_is_running ) KS_EventSignal(HS_FLUSH_EVENT); break; case LS_NOP_REQUEST: KS_TaskSleep(3); // wait 3 msecs break; case HK_EVENT: KS_EventSignal(HK_EVENT); break; case MEAS_EVENT: KS_EventSignal(MEAS_EVENT); break; case NP_HK_COMPLETED: case SEND_MEM_HK_REPORT: case SEND_SINGLE_HK_REPORT: case MKSTEP_VEC_SCAN_CMD: case MKSTEP_FCU_PARAM_SCAN: case MKSTEP_DIP_SCAN_NOIF: case LCU_IVCURVE_REPORT: case LCU_IVCURVE_STATUS: case MKSTEP_VERIFY_LCU: case LAST_STEP_VERIFY_LCU: case MKSTEP_VERIFY_LCU_CHUNK: case LAST_STEP_VERIFY_LCU_CHUNK: case MKSTEP_VERIFY_LCU_MODE1: case LAST_STEP_VERIFY_LCU_MODE1: { LS_HDL_MSG msg; // structure of command for ls_hdl msg.block_loaded = 0; msg.operation_id = cmd_queue.event_number; // set the operation id (ask ls_hdl for another step) msg.command_number = (int) cmd_queue.ans_add; // this field is a label of the current procedure // send to task ls_hdl if (KS_FIFOPut(LS_HDL_QUEUE, (void *) &msg) == RC_FAIL) generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_LS_FIFOPUT_LS_HDL_QUEUE, 0, NULL); break; } case SEND_MEM_DUMP_LCU_REPORT: case ENGSCAN_ROUTINE: case ENGSCAN_REPORT: case MKSTEP_NEW_CALIB_RUN: { HS_HDL_MSG msg; // structure of command for hs_hdl msg.block_loaded = 0; msg.operation_id = cmd_queue.event_number; // set the operation id (ask hs_hdl for another step) msg.command_number = (int) cmd_queue.ans_add; // this field is a label of the current scan procedure // send to task hs_hdl if (KS_FIFOPut(HS_HDL_QUEUE, (void *) &msg) == RC_FAIL) generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_LS_FIFOPUT_HS_HDL_QUEUE, 0, NULL); break; } default: was_event = 0; break; } // if an event was trapped go back to wait a msg if ( was_event ) continue; // now a check on the 32-bit word to be sent on the LS bus; if the first // bit is not high (i.e. the word is not correct) then avoid sending the word if ((*cmd_queue.cmd_add & 0x80000000) != 0x80000000) { // if it is not a filler, i.e. 0x0FFF FFFF send an error if ( *cmd_queue.cmd_add != 0x0FFFFFFF ) { event_par[0] = ((*(cmd_queue.cmd_add)) >> 16) & 0x0FFFF; event_par[1] = (*(cmd_queue.cmd_add)) & 0x0FFFF; generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_LS_INCORRECT_WORD, 2, event_par); } // go back to the wait on the input semaphore continue; } // if it is a LCU cmd and the no interaction flag is set abort the command // if ( ((*cmd_queue.cmd_add & 0x30000000) == 0x30000000) && LCU_non_interaction == TRUE ) continue; // is a LCU command if (LCU_non_interaction == TRUE ) { if ( ((*cmd_queue.cmd_add & 0x30000000) == 0x30000000) && ((*cmd_queue.cmd_add & 0xFC000000) != 0xFC000000) ) continue; } // if it is a LCU cmd set the flag if ( ((*cmd_queue.cmd_add & 0x30000000) == 0x30000000) && ((*cmd_queue.cmd_add & 0xFC000000) != 0xFC000000) ) // is a LCU command it_is_LCU_req = 1; else it_is_LCU_req = 0; // Send command to LSS port // check the IRQ3 flag via call to send function as a critical section // RC_TIME means IRQ3 flag not free, RC_FAIL =tx error, RC_OK =data has been sent while ((result = KS_CriticalSection (send, cmd_queue.cmd_add)) == RC_TIME) KS_TaskSleep(1); // check the result of the send operation if (result == ERR_LS_TRX_REG_BUSY) { event_par[0] = (ls_tx_reg_content >> 16) & 0x0FFFF; event_par[1] = ls_tx_reg_content & 0x0FFFF; event_par[2] = ((*(cmd_queue.cmd_add)) >> 16) & 0x0FFFF; event_par[3] = (*(cmd_queue.cmd_add)) & 0x0FFFF; event_par[4] = N_LS_event++; generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_LS_TRX_REG_BUSY, 5, event_par); // set to true the flag, to indicate that a ls tx busy has been encountered ls_tx_busy_flag = TRUE; // sleep 3 ms KS_TaskSleep(3); // second attempt to write the LS TX register while ((result = KS_CriticalSection (send, cmd_queue.cmd_add)) == RC_TIME) KS_TaskSleep(1); // in any case: bring the flag back to FALSE ls_tx_busy_flag = FALSE; if (result == ERR_LS_TRX_REG_BUSY_ABORT) { // the LS TX register has been found busy again: send event packet // and start abort procedure event_par[0] = (ls_tx_reg_content >> 16) & 0x0FFFF; event_par[1] = ls_tx_reg_content & 0x0FFFF; event_par[2] = ((*(cmd_queue.cmd_add)) >> 16) & 0x0FFFF; event_par[3] = (*(cmd_queue.cmd_add)) & 0x0FFFF; event_par[4] = N_LS_event++; generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_LS_TRX_REG_BUSY_ABORT, 5, event_par); // start abort of ongoing activities abort_measurement(); } } // get the answer (if hk request) or just wait a bit (if simple command) if ((*cmd_queue.cmd_add & 0x40000000) == 0) // bit 31 not set: is a hk req { KS_TaskSleep(3); // wait for the answer from LSS port // get the answer (hk datum) and put into the appropriate location if (GetLss(cmd_queue.ans_add) == RC_FAIL) { *(cmd_queue.ans_add) = LS_RECEIVE_ERROR; *(cmd_queue.err_code) = 1; // RX error // if HK from LCU handle the check if (it_is_LCU_req && HK_LCUnonresp_check) { HK_lcu_nonres_breach++; HK_lcu_nonres_ok = 0; } } else { *(cmd_queue.err_code) = 0; // RX was all right // if HK from LCU handle the check if (it_is_LCU_req) { HK_lcu_nonres_ok++; if (HK_lcu_nonres_ok >= 2 ) HK_lcu_nonres_breach = 0; } } } else // is a simple command { if ((*cmd_queue.cmd_add & 0x30000000) == 0x30000000) // is a LCU command KS_TaskSleep(3); // wait at least 3 msec before next write else // command not directed to LCU KS_TaskSleep(1); // wait at least 1 msec before next write } // perform the check on the LCU nonresponse if (HK_lcu_nonres_breach >= HK_LCUnonresp_Nbreach) { LCU_safe_and_block (); generate_event(EVENT_ALARM_REPORT, ERR_LS_LCU_NONRESP, ERR_LS_LCU_NONRESP, 1, &HK_lcu_nonres_breach); HK_lcu_nonres_breach = 0; } // check if this is the last frame of a measurement or of a tuning proc if (cmd_queue.event_number == HS_FLUSH_EVENT) if ( ! hs_flush_is_running ) KS_EventSignal(HS_FLUSH_EVENT); } } //--------- push_lp_queue ------------------------------------------------------ int push_lp_queue (void * datin) { if (KS_FIFOPut(LS_LP_QUEUE, datin) == RC_OK) { KS_SemaSignal(LS_SEMA); return RC_OK; } else { generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_LS_FIFOPUT_LP_QUEUE, 0, NULL); return RC_FAIL; } } //---------- ls_put_msg_hp ----------------------------------------------------- // prepares a structure with the arguments received and puts it into the LS_HP_QUEUE // by calling the function push_hp_queue. int ls_put_msg_hp (unsigned int *cmd, unsigned int *ans, unsigned int evnt, unsigned int *err) { LS_CMD_MSG cmd_out_queue; // structure of command list to LS static unsigned int trash = 0, dummy = 0; // command address if ( cmd == NULL ) cmd_out_queue.cmd_add = &dummy; else cmd_out_queue.cmd_add = cmd; // answer address if ( ans == NULL ) cmd_out_queue.ans_add = &trash; else cmd_out_queue.ans_add = ans; // event to set cmd_out_queue.event_number = evnt; // error address if ( err == NULL ) cmd_out_queue.err_code = &trash; else cmd_out_queue.err_code = err; // push in queue return push_hp_queue((void *) &cmd_out_queue); } //---------- ls_put_msg_lp ----------------------------------------------------- // prepares a structure with the arguments received and puts it into the LS_LP_QUEUE // by calling the function push_lp_queue. int ls_put_msg_lp (unsigned int *cmd, unsigned int *ans, unsigned int evnt, unsigned int *err) { LS_CMD_MSG cmd_out_queue; // Structure of command list to LS static unsigned int trash = 0, dummy = 0; // command address if ( cmd == NULL ) cmd_out_queue.cmd_add = &dummy; else cmd_out_queue.cmd_add = cmd; // answer address if ( ans == NULL ) cmd_out_queue.ans_add = &trash; else cmd_out_queue.ans_add = ans; // event to set cmd_out_queue.event_number = evnt; // error address if ( err == NULL ) cmd_out_queue.err_code = &trash; else cmd_out_queue.err_code = err; // push in queue return push_lp_queue((void *) &cmd_out_queue); } //---------- push_hp_queue ----------------------------------------------------- int push_hp_queue (void * datin) { if (KS_FIFOPut(LS_HP_QUEUE, datin) == RC_OK) { KS_SemaSignal(LS_SEMA); return RC_OK; } else { generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_LS_FIFOPUT_HP_QUEUE, 0, NULL); return RC_FAIL; } } //--------- SendLss ------------------------------------------------------------ //! writes data into the LS TX register; prior to this, the TX busy bit of the LS //! status register is checked: when the transmit register is found busy, some //! actions are taken, which are different depending on whether the ls_tx_busy_flag //! is false or true (i.e. it is a first attempt or a retry); int SendLss (unsigned int *datum) { if ((*LSTREGADD & 0x1) != 0) { // TX busy bit in LS STATUS REG found set (it should not happen) if (ls_tx_busy_flag == TRUE) { // it is a second attempt, hence reset the ls bus, perform transmission, // and return with a value that will trigger an abort // save current content of the LS transmit register (blocking ls word) ls_tx_reg_content = *LTXREGADD; // reset LS *BRDREG_RST = 0x20; *BRDREG_RST = 0x0; // write the word into the transmit register *LTXREGADD = *datum; return ERR_LS_TRX_REG_BUSY_ABORT; } else { // it is the first time that the busy bit is found high: just save the // current word present on the transmit register and return with a // proper value // save current content of the LS transmit register (blocking ls word) ls_tx_reg_content = *LTXREGADD; return ERR_LS_TRX_REG_BUSY; } } else { // write the word into the transmit register *LTXREGADD = *datum; return RC_OK; } } //------- GetLss --------------------------------------------------------------- //! Waits for the RX status register signalling data ready, then reads it. int GetLss (unsigned int * datum) { if (((*LSTREGADD) & 0x2) == 0) return RC_FAIL; // error: data not ready *datum = *LRXREGADD; return RC_OK; } //-------- send ---------------------------------------------------------------- // local function called as a critical section to check IRQ3 and possibly // send command without interruption from the scheduler int send (unsigned int * datum) { if (Irq3_flag != FALSE) return RC_TIME; // port has been reserved by VM return SendLss(datum); }