// $RCSfile: hs0.c,v $Revision: 1.92 $Date: 2005/03/11 15:08:57 //! Contains tasks hs0 and hs_flush which are in charge of extracting data frames from the HW fifo and passing it to task hs1 #include "hs0.dox" #include "hs1.h" #include "allnodes.h" #include "node1.h" #include "configura.h" #include "err_hdl.h" #include "cmd_exec.h" #include "cmd_seq.h" #include "pubfuncs.h" #include "hifi_pool.h" #include "hs1.h" #include "main.h" #include "hs_hdl.h" #include "hs_lib.h" #include "data_hdl.h" #include "hs0.h" //----- Defines -------------------------------------------------------- // Masks for testing the Half Full Interrupt in the Interrupt Register #define HRS_V_IV_MASK 0x40 #define HRS_H_IV_MASK 0x20 #define WBS_V_IV_MASK 0x10 #define WBS_H_IV_MASK 0x08 // Block dims and related constants for AVM2 #define WBS_BLOCK_DIM 4105 #define WBS_BLOCK_PER_FRAME 2 #define HRS_BLOCK_DIM 4160 #define HRS_BLOCK_PER_FRAME 1 /* // Block dims and related constants for AVM1 #define WBS_BLOCK_DIM 1642 #define WBS_BLOCK_PER_FRAME 5 #define HRS_BLOCK_DIM 1040 #define HRS_BLOCK_PER_FRAME 4 */ // Masks for testing the Half Full Fifo Status in the Board Status Register #define BST_HF_MASK_HRS_V 0x2000 #define BST_HF_MASK_HRS_H 0x0200 #define BST_HF_MASK_WBS_V 0x0020 #define BST_HF_MASK_WBS_H 0x0002 //---- Global variables ----------------------------------------------------------// //! pointer to the vector of registers' addresses (used only by functions that access HIGH speed serial port) int hs_flush_is_running = 1; //----- Local Functions -------------------------------------------------------- void hs0_init( void ); // Initialization of the static variables void reset_TS_fifos(void); void reset_TS_pools(void); void deliver_frame( int fifo_id, int * pblock_nr, int ** pdata); int get_fifo( int fifo_id, int * pdata, int * nread, unsigned int iv_mask, unsigned int hf_mask, unsigned int subsys_mask, unsigned int read_block_dim); int flush_fifo(int fifo_id, int * pdata, int * nread, unsigned int iv_mask, unsigned int hf_mask, unsigned int subsys_mask, unsigned int read_block_dim); //---- Local variables ----------------------------------------------------------// static int hrs_v_block; //!< Number of the block in HRS_FRAME_POOL where the data from hrs_v are to be copied static int hrs_h_block; //!< Number of the block in HRS_FRAME_POOL where the data from hrs_h are to be copied static int wbs_v_block; //!< Number of the block in WBS_FRAME_POOL where the data from wbs_v are to be copied static int wbs_h_block; //!< Number of the block in WBS_FRAME_POOL where the data from wbs_h are to be copied static int* p_hrs_v_block; //!< Pointer to the block in HRS_FRAME_POOL where the data from hrs_v are to be copied static int* p_hrs_h_block; //!< Pointer to the block in HRS_FRAME_POOL where the data from hrs_h are to be copied static int* p_wbs_v_block; //!< Pointer to the block in WBS_FRAME_POOL where the data from wbs_v are to be copied static int* p_wbs_h_block; //!< Pointer to the block in WBS_FRAME_POOL where the data from wbs_h are to be copied static int hrs_v_nread = 0; //!< Number of hrs_v frames stored in the current block of FRAME_POOL. static int hrs_h_nread = 0; //!< Number of hrs_h frames stored in the current block of FRAME_POOL. static int wbs_v_nread = 0; //!< Number of half wbs_v frames stored in the current block of FRAME_POOL. static int wbs_h_nread = 0; //!< Number of half wbs_h frames stored in the current block of FRAME_POOL. //---- hs0 --------------------------------------------------------------------- //! Task handling the fifo data transfer, triggered by HS_EVENT void hs0 (void) { int got_block; int check_round; // Inits: allocates the first blocks in the pool and set nreads hs0_init(); // Loop on HS_Event for(;;) { // Wait for Half FIFO Event KS_ISREnable(IRQ0_N); // Enable the Half Full Interrupt KS_EventTestW(HS_EVENT); // Wait for HS_Event got_block = 1; check_round = 0; while( got_block > 0 ) { got_block = 0; check_round++; // Check FIFOs and, if all checks passed, get data got_block += get_fifo(HRS_V_ID, p_hrs_v_block, &hrs_v_nread, HRS_V_IV_MASK, BST_HF_MASK_HRS_V, HRS_V_MASK, HRS_BLOCK_DIM); got_block += get_fifo(HRS_H_ID, p_hrs_h_block, &hrs_h_nread, HRS_H_IV_MASK, BST_HF_MASK_HRS_H, HRS_H_MASK, HRS_BLOCK_DIM); got_block += get_fifo(WBS_V_ID, p_wbs_v_block, &wbs_v_nread, WBS_V_IV_MASK, BST_HF_MASK_WBS_V, WBS_V_MASK, WBS_BLOCK_DIM); got_block += get_fifo(WBS_H_ID, p_wbs_h_block, &wbs_h_nread, WBS_H_IV_MASK, BST_HF_MASK_WBS_H, WBS_H_MASK, WBS_BLOCK_DIM); // If frame completed, deliver it and allocate new blocks from the FRAME_POOL if (hrs_v_nread == HRS_BLOCK_PER_FRAME) { deliver_frame(HRS_V_ID, &hrs_v_block, &p_hrs_v_block); hrs_v_nread = 0; } if (hrs_h_nread == HRS_BLOCK_PER_FRAME) { deliver_frame(HRS_H_ID, &hrs_h_block, &p_hrs_h_block); hrs_h_nread = 0; } if (wbs_v_nread == WBS_BLOCK_PER_FRAME) { deliver_frame(WBS_V_ID, &wbs_v_block, &p_wbs_v_block); wbs_v_nread = 0; } if (wbs_h_nread == WBS_BLOCK_PER_FRAME) { deliver_frame(WBS_H_ID, &wbs_h_block, &p_wbs_h_block); wbs_h_nread = 0; } } } } //------- hs_flush ------------------------------------------------------------- //! Task handling the flushing of the fifos, triggered by HS_FLUSH_EVENT void hs_flush (void) { HS_HDL_MSG cmd_queue; int got_block; for(;;) { hs_flush_is_running = 0; // signal that we are going into the wait status KS_EventTestW(HS_FLUSH_EVENT); // Wait for HS_FLUSH_Event // in this case we dont have to flush, just trigger the next step if (AID_spectroscopy == NEW_CALIB_RUN_AID) { cmd_queue.operation_id = MKSTEP_NEW_CALIB_RUN; cmd_queue.command_number = new_cal_command_number; cmd_queue.block_loaded = 0; if (KS_FIFOPut(HS_HDL_QUEUE, (void *) &cmd_queue) == RC_FAIL) generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS0_LS_HP_QUEUE, 0, NULL); continue; } hs_flush_is_running = 1; // signal that we are going into the operational status // Sleep a time for the data to be transferred (worst case = WBS) if ( fifo_0_pending_frames>0 || fifo_1_pending_frames>0 ) KS_TaskSleep(WBS_TRANSF_TIME); else KS_TaskSleep(HRS_TRANSF_TIME); // Check FIFOs and, if non empty, get data got_block = 0; got_block += flush_fifo(HRS_V_ID, p_hrs_v_block, &hrs_v_nread, HRS_V_IV_MASK, BST_HF_MASK_HRS_V, HRS_V_MASK, HRS_BLOCK_DIM); got_block += flush_fifo(HRS_H_ID, p_hrs_h_block, &hrs_h_nread, HRS_H_IV_MASK, BST_HF_MASK_HRS_H, HRS_H_MASK, HRS_BLOCK_DIM); got_block += flush_fifo(WBS_V_ID, p_wbs_v_block, &wbs_v_nread, WBS_V_IV_MASK, BST_HF_MASK_WBS_V, WBS_V_MASK, WBS_BLOCK_DIM); got_block += flush_fifo(WBS_H_ID, p_wbs_h_block, &wbs_h_nread, WBS_H_IV_MASK, BST_HF_MASK_WBS_H, WBS_H_MASK, WBS_BLOCK_DIM); // check that at least one block has been read if ( (got_block == 0) && (SubsysStatus & 0xF != 0) ) generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS0_HSFLUSH_FOUND_NOBLOCK, 0, NULL); // If frame completed, deliver it and allocate new blocks from the FRAME_POOL if (hrs_v_nread == HRS_BLOCK_PER_FRAME) { deliver_frame(HRS_V_ID, &hrs_v_block, &p_hrs_v_block); hrs_v_nread = 0;} if (hrs_h_nread == HRS_BLOCK_PER_FRAME) { deliver_frame(HRS_H_ID, &hrs_h_block, &p_hrs_h_block); hrs_h_nread = 0;} if (wbs_v_nread == WBS_BLOCK_PER_FRAME) { deliver_frame(WBS_V_ID, &wbs_v_block, &p_wbs_v_block); wbs_v_nread = 0;} if (wbs_h_nread == WBS_BLOCK_PER_FRAME) { deliver_frame(WBS_H_ID, &wbs_h_block, &p_wbs_h_block); wbs_h_nread = 0;} } } //-------- deliver_frame ------------------------------------------------------- //! Delivers a SD frame by putting a message in the frame_queue and gets a new pool block void deliver_frame (int fifo_id, int *pblock, int **pdata) { FRAME_MSG msg; int pool_id; // prepare variable pool_id switch (fifo_id) { case HRS_H_ID: case HRS_V_ID: pool_id = HRS_FRAME_POOL; break; case WBS_H_ID: case WBS_V_ID: pool_id = WBS_FRAME_POOL; break; default: generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS0_FRAME_POOL_ID, 1, &fifo_id); break; } // Prepare message to be sent to task hs1 msg.fifo_id = fifo_id; // FIFO id msg.block_nr = (*pblock); // Pointer to block in FRAME_POOL // Deliver message if (KS_FIFOPut(FRAME_QUEUE, (void*) &msg) != RC_OK) { hifi_pool_free_block(pool_id, (*pblock)); generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS0_FIFOPUT_FRAME_QUEUE, 0, NULL); } // Get new block (*pblock) = hifi_pool_get_block(pool_id); (*pdata) = hifi_pool_get_pointer(pool_id, (*pblock)); } //---- hs_init ----------------------------------------------------------------- //!Initializes the static variables of this file void hs0_init (void) { // init hifi_pool hifi_pool_init(); // Allocate the blocks hrs_v_block = hifi_pool_get_block(HRS_FRAME_POOL); hrs_h_block = hifi_pool_get_block(HRS_FRAME_POOL); wbs_v_block = hifi_pool_get_block(WBS_FRAME_POOL); wbs_h_block = hifi_pool_get_block(WBS_FRAME_POOL); // Get pointers to data p_hrs_v_block = hifi_pool_get_pointer(HRS_FRAME_POOL, hrs_v_block); p_hrs_h_block = hifi_pool_get_pointer(HRS_FRAME_POOL, hrs_h_block); p_wbs_v_block = hifi_pool_get_pointer(WBS_FRAME_POOL, wbs_v_block); p_wbs_h_block = hifi_pool_get_pointer(WBS_FRAME_POOL, wbs_h_block); // Reset number of blocks read hrs_v_nread = 0; // Number of hrs frames stored in the current block of FRAME_POOL. hrs_h_nread = 0; wbs_v_nread = 0; // Number of half wbs frames stored in the current block of FRAME_POOL. wbs_h_nread = 0; } //---- reset_HS ---------------------------------------------------------------- //!Resets the static variables of the HS system (this file and hs1) void reset_HS (void) { // Reset number of blocks read hrs_v_nread = 0; // Number of hrs frames stored in the current block of FRAME_POOL. hrs_h_nread = 0; wbs_v_nread = 0; // Number of half wbs frames stored in the current block of FRAME_POOL. wbs_h_nread = 0; reset_hs1(); reset_TS_fifos(); reset_TS_pools(); } //------ get_fifo -------------------------------------------------------------- //! If the fifo is half full, gets a block of data (of dimension read_block_dim) from // a fifo (identified by argument fifo_id) and returns 1; if the fifo is not half // full, no block read and return value equal to 0. int get_fifo (int fifo_id, int *pdata, int * nread, unsigned int iv_mask, unsigned int hf_mask, unsigned int subsys_mask, unsigned int read_block_dim) { int * source; // pointer to HW FIFO int * dest; // pointer to the pool block unsigned int ff_mask; // in any case acknowledge interrupt (never mind if it isn't raised) *IRQACK |= iv_mask; // Check if the subsystem is active, if not return if ( !(SubsysStatus & subsys_mask)) return 0; // signal that no block has been read // Check if the fifo is half full if ( ! ((*BSTREGADD) & hf_mask) ) // if fifo half full { // check if a fifo overflow has occurred; if yes, the right thing to do is abort ff_mask = hf_mask << 1; if ( ! ((*BSTREGADD) & ff_mask )) // if the fifo is full { generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS0_FIFO_OVFL, 1, &fifo_id); abort_measurement(); return 0; } // now read a block of data from the fifo dest = (int*) (pdata + (*nread) * read_block_dim); // destination: the block switch (fifo_id) { case 0: source = (int*) FRXREGADD_0; break; case 1: source = (int*) FRXREGADD_1; break; case 2: source = (int*) FRXREGADD_2; break; case 3: source = (int*) FRXREGADD_3; break; } while(read_block_dim--) *dest++= (*source) & 0x00FFFFFF; // perform transfer // increase the number of data blocks transferred (*nread)++; return 1; // signal that a block has been read } else return 0; // this signals that no data has been read (because the fifo is not half full) } //------------ flush_fifo ------------------------------------------------------ //! Gets a block of data from a FIFO, if the fifo is Non Empty int flush_fifo (int fifo_id, int * pdata, int * nread, unsigned int iv_mask, unsigned int hf_mask, unsigned int subsys_mask, unsigned int read_block_dim) { int word_to_read; // Loop counter for the data transfer int * source; // pointer to HW FIFO int * dest; // pointer to the pool block // Check if the subsystem is active, if not return if ( !(SubsysStatus & subsys_mask)) return 0; // Check if the FIFO is half full if ( ! ((*BSTREGADD) & hf_mask )) // if fifo is half full { KS_EventSignal(HS_EVENT); // Trigger hs0 KS_EventSignal(HS_FLUSH_EVENT); // Trigger hs_flush again generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS0_FIFO_HALF_FULL, 1, &fifo_id); return 0; } // Check if the FIFO is empty. If yes return. if ( !((*BSTREGADD)& (1 << (fifo_id*4))) ) return 0; // 1 << (fifo_id*4) is the FIFO_empty_mask // Set source, dest and number of words to transfer dest = (int*) (pdata + (*nread) * read_block_dim); // destination: the block switch (fifo_id) // source: HW FIFO { case 0: source = (int*) FRXREGADD_0; break; case 1: source = (int*) FRXREGADD_1; break; case 2: source = (int*) FRXREGADD_2; break; case 3: source = (int*) FRXREGADD_3; break; } word_to_read = read_block_dim; // Get a block of data while( word_to_read-- ) (*dest++) = (*source & 0x00FFFFFF); // Increase the number of data blocks transferred (*nread)++; // Check if the FIFO is empty. If not send warning and issue an abort !! if ( ((*BSTREGADD)& (1 << (fifo_id*4))) ) { generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS0_FIFO_NOT_EMPTY, 1, &fifo_id); abort_measurement(); } return 1; // a block was read } //--------------- reset_FIFO --------------------------------------------------- //! To reset ALL the Hardware FIFOs status. FIFO are emptied. void reset_FIFO (void) { // reset fifos *BRDREG_RST = 0xF; *BRDREG_RST = 0x0; } //--------------- reset_FIFO_by_mask ------------------------------------------- //! To reset the Hardware FIFOs specified by the mask parameter status. void reset_FIFO_by_Mask (int fifo_mask) { *BRDREG_RST = fifo_mask; *BRDREG_RST = 0x0; } /********************************************************************************************************** ********************************************************************************************************** TIME STAMP AND ATTACHED HK FIFOs ********************************************************************************************************** **********************************************************************************************************/ // maximum capacity of a time stamp fifo #define MAX_FIFO_TS 4 // these are the time stamps fifos unsigned int dummy_chk_mem[400]; //to shift the TS_fifo variable to a safe mem position in case of CFM2 static START_FRAME_DATA TS_fifo[MAX_FIFO_TS][4]; // time stamp fifos position wher to store a new element and where to pick an element: if equal the fifo is void static int TS_in[4] = {0, 0, 0, 0}; static int TS_out[4] = {0, 0, 0, 0}; //--------------- reset_TS_fifos ----------------------------------------------- //! To reset the TS fifos void reset_TS_fifos (void) { int i; for (i=0; i<4; i++) TS_in[i] = TS_out[i] = 0; } //--------------- push_TS ------------------------------------------------------ //! To push a time_stamp into the corresponding fifo void push_TS (START_FRAME_DATA time_stamp, int fifo_id, int attach_HK) { static SD_PKT_MSG data_msg; // structure which holds the message to data_hdl task // push the data TS_fifo[TS_in[fifo_id]][fifo_id] = time_stamp; // check if additional HKs are to be required if ( attach_HK ) { // post message to data_hdl data_msg.subsysID = (unsigned int) &(TS_fifo[TS_in[fifo_id]][fifo_id]); // pass the address of the structure data_msg.measID = ATTACH_HK_REQ; // request the HK attaching if (KS_FIFOPut(SD_PKT_QUEUE, (void *) &data_msg) == RC_FAIL) generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS1_FIFOPUT_SD_PKT, 0, NULL); } else { // attach zero HKs TS_fifo[TS_in[fifo_id]][fifo_id].HK_rot_1 = 0; TS_fifo[TS_in[fifo_id]][fifo_id].HK_rot_2 = 0; TS_fifo[TS_in[fifo_id]][fifo_id].HK_freq = 0; TS_fifo[TS_in[fifo_id]][fifo_id].HK_main_ms = 0; TS_fifo[TS_in[fifo_id]][fifo_id].HK_main_lo = 0; TS_fifo[TS_in[fifo_id]][fifo_id].HK_off_lo = 0; } // increase input position TS_in[fifo_id]++; // wrap the counter if ( TS_in[fifo_id] >= MAX_FIFO_TS ) TS_in[fifo_id] = 0; // check if fifo is full if ( TS_in[fifo_id] == TS_out[fifo_id] ) { // error block everything abort_measurement(); // issue an error generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS0_TS_FIFO_FULL, 1, &fifo_id); } } //--------------- pop_TS ------------------------------------------------------- //! To pop a time_stamp into the corresponding fifo void pop_TS (START_FRAME_DATA *time_stamp, int fifo_id) { // check if fifo is not empty if ( TS_in[fifo_id] == TS_out[fifo_id] ) { // error fifo is empty abort_measurement(); // issue an error generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS0_TS_FIFO_VOID, 1, &fifo_id); } // pop the data *time_stamp = TS_fifo[TS_out[fifo_id]][fifo_id]; // increase input position TS_out[fifo_id]++; // wrap the counter if ( TS_out[fifo_id] >= MAX_FIFO_TS ) TS_out[fifo_id] = 0; } /********************************************************************************************************** ********************************************************************************************************** TIME STAMP POOLs ********************************************************************************************************** **********************************************************************************************************/ // maximum capacity of the time stamp pool #define MAX_TS_POOL 40 // pool structure typedef struct { START_FRAME_DATA TS; unsigned int free; } TS_pool_item; // Here is the pool static TS_pool_item TS_pool[MAX_TS_POOL]; //--------------- reset_TS_pools ----------------------------------------------- //! To reset the TS pool void reset_TS_pools (void) { int i; for (i=0; i= MAX_TS_POOL || TS_pool[time_code].free ) { abort_measurement(); generate_event(EVENT_EVENT_REPORT, RUNTIME_ERROR_EVID, ERR_HS0_TS_POOL_ERR, 0, NULL); } // write the TS and free the block *time_stamp = TS_pool[time_code].TS; TS_pool[time_code].free = 1; }