From eb0b599ba5734223fe507514e738a1dd21db7e67 Mon Sep 17 00:00:00 2001 From: Patrick Robbe <robbe@lal.in2p3.fr> Date: Wed, 5 Feb 2020 16:55:08 +0900 Subject: [PATCH] Program for KLM test --- .../main_pcie40_klmbytestream.c | 112 ++++++++++++++++++ Pcie40Applications/pcie40_klmbytestream | Bin 9766 -> 16478 bytes 2 files changed, 112 insertions(+) diff --git a/Pcie40Applications/main_pcie40_klmbytestream.c b/Pcie40Applications/main_pcie40_klmbytestream.c index 738e604..9b5d4ee 100644 --- a/Pcie40Applications/main_pcie40_klmbytestream.c +++ b/Pcie40Applications/main_pcie40_klmbytestream.c @@ -1,10 +1,122 @@ #include "pcie40_ecs.h" #include "pcie40_b2slc.h" #include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +typedef struct { + unsigned int chip_no; + unsigned int rpc_board; + __uint16_t thresh_values[48]; +}KLMFPGAconfig; + +typedef union { + char charval[2]; + __uint16_t uint16val; +}uint16toChar; + +int writeConfig(int fd, KLMFPGAconfig * config) { + const unsigned int lane_no = 8 + (*config).rpc_board; + const unsigned int chip_no = (*config).chip_no; + + const __uint16_t sof = 0xF000; // start of frame pre-shifted + const __uint16_t eof = 0x0008; + const __uint16_t type_wr = 0x0200; // write command (1) pre-shifted + const __uint16_t type_ud = 0x0E00; // update command (7) pre-shifted + const size_t sof_eof_nbits = 4; // SOF/EOF bits + // const size_t lane_nbits = 5; // lane bits + const size_t chip_nbits = 4; // channel bits + const size_t rc_pkt_size = 3; // 16-bit words + + // const unsigned int rpc_nbds = 13; // number of boards + // const unsigned int rpc_nfpga = 2; // number of FPGAs + const unsigned int rpc_nchan = 48; // number of channels per FPGA + const unsigned int rpc_naddr = rpc_nchan / 16 + rpc_nchan; // number of addresses/FPGA + + // const size_t rpc_pkt_size = rpc_nbds * rpc_nfpga * rpc_naddr * rc_pkt_size; // total size + const unsigned int fpga_pkt_size = rpc_naddr * rc_pkt_size; // packet size per FPGA + + const __uint16_t rpc_pulser[rpc_nchan / 16] = {0}; + __uint16_t rpc_thresh[48] = {0} ; + // const __uint16_t (&rpc_thresh)[48] = config.thresh_values; + + int ii = 0 ; + for ( ii = 0 ; ii < 48 ; ++ii ) rpc_thresh[ ii ] = (*config).thresh_values[ ii ] ; + + __uint16_t fpga_word[48*3] = {0}; + __uint16_t data, temp; + unsigned int idx = 0; + unsigned int addr = 0 ; + + for (addr = 0; addr < rpc_naddr; addr++) { + if (addr <= 47) + data = rpc_thresh[addr]; + else + data = rpc_pulser[addr - 48]; + temp = chip_no | (lane_no << chip_nbits); + if (addr == rpc_naddr - 1) + temp = temp | sof | type_ud; + else + temp = temp | sof | type_wr; + fpga_word[idx] = temp; + temp = (addr << 4) | (data >> 12); + fpga_word[idx + 1] = temp; + temp = (data << sof_eof_nbits) | eof; + fpga_word[idx + 2] = temp; + idx = idx + 3; + } + + __uint16_t word; + uint16toChar uch; + const size_t fpga_pkt_n_bytes = 2 * fpga_pkt_size; + char stream_data[fpga_pkt_n_bytes]; + size_t i = 0 ; + for (i = 0; i < fpga_pkt_size; i++) { + word = fpga_word[i]; + uch.uint16val = word; + stream_data[2 * i] = uch.charval[1]; + stream_data[2 * i + 1] = uch.charval[0]; + } + + int ret = pcie40_writebytestream(0,fd,fpga_pkt_n_bytes,stream_data); + return ret; +} int main(int argc, char *argv[]) { ecs_open( 0 , 2 ) ; + KLMFPGAconfig config; + unsigned int thresh = strtoul(argv[1],0,16); + size_t i = 0 ; + for (i = 0; i < 48; i++) + config.thresh_values[i] = thresh; + printf( "Setting threshold value %d for all channels.\n" , thresh ); + int b = 0 ; + int c = 0 ; + int hslb_id = 0 ; + int try_no = 0 ; + int ret; + + for(b=0;b<13;b++){ + for( c=0;c<2;c++){ + config.chip_no = c; + config.rpc_board = b; + + // Stream the config through HSLBs + for(hslb_id=0;hslb_id<4;hslb_id++){ + for(try_no = 0; try_no < 3; try_no++){ + ret = writeConfig(hslb_id, &config); + if(ret == 0) + break; + } + if(ret) + printf("Packet streaming failed for HSLB= %d, board= %d, chip= %d\n", hslb_id , b , c ) ; + else + printf( "Packet streamed successfully for HSLB= %d, board = %d ,chip= %d\n" , hslb_id , b , c ) ; + usleep(500); + } + } + } ecs_close( 0 , 2 ) ; diff --git a/Pcie40Applications/pcie40_klmbytestream b/Pcie40Applications/pcie40_klmbytestream index 29120dff0dce46248dd09d8b3c85d712772a2207..c717e91a80e8605ec62571ec4947bc71a04fe9a4 100755 GIT binary patch literal 16478 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 P5ufW8IxxP|<re-IMPZH4 literal 9766 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 -- GitLab