/********************************************************************\ Name: dummy_fe.cxx Created by: Frederik Wauters Changed by: Marius Koeppel Contents: Dummy frontend producing stream data \********************************************************************/ #include #include #include #include #include #include #include #include #include "midas.h" #include "msystem.h" #include "mcstd.h" #include #include #include "mfe.h" using namespace std; /*-- Globals -------------------------------------------------------*/ /* The frontend name (client name) as seen by other MIDAS clients */ const char *frontend_name = "Dummy Stream Frontend"; /* The frontend file name, don't change it */ const char *frontend_file_name = __FILE__; /* frontend_loop is called periodically if this variable is TRUE */ BOOL frontend_call_loop = FALSE; /* a frontend status page is displayed with this frequency in ms */ INT display_period = 0; /* maximum event size produced by this frontend */ INT max_event_size = 1 << 25; // 32MB /* maximum event size for fragmented events (EQ_FRAGMENTED) */ INT max_event_size_frag = 5 * 1024 * 1024; /* buffer size to hold events */ INT event_buffer_size = 10000 * max_event_size; /*-- Function declarations -----------------------------------------*/ INT read_stream_thread(void *param); uint64_t generate_random_pixel_hit(uint64_t time_stamp); uint32_t generate_random_pixel_hit_swb(uint32_t time_stamp); BOOL equipment_common_overwrite = TRUE; //true is overwriting the common odb /* DMA Buffer and related */ volatile uint32_t *dma_buf; #define MUDAQ_DMABUF_DATA_ORDER 25 // 29, 25 for 32 MB #define MUDAQ_DMABUF_DATA_LEN (1 << MUDAQ_DMABUF_DATA_ORDER) // in bytes size_t dma_buf_size = MUDAQ_DMABUF_DATA_LEN; uint32_t dma_buf_nwords = dma_buf_size/sizeof(uint32_t); /*-- Equipment list ------------------------------------------------*/ EQUIPMENT equipment[] = { {"Stream", /* equipment name */ {1, 0, /* event ID, trigger mask */ "SYSTEM", /* event buffer */ EQ_USER, /* equipment type */ 0, /* event source */ "MIDAS", /* format */ TRUE, /* enabled */ RO_RUNNING , /* read always and update ODB */ 100, /* poll for 100ms */ 0, /* stop run after this event limit */ 0, /* number of sub events */ 0, /* log history every event */ "", "", ""} , NULL, /* readout routine */ }, {""} }; /*-- Dummy routines ------------------------------------------------*/ INT poll_event(INT source, INT count, BOOL test) { return 1; }; INT interrupt_configure(INT cmd, INT source, POINTER_T adr) { return 1; }; /*-- Frontend Init -------------------------------------------------*/ INT frontend_init() { // create ring buffer for readout thread create_event_rb(0); // create readout thread ss_thread_create(read_stream_thread, NULL); set_equipment_status(equipment[0].name, "Ready for running", "var(--mgreen)"); return CM_SUCCESS; } /*-- Frontend Exit -------------------------------------------------*/ INT frontend_exit() { return CM_SUCCESS; } /*-- Frontend Loop -------------------------------------------------*/ INT frontend_loop() { return CM_SUCCESS; } /*-- Begin of Run --------------------------------------------------*/ INT begin_of_run(INT run_number, char *error) { set_equipment_status(equipment[0].name, "Running", "var(--mgreen)"); return CM_SUCCESS; } /*-- End of Run ----------------------------------------------------*/ INT end_of_run(INT run_number, char *error) { set_equipment_status(equipment[0].name, "Ready for running", "var(--mgreen)"); return CM_SUCCESS; } /*-- Pause Run -----------------------------------------------------*/ INT pause_run(INT run_number, char *error) { return CM_SUCCESS; } /*-- Resume Run ----------------------------------------------------*/ INT resume_run(INT run_number, char *error) { return CM_SUCCESS; } uint64_t generate_random_pixel_hit(uint64_t time_stamp) { // Bits 63 - 35: TimeStamp (29 bits) // Bits 34 - 30: Tot (5 bits) // Bits 29 - 26: Layer (4 bits) // Bits 25 - 21: Phi (5 bits) // Bits 20 - 16: ChipID (5 bits) // Bits 15 - 8: Col (8 bits) // Bits 7 - 0: Row (8 bits) uint64_t tot = rand() % 31; // 0 to 31 uint64_t layer = rand() % 15; // 0 to 15 uint64_t phi = rand() % 31; // 0 to 31 uint64_t chipID = rand() % 5; // 0 to 31 uint64_t col = rand() % 250; // 0 to 255 uint64_t row = rand() % 250; // 0 to 255 uint64_t hit = (time_stamp << 35) | (tot << 30) | (layer << 26) | (phi << 21) | (chipID << 16) | (col << 8) | row; //printf("tot: 0x%2.2x,layer: 0x%2.2x,phi: 0x%2.2x,chipID: 0x%2.2x,col: 0x%2.2x,row: 0x%2.2x\n",tot,layer,phi,chipID,col,row); //cout << hex << hit << endl; //cout << hex << time_stamp << endl; //cout << hex << (hit >> 35 & 0x7FFFFFFFF) << endl; //cout << hex << (hit >> 32) << endl; return hit; } uint32_t generate_random_pixel_hit_swb(uint32_t time_stamp) { uint32_t tot = rand() % 31; // 0 to 31 uint32_t chipID = rand() % 5; // 0 to 5 uint32_t col = rand() % 250; // 0 to 250 uint32_t row = rand() % 250; // 0 to 250 uint32_t hit = (time_stamp << 28) | (chipID << 22) | (row << 13) | (col << 5) | tot << 1; // if ( print ) { // printf("ts:%8.8x,chipID:%8.8x,row:%8.8x,col:%8.8x,tot:%8.8x\n", time_stamp,chipID,row,col,tot); // printf("hit:%8.8x\n", hit); // std::cout << std::bitset<32>(hit) << std::endl; // } return hit; } uint64_t generate_random_scifi_hit(uint32_t time_stamp, uint32_t counter1, uint32_t counter2) { uint64_t asic = rand() % 8; uint64_t hit_type = 1; uint64_t channel_number = rand() % 32; uint64_t timestamp_bad = 0; uint64_t coarse_counter_value = (time_stamp >> 5) & 0x7FFF; uint64_t fine_counter_value = time_stamp & 0x1F; uint64_t energy_flag = rand() % 2; uint64_t fpga_id = 10 + rand() % 4; if (counter1 > 0) { fpga_id = counter1; } return (asic << 60) | (hit_type << 59) | (channel_number << 54) | (timestamp_bad << 53) | (coarse_counter_value << 38) | (fine_counter_value << 33) | (energy_flag << 32) | (fpga_id << 28) | ((time_stamp & 0x0FFFFFFF)); } uint64_t generate_random_delta_t_exponential(float lambda) { float r = rand()/(1.0+RAND_MAX); return ceil(-log(1.0-r)/lambda); } uint64_t generate_random_delta_t_gauss(float mu, float sigma) { std::default_random_engine generator; generator.seed(rand()); std::normal_distribution distribution(mu,sigma); float r = ceil(distribution(generator)); if (r<0.0) r=0.0; return r; } INT read_stream_thread(void *param) { uint32_t* pdata; // init bank structure - 64bit alignment uint32_t SERIAL = 0x00000001; uint32_t TIME = 0x00000001; uint64_t hit; // tell framework that we are alive signal_readout_thread_active(0, TRUE); // obtain ring buffer for inter-thread data exchange int rbh = get_event_rbh(0); int status; while (is_readout_thread_enabled()) { // obtain buffer space status = rb_get_wp(rbh, (void **)&pdata, 10); // just sleep and try again if buffer has no space if (status == DB_TIMEOUT) { set_equipment_status(equipment[0].name, "Buffer full", "var(--myellow)"); continue; } if (status != DB_SUCCESS){ cout << "!DB_SUCCESS" << endl; break; } // don't readout events if we are not running if (run_state != STATE_RUNNING) { set_equipment_status(equipment[0].name, "Not running", "var(--myellow)"); continue; } set_equipment_status(equipment[0].name, "Running", "var(--mgreen)"); int nEvents = 5000; size_t eventSize=76; uint32_t dma_buf_dummy[nEvents*eventSize]; uint64_t prev_mutrig_hit = 0; uint64_t delta_t_1 = 100; uint64_t delta_t_2 = 100; uint64_t delta_t_3 = 100; for (int i = 0; i> 32); // hit1 dma_buf_dummy[15+i*eventSize] = (hit >> 32); // hit1 hit = generate_random_pixel_hit(TIME); dma_buf_dummy[16+i*eventSize] = ((hit << 32) >> 32); // hit2 dma_buf_dummy[17+i*eventSize] = (hit >> 32); // hit2 // bank PCD1 dma_buf_dummy[18+i*eventSize] = 0x31444350; // bank name dma_buf_dummy[19+i*eventSize] = 0x6; // bank type TID_DWORD dma_buf_dummy[20+i*eventSize] = 8*4; // data size dma_buf_dummy[21+i*eventSize] = 0x0; // reserved dma_buf_dummy[22+i*eventSize] = 0xE80000BC; // preamble dma_buf_dummy[23+i*eventSize] = 0x00000000; // TS1 dma_buf_dummy[24+i*eventSize] = 0x00000001; // TS1 uint32_t hit = generate_random_pixel_hit_swb(TIME); dma_buf_dummy[25+i*eventSize] = hit; // reserved dma_buf_dummy[26+i*eventSize] = hit; // hit1 dma_buf_dummy[27+i*eventSize] = 0x0FC0009C; // TRAILER dma_buf_dummy[28+i*eventSize] = 0xAFFEAFFE; // PADDING dma_buf_dummy[29+i*eventSize] = 0xAFFEAFFE; // PADDING // bank ITIL dma_buf_dummy[30+i*eventSize] = 0x4c495449; // bank name dma_buf_dummy[31+i*eventSize] = 0x6; // bank type TID_DWORD dma_buf_dummy[32+i*eventSize] = 6*4; // data size dma_buf_dummy[33+i*eventSize] = 0x0; // reserved dma_buf_dummy[34+i*eventSize] = 0x1; // overflow dma_buf_dummy[35+i*eventSize] = 0x1; // overflow dma_buf_dummy[36+i*eventSize] = 0xAFFEAFFE; // reserved dma_buf_dummy[37+i*eventSize] = 0xAFFEAFFE; // reserved dma_buf_dummy[38+i*eventSize] = 0xAFFEAFFE; // hit dma_buf_dummy[39+i*eventSize] = 0xAFFEAFFE; // hit // bank ISCI dma_buf_dummy[40+i*eventSize] = 0x49435349; // bank name dma_buf_dummy[41+i*eventSize] = 0x6; // bank type TID_DWORD dma_buf_dummy[42+i*eventSize] = 8*4; // data size dma_buf_dummy[43+i*eventSize] = 0x0; // reserved dma_buf_dummy[44+i*eventSize] = 0x1; // overflow dma_buf_dummy[45+i*eventSize] = 0x1; // overflow dma_buf_dummy[46+i*eventSize] = 0xAFFEAFFE; // reserved dma_buf_dummy[47+i*eventSize] = 0xAFFEAFFE; // reserved uint64_t hit1=0,hit2=0,hit3=0; // delta between the two hits inside the bank delta_t_2 = generate_random_delta_t_gauss(100.0,10.0); delta_t_3 = generate_random_delta_t_gauss(100.0,10.0); uint32_t fpga_id = 0; // simulate the two hits in the same fiber for every second event which was close in time to last one if (rand() % 2 == 0 && delta_t_1 < 50 && TIME > 100) { uint64_t prev_fpga_id = (prev_mutrig_hit >> 28) & 0xF; if (prev_fpga_id == 10) fpga_id = 11; if (prev_fpga_id == 11) fpga_id = 10; if (prev_fpga_id == 12) fpga_id = 13; if (prev_fpga_id == 13) fpga_id = 12; int64_t delta_t_1_correlated = (rand() % 60) - 30; // uniform distribution hit1 = generate_random_scifi_hit(TIME - delta_t_1 + delta_t_1_correlated, fpga_id, 0); hit2 = generate_random_scifi_hit(TIME - delta_t_1 + delta_t_1_correlated + delta_t_2, fpga_id, 0); hit3 = generate_random_scifi_hit(TIME - delta_t_1 + delta_t_1_correlated + delta_t_2 + delta_t_3, fpga_id, 0); // (try to) select the same fiber for hit1 uint64_t asic = 7 - ((prev_mutrig_hit >> 60) & 0xF); uint64_t channel_number = 31 - ((prev_mutrig_hit >> 54) & 0x1F); hit1 = (hit1 & 0x83FFFFFFFFFFFFF) | (asic << 60) | (channel_number << 54); // now hit1 is hopefully correlated to the previous bank and has a hit in the same fiber // printf("correlated hit: %d %d -> %d %d %X\n", ((prev_mutrig_hit >> 60) & 0xF), ((prev_mutrig_hit >> 54) & 0x1F), asic, channel_number, hit1); } else { // new uncorrelated hits hit1 = generate_random_scifi_hit(TIME, 0, 0); fpga_id = (hit1 >> 28) & 0xF; hit2 = generate_random_scifi_hit(TIME + delta_t_2, fpga_id, 0); fpga_id = (hit2 >> 28) & 0xF; hit3 = generate_random_scifi_hit(TIME + delta_t_2 + delta_t_3, fpga_id, 0); } // delta between two banks delta_t_1 = generate_random_delta_t_exponential(0.005); dma_buf_dummy[48+i*eventSize] = ((hit1 << 32) >> 32); dma_buf_dummy[49+i*eventSize] = (hit1 >> 32); dma_buf_dummy[50+i*eventSize] = ((hit2 << 32) >> 32); dma_buf_dummy[51+i*eventSize] = (hit2 >> 32); // bank SCSW dma_buf_dummy[52+i*eventSize] = 0x57534353; // bank name dma_buf_dummy[53+i*eventSize] = 0x6; // bank type TID_DWORD dma_buf_dummy[54+i*eventSize] = 8*4; // data size dma_buf_dummy[55+i*eventSize] = 0x0; // reserved dma_buf_dummy[56+i*eventSize] = 0xE80000BC + (fpga_id<<8); // preamble dma_buf_dummy[57+i*eventSize] = (TIME >> 16); // 48-bit TS 47:16 dma_buf_dummy[58+i*eventSize] = ((TIME & 0xFFFF) << 16); // 48-bit TS 15:0 // old convention: dma_buf_dummy[59+i*eventSize] = (0x3F << 22) | (((TIME >> 4) & 0x3F) << 16); // 0000111111 + TS 9:4 + overflow x16 dma_buf_dummy[59+i*eventSize] = (0x3F << 26) | (((TIME >> 4) & 0x3FF) << 16); // 111111 + TS 13:4 + overflow x16 // to test missing subheaders: //if (rand() % 32 == 0) { // dma_buf_dummy[59+i*eventSize] = 0; //test error word //} // check if lowest 4 bit of hit TS overflow if ( ((hit2 >> 33) & 0xF) > ((hit1 >> 33) & 0xF) ) { // no => no subheader needed! dma_buf_dummy[60+i*eventSize] = (hit1 >> 32); dma_buf_dummy[61+i*eventSize] = (hit2 >> 32); dma_buf_dummy[62+i*eventSize] = 0x0000009C; // TRAILER dma_buf_dummy[63+i*eventSize] = 0xAFFEAFFE; // PADDING } else { // yes => place additional subheader! dma_buf_dummy[60+i*eventSize] = (hit1 >> 32); dma_buf_dummy[61+i*eventSize] = (0x3F << 26) | ((((TIME + delta_t_2) >> 4) & 0x3FF) << 16); // subheader for 2nd hit at TIME + delta_t_2 dma_buf_dummy[62+i*eventSize] = (hit2 >> 32); dma_buf_dummy[63+i*eventSize] = 0x0000009C; // TRAILER } // bank SCD1 -- format integration run dma_buf_dummy[64+i*eventSize] = 0x31444353; // bank name dma_buf_dummy[65+i*eventSize] = 0x6; // bank type TID_DWORD dma_buf_dummy[66+i*eventSize] = 8*4; // data size dma_buf_dummy[67+i*eventSize] = 0x0; // reserved dma_buf_dummy[68+i*eventSize] = 0xE80000BC + (fpga_id<<8); // preamble dma_buf_dummy[69+i*eventSize] = (TIME >> 16); // 48-bit TS 47:16 dma_buf_dummy[70+i*eventSize] = ((TIME & 0xFFFF) << 16); // 48-bit TS 15:0 // check if lowest 4 bit of hit TS overflow //if ( ((hit2 >> 33) & 0xF) > ((hit1 >> 33) & 0xF) ) { // no => no subheader needed! dma_buf_dummy[71+i*eventSize] = (hit1 >> 32); dma_buf_dummy[72+i*eventSize] = (hit2 >> 32); dma_buf_dummy[73+i*eventSize] = (hit3 >> 32); dma_buf_dummy[74+i*eventSize] = 0xFC00009C; // TRAILER dma_buf_dummy[75+i*eventSize] = 0xAFFEAFFE; // PADDING //} else { // yes => place additional subheader! //dma_buf_dummy[75+i*eventSize] = (hit1 >> 32); //dma_buf_dummy[76+i*eventSize] = (0x3F << 26) | ((((TIME + delta_t_2) >> 4) & 0x3FF) << 16); // subheader for 2nd hit at TIME + delta_t_2 //dma_buf_dummy[77+i*eventSize] = (hit2 >> 32); //dma_buf_dummy[78+i*eventSize] = 0xFC00009C; // TRAILER //} // to temporarily hide pixel data uncomment: // dma_buf_dummy[6+i*eventSize] = 0xAFFEAFFE; // bank name // dma_buf_dummy[18+i*eventSize] = 0xAFFEAFFE; // bank name SERIAL += 1; TIME += 1 + delta_t_1; // keep last mutrig hit for simulation of correlations prev_mutrig_hit = hit1; } uint32_t * dma_buf_volatile; dma_buf_volatile = dma_buf_dummy; copy_n(&dma_buf_volatile[0], sizeof(dma_buf_dummy)/4, pdata); // print data if (true) { EVENT_HEADER* eh=(EVENT_HEADER*)(&pdata[0]); BANK_HEADER* bh=(BANK_HEADER*)(&pdata[4]); BANK32A* ba=(BANK32A*)(&pdata[6]); char bank_name[5]; bank_name[4] = 0; memcpy(bank_name, (char *) (ba->name), 4); printf("EID=%4.4x TM=%4.4x SERNO=%8.8x TS=%8.8x EDsiz=%8.8x\n",eh->event_id,eh->trigger_mask,eh->serial_number,eh->time_stamp,eh->data_size); printf("DAsiz=%8.8x FLAG=%8.8x\n",bh->data_size,bh->flags); printf("BAname=%s TYP=%8.8x BAsiz=%8.8x BAres=%8.8x\n",bank_name,ba->type,ba->data_size,ba->reserved); } pdata+=sizeof(dma_buf_dummy); rb_increment_wp(rbh, sizeof(dma_buf_dummy)); // in byte length std::this_thread::sleep_for(std::chrono::milliseconds(2000)); } return 0; }