From 9a08ecc5a58301c3fa6f2826bbef90bf92d8e65e Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Wed, 10 Jan 2024 16:23:52 +0100 Subject: [PATCH] Xilinx client tests (#887) * implemented testbus, testfpga, set/get #frames, triggers, allowed that and for connection to client, also allowed, getnumchannels, configuremac, getrunstatus, setdetectorposition with dummy values * allowing tests for xilinx * binaries in --- .../bin/ctbDetectorServer_developer | Bin 328424 -> 328424 bytes .../bin/eigerDetectorServer_developer | Bin 444195 -> 444195 bytes .../bin/gotthard2DetectorServer_developer | Bin 286768 -> 286768 bytes .../bin/gotthardDetectorServer_developer | Bin 277364 -> 277364 bytes .../bin/jungfrauDetectorServer_developer | Bin 312616 -> 312616 bytes .../bin/moenchDetectorServer_developer | Bin 295380 -> 295380 bytes .../bin/mythen3DetectorServer_developer | Bin 300752 -> 300752 bytes .../slsDetectorServer/include/arm64.h | 6 +- .../include/slsDetectorFunctionList.h | 14 +- .../src/slsDetectorServer_funcs.c | 32 +- .../bin/xilinx_ctbDetectorServer_developer | Bin 231752 -> 232088 bytes .../slsDetectorFunctionList.c | 194 ++- .../slsDetectorServer_defs.h | 5 + slsDetectorSoftware/src/Detector.cpp | 1 - .../Caller/test-Caller-chiptestboard.cpp | 37 +- .../tests/Caller/test-Caller-rx.cpp | 1497 +++++++++-------- .../tests/Caller/test-Caller.cpp | 1205 +++++++------ slsSupportLib/include/sls/versionAPI.h | 16 +- tests/scripts/test_simulators.py | 5 +- 19 files changed, 1720 insertions(+), 1292 deletions(-) diff --git a/slsDetectorServers/ctbDetectorServer/bin/ctbDetectorServer_developer b/slsDetectorServers/ctbDetectorServer/bin/ctbDetectorServer_developer index 0389e28a7b3f1e65a899258bae9d82b9e5fd5357..2e08e740bd4cb9cea7585082237fbcc032ba2172 100755 GIT binary patch delta 50 zcmaFSD)ORLWP&F1Ts?#7g%T_hjV`S&jIAzATV0qLgBUHhy9F`FOEOxvFUw}$zAT%? GX*vL@!Vnz* delta 50 zcmaFSD)ORLWP&F1w5$847fP^5G`h69Ft)ldZFOO03}Q6d?iR!xFUe@qzAT%0`?72n Gr|AIK?h!%& diff --git a/slsDetectorServers/eigerDetectorServer/bin/eigerDetectorServer_developer b/slsDetectorServers/eigerDetectorServer/bin/eigerDetectorServer_developer index 55d73d6b48dae331cca5cc28cd5c4d6718ebfb48..fb03bc42d2a64261660ba5e2a2be8c548d90b0ec 100755 GIT binary patch delta 41 vcmZ47C%w2&x}k-!g{g&k3(H?VM$7I0_*lBb87 delta 41 vcmZ47C%w2&x}k-!g{g&k3(H?VMw9LT_*lBb8BN-|(pZ3)b$eGD+sp(2Kxz*j diff --git a/slsDetectorServers/gotthard2DetectorServer/bin/gotthard2DetectorServer_developer b/slsDetectorServers/gotthard2DetectorServer/bin/gotthard2DetectorServer_developer index b1ddbb69c5977f3798d6e71e194335d6a7fb0c01..f135ab12f3340247bacad2223b798f7a93ea756b 100755 GIT binary patch delta 37 scmdmRKyU*P8D3}dIoE7_z1{da<96fgOv|JgE!%H>WZHh~BXd|D089Z9Pyhe` delta 37 scmdmRKyU*P8D3}NIooV}z1{da<96fgOv|JgP1;5RfSYoh~t#F>(VKfkcHw0kuQ|-O&L#w<6L4rxgJ?hsx&yx60=O Fs#Doz6S)8Y delta 47 zcmV+~0MP&R_7L>;5RfSYmes(QF>(VKfkcHw0kuQ|-O&Lww<6L4rxgJ-hsx&yx60=O Fs#63L6y5*; diff --git a/slsDetectorServers/jungfrauDetectorServer/bin/jungfrauDetectorServer_developer b/slsDetectorServers/jungfrauDetectorServer/bin/jungfrauDetectorServer_developer index dbf4172f509cba83d72310d212642e858db82432..5e2a3ec150e7fc8684c4968ffd965c38c20db25b 100755 GIT binary patch delta 50 zcmZ3{CA^|bc!DPLTs`CIiO-oO8eLjl7+YPKwz@DsRb#Z=uBFbLEzfA#KFy7J`!qL} GNp%3YZxFTs delta 50 zcmV-20L}lXiW8`c6Obtbmes3#o?-sR6eOsRGJ)0Xc`(Ap^J8Aq4t#FY^zY delta 37 vcmV+=0NVf1trF0!60ixW0u0TA3#o?-sR6eOsRGJ)0W^o!Ap^J8Aq4t#DB=%P diff --git a/slsDetectorServers/slsDetectorServer/include/arm64.h b/slsDetectorServers/slsDetectorServer/include/arm64.h index f095790e0..06e8f7b26 100644 --- a/slsDetectorServers/slsDetectorServer/include/arm64.h +++ b/slsDetectorServers/slsDetectorServer/include/arm64.h @@ -5,6 +5,8 @@ #include #include -int mapCSP0(void); void bus_w(u_int32_t offset, u_int32_t data); -u_int32_t bus_r(u_int32_t offset); \ No newline at end of file +u_int32_t bus_r(u_int32_t offset); +uint64_t getU64BitReg(int aLSB, int aMSB); +void setU64BitReg(uint64_t value, int aLSB, int aMSB); +int mapCSP0(void); diff --git a/slsDetectorServers/slsDetectorServer/include/slsDetectorFunctionList.h b/slsDetectorServers/slsDetectorServer/include/slsDetectorFunctionList.h index 6b3b43cb3..6c0a8fad5 100644 --- a/slsDetectorServers/slsDetectorServer/include/slsDetectorFunctionList.h +++ b/slsDetectorServers/slsDetectorServer/include/slsDetectorFunctionList.h @@ -65,10 +65,8 @@ typedef struct udpStruct_s { int isInitCheckDone(); int getInitResult(char **mess); void basictests(); +#if !defined(EIGERD) int checkType(); - -#if defined(GOTTHARDD) || defined(JUNGFRAUD) || defined(MOENCHD) || \ - defined(CHIPTESTBOARDD) || defined(MYTHEN3D) || defined(GOTTHARD2D) int testFpga(); int testBus(); #endif @@ -251,11 +249,11 @@ int getMaxStoragecellStart(); int setNextFrameNumber(uint64_t value); int getNextFrameNumber(uint64_t *value); #endif -#ifndef XILINX_CHIPTESTBOARDD void setNumFrames(int64_t val); int64_t getNumFrames(); void setNumTriggers(int64_t val); int64_t getNumTriggers(); +#ifndef XILINX_CHIPTESTBOARDD #ifndef MYTHEN3D int setExpTime(int64_t val); int64_t getExpTime(); @@ -501,9 +499,7 @@ void calcChecksum(udp_header *udp); int getAdcConfigured(); #endif -#ifndef XILINX_CHIPTESTBOARDD int configureMAC(); -#endif int setDetectorPosition(int pos[]); int *getDetectorPosition(); @@ -715,9 +711,7 @@ int softwareTrigger(int block); #if defined(EIGERD) || defined(MYTHEN3D) || defined(CHIPTESTBOARDD) int startReadOut(); #endif -#ifndef XILINX_CHIPTESTBOARDD enum runStatus getRunStatus(); -#endif #ifdef EIGERD void waitForAcquisitionEnd(int *ret, char *mess); #else @@ -748,9 +742,11 @@ u_int32_t runState(enum TLogLevel lev); #ifndef XILINX_CHIPTESTBOARDD int calculateDataBytes(); int getTotalNumberOfChannels(); -#if defined(CHIPTESTBOARDD) +#endif +#if defined(CHIPTESTBOARDD) || defined (XILINX_CHIPTESTBOARDD) void getNumberOfChannels(int *nchanx, int *nchany); #endif +#ifndef XILINX_CHIPTESTBOARDD int getNumberOfChips(); int getNumberOfDACs(); int getNumberOfChannelsPerChip(); diff --git a/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c b/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c index 80520a0ca..5256a3490 100644 --- a/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c +++ b/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c @@ -2219,9 +2219,6 @@ int get_num_frames(int file_des) { memset(mess, 0, sizeof(mess)); int64_t retval = -1; -#ifdef XILINX_CHIPTESTBOARDD - functionNotImplemented(); -#else // get only if (!scan) { retval = getNumFrames(); @@ -2231,7 +2228,6 @@ int get_num_frames(int file_des) { LOG(logDEBUG1, ("retval num frames (num scan steps) %lld\n", (long long int)retval)); } -#endif return Server_SendResult(file_des, INT64, &retval, sizeof(retval)); } @@ -2244,9 +2240,6 @@ int set_num_frames(int file_des) { return printSocketReadError(); LOG(logDEBUG1, ("Setting number of frames %lld\n", (long long int)arg)); -#ifdef XILINX_CHIPTESTBOARDD - functionNotImplemented(); -#else // only set if (Server_VerifyLock() == OK) { // only set number of frames if normal mode (not scan) @@ -2292,7 +2285,6 @@ int set_num_frames(int file_des) { } } } -#endif return Server_SendResult(file_des, INT64, NULL, 0); } @@ -2301,13 +2293,9 @@ int get_num_triggers(int file_des) { memset(mess, 0, sizeof(mess)); int64_t retval = -1; -#ifdef XILINX_CHIPTESTBOARDD - functionNotImplemented(); -#else // get only retval = getNumTriggers(); LOG(logDEBUG1, ("retval num triggers %lld\n", (long long int)retval)); -#endif return Server_SendResult(file_des, INT64, &retval, sizeof(retval)); } @@ -2320,9 +2308,6 @@ int set_num_triggers(int file_des) { return printSocketReadError(); LOG(logDEBUG1, ("Setting number of triggers %lld\n", (long long int)arg)); -#ifdef XILINX_CHIPTESTBOARDD - functionNotImplemented(); -#else // only set if (Server_VerifyLock() == OK) { #if JUNGFRAUD @@ -2342,7 +2327,6 @@ int set_num_triggers(int file_des) { validate64(&ret, mess, arg, retval, "set number of triggers", DEC); } } -#endif return Server_SendResult(file_des, INT64, NULL, 0); } @@ -3622,7 +3606,7 @@ int write_adc_register(int file_des) { uint32_t val = args[1]; LOG(logDEBUG1, ("Writing 0x%x to ADC Register 0x%x\n", val, addr)); -#if defined(EIGERD) || defined(GOTTHARD2D) || defined(MYTHEN3D) +#if defined(EIGERD) || defined(GOTTHARD2D) || defined(MYTHEN3D) || defined(XILINX_CHIPTESTBOARDD) functionNotImplemented(); #else #ifndef VIRTUAL @@ -4017,7 +4001,7 @@ int reset_fpga(int file_des) { LOG(logDEBUG1, ("Reset FPGA\n")); #if defined(EIGERD) || defined(GOTTHARDD) || defined(GOTTHARD2D) || \ - defined(MYTHEN3D) + defined(MYTHEN3D) || defined (XILINX_CHIPTESTBOARDD) functionNotImplemented(); #else // only set @@ -5026,9 +5010,6 @@ int set_detector_position(int file_des) { LOG(logDEBUG, ("Setting detector positions: [maxy:%u, modIndex:%u]\n", args[0], args[1])); -#ifdef XILINX_CHIPTESTBOARDD - functionNotImplemented(); -#else // only set if (Server_VerifyLock() == OK) { // if in update mode, there is no need to do this (also detector not set @@ -5039,14 +5020,10 @@ int set_detector_position(int file_des) { calculate_and_set_position(); } } -#endif return Server_SendResult(file_des, INT32, NULL, 0); } int check_detector_idle(const char *s) { -#ifdef XILINX_CHIPTESTBOARDD - return FAIL; -#else enum runStatus status = getRunStatus(); if (status != IDLE && status != RUN_FINISHED && status != STOPPED && status != ERROR) { @@ -5058,7 +5035,6 @@ int check_detector_idle(const char *s) { LOG(logERROR, (mess)); } return ret; -#endif } int is_udp_configured() { @@ -5125,7 +5101,6 @@ int is_udp_configured() { } void configure_mac() { -#ifndef XILINX_CHIPTESTBOARDD if (isControlServer) { if (is_udp_configured() == OK) { ret = configureMAC(); @@ -5152,7 +5127,6 @@ void configure_mac() { } configured = FAIL; LOG(logWARNING, ("Configure FAIL, not all parameters configured yet\n")); -#endif } int set_source_udp_ip(int file_des) { @@ -7105,7 +7079,7 @@ int get_num_channels(int file_des) { LOG(logDEBUG1, ("Getting number of channels\n")); -#if !defined(CHIPTESTBOARDD) +#if !defined(CHIPTESTBOARDD) && !defined(XILINX_CHIPTESTBOARDD) functionNotImplemented(); #else // get only diff --git a/slsDetectorServers/xilinx_ctbDetectorServer/bin/xilinx_ctbDetectorServer_developer b/slsDetectorServers/xilinx_ctbDetectorServer/bin/xilinx_ctbDetectorServer_developer index cdf9b7c45727680214b13cf9c0450510f1642dfb..c50684e34a42f1c07c4cc35e4be73ad49b4c1199 100755 GIT binary patch delta 63201 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 AQvd(} delta 59023 zcmb5X33wF6_CDOz2@tXovXTUnNq__bgph;eLc%7|V?L>3nmQD#)!y^ylh z=DOgpsK9jzf?xn)P*haJ2&gCs!y+P^QMt+>kncU!T}jiI`+t5P&lBp@TW6`QPo1h> zX2J9ETc3@uY^M+O^Mco-r|0S#{hOZ4f7qBa=^&H2Ne9a>N|(mUthRJjHLGi?8+ohN z#axKjYjv?M)G_4t*Usq@L(6r=w%-f7V z1+2u0g_`k4ffYJ2BZ2#YwRd8H1U?&B8wcjowB~#!z-$Mod7JYYz%razusNRsEX9d= z68Wvb5}cSnkxv8`sZW@ZDn?~pJO%IsTcMxoUb#9X0~n3o6aYr8KF!)F?=Aie^}G} zBU2^NKYXv?SxLg19eG71)P*`nR*#`HNe>U9w3!~Rt7FSUOEk`A`*$3SU@I6&Ux2!s zG_F7B-$D6AJKtFoE3)%j`qO!T(%(c6A867)Y=Gkwaey8!PG)E7UzUq#Pur|2&D)9> z5NC`Qrl~?T`<6ICcNarFX-RdLX)Z6ymz0Y?+gx>16$@rj2UlsK zEWUyop2WhTM?l7kRyB$R8rv2(3W!8N?T{q95=Bz^Oe`Kr0=Z7U|y+dtS`R%gFkY zblnxnZF!muRm^M2?>jHnXRB8S^PDA2w8<=)^ycaNs+du{L zc~@W#w}A@g^P=;0NwQOLan@)?HaUQB#Ch{A1qmxp)#E&3L=%|^X@@@sK12Fym`Mds!5 zVr(q)mxueE6Au@5X;!5Ndhtcj6?n&}&O9eREX>zOM2q8vEhEtty+lms^ypNWLls9( z`CAlrPREtvFO##m3^=*Q0MkY~;!7AWHxWWooNKFj1Mm{I}I)I<;TT#Z!rSRhKe z%memSqIr7r7?OPivX78H|H!o@3%V9E(=fyVtr3j)dy6kRrw=${E9{L_8u#|$f0Dpm zP;i%}V6n_!9^Rvj2IDz=boE%N47#+wqC-*o*zKwuemn<;v4mD%sd)T-`5w|UAA09o zdLNhh%fmq>2Vbw`%9Na^pLnS#J@Z|~1J_2jX`;*e`umBmiqex_LpgQK-)ChzFqJg% zcTu|UMH{cJ#~EKicArK)p0+x7jLcsio^SL11YUbEYBWvf9|Nbs+wa6ZI^SgTe^0t6 z46epNb~$jgZZrakWV+5VK<#QYR9G!)p&YrW)o2%w8Y-)c^iA z#?T@=RBxyc(+ppAsP5H~{WR_NXQ0r{d>kvS!oXY|w0YmUSV^_wp+;+wTJuBTvz>U2 z=8fQ2P=zi-1uwHI_&dBp0Cb1H3uQMaUdd!QP~S^?ue6qTgjJ(442fthg$p&$mi)V- zMh{~78g+U2a6dc7Ky74KXpOi|mWIR9aLdx$WC`@o7_Y^UAwCw26u*|VYP|&*b;$wM za>rbh`uvSW=hAfFm*9)G=3b5FX~OrB&cU!T_;R_VKPB^*hd&~H5m@3PqU&AHRA7OK z#$5MU0m5YDoxQaLWvZuGu!(dKoxrncd`xv`vN`@~@o8ytObrWBp}u0`S#hMaSikzL z$mp7(9|?sv7*qQrT~@1wtWGp9M4ATm&Z^k{ zq(<{c@q4LBx1x!+T1{*%^OuLOvn{CEjKRKYy=$!Qg5Dghn}0`u`A6=C@gt28K#{Ar zF9EH$miS4j_8b|MxVJMWzd^K^(yePjD2fjzgJq~dnN@+m$ajM-LIv!xz(Uzne9tj$A2*b;u!J|`hk;$ZgeUO*z%E|G z6Zj9nE?&YD_&2~VUc#I68ekVM;m!FM;f5u=zT*~#ttC7rESKF~skmLy{xm*G(V;Z{4@Da-_(VnfTkr{r4z}ReDcY0HuTeBM8DkV3Nav#z z9ZKgTB<-WAmcfUrflUFD@n90i(?P1s`rf8!b|5?$2cKooSwe}ni%a(1=_bEEip6^j~ zs6F4UXiowEM$!HPzC+O=UjhG0WsDAdo1%jq_-BgtbmX5XI?$1Sq-akk9#piy6aPTb zp-z0AqK!hnR?&e%zFN^*XTFkXANe-8$hTENpfmrsqO~HvOwmRWe@)SWBEDGBp(6gO zqKz*6Wkmh~Dmut`3q>PjPEoX9=ZT_VM3TMr*=PDcakF zA6GO2v7?IiMDd>#jmYSrq7kI*SG3WT?^Sf5DgR#4h#sGqK!muDmswJpR;NBpCpbw z4Y|@9&6~vMDH?14(~9;a^CuMTPv(y*8f*W~GI->7J;_ctgS>-~5|W4#}zXio;e zTG3u#1|O+1So?=7+LOtLC>m@3m5L5z@+%arwd9v6+S`&FiVn8qeH86!#d|5*-->rv zG~$3#qS60oeHQPc3IbWYP|=79Iw%_Pa63f@vUyuYhq5^i&aL6|czCv=5i7J*G~$DF zMI$~)RW#xQUy{lMb9jQHJ-Iwi(Fhiz6^&S-iJ}oJL@FAw0#h_%g$vjqTJxz5|69?) zHvEjDJ#G1aEZT=j*OvdT3Ic8UuZq_4_z6XO^Y|}{4&?D8iVo%RLy9)?>9E-{9LVQC zDq3sDe^9iy9sf?z!FGHXv;04HlI{7|s=(WxZ&!4%J^w<{2qLyB8bQRziVhX<4;76V zVw0i+9ry-CYaMyDqP-pY8b$kp9r-GiF*@-oMF%?Zw-l`vavX45Eki)@hNAt2e5s;? zg?y2s5nL=(w9%Qrq-ewz3lxpm;(5@P|MwR0XH`M4h|gEFrwhkPgk{*@g+FQ0I8^Jx zA5*kZ%pXy-znJ?K9V+GzD%vRF_bVE4#=VO6l=}GHD&sBXGZc-WW2&Mg747ZI^AwF3qP3#E{kX@Xadf8fR*FWfkfCVA3TZa&(-15qtAY^Y%@ys{dAy<# zAH*oyAHky(?TO@#6zz}Xx}rmoybc>-=>rfGoKtk55yt_pjW_0hYRdly8uLHu3!3m+ zMF*PjlZwXLe@xMVDE_meJx%#xMPt1`plDAt->2w6G~c6WBZlu*bjTOOzfl=)EZ?E% zP%QsS(cU<|P0?7(KT|Z;@=p|v6WNaxZ8YOSMPvE?K+#45U#I9`0$)qC<^P-W)%69< z`AS7&&3;?a!9@OVMH@+cnWC{wzouv-nJ-p!FqyxqXe`YyD;nGKe<|8X<-QkGCYZ{F zqP=OnQqiF_{!c}FTkxk8jb-<7MPu2WtLR`le@M|-YUd~#tLtnkXkD~Md997{5C~n8NEf(SVeDAG*(fsqOpozuV{ZZzgE$jhmX~i z|HpEPvrTJeV!6CZ(cTSUXh}MdAyUNvC0)FI+)M%6>YTRbRZ>Vv9jeT+Gx+S6dh>K zGZn2B@D`vg|Buy-4y2^8)`2G~8Y@^cMH?MC?!DUvI`XE9_H^QOASGq}op^+zL!CHo zlVXQF;oI}G*DgPgv)E9!Rt>&dhB%OJZF(XNA%0I49}jsXQQ}$(E#XxfHbRX~i))AG zGQW7}xuopsZrXDmoVTB!{n;{0;YO*DgtSnacxPyOqdQLH2820dB1;mXp$U4@Y4Q8e z{&A1~r_Oxi&pL#@T5`20AJ&ic5)Ta<)kI1LTZlcw()HZa;?H3_x=YANSFNn2JJfb7 zYw2cy-O5@mkgi%;s|C|V-SF3ap>)-Oa9tUy18X&00Coq~(lL|Wfl!yxpgNe*pgNS{ zR9)YJ=*X{S#{^>NaJD7~S2WVF!mx?}oZf=7$Ocei!F0}|Tv#ZRvsf4A&EhP~K*DMw zIUDW5iW+k^&V^M0yUv9rL~-VIVOlh2H@h%z4EM1~E^tH~XH#5QRXk_YU05K2v%6iG zmdM$CF03|*vj<$*2uwo1#BhpZb$@M+k;d6v7o!)G@Cg@Ig-Q5~3rlFlS)~hu_h!$z zFfS(N0w?A}SC7c$>}4kitg1C<0T+fX23zXFG)&B8F02+4^Gz2v0u!^!g~2Z}-)a|# z=$*aq!Vs0S4K56UHw(J3ASUn@7lxBMw$+9CF{!s%n6JM3aT3RBT#N{U*)A7`Lo~MA zg=x4V_PQ_+u82?rmV+Ck_~Y#GMVPNL#~Z=f(Tl*!oas$DJK@3-;K6ELSP+x-vBkR4MtV{?K^PJDc=t+fp#3MJfmSAE^#wzlTF03{K-qD2>VG_nltg^mW zr(+T(xG+QpEZN3l0*3fY&VF=%RSu2?*mia!S#8r0hE{@UP{yJFHeclM2d7_v?@lqFmgz-E(~WMEWw2(^hW%b>;k7_ z>{?ue)xbDBp$o(D1M|4BN?hA*To~>Suy!u266;Gx!hH4JUz1Y{A5i3C^kac3bzvdQ zj~*^;dUJR}7e+q7aA96VJ{1m(cJVpbK(m1kkgysoIzwC-EjlAy7%e)ZT^KDo<6KxJ zhVwcXhHa*gd0k)-<9V|S(=eWsT$q6cW{L~Lj*d-tVFCDxyImLsAooekr)ED|j7j)_ zi;=ElzYD9v^*;9^tTHD7m**2MtQHk~<|3>n2j^X^(uq<0Hysn{IVT9L28+o87gmJD zj6!B^iPVZQogA-a7>B4F;fukC*a*BeB;LKuejN(5DPRE2xa53W0lO?;bnkaZj z7e;%#mM*Lcj?3f15-^Y2T#Wg0aJIWA&&Q0g^MwSRdJvT!-*Xm;=)E?RUF~MaM;F1yD-|?jZ+xn zKWVrUUhg^uDhw0O>%u~CG&j32+__A+wC(htOicy zoC_<$Flh}gSjyrhB^K$zJQ$Lw28_|LS9bHk6*hoUxC-Nx;KFE^lB2@}(eb#jD)^K(gxT?*G)xCZ?OcpOIEzvj=7F#1;lk+5r?(4Bfd4RD7@Y%EM23U( z&J?-+G1Lt~IFNx3kT7pCJe&)otR@)mM?jo!v$D@g_Zn?Qx6@xpKmT)Tm^hweG z*4)U(r|L|zHU)2aJ$P#_IB=q?IHsQzZ{M1$A3rH}+Hfr|6Ewp@+%2>vy6Zvf`Eoe&FeE9~_I)Fc2} zJhnd`5$_+SqDM$I@(ic_0bohU2asPppnsSiQ6}u|lcMqDPT6R-WjYtHkl=hjoReV8 z!Xfso0C>^xk&_FDkA?Um)RbzZqyMPJ8aCmp{(#!&3GPGT%R30)BdOIWP@x z!6j=maI<;zB2-Jt1+v6flhgIKC&jVJ6AL$3jjPo>{Wv{pkC#{qh)oY!?|w0Fc6~=Y zctYHNdv3}Zh(w@a^a{a^NJH61br-Sn_U`)gC&aPaGcx9Zq0Xl-4}AoG;dry{i4!7g zN^0tt1$f3@(`HP@gZSglSTzk7ia}Ef^}0fF|CDY~H$j1hC%w(82%JOxB5s_KCK9H$ z)Q6oArxxew^9w}b9R=)D@#CEt;`o$wz2gZn?~X$K_5!i-j$Zn!g<{TK>7w)PjYRE~ zWIghPD4d$b28f|kJ20Qp6@U1+d`;llP?8o-I3?Ci?SwbDJRWg;Y9~D%6`hmHt`c3Q zbx(f}jP#D4nt3bj{C4rsv^2dtjMZhx+P!pK?3k9TdkV#=dsD^HDJ|0<1?w6-b*_3V z$L_5-Q9fPPJmXGqEV%^7*-m2K^oBM}I4(BM&e9jR7YC>3>3cef8}4r?G>(hDGjiF- z;*ObV!gxAL_-DlF0gsqJV<7cTOcHF!IUe$ezh`t|!$qe%JFv&agLh@rchZStV&0v( ztWd1Hvx9z1C$aC&bdqIXh=1PEnMI58yUJMKizJpDlVfqXo%rFdf@Uo{Y0sUX{gHiJ zt6J=z(pG=ynCNwPUQ{C#(Pbwl-QBY3vi8>49}_oDP7-^k#!#o{hmsp5fq z&?7nG>3iC!7PD5O)6{I{6~Elmfh`c%-`~&|=YJ7{X6EV-cN9}+c1t_*3yfoi(~R|6 zFUVACp&YS(W_m#ZDiKZB8NFy@FaUz#D`;us?HM%Z&qT$q{4#)*`BZ`G@Q z5p(WM)q8Zr2p8+G{31TTH<#s#llP8__raE?`JW{nZ~ra!O-p5ws9K4B+b`mRKdb$l z`3+Z2cia+e0^9TOLXMhW<@WsgNpzWA5VvZq^`Q7G&58BJ9K@CTbNX{HsYaslh|x29XcvoCZ(JGEw;aq%Kjnc zKey!L9P$fn`Cr9vvy<2r#1{8&hx`v>#_Tj!B*mY%#CPX4bj(e*_&O=xT(ZqPDrVN? zrL1+Z^#@xNYWXkGYEGK|YXPQwu|E2!m^>#h{&@$V=d@TjCpGmhyn5m8=Fbb@Xo}-I zTXmD8cEedYYO6(#uS8EjDo5=)hqj;Lp{Z~BUP9gTBou%4=Y~1Z-qPly0%6=2E217s zZlCW^_pYt3=_S;8NhwmU~k1CEE?~s3rPQ?|dbt&*9JlGkJj`&%q}Dnq<;PkOx9Q8?c!{7Dt+gN~51O?|pe z!)T@cZq462&WKZYrLvC{Z)7_t62=qBad$Yl&xk&cXU9!+AScCbk7p;3bsz_St261D z2~qh(i}pht1>d27CT$@WYjq8%rR-7IElEH2Q=OT4iPAeo`zJa?wSX>qP{N#^g?mlS z#f&F1v84PH|3`@BPxRAQ|0Iq*kr8*MbwleO5zU``+V?;^2x93)$h5*w4@m@a`4Geg zq1N!Rttp=Ik32)mG3afm0{LRer{Vb(;>!nLzQuQn_&|RMJ}ewnnuZMyy?;nF9mi{0 zH9cPODLj$HLVZQ%Q>~huLjL^hkHuI1PWq^y#MGyX*)GAJDbaiWB*)}_N39#7qsXUR z_m>=#cfluD{(&MFI&Txm|4_GLYAV@s4&^(Qm?>_O_)7{wv($;~) z(v!4th`a+48kELRtp-K;|LaL8{=>r!7s79U%4t0yU#{%GK9jD$d05;qKTEXxXF}@n z+=h;y3ANOOFQq_}*0S|mMCbXPVxE9L>Rl$|hz#+;KeJOlbchbMMVE@-{+Xtq&681B zGk>~1;jrjCuP|kygSWlSiw9%orLk|tjXX_+{4Mn|i}ij7Ya^TWI%3t|&8u%g8nvJ> zb&P}ez^_*Adsxk#*HDK)4#^(u=3w3oX6nHfc(6wGpqkdxRE^?y9ct*s2&tA`qYCwn zQfmrxXnn@kdPw9{CgCw1yJc~&I`nK8i{_`XHmXd2^3e0!Szi3-ISu1*^{>xQWvS9X zyX#gb`17*2*v;ahr}I-^bBGn$9q{;n4#60^+7o59 ztLx>mE+KcFL+)qn;pBoQ<(^k^`q_grF6iT6-Dv|95$c5oTucm#LbOzqm+)F{69hi~Rh?RLG z9D>Hp^lX-R<^^dZ?m^3j3{>6}U!$WBTP6CfWFn*d-=2m+>UJq}S{t6@GWR7Sgb-rF zMNs~*H1~vQnd|E?cZW0=vP$%J(wrz-5X=4&%6iU5&7sQKGW}g1b0ojaBj%K`%?V_vKut{#qm$=Lgx6QSNxkxg{#)|`H zNqo>@?AJeJaCf=*aY0Gk3KTFqCY>W%{VQF3zB5|f$6NL^QIcpcF`Jv z#d>Rt@n#3(uUOlN@d}IaWs8wnjQt&qU)qdqEXMmS#{D5_+T&pSx6PfE4=lzD zSq*i3(q;_(E-u`Y#w@;;KSmo3KMb4B4R#aUxR zb>`>jKpG|V{Ag|Wf{}qnfjhqhzU6?J^Ge&u8Ww76zS9h+M;l&A$Y?BwyiztYu z!DAtDdBsN!U4rGYomFYOR=<;HIYJr23&Jt+gVr665M8&Fqx}P>4o+t;eu(cjTP@(E0 zLW@$xg;(RmY@VL?`u>I)eV~g!k!Gr5RO?uWT#@y!7UIR}(Q?xLbHA7q$Y}p{tA+u+ z&Nj2kVMa+utNO)FgDvb#r9W9H*rGIcT9hx5&D5{4l)mCn+Rj$$yM)qjm0(<%L+NCx zG^on-wwBV{97<1Pw@uwV_!3GNE5W!X4yE0s(q~i|`%PT+a(-&DL+1z3NduDnn_Mp^ z*Ry^_tSJc&)|YJ7-^I!$X>6e4Z1mPXxGC}VeQE7~YuV7P57?F6iReWQO1bR{3zTf! ze8{3(<<@bdcxY)FOIBt2tbOFD$9&*WIuJ_#%TeR0zY@f>&gE@Cd>ySftDyclM+MZl z9`}%Ei63EEmxJo7CBLnIBTMvNmhCwX+f6TJ+ndi%OIx_`V2{?MfNlG3D8Kp=w%@dD zH+R@JEZZ;05^RYc3}hDcbC~`d%P9?f&Lz~{=MjBhD~|v1$A_fYeOnJLq%t+1~sGt^wJ;2#N|Wr=`2qN$VRQ$_@h|2{9X2rxMM|0 z(?}?)>!4NFiOn0+Dh6aW%*q{DtEea2Bid85QcVg!mIHN!C!f^Dm%%(}G(G+2+qdbz2k$EG$f3LXZEwZl_*2@pPgnT*i z+baUepF~JNEBWTVV&7Z6BI#Q^Vnm>$K4vdnnei`XG<0m+qvENR*J34>D+FS@(^<19IW3s9`t4)&T;@>+aHmgvdSTHH8?wL{{eDo-J$-Qld>%xEcKO^`d#S_JvTwB$L;6=F7MkQxr53` zd|Rsq(sPeKDG&Wts6xG&tU=r;M-BD~{$6sazYG6NnrIlZdu)?eLSexrOg^Nv#vl2i zVX;WDOx~^v^_m~3(Q(NRldqCVk5)>UrHzx~>$P%Z^^re_8{W^j z`UQuL90X=^@P-?+;2UXESEb=y%vhJn_idBUK>ZzvD%IdIT!nOkzeO2|Z*Nr~F*HG& zHSUCnuTEuet3o}=s=-)C4Gv;`{jVB?N;pNM%HhzpKFhAbQ0OnbL=7H=k&^gh-`iIo ztm94-tn1TSBI->S{i@S(xOC&n%>FGL)|bF~M>uWArnXYUQ)~0cn!WQO>%C;&2*<;E z&0evlx@&PI!=oC~Wn=Zb4|WxOm!sxzJ0r90n*U+42$qB~@3O8Wfvbw*$bS(oa_e?n z3N?b=Pu0A7V_L&hxKede!`>Skv~IlAVT!65LV!jyV>Prtk2p~clUj#Ph%W0(;;(Yp z_8*sf%5SNFl}W=shvDc;8OH0g|B;3ouCztA;d`KZ%q0xJB@HJ!43}GmO)AjO?IzcF zwc)V*1y*NQJccHB=WAS+C)$>~L3i3EEKik|ckXWR%DQEFoV5Ibv|P>{mY=zlWxN`E zugh|4+wxz~y<0Tjn8Z4h%DCqowmuRw)~B&_X==`Hv0_VJ%BIwYaUBFx6f-Q6;%5Zg zRH9$MTkaqiI@sESjUs9PF)`<*G~$XWgArV;m2_aJ&YWgBL?Ug?bIrpMpE_U@8s#{atB+f zt@>%fgK7GKbWymnSij;sc?kHpgD>%rnEYv`$LPWTrr6MNfc1vV8{yfg&~;=?UzINU zt}01E9@lds!p>@$;?lkR7jeUuRQ;uNb9*C}D$cCJ7Zqf$#Faa2Z4*Ck$<}v%D=uuw z@)gg?jM$)T~S`RUW30vnZ2*5pD*dTCwuur1nj1 zH8>gg%}c7GG7^~Ejr0*GKh7YJsxSUlx-h7X7Ny_3OWt_0xadB~NQg9CkNiF{O@4xrB}>qRW>h(O>VfhMN5> zhk7i5sT%;g-NG+N$SsK4FH0LOMe#SH{q_NkIH(WBJ=+I2dJxpx;^XZD^vSzK{8t6h zJ#5qSkBI(XT@gQ6sl>Fp{|MOf^3yHn$j{gJu--3VLnM}v80k?99KmA12eRf9+S*gHIx&*|C9kE^Ml~QJ(q>XmUZW{M(OB%4aC&8kI@_q5jw{n2>yLQkp_FtRO;6?hw z+J6nF)|+=i80H+#?-8evlYI+{=N%STd?#mX{2+&&S%>8eulmlKGo{klv%6!vMO?~; zzc)W6bvAg*7i}9;p>+6R(SNsfMa1l&;6S{;J2v_oxPI!Jjxe=*P|VL?%MPq@1W#hf z_p#AcU?UIEB}C=uXXV#A6@tVEjhDBJ)Og#@C{F?-lXQzzSF{ z4}A~GyL&J1Eo~I8!M<45;ppB{{YZ_-`mvztYOFof2{E$Z<{wKNeG0ZZb7cfR>Af1+ zRmdI|SN)ju?7q^N05WjEsw=UCUcGN{+@nC%G+Hg*+BaCARzpYoqQ(B$rhRM!&yfyc z>@O9S-^S{`gK`!u*k7vmsuA1w=QX9X52}b)@+E{a#aG{^$G3E-9&E`>vWoP^HDY0? zFnTAp-Za<+2Psw+C+yOnzM^PV3_K9qbR{@QbClFP{eaZmbjw$0CNApJ;-UR%VvB|9 z?|daAfj{CJ=KdU89B%z!AyrD}U(s`rqViyD^aR`b8r(60^$iE5a(%{E6q$$?hhp_U zd+7GFUU@+DJ=BTBaN++`m#frVth@y-t8-~?+`u@wnq#@*gZ;?4LmH%V&WmC zx*lt-s5%_Wz7roD&eq!<5c>{G)lCm?w;Gi!MJs-?YV*~0asN*R&0m49rSDhZ;Ix|D z+3(`Lp9)3Y?u zLuul)Eq>E>IS&T@92?!m7JDKjZur^ihzf_?T~coA&z9LjnEkmR`W)N~nHm)m#Yd%# z-ptat;Am|0k9KKkNW3jen~T~5QE|0jHgs>c)Y{^gQvHW7#jsxrnl7_t>cm6842WCr zU_B;Q{+uRG{8AeCngiV>(TZcG`us1&{l~gBy%q}cQKgll%h4pU?bvF4=$GQ*BI!qTk-}@l*XOe)=;;6srt-`()I^|Vra3}^ySNG zadT`>u9kTt+#Z#RmUwJXxw&ZId_D{)lcEtU2&5)PtD3rv~7& zMGfY000*(>PL=AjrI`iutvvI-d1;qZW_u_7h*!=C$(net}>w8o%kY6Eh49kA-_v1^6Z9K%rSI8R%BV@iJ+y;g>)iqfjXpOfe98W}V|3b|9 zEtf46i+)S)8Nv+;;vWn7v6g&SnXd>pg?u0)foDI^czNI>ywKp#@$MJm)Nh48AFA{! zRq2uD@(u!Bb(%-xlS#!Ws2pXfOqKbH@UbuOh&p)X)#=AqZLrXO1B@1k8*#_gZ$Dg1 z$1-$h5&2qr_FVGgog3oEmv7$EBDJ?Xk>%#5W~{OJU`SL+0FSQ+v{}SYUjIt6Hyrkd zS0McGkNgj<2%tZMtx$wUU(#J+77fOBec&Ih2g~PqmC3+mIrJg(71AU=V%89GYP5 zM{@|rJ*y`P?~WT%=SJ_OhyCkq8;$C1KjX0dIN2JHKxVvk6RSk#jc}9t_KAc4$ze4j z^3PJwuMoT!`$1HqfV!MIn$k#Nc_1ln{wtHX^Z}oX7yl}VO@aO1%3jT1 z9eg#qzp*uKLyha3cmM}N?pk^vMZ=(bn*104;7jl)+g7NRYR<}G^fsxtv*)um4deJN z;sWI+=~{SL=8f=}&&9$sU8oW9e|*-^)ZD!?+=vaA>OX!amn3gEHu~S#PLgxf_llX} zE21|-fFgoZdnEH-Ffad%!U56oY;4o}Z04^-`Pl*SPdk*av-saUTdLplncM-LI~&`z z0{n?kuFjg#960zW-q}&}0BXJm>pIP{cc8Hnx|76+zf0qXIP}l9^e_9nRPXkg*!Oo{ z*G8ApjZfg!N?i@1^2@gF>CkqS)IH=}X?&bRckex7-nl{gUt6i(ab-;!R*p{uJCA!F zP5DZf((7%dU7#jWDjj&fG;aIWhTc9e_}^(FaK2Q3U+NXL=VS4f1nKiP<#)RDW!d_E zhlZV^%Y^}P^BuZ2N?k8sDAi|el>=9MA-3rN?3iib7J@xVw5aQmdJROJOV!oLKZe^6 z*b_cb*Q1evY@K+pCR^;Ti;a$hIE9Qi{~%7)brHV5()H}E6tF$-#g|@=n~bqE92`LR z^9xv}EI<1x%8S`2RvAusFC>{A845EY{LQE4M8>-5*#A=8_J_HWv0@U7d;8OdUip#W zG}EJ7D)FjBc{n>|4}N}u7K+I@fV%~2JvHkCdF#M@S#i!1&Ch02u|o$c&8tj3Re*)B!uw^vO`)5e>gE@Rkwd9~ZgP)xm{YKNiKq}cH|n^)$Ia48JM z!_f2e%V9Wg!UF--jnFu%bYw7w9~wZ7VAAU{R343xhF>>tY{HVv>F7i`CANHGzTSwH z%Ng+2C*&v0mW^3#@dKCY%uo!!mFznnqfU}}BmDCx=CzGktN%w&8nN{a9O-D_P*ULN z$uL42y2<_}cvMdg_&@jLEp$o{S8u3?!%&IrIk*)Z(vq{?PliCR0uS{hjQw{{2I4N+ zlje0z@QIG`pP5fJVY&Lq&&;=*u+)tH@FnVriSx5J$#3}$kZ#JH*Mw#1eLpiVfG@HT zm`Dg0>6xFHgQ8eQ%PSDDx(^FqiPD~o8q*|1p<0Wql(nbEYSn$D3kqhvIm5G_eQD4&c|qFhMFceB-kiScwzE zw>~=oD|BLb&AA=0_D;;-jJF0xpJlAq7iz|{fWZYcV0d>w9hfh}2?i2)GQbokrZwly zfF(FFZ*v|EEXIl9#ob20=!1pzhCPW~14fTxptI1hY&r`I@BG-p@RMj}L=3x1H$IlX z7xL-H^m`#Wk(JCyq8|&H(itMjoWAZT`vo7VIMC0SbqE)Z9cWfEKYkU2E*@M&`?r{r zV_B}}TBu(I8NBg0k`{UcfByg$nucdXry13zKaOSpUsR{mt6smwJPXx&w~x)NIF{FI z>lXZw9MpzJX|rgyRw7T^-4Lqx6KMK@o6uNomRv4$`%oIDpWR~4iDNnc2jlpfm}=K! zTg>foEH{y%4cDSwi^wpP-MD3~9?u%F|9{##ZZW$xLsQ<^VqV*fz16LTVT3~wjS60& zHZ)+{s&j5Y(pe^CY8JQoG18CTKH)W=<^27+aa-7@i~yj~r#Zi<(Rak2ZfE zQaT(y7?E6XAR=jn97=q*=9LSu=ff56v#$6nW!?yn++x0+z`C*;^Kb&Y3`x7@xQ=Sf z5zUz=`TLI`6oX2}Se2aILK|(?#X&97Z_d)Yp95o=Eres%tFoVCGbSZ!qi@7@nqy@C*Du&eVSfv=ED^#-A-q9N zUVIv$J+*KET0FpN@i*rwZ-n=O?_I^GrJGNa@GgMM6lma6pCmjA!lNwV%_I!^bMP%x zeBN|(4+#eWKBquG-gYP9u@D|>3BN_cpx1!!Da98^H#;Oj_)UO*1qRc({3S!jp5k95 zjQz!8@Xb_wp>z|k|D|_d0C0)|JsJFaVx9)e(=5x6%DfSt2fm4l&zoU>LBewZj#D6B z$p4s_heLR{B|Jmsjqv^88>aYz8D?fOgr@_nP+%y7uO#MMA$+SPOuv*E0(}ekdMQ3F z)4UzR8P@?U0$AsZTu%EgUAKO%tMNzX!eo{eOKru1O%uGv+?p&WWNk8QZJO~cF*6~F z{95%vOv(fJn}8ov%L({1B(sr%K(EFemx7Ns9r@5)n8I2iyCFrYIGln{1bq4-y;zSq z-15KOowe1i)B-u?@KlzrAG%0G_ZoV*??&7P(C^DRL+0q06{so@IFB7$YW3zc}CMz6tDS>)}_-?{(GGHH2k$ash^LQ$6Gw|U?HG%caxc`TO=XoU~i{3i^(_ADX2 zi)7viuh?V`Yt6d13gOvTf@~iaddH}KM&^z1^P9}YV9||^=APEj>fdDk*_z#?`#YNB z+aT}VL|vO1^Jf$I{tebCw6&m_Q!P1v;C*61LtvPgt9LSi@)e zej-u(X<@R)W!?zCxRH7hV^PGn5TwQeEYoG)2+!JRCbnZ8bfb&euN@k4>qhh1c5IsN zDK@{Le8oodNITXuyGFy4db3E#vBPL9^G3LEquIATyE3vy^Ou-Uw})8rM)URd>}nuJ z2eXclzdkTC3fPs+u*8>guYJOI{Rifq1z7)ge_*~)zaCgUR;SVEE?MuKVO_$slYptPTk-{Z@pxb=?3NflYuPjfAjRDnc8stUckkU`{XE~58)Ud$vqAnmpE;tG zHDhIYWVyPMeS(DZx1z>UtIk#GCA|4I*ca9q3s59Vi%U{OMnV;(#jT= ztFWS_-AHZaLpb`in%0*OA$j|`b<%f+VjIkiXy_rQ-U?l&Au>C|2@IH{dfv0 zr1o`EZ?GSy#yTcgt!CgyUV%9#SgjV&cw=CW30AAoce8*sOfaoh{*1;sRNOJaYPBHa z)ELJEtJOR@{~efPg4Jq%ou35em|(S9Nasg^IVKn?7{Lz#b4)N)FoN$}Z~y+I*D=9X zuD2#w)_OU?URy6GSYtH4mIcl2F|36-wUj*=iCQ)?e=UWJDqC+xcV+kLEe4p6bY(O2 z7VFJFyRtjSh;=xp$2o%*seMg*y+v3YNsWfX;n7sq8IM*2a;4MZO?d6vMUkqNWc~)76b!M;b?1rRwz=Lz%@WGoHm*t@*=D)kMR{E-S z=I7nvAeXH(|Lo54^v|o!tRC>BYpTtuJy@sKwdzM(cU8+8{B|R1K+`&v9ONS!FF-4L zu$=5#%^Su4P1AA}*1T0#j5}85vD~jSFZ5uA*$1J7Jm=li9Q5w5E3w^i97%4Z{&J4tWhBxXDq34Aem+n6 z^6>U*b7L>u)DBgf-}YkpxxCJ!w%W`nV;x%Iz$%eMJ3zF9CAyJBLBCdQP6Ugt z#hLTVAR?;G6=f{5l_#Fl?+%AbAW~8;+q6*T%fpXWn+MC-qgU53e4>>OxPE-!I=?-P z8`+0CBa}qED|-zGEL8pt$|;pL?L}TgCru`Wm~20SD3b|EQLlm<37QSyz?Smt#jB0aUAND;xu+iMSy)V93 zR-NHPyqxssK6dlfW6(K;Z_A6mw6*R^?kFi!7_aTR3AE?hh9304bY3e{fsaj z=wOAYUW_u?%pmy6jPQ4B>&!(+<>ZC>jie5tCjCUa92c3#xY+HBL;C`cTSw7SCYZ!m z5)XFCi^dvZbGN}_qbjIX;4+H_vMe*YoaMLjBy$sdbhGZj1U!$0`dlXSM!4X8b67dc zY#&UF(7CTeL~*3bS;dGtEW)en3LTpIEL0XHe^TZ-txCBPTk zy~F}(oO*QlT60BzOs+3rA8G1v$kp?pDa6xjt$BfX)~q$NE@MyW^C5E?D;|@05pRm* zJ--HaAwxehAMl}`K5GP?m3f4}kfHXqrV+?~sCo(NM=l;Cy90e4zGJOfT!E`M(88Qh z!P3(v$aWavU!Zpp?#NRcBaL)(eg&I(bs(KDCcSUK&Kp*L43l{y+!b>5{ed=rO!ZoV z{#fGZ58#Wjp_6>n9|Mf=k~QYFm!qxOYt8$SrY?b8JrDHA!-zJ{uwdVHA(I1B( za|IilV&LaiU>0j)l?u8-Ys^osUq(8OB+&IAMo#O-0I}gZK8R5oA7u{s{4o)>P2eO$>J(+T5 z?R?LC5%YKAaPUyim!s!Hm*J4ZunsxG?_sg>>D6?H)Oq;v2k?;Z;pzjIHRYa3-X1u3 zl|NOE-l}3A>$81pz;ggN={xkEnQ_B$ zWWU7*l%7KQz}CG4x=B_ua(FiJ+K*lYG=I!U{KU3=_Tt_5%)-I!p4L_PC>jr3RuP^H zPO8BHYZ=8@;A3X67WJO_$zYb%Z?3H!_xqAxL#>xWroJEWeGRK08m+jn+Uke5oc$1J zE&IXjIfS*=Z+XwWVF*jjoAtli9BNbF<~^&;7l*K{%ZA(5yTbZn^!_4Pmu1 z+s}WXjU&fX6Y=~{JUF%psnf9-;CKG3ZJ~=w$Z03c+3eYV+Ew z*r!cBcv~1UOY?S=d?X8??&YNcuimW$uF>_PzO^k<4?22OngnDF}-_Ax&upIx>)kYdy`n)<5}+ z@)hB?P_71pv@f!2poNOe@uSd!z$$a*D7LeY-GZOqwe)Q#`55SnvGm<9^A+J6ZGG3F z6Rqt_MYv*>`PgWdH71hkLQkHZ)0YPh;fu$PC(q79@6rg?&;wq4Kbm?Q9`SROkw>J# ztM384{z~my|E_r!y07SN+bxFOMN9DOztBa4H;C@$!5cjU*#L0z_Dj*mC1|UhBnG}m zYxmWPcg-8FMsH@VGUr^)(uRhL`5f6zR=3f7EU>$+In2>wa8Z}xJ<>a=JQMtx))R7B zGG7sHBzrO2WMlAi51|q>dkjk-@GIIyFNf%`Pkr^0oj>@1e+Qj8$cqA7%IgWw)Wf07 z{&IstTgv*G7A!S=P^N$PuKD5^R@MqXcT@zia+Jh7B(F zASi`bGN6_M%D`AF>T<8Uj6>W(8z3S2d)Sqn83%r1P_oHLd^+@TZ6k3xt7 zc^OnAK;H_Cf@+5DuGi)1Zgv=lDo%OVykZ>dkcDF_3g+h%F9pwJ7kOzn*xj5@yrbSV zSAe%Ij;`J&y8}=U#3VEZ*UG#RE|>MkYr!kcc|%znGwT}G)`xr7eg4Yaqdy61$*)_z#Qium6``Xjt}xwb1SWLkK0ztbC24U^4xLt9E4sncPu|a_A`NFm_9R3*`?rD!5cDfgukycpS^)iPI?ORGH$iwDlHUYHk$w)tE$X`39PfOH8RH|9~A&2U9Tdz zQ#LtSUrOIBn80%I1c}GXvXK~GmWiN4Yiv&N zvh=(O&|~#Y6Mi4bWTN_5&1nGI$UNeWDms(IaimsjeUgg~WZ~_0)V*VMuC*P(N7Qk$ zs%Uh67_MO@xsiwLN;h#<+S`Q7(-WMgQ{Q?KIB3R6gETc5ad(s z&d@;!=z=P9*o`cGT$P4NNml=fTETJ`vV4PW`LJD6*;G8hSSl@9bB!#ANEs|Ax-I*o z%uUd)H<4CSee$Yo=mzQZPdg0uv<+@@8Vp78W-f#4ZG$JlcTrP~raY2(9WAZ0TY3<@ z((L|UKoDO>mAP@EoC%?ctOPS5`6ihRw2}vI!UIOe zJ8Re6#NJNQYnPk1+>25nix@}X%1rcJwf;;erZ78c^jYVFBK*v@`yjV<_@BD3ZbwsmdP zR<B=>vT()a^!k80i_LZTdn_yrxwkEsDoomp1(_)Qte385ioN zBOQUX5^01w3skZwSlfS*l0*B^?I?!F9qke)$09ce-ZDui^z za8v+k6EK3)U`nO1aCq^5`3Dr?dA)0qX9(z<3iotNFPA@9MaXdpan>aZoN>q zmC{KU>Oz#xK?RTokhW~DX|cWwb-j@edH6!zGf0mjeG}>GM^JI3QFAZU)grA#nve+j zM^Ry2pXsJ`Tf3??bu^=@z7?ks422s7p@Lv;{~@k=7s`jr26q zDM%}yLF4P}c@&1=0$nFC)DfX^YAWb#swUN4ga038Y()R&dB8 z4I+(91>dufNBZ2e7kqUUAWi_d8R;Ye1xRa=E=4-`IVeE77wKW7zx(n$Rq#YMP9_ccqkuAXYFUTVu_b-fH1&AsDHzSRD5ekrc zkuF90KGH2n6JCM>q?3?FrlTcD+aPW6GUSm4klu`R0iKbXi*))z$Rj=dD&&z~hvnoj z(!)q25%EMVf;`dZ4tb=$T_7qzj938$NS7gVqc+Fqn{k&b>J@<`uAx&>*QYRDsf0BNKLm-{-%dwiPq42TK>)yXYx zs%`lH`nn#tsH(JmXD;HXgo6kWRTh?X0-*e9U9%I~8%1i(UI2XGWP04#VF31;JL044#GUPC-EeIMe1&A=*P5ZD0he;q3;@EEWg zSl@y505}A6dK1y5Z(uOd!MfAao} zcwjv+U)~N4ARbr-tOXjMAs$!_>;{eihk&Kt&yiq0CJQhfSn?Mn0CoZ^fa%9hTJ^w6 zU>mUK3+!gV#xJp(0TaH$CbR%u3Cse<4W6`$faSnSVDw)x34x8kc3{TWC#^o9aU7c% z(Ax!)kcz+|Bmjneg9N}LU?s2#*Z@rW772hAz&>CQI0{Vt8{!wDr+`^NV;J$kLSQAZ z8`uC$`8(o)&A>ij`ge$5i1WV+Bq0r53Csdk{sRes&JiR4mI51qj(;KnFaYcWhMhnH zU^Osd5#|Ok3t03o!~ z1i%QxvKoNJHp^-UwgLNqDR#>m1^R#qi_rjJ7O=pytRi4Huo9RVW?6n<6)*_w0QLhb zCRtXxcL`1xkbGcpie;4plOimu7FcnbWd(p;z;0k}q-6~O8-UKG7~82x04xLM1D#I9 z151Imz=$Zs151G2K*u!11B-#q3^Wigc6if4ia_##y})vyJKD19fE~aVVBr~-)dL&^ z4g;%WEGznKbU82sSQKkn1;8F)1u!)Z@xW?e3otz%@xU73Ffbzl@#o;INwBBM0@wqr1NzTI0$}A#%jyNT&$6r$V7<$-;?BkFPqM5`V8(pQDgg$7RlueNmemL> zNyCr<>wta0F5oCIX)%T@6Q}bMFUAbSnTat2_ASSl0SnK^m;?R5c3^`W34mGINB|4~ z6V8L*3d?c>>o2gZVqis%W%+>ZzF;7C>Yp%IpTnoSHd6Y z_$mCd5PvoNfaTXiX+j%t z7}yJ}x)nnKtlWf_EXORbKtq7Vn-K?eZb3tU4ZwO}`fZ2@76N;LKH$i5<6NT!B<_4{ zkHAb|f(HqJ`9Ke_4OkD1e$cWyfVmG@*1-AVg@4%+FE3btQx<>j7>s}xdM{S8QePi+@KySpqt_5PCg;^E+pt9d(gfsW%sfzspC+i1T6r~K@#-c%DGMIm4%!V` zUGV5`&>_(Nf=6Go$9tWapCfCryC6;;vQv_v6<>bRGSItnxVIy-EHevw?iJ8uNH@1n zI8|mLY^fV?r2&&}-?}j);eovpb~&wKPu~^3d%~56KM}L0+b2wx9Z?U5&JE&vn|*ci zG4Qr>?3H7juj6DcXpRY(v$u*5Z1$Pqso;ILiaoLR_z8L7PO)KveMWd0sAr>CW=C^t zz(+QUb&@xO7j6 zrU|_qJZUre*Mb*q7FR=G9ssY{j7xH=zw1JDlN^{%=sxJ&F840S?uoix(tZr~(aj=l zDsnp}Vi2}a15&{Iw}_i3*yEFP!E~>c3*};O*2;KJXFt@e^159RyF`O8wdoUb9vCi$Iutf{k_8B&?0wD32Sw za2xp-gSW8m10Q7F51v~|{y}hGCFck4t5p3NZcN76eup>^jyk)*+wS1};6rzCe(=2Q zr2D|Dwv+A$?`J&-9_Qu!;1yo-H>O~jW8DSr@Ns@{w~zCKH?Zyl?_ur-kGPZkgWx&L z`@t)jz;9d7oefq(}s>L4Z zV_@!7REqb06UT2XB0U`v<&_^?vZo2T3=kq7Dz@ z{ZW}8eBeQCd-9qB>vQs({O-OLSaDw&Up1Cg@NzzZIu{&0f_9;4V|@HnB? zs$?H{rNAQxS`XAVe8re`#t(Z?h@0iQ7L;-I+>hY-^`sl8V<%?a1>VoP8$9!I?nm(Q z$GJ`5z0CdK?k6}uc>NQcAH4es9w#hT1y7Rh0CMvTS@Q1!Pj4iBQ2I2I9)Znyg!NSL^j}ar^T1nv!TG@l zS+4;ve~$BmH$6xGUEry|5j@_dTGl}665$Uhal@>iT+UV$`oe(=m@(rdumS#Jg(X1xpC z^K0@S1P}b0_SJ~#xX9TsrXa89Wv5w8`_N3%u&L z>bfR;5WEds_0J6K?|6SrUYDeTS1`{5Z~h-TPs_j^t>jY!?#7#!@_MBiyrEU>h?Duj z^V`H8$p^s)@tUwKHv$tg=M^e972NX**B`v?7240szz1FtYo^1$20VH%>CNEoy;N2g zcmrNHm-QS3@7YUxY{Z%9hu?Akg9m;mBIDtc2X3?zF9XkS=lX+Jmm3%*}3GhiQn4UfK19M0GLU6XfD+Q@5_ z3sM2>jlUP?%s^fb_{i@?8ZIa&fTjn*N@6MJHy&cd>=PaI&H z{|6DDfZ7*A9%b$UZ+cy%O(*Z3*Tq)p(gxYzL8(D|JE&hrz{Bv{<8ln+P|4yq#0lx1 z310gK`4ob;zab)JMo`Cosy3*5zgQ#d3fi!ra)b8l7dv7}O??x8U&BA2#Kx^`@X9QPLOvAy6mZ;2faa_M-BE@9&mF|FPfCuYiO zgLl0xzK(+nsPPUJSc^%uKYe4zB^v`cT}Q2)!A+{zI`t@-Fb)KZ!k(4}#bHNgR+oA{lu;;^hE*_#>Jo zdEogU)2Nk!SA9&UcMW*o$K>A(9^I#wl?h$o_2QDbxOEx??PfV*9?l5yl9W?HYd+z{ z7~FZ7vXp`69_Gauyo>c_@USD)3tiyFN2nL%!|ui-G~~_{%+!9GIO*V(#FO*Ehw$9H z0kZ=q>3`fPmBU{4DV1Lf-uNlCIsk4QrIvPs7ak>_A@JIxYO_gpo`pK%S$UI9yaw(y7GO!k z)An||%8_pWb)+gY4!R!?(bFL#x2pHp8_!JG1F&b3U5#(vn0_mSy%Y9A%1dKZM-H-I zJg^)8JXvg|(jck=?5n)D8K)3PO`*Rqqgbc@=K8P$>NE# z?D6NwFG2<5jh{jn-5+) zMWoF~VHMy55mea3I(!I=#0Lwn7Pa6*FcOdI$DTy|WDcvG(F6O?RPpkBdtx}gS}}^F z#78oFLK=*xixZM(fj68k;unAyf&0%8%OtM^&x;Z3ByRwB#EPv8?90OYz_a4TUa60Q zr_2x^Nj+;3ChM6ZJ{7zYyx%3(rOH_FtVH}uF_zUq@ZP!NZK+3KR>q}>FH>d9!E??M zkqhnf!;8VQ7Kr7N*MfT%;me_6~JD#6c3uoPWN$@-`gu-FFG5K_~DCLre?v0F|(u&_7T`q#>VHKiuW2V za4^orqx3NeZW@!I2liUnYsT2ukFgKKJ_>u?82hzj?9oebVTPFofw}catT}0-6uz8k&XNNBud}Vzskj~rOk=9i#zlnc zPNVcF6&r2x5>*ebl$ebZY?R)d9^-1@5mCdWFGRmzZF~O zA+P84?2ve!cfbhMbzZHH&zocy->SUR#j+IS4ZIr~uk!|zLUo;2>*Mnp$>L??vp3BU zM}gkn_d?@!-mq=;Sd?kFBU@OI77%s77zL^%^wk|YYSE_%u*edO1iJ_IlFAW&@V_HU8 zqWHsn$5TRwjZ10R-e^s z4Yr>3lnT-dl@$v%>&_n1D_P&cy64+a|6QyHw<+DLzPpq$dvpQsQ$U#%alFZTSiM_) zu2w&B)5m&C3F!^2_pl!K0_nPk8Jh-E~K({vzv@`$P3t zbveH$y}+QOi}n2HNLTwgOov%d*r0SVFU>q_Nm(B`Rlz|Xv0>EM&MRnI=->sc7j6-E zrI~3j*xvmS>3(I!pQ2)Y;7M^b&Ad7)>`Kb3E)w7~MO?B73wp^LV&ft# z6{AivXL9%iTz<>G_i$QWTny_Ox4M<5*5|UGcenTw`QpP~47Fdwc3*{9l8!M5en57Q z%3>IgvOV)cs)xEfg{_hGmWM*~y{7YR4AtLby9X~lOc;I zUzZedM6({z?N*;_)lb8i!@Bc%(sc(cWxZlO>23_VJXWx7>~yQodFp4DVf=&*j)%$6 zs0A#x`yijjI_^!@4U>9S-8CZSkkH#_<6(AeIq4SHE;Sd%*YJdMDKjn^wL`gh0SWA$JH$so z@6d=_dFXM8b5Ko+=kdhi__?fi@nWF6Ka=&rEuncXV7=tCP<<`yaivO6G}^d;o7hk| zNCDk8GF&cpo@>U6V20^fUHKl_bl>mfm}70ES5t`bEbCcYN!N|r%laVxw$#~}6PX`| z+P`Icvy1e8gAUsy>Xe!}r0bP(D(mTQlU~aHF4lv*h@`N-jP=x;l>Y)lPr5a1=vhjM z)XNSCx}NpEcZK~NGwn)GJdKLFn}_`owjbky^yJ&ax;vTjx!^007Sae=DpYSI1_ z=^jp(Bo3Zu#@fynpJtk|i+{{sx&I_DJuTL=?tg%EJ?}SAv{z&!iFYS^9UBOZZe+bT zl{&88Muoq~di6czuY2Ha)`R~by^h?C9@gF8k*;U?7fLt8hv%75UW=VZs>n%K)fqt@ zP(SWeNMSvW_w@oU>>Sn;E~ZLHaHTI~z2oncUw6?}q)#)V8_5vOiRP+4^4`L6^>33o zkImayuiZ;}8|yn*Z%ZV-hxJ{omvQ;}EO?3aoF~ZN!~SoPezno@C>g5R(8mFV)uii0 ze}yjRanlT%Sq}Ec6jt-NV;A}B(V8T6+?bwzW;}c3{*F9~IdY-)@aC|`$j`{5iaqjJ z&ub-J4_XoH2}z{ux@=}WH8XT@cCeoQI{CMA{-;S_VH9j8gC4b4bfSAn*99Nc`d>&7 zgi)qX#jROp>~#ERK&mf>-XwE5S&d2JX_!~dh~&9;1DSnnUch<;uSiX-FV+6VwT9M~JXJE27TFLir+_i}*BX;ILNK;~sD;MGy3w ztascMs(+~S1WDHeeT?-?&Yxt^ae{RG+6`aS=5j|(aMF;J9;8INV`Eq^Pos7O**}H# z)Nw0xI_m>JBL5oRm2z2ks0Sl>a@oflf#ta8*AT(^xkGr0aHOv!44&sQ(qL zSMVwCK@NHRjP&_N@HV#+bfUXCAnr68sS#y0j2&Wjwi&zL&*tLagoeG$dX0;87l*yU zddf=D^=^5D_0rv>>*9~8Viu3GIpcrGtb1Gjrljna_RmPy-I6GtUV-J;&F1J|g=TG| zOQ*}&oH}m3ELPFiZH8G6iW`*~>PTcEq- z&@X#U@7x-;L4=ecH^CT8bg zeMvl>y02$HIqDiOX1)9s(rYQNk ziq;%lh*jyNLv9sRpne+0PS)ebwc_L~*(tF`8(-0evH#QT-+v?J$zy#F>&1IW*PR{qe-0#Uiq|^ju$z=*iQkv;8$4>?k2sF{d-ui+&~q|;0^N6tY^GN{%!34 z9qS|4lkS(gTvMl>p$B8OWLN`gX1k^F)RwV`b>}wHbtj(BdT$O@p_r@i6V?MeLjB8F zZ@DE@zms&YQS=8g^cZy1almK=>AGO~j-ae)3Ex_2{dLycc#F|`59{UQP5}J>=qgYB zYMCE{q2BrjNR$N_yq#xC4Mzm)MJ;aiSr;&q^*rA6^fb<3J-V0tt5lR>T)=t~-!iGe z4uf%>SiB0G!L4l1>Y})Aj@!z5*f*qmSig_;;O(UA$y3jI=buT}^?gAVGrgV7zU^ez zC&2+_wjEZmc!<5)?n;BYN`#b!dlh`-86Xy z`NHK!){S3=`fp>sY*(nhll9U!N!M-glfJ?z=LxS3uW&%uTNF@Y(D4TA5$}?&`?gQK zv>JC9U$8lBBbjw;M_6w-NqQV*Gw?sysww2|5A}}{Q5PXy4E*E_EBlnp4jaX#uwLUQ zJ%YRC0@myJvZavRjmyNXNH^gMX_hOh?FR8Qgy~-PPk)f|=s}w*4#MoMV{_AYWUk_L zFSG98CBBe#`Ahk-x{VviU;SnVZ11sNolB#b!b`vr*6W`of8ASuCw;!r_f@E2+H@+w z*-UyNlFK7m?94-RGT5B5-K}J8UM2Ry?7a$Rxe90fmZ}k^oDAb84$C-1VR|Rqs!Ll+ z{$1>UH|y;$lYb-YkLoMX;iV@js@H8r!&21f&yO@)l%X-b%r0d=9Lh5wHZ$;U{nVRH)icnPPwT8G_1>2%o5Dr}XH&4aI#S@-3a?qY{o^K3E9+%^=cMQG zJFM5QqICFXTpb_lVqB!N)sXL(%SQG3NU37~5z@Uz7;mt;fHTgdfD%5J3sic;n8$h& zF9BJsFNCgck*4G*#ld<8``0|_R*D{+3s`qPF7+Sb>{e#OSj&bWZ#|W)7qeb4A_MSV zocf7Zk;SK%VSU`n=JFTZ%Aniv5bG63NiX1rKLuUhy|j;8AAiCAsrQq=uJ2yfOL>RU z`QIUZg;BaKG~g2sh~Rrko#<=U{e1DJ^$F^ml%U-n1x*Ll8Uz3pbw^%-TGrMhUHQJP2wy@#C+18!&k zV-K4}0mi`EY(pOH>L*?WWW8Frm7+T{SKN6yu8P*dtey+3s$j>?VRF=iU(I^+rqBe> zv);QgRDVWwoNcelzy1UEs^`Ae?f#1O?#&dfm%)Fqp3+FVi?{koE}AmOj*zbN#EYk| zz?50QX2*Im>)}|=dIB#Yy7jAAAH0luYlP33pR!)uM0o-R9UEBhOD6wZ);E#vHOjfy zbiMB5fI_}T*NL8Bz2g(NArI}}{?s8`^f zOn^K-c99|aQ@8whs(>$Cq!0DErF=@aT%-qXp_a*C3YW)ev!Tm{b?C zb&p!;_n>L_InD@r$Bfj^*|qAPwGLK!FmIzhTleIx6Ydn1&;bmNgf+M;Y{iuG6F9BO6Pwv2353Hi4Llpt-AKAFAeHrm>q*z!_Hx$i zdqed#tT)bST~}mYJ6Y_%-n^}K^$q6QDXq;LO-Gp6x5aF2_1$JZXKP)0yE(xW%dRmK zTW_p1@3e{io6Kl&+IF*}^|S5fxAxZFJ585qcU>t?RGDd$_4oC7vvkQl<~h^!E30jr zY^oJ6-YmA>W2QyvS5`}plHMp@xyM{I&3T;q+IgJh;-#%8?lDiAc2AZ#ald)a 0) { + LOG(logINFO, ("Setting number of frames %ld\n", val)); + setU64BitReg(val, FRAMESINREG1, FRAMESINREG2); + } +} + +int64_t getNumFrames() { return getU64BitReg(FRAMESINREG1, FRAMESINREG2); } + +void setNumTriggers(int64_t val) { + if (val > 0) { + LOG(logINFO, ("Setting number of triggers %ld\n", val)); + setU64BitReg(val, CYCLESINREG1, CYCLESINREG2); + } +} + +int64_t getNumTriggers() { return getU64BitReg(CYCLESINREG1, CYCLESINREG2); } + int setDetectorPosition(int pos[]) { memcpy(detPos, pos, sizeof(detPos)); + // TODO + return OK; +} + +int configureMAC() { + // TODO + LOG(logINFO, ("Configuring MAC\n")); return OK; } int *getDetectorPosition() { return detPos; } -int getNumberofUDPInterfaces() { return 1; } \ No newline at end of file +int getNumberofUDPInterfaces() { return 1; } + +/* aquisition */ + +enum runStatus getRunStatus() { + LOG(logDEBUG1, ("Getting status\n")); + // scan error or running + if (sharedMemory_getScanStatus() == ERROR) { + LOG(logINFOBLUE, ("Status: scan ERROR\n")); + return ERROR; + } + if (sharedMemory_getScanStatus() == RUNNING) { + LOG(logINFOBLUE, ("Status: scan RUNNING\n")); + return RUNNING; + } +#ifdef VIRTUAL + if (sharedMemory_getStatus() == RUNNING) { + LOG(logINFOBLUE, ("Status: RUNNING\n")); + return RUNNING; + } + LOG(logINFOBLUE, ("Status: IDLE\n")); + return IDLE; +#endif + //TODO: get status + LOG(logINFOBLUE, ("Status: IDLE\n")); + return IDLE; +} + +void getNumberOfChannels(int *nchanx, int *nchany) { + // TODO + *nchanx = NCHAN; + *nchany = 1; +} \ No newline at end of file diff --git a/slsDetectorServers/xilinx_ctbDetectorServer/slsDetectorServer_defs.h b/slsDetectorServers/xilinx_ctbDetectorServer/slsDetectorServer_defs.h index edb3c32b9..391a4b327 100644 --- a/slsDetectorServers/xilinx_ctbDetectorServer/slsDetectorServer_defs.h +++ b/slsDetectorServers/xilinx_ctbDetectorServer/slsDetectorServer_defs.h @@ -16,3 +16,8 @@ enum ADCINDEX { V_PWR_IO }; enum DACINDEX { D0 }; + + +/** Default Parameters */ +#define DEFAULT_NUM_FRAMES (1) +#define DEFAULT_NUM_CYCLES (1) diff --git a/slsDetectorSoftware/src/Detector.cpp b/slsDetectorSoftware/src/Detector.cpp index bc7d138cb..0473c3c9a 100644 --- a/slsDetectorSoftware/src/Detector.cpp +++ b/slsDetectorSoftware/src/Detector.cpp @@ -653,7 +653,6 @@ std::vector Detector::getTemperatureList() const { std::vector retval; switch (getDetectorType().squash()) { case defs::CHIPTESTBOARD: - case defs::XILINX_CHIPTESTBOARD: return std::vector{defs::SLOW_ADC_TEMP}; case defs::JUNGFRAU: case defs::MOENCH: diff --git a/slsDetectorSoftware/tests/Caller/test-Caller-chiptestboard.cpp b/slsDetectorSoftware/tests/Caller/test-Caller-chiptestboard.cpp index bcdc91af4..fa4c278f6 100644 --- a/slsDetectorSoftware/tests/Caller/test-Caller-chiptestboard.cpp +++ b/slsDetectorSoftware/tests/Caller/test-Caller-chiptestboard.cpp @@ -24,7 +24,7 @@ TEST_CASE("CALLER::dacname", "[.cmdcall]") { Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type == defs::CHIPTESTBOARD) { + if (det_type == defs::CHIPTESTBOARD || det_type == defs::XILINX_CHIPTESTBOARD) { defs::dacIndex ind = static_cast(2); std::string str_dac_index = "2"; auto prev = det.getDacName(ind); @@ -58,7 +58,7 @@ TEST_CASE("CALLER::dacindex", "[.cmdcall]") { Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type == defs::CHIPTESTBOARD) { + if (det_type == defs::CHIPTESTBOARD || det_type == defs::XILINX_CHIPTESTBOARD) { defs::dacIndex ind = static_cast(2); std::string str_dac_index = "2"; @@ -83,7 +83,7 @@ TEST_CASE("CALLER::adclist", "[.cmdcall]") { Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type == defs::CHIPTESTBOARD) { + if (det_type == defs::CHIPTESTBOARD || det_type == defs::XILINX_CHIPTESTBOARD) { auto prev = det.getAdcNames(); REQUIRE_THROWS(caller.call("adclist", {"a", "s", "d"}, -1, PUT)); @@ -115,7 +115,7 @@ TEST_CASE("CALLER::adcname", "[.cmdcall]") { Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type == defs::CHIPTESTBOARD) { + if (det_type == defs::CHIPTESTBOARD || det_type == defs::XILINX_CHIPTESTBOARD) { int ind = 2; std::string str_adc_index = "2"; auto prev = det.getAdcName(ind); @@ -149,7 +149,7 @@ TEST_CASE("CALLER::adcindex", "[.cmdcall]") { Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type == defs::CHIPTESTBOARD) { + if (det_type == defs::CHIPTESTBOARD || det_type == defs::XILINX_CHIPTESTBOARD) { int ind = 2; std::string str_adc_index = "2"; @@ -174,7 +174,7 @@ TEST_CASE("CALLER::signallist", "[.cmdcall]") { Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type == defs::CHIPTESTBOARD) { + if (det_type == defs::CHIPTESTBOARD || det_type == defs::XILINX_CHIPTESTBOARD) { auto prev = det.getSignalNames(); REQUIRE_THROWS(caller.call("signallist", {"a", "s", "d"}, -1, PUT)); @@ -206,7 +206,7 @@ TEST_CASE("CALLER::signalname", "[.cmdcall]") { Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type == defs::CHIPTESTBOARD) { + if (det_type == defs::CHIPTESTBOARD || det_type == defs::XILINX_CHIPTESTBOARD) { int ind = 2; std::string str_signal_index = "2"; auto prev = det.getSignalName(ind); @@ -240,7 +240,7 @@ TEST_CASE("CALLER::signalindex", "[.cmdcall]") { Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type == defs::CHIPTESTBOARD) { + if (det_type == defs::CHIPTESTBOARD || det_type == defs::XILINX_CHIPTESTBOARD) { int ind = 2; std::string str_signal_index = "2"; @@ -266,7 +266,7 @@ TEST_CASE("CALLER::powerlist", "[.cmdcall]") { Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type == defs::CHIPTESTBOARD) { + if (det_type == defs::CHIPTESTBOARD || det_type == defs::XILINX_CHIPTESTBOARD) { auto prev = det.getPowerNames(); REQUIRE_THROWS(caller.call("powerlist", {"a", "s", "d"}, -1, PUT)); @@ -298,7 +298,7 @@ TEST_CASE("CALLER::powername", "[.cmdcall]") { Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type == defs::CHIPTESTBOARD) { + if (det_type == defs::CHIPTESTBOARD || det_type == defs::XILINX_CHIPTESTBOARD) { defs::dacIndex ind = static_cast(2 + defs::V_POWER_A); std::string str_power_index = "2"; auto prev = det.getPowerName(ind); @@ -332,7 +332,7 @@ TEST_CASE("CALLER::powerindex", "[.cmdcall]") { Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type == defs::CHIPTESTBOARD) { + if (det_type == defs::CHIPTESTBOARD || det_type == defs::XILINX_CHIPTESTBOARD) { defs::dacIndex ind = static_cast(2 + defs::V_POWER_A); std::string str_power_index = "2"; @@ -382,7 +382,7 @@ TEST_CASE("CALLER::slowadclist", "[.cmdcall]") { Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type == defs::CHIPTESTBOARD) { + if (det_type == defs::CHIPTESTBOARD || det_type == defs::XILINX_CHIPTESTBOARD) { auto prev = det.getSlowADCNames(); REQUIRE_THROWS(caller.call("slowadclist", {"a", "s", "d"}, -1, PUT)); @@ -414,7 +414,7 @@ TEST_CASE("CALLER::slowadcname", "[.cmdcall]") { Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type == defs::CHIPTESTBOARD) { + if (det_type == defs::CHIPTESTBOARD || det_type == defs::XILINX_CHIPTESTBOARD) { defs::dacIndex ind = static_cast(2 + defs::SLOW_ADC0); std::string str_slowadc_index = "2"; auto prev = det.getSlowADCName(ind); @@ -449,7 +449,7 @@ TEST_CASE("CALLER::slowadcindex", "[.cmdcall]") { Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type == defs::CHIPTESTBOARD) { + if (det_type == defs::CHIPTESTBOARD || det_type == defs::XILINX_CHIPTESTBOARD) { defs::dacIndex ind = static_cast(2 + defs::SLOW_ADC0); std::string str_slowadc_index = "2"; @@ -478,12 +478,17 @@ TEST_CASE("CALLER::dac", "[.cmdcall][.dacs]") { Detector det; Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type == defs::CHIPTESTBOARD) { + if (det_type == defs::CHIPTESTBOARD || det_type == defs::XILINX_CHIPTESTBOARD) { for (int i = 0; i < 18; ++i) { SECTION("dac " + std::to_string(i)) { - test_dac_caller(static_cast(i), "dac", 0); + if (det_type == defs::CHIPTESTBOARD) { + test_dac_caller(static_cast(i), "dac", 0); + } else { + REQUIRE_THROWS(caller.call("dac", {std::to_string(i)}, -1, GET)); + } } } + // eiger // REQUIRE_THROWS(caller.call("dac", {"vthreshold"}, -1, GET)); // REQUIRE_THROWS(caller.call("dac", {"vsvp"}, -1, GET)); diff --git a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp index 195c884d9..e3429dfc2 100644 --- a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp +++ b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp @@ -27,155 +27,191 @@ python/scripts/list_tested_cmd.py to check if all commands are covered TEST_CASE("Caller::rx_version", "[.cmdcall][.rx]") { Detector det; Caller caller(&det); - std::ostringstream oss; - caller.call("rx_version", {}, -1, GET, oss); - sls::Version v(APIRECEIVER); - std::ostringstream vs; - vs << "rx_version " << v.concise() << '\n'; - REQUIRE(oss.str() == vs.str()); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + std::ostringstream oss; + caller.call("rx_version", {}, -1, GET, oss); + sls::Version v(APIRECEIVER); + std::ostringstream vs; + vs << "rx_version " << v.concise() << '\n'; + REQUIRE(oss.str() == vs.str()); - REQUIRE_THROWS(caller.call("rx_version", {"0"}, -1, PUT)); + REQUIRE_THROWS(caller.call("rx_version", {"0"}, -1, PUT)); + } else { + REQUIRE_THROWS(caller.call("rx_version", {}, -1, GET)); + } } /* acquisition */ TEST_CASE("Caller::rx_start", "[.cmdcall][.rx]") { Detector det; Caller caller(&det); - det.setFileWrite(false); // avoid writing or error on file creation - // PUT only command - REQUIRE_THROWS(caller.call("rx_start", {}, -1, GET)); - { - std::ostringstream oss; - caller.call("rx_start", {}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_start successful\n"); - } - { - std::ostringstream oss; - caller.call("rx_status", {}, -1, GET, oss); - REQUIRE(oss.str() == "rx_status running\n"); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + det.setFileWrite(false); // avoid writing or error on file creation + // PUT only command + REQUIRE_THROWS(caller.call("rx_start", {}, -1, GET)); + { + std::ostringstream oss; + caller.call("rx_start", {}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_start successful\n"); + } + { + std::ostringstream oss; + caller.call("rx_status", {}, -1, GET, oss); + REQUIRE(oss.str() == "rx_status running\n"); + } + } else { + REQUIRE_THROWS(caller.call("rx_start", {}, -1, GET)); } } TEST_CASE("Caller::rx_stop", "[.cmdcall][.rx]") { Detector det; Caller caller(&det); - // PUT only command - REQUIRE_THROWS(caller.call("rx_stop", {}, -1, GET)); - { - std::ostringstream oss; - caller.call("rx_stop", {}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_stop successful\n"); - } - { - std::ostringstream oss; - caller.call("rx_status", {}, -1, GET, oss); - REQUIRE(oss.str() == "rx_status idle\n"); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + // PUT only command + REQUIRE_THROWS(caller.call("rx_stop", {}, -1, GET)); + { + std::ostringstream oss; + caller.call("rx_stop", {}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_stop successful\n"); + } + { + std::ostringstream oss; + caller.call("rx_status", {}, -1, GET, oss); + REQUIRE(oss.str() == "rx_status idle\n"); + } + } else { + REQUIRE_THROWS(caller.call("rx_stop", {}, -1, GET)); } } TEST_CASE("Caller::rx_status", "[.cmdcall][.rx]") { Detector det; - det.setFileWrite(false); // avoid writing or error on file creation Caller caller(&det); - det.startReceiver(); - { - std::ostringstream oss; - caller.call("rx_status", {}, -1, GET, oss); - REQUIRE(oss.str() == "rx_status running\n"); - } - det.stopReceiver(); - { - std::ostringstream oss; - caller.call("rx_status", {}, -1, GET, oss); - REQUIRE(oss.str() == "rx_status idle\n"); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + det.setFileWrite(false); // avoid writing or error on file creation + Caller caller(&det); + det.startReceiver(); + { + std::ostringstream oss; + caller.call("rx_status", {}, -1, GET, oss); + REQUIRE(oss.str() == "rx_status running\n"); + } + det.stopReceiver(); + { + std::ostringstream oss; + caller.call("rx_status", {}, -1, GET, oss); + REQUIRE(oss.str() == "rx_status idle\n"); + } + } else { + REQUIRE_THROWS(caller.call("rx_status", {}, -1, GET)); } } TEST_CASE("Caller::rx_framescaught", "[.cmdcall][.rx]") { Detector det; Caller caller(&det); - - // This ensures 0 caught frames - auto prev_val = det.getFileWrite(); - det.setFileWrite(false); // avoid writing or error on file creation - det.startReceiver(); - det.stopReceiver(); - { - std::ostringstream oss; - caller.call("rx_framescaught", {}, -1, GET, oss); - if (det.getNumberofUDPInterfaces().tsquash( - "inconsistent number of interfaces") == 1) { - REQUIRE(oss.str() == "rx_framescaught [0]\n"); - } else { - REQUIRE(oss.str() == "rx_framescaught [0, 0]\n"); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + // This ensures 0 caught frames + auto prev_val = det.getFileWrite(); + det.setFileWrite(false); // avoid writing or error on file creation + det.startReceiver(); + det.stopReceiver(); + { + std::ostringstream oss; + caller.call("rx_framescaught", {}, -1, GET, oss); + if (det.getNumberofUDPInterfaces().tsquash( + "inconsistent number of interfaces") == 1) { + REQUIRE(oss.str() == "rx_framescaught [0]\n"); + } else { + REQUIRE(oss.str() == "rx_framescaught [0, 0]\n"); + } } - } - // Currently disabled may activate if we have a stable env - // Now take one frame and see that we caught it - // det.setNumberOfFrames(1); - // det.acquire(); - // { - // std::ostringstream oss; - // caller.call("rx_framescaught", {}, -1, GET, oss); - // REQUIRE(oss.str() == "rx_framescaught 1\n"); - // } + // Currently disabled may activate if we have a stable env + // Now take one frame and see that we caught it + // det.setNumberOfFrames(1); + // det.acquire(); + // { + // std::ostringstream oss; + // caller.call("rx_framescaught", {}, -1, GET, oss); + // REQUIRE(oss.str() == "rx_framescaught 1\n"); + // } - for (int i = 0; i != det.size(); ++i) { - det.setFileWrite(prev_val[i], {i}); + for (int i = 0; i != det.size(); ++i) { + det.setFileWrite(prev_val[i], {i}); + } + } else { + REQUIRE_THROWS(caller.call("rx_framescaught", {}, -1, GET)); } } TEST_CASE("Caller::rx_missingpackets", "[.cmdcall][.rx]") { Detector det; - auto prev_val = det.getFileWrite(); - det.setFileWrite(false); // avoid writing or error on file creation Caller caller(&det); - auto prev_frames = - det.getNumberOfFrames().tsquash("inconsistent #frames in test"); - det.setNumberOfFrames(100); - { - // some missing packets - det.startReceiver(); - det.stopReceiver(); - std::ostringstream oss; - caller.call("rx_missingpackets", {}, -1, GET, oss); - if (det.getNumberofUDPInterfaces().tsquash( - "inconsistent number of interfaces") == 1) { - REQUIRE(oss.str() != "rx_missingpackets [0]\n"); - } else { - REQUIRE(oss.str() != "rx_missingpackets [0, 0]\n"); - } - } auto det_type = det.getDetectorType().squash(); - if (det_type != defs::CHIPTESTBOARD && det_type != defs::MOENCH) { - // 0 missing packets (takes into account that acquisition is stopped) - det.startReceiver(); - det.startDetector(); - det.stopDetector(); - det.stopReceiver(); - std::ostringstream oss; - caller.call("rx_missingpackets", {}, -1, GET, oss); - if (det.getNumberofUDPInterfaces().tsquash( - "inconsistent number of interfaces") == 1) { - REQUIRE(oss.str() == "rx_missingpackets [0]\n"); - } else { - REQUIRE(oss.str() == "rx_missingpackets [0, 0]\n"); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getFileWrite(); + det.setFileWrite(false); // avoid writing or error on file creation + Caller caller(&det); + auto prev_frames = + det.getNumberOfFrames().tsquash("inconsistent #frames in test"); + det.setNumberOfFrames(100); + { + // some missing packets + det.startReceiver(); + det.stopReceiver(); + std::ostringstream oss; + caller.call("rx_missingpackets", {}, -1, GET, oss); + if (det.getNumberofUDPInterfaces().tsquash( + "inconsistent number of interfaces") == 1) { + REQUIRE(oss.str() != "rx_missingpackets [0]\n"); + } else { + REQUIRE(oss.str() != "rx_missingpackets [0, 0]\n"); + } } + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::CHIPTESTBOARD && det_type != defs::MOENCH) { + // 0 missing packets (takes into account that acquisition is stopped) + det.startReceiver(); + det.startDetector(); + det.stopDetector(); + det.stopReceiver(); + std::ostringstream oss; + caller.call("rx_missingpackets", {}, -1, GET, oss); + if (det.getNumberofUDPInterfaces().tsquash( + "inconsistent number of interfaces") == 1) { + REQUIRE(oss.str() == "rx_missingpackets [0]\n"); + } else { + REQUIRE(oss.str() == "rx_missingpackets [0, 0]\n"); + } + } + for (int i = 0; i != det.size(); ++i) { + det.setFileWrite(prev_val[i], {i}); + } + det.setNumberOfFrames(prev_frames); + } else { + REQUIRE_THROWS(caller.call("rx_missingpackets", {}, -1, GET)); } - for (int i = 0; i != det.size(); ++i) { - det.setFileWrite(prev_val[i], {i}); - } - det.setNumberOfFrames(prev_frames); } TEST_CASE("Caller::rx_frameindex", "[.cmdcall][.rx]") { Detector det; Caller caller(&det); - caller.call("rx_frameindex", {}, -1, GET); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + caller.call("rx_frameindex", {}, -1, GET); - // This is a get only command - REQUIRE_THROWS(caller.call("rx_frameindex", {"2"}, -1, PUT)); + // This is a get only command + REQUIRE_THROWS(caller.call("rx_frameindex", {"2"}, -1, PUT)); + } else { + REQUIRE_THROWS(caller.call("rx_frameindex", {}, -1, GET)); + } } /* Network Configuration (Detector<->Receiver) */ @@ -183,7 +219,12 @@ TEST_CASE("Caller::rx_frameindex", "[.cmdcall][.rx]") { TEST_CASE("Caller::rx_printconfig", "[.cmdcall][.rx]") { Detector det; Caller caller(&det); - REQUIRE_NOTHROW(caller.call("rx_printconfig", {}, -1, GET)); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + REQUIRE_NOTHROW(caller.call("rx_printconfig", {}, -1, GET)); + } else { + REQUIRE_THROWS(caller.call("rx_printconfig", {}, -1, GET)); + } } /* Receiver Config */ @@ -191,32 +232,37 @@ TEST_CASE("Caller::rx_printconfig", "[.cmdcall][.rx]") { TEST_CASE("Caller::rx_hostname", "[.cmdcall][.rx]") { Detector det; Caller caller(&det); - auto prev_val = det.getRxHostname(); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getRxHostname(); - // Cannot set rx_hostname (will reset parameters in rxr and no shm variables - // to update) - // { - // // disable receiver - // std::ostringstream oss; - // caller.call("rx_hostname", {"none"}, -1, PUT, oss); - // REQUIRE(oss.str() == "rx_hostname [none]\n"); - // } - // { - // std::ostringstream oss; - // caller.call("rx_hostname", {}, -1, GET, oss); - // REQUIRE(oss.str() == "rx_hostname none\n"); - // // receiver should be disabled - // REQUIRE(det.getUseReceiverFlag().tsquash( - // "different values of flag in test") == false); - // } - // put back old values (not necessary when we dont set it to none) - // for (int i = 0; i != det.size(); ++i) { - // det.setRxHostname(prev_val[i], {i}); - // } - { - std::ostringstream oss; - caller.call("rx_hostname", {}, 0, GET, oss); - REQUIRE(oss.str() == "rx_hostname " + prev_val[0] + "\n"); + // Cannot set rx_hostname (will reset parameters in rxr and no shm variables + // to update) + // { + // // disable receiver + // std::ostringstream oss; + // caller.call("rx_hostname", {"none"}, -1, PUT, oss); + // REQUIRE(oss.str() == "rx_hostname [none]\n"); + // } + // { + // std::ostringstream oss; + // caller.call("rx_hostname", {}, -1, GET, oss); + // REQUIRE(oss.str() == "rx_hostname none\n"); + // // receiver should be disabled + // REQUIRE(det.getUseReceiverFlag().tsquash( + // "different values of flag in test") == false); + // } + // put back old values (not necessary when we dont set it to none) + // for (int i = 0; i != det.size(); ++i) { + // det.setRxHostname(prev_val[i], {i}); + // } + { + std::ostringstream oss; + caller.call("rx_hostname", {}, 0, GET, oss); + REQUIRE(oss.str() == "rx_hostname " + prev_val[0] + "\n"); + } + } else { + REQUIRE_THROWS(caller.call("rx_hostname", {"localhost"}, -1, PUT)); } } @@ -262,205 +308,255 @@ TEST_CASE("Caller::rx_tcpport", "[.cmdcall][.rx]") { TEST_CASE("Caller::rx_fifodepth", "[.cmdcall][.rx]") { Detector det; Caller caller(&det); - auto prev_val = det.getRxFifoDepth(); - { - std::ostringstream oss; - caller.call("rx_fifodepth", {"10"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_fifodepth 10\n"); - } - { - std::ostringstream oss; - caller.call("rx_fifodepth", {"100"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_fifodepth 100\n"); - } - { - std::ostringstream oss; - caller.call("rx_fifodepth", {}, -1, GET, oss); - REQUIRE(oss.str() == "rx_fifodepth 100\n"); - } - for (int i = 0; i != det.size(); ++i) { - det.setRxFifoDepth(prev_val[i], {i}); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getRxFifoDepth(); + { + std::ostringstream oss; + caller.call("rx_fifodepth", {"10"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_fifodepth 10\n"); + } + { + std::ostringstream oss; + caller.call("rx_fifodepth", {"100"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_fifodepth 100\n"); + } + { + std::ostringstream oss; + caller.call("rx_fifodepth", {}, -1, GET, oss); + REQUIRE(oss.str() == "rx_fifodepth 100\n"); + } + for (int i = 0; i != det.size(); ++i) { + det.setRxFifoDepth(prev_val[i], {i}); + } + } else { + REQUIRE_THROWS(caller.call("rx_fifodepth", {}, -1, GET)); } } TEST_CASE("Caller::rx_silent", "[.cmdcall][.rx]") { Detector det; Caller caller(&det); - auto prev_val = det.getRxSilentMode(); - { - std::ostringstream oss; - caller.call("rx_silent", {"1"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_silent 1\n"); - } - { - std::ostringstream oss; - caller.call("rx_silent", {}, -1, GET, oss); - REQUIRE(oss.str() == "rx_silent 1\n"); - } - { - std::ostringstream oss; - caller.call("rx_silent", {"0"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_silent 0\n"); - } - for (int i = 0; i != det.size(); ++i) { - det.setRxSilentMode(prev_val[i], {i}); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getRxSilentMode(); + { + std::ostringstream oss; + caller.call("rx_silent", {"1"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_silent 1\n"); + } + { + std::ostringstream oss; + caller.call("rx_silent", {}, -1, GET, oss); + REQUIRE(oss.str() == "rx_silent 1\n"); + } + { + std::ostringstream oss; + caller.call("rx_silent", {"0"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_silent 0\n"); + } + for (int i = 0; i != det.size(); ++i) { + det.setRxSilentMode(prev_val[i], {i}); + } + } else { + REQUIRE_THROWS(caller.call("rx_silent", {}, -1, GET)); } } TEST_CASE("Caller::rx_discardpolicy", "[.cmdcall][.rx]") { Detector det; Caller caller(&det); - auto prev_val = det.getRxFrameDiscardPolicy(); - { - std::ostringstream oss; - caller.call("rx_discardpolicy", {"discardempty"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_discardpolicy discardempty\n"); - } - { - std::ostringstream oss; - caller.call("rx_discardpolicy", {}, -1, GET, oss); - REQUIRE(oss.str() == "rx_discardpolicy discardempty\n"); - } - { - std::ostringstream oss; - caller.call("rx_discardpolicy", {"discardpartial"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_discardpolicy discardpartial\n"); - } - { - std::ostringstream oss; - caller.call("rx_discardpolicy", {"nodiscard"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_discardpolicy nodiscard\n"); - } - for (int i = 0; i != det.size(); ++i) { - det.setRxFrameDiscardPolicy(prev_val[i], {i}); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getRxFrameDiscardPolicy(); + { + std::ostringstream oss; + caller.call("rx_discardpolicy", {"discardempty"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_discardpolicy discardempty\n"); + } + { + std::ostringstream oss; + caller.call("rx_discardpolicy", {}, -1, GET, oss); + REQUIRE(oss.str() == "rx_discardpolicy discardempty\n"); + } + { + std::ostringstream oss; + caller.call("rx_discardpolicy", {"discardpartial"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_discardpolicy discardpartial\n"); + } + { + std::ostringstream oss; + caller.call("rx_discardpolicy", {"nodiscard"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_discardpolicy nodiscard\n"); + } + for (int i = 0; i != det.size(); ++i) { + det.setRxFrameDiscardPolicy(prev_val[i], {i}); + } + } else { + REQUIRE_THROWS(caller.call("rx_discardpolicy", {}, -1, GET)); } } TEST_CASE("Caller::rx_padding", "[.cmdcall][.rx]") { Detector det; Caller caller(&det); - auto prev_val = det.getPartialFramesPadding(); - { - std::ostringstream oss; - caller.call("rx_padding", {"0"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_padding 0\n"); - } - { - std::ostringstream oss; - caller.call("rx_padding", {}, -1, GET, oss); - REQUIRE(oss.str() == "rx_padding 0\n"); - } - { - std::ostringstream oss; - caller.call("rx_padding", {"1"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_padding 1\n"); - } - for (int i = 0; i != det.size(); ++i) { - det.setPartialFramesPadding(prev_val[i], {i}); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getPartialFramesPadding(); + { + std::ostringstream oss; + caller.call("rx_padding", {"0"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_padding 0\n"); + } + { + std::ostringstream oss; + caller.call("rx_padding", {}, -1, GET, oss); + REQUIRE(oss.str() == "rx_padding 0\n"); + } + { + std::ostringstream oss; + caller.call("rx_padding", {"1"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_padding 1\n"); + } + for (int i = 0; i != det.size(); ++i) { + det.setPartialFramesPadding(prev_val[i], {i}); + } + } else { + REQUIRE_THROWS(caller.call("rx_padding", {}, -1, GET)); } } TEST_CASE("Caller::rx_udpsocksize", "[.cmdcall][.rx]") { Detector det; Caller caller(&det); - int64_t prev_val = det.getRxUDPSocketBufferSize().tsquash( - "Need same udp socket buffer size to test"); - std::string s_new_val = std::to_string(prev_val); - /*std::string s_new_val = std::to_string(prev_val - 1000); - { Need permissions - std::ostringstream oss; - caller.call("rx_udpsocksize", {s_new_val}, -1, PUT, oss); - REQUIRE(oss.str() >= "rx_udpsocksize " + s_new_val + "\n"); - }*/ - { - std::ostringstream oss; - caller.call("rx_udpsocksize", {}, -1, GET, oss); - REQUIRE(oss.str() >= "rx_udpsocksize " + s_new_val + "\n"); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + int64_t prev_val = det.getRxUDPSocketBufferSize().tsquash( + "Need same udp socket buffer size to test"); + std::string s_new_val = std::to_string(prev_val); + /*std::string s_new_val = std::to_string(prev_val - 1000); + { Need permissions + std::ostringstream oss; + caller.call("rx_udpsocksize", {s_new_val}, -1, PUT, oss); + REQUIRE(oss.str() >= "rx_udpsocksize " + s_new_val + "\n"); + }*/ + { + std::ostringstream oss; + caller.call("rx_udpsocksize", {}, -1, GET, oss); + REQUIRE(oss.str() >= "rx_udpsocksize " + s_new_val + "\n"); + } + det.setRxUDPSocketBufferSize(prev_val); + } else { + REQUIRE_THROWS(caller.call("rx_udpsocksize", {}, -1, GET)); } - det.setRxUDPSocketBufferSize(prev_val); } TEST_CASE("Caller::rx_realudpsocksize", "[.cmdcall][.rx]") { Detector det; Caller caller(&det); - uint64_t val = 0; - { - std::ostringstream oss; - caller.call("rx_udpsocksize", {}, -1, GET, oss); - std::string s = (oss.str()).erase(0, strlen("rx_udpsocksize ")); - val = std::stol(s); - } - { - std::ostringstream oss; - caller.call("rx_realudpsocksize", {}, -1, GET, oss); - std::string s = (oss.str()).erase(0, strlen("rx_realudpsocksize ")); - uint64_t rval = std::stol(s); - REQUIRE(rval >= val * 2); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + uint64_t val = 0; + { + std::ostringstream oss; + caller.call("rx_udpsocksize", {}, -1, GET, oss); + std::string s = (oss.str()).erase(0, strlen("rx_udpsocksize ")); + val = std::stol(s); + } + { + std::ostringstream oss; + caller.call("rx_realudpsocksize", {}, -1, GET, oss); + std::string s = (oss.str()).erase(0, strlen("rx_realudpsocksize ")); + uint64_t rval = std::stol(s); + REQUIRE(rval >= val * 2); + } + } else { + REQUIRE_THROWS(caller.call("rx_realudpsocksize", {}, -1, GET)); } } TEST_CASE("Caller::rx_lock", "[.cmdcall][.rx]") { Detector det; Caller caller(&det); - auto prev_val = det.getRxLock(); - { - std::ostringstream oss; - caller.call("rx_lock", {"1"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_lock 1\n"); - } - { - std::ostringstream oss; - caller.call("rx_lock", {}, -1, GET, oss); - REQUIRE(oss.str() == "rx_lock 1\n"); - } - { - std::ostringstream oss; - caller.call("rx_lock", {"0"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_lock 0\n"); - } - for (int i = 0; i != det.size(); ++i) { - det.setRxLock(prev_val[i], {i}); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getRxLock(); + { + std::ostringstream oss; + caller.call("rx_lock", {"1"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_lock 1\n"); + } + { + std::ostringstream oss; + caller.call("rx_lock", {}, -1, GET, oss); + REQUIRE(oss.str() == "rx_lock 1\n"); + } + { + std::ostringstream oss; + caller.call("rx_lock", {"0"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_lock 0\n"); + } + for (int i = 0; i != det.size(); ++i) { + det.setRxLock(prev_val[i], {i}); + } + } else { + REQUIRE_THROWS(caller.call("rx_lock", {}, -1, GET)); } } TEST_CASE("Caller::rx_lastclient", "[.cmdcall][.rx]") { Detector det; Caller caller(&det); - std::ostringstream oss; - REQUIRE_NOTHROW(caller.call("rx_lastclient", {}, -1, GET, oss)); - if (test::my_ip != "undefined") { - REQUIRE(oss.str() == "rx_lastclient " + test::my_ip + "\n"); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + std::ostringstream oss; + REQUIRE_NOTHROW(caller.call("rx_lastclient", {}, -1, GET, oss)); + if (test::my_ip != "undefined") { + REQUIRE(oss.str() == "rx_lastclient " + test::my_ip + "\n"); + } + } else { + REQUIRE_THROWS(caller.call("rx_lastclient", {}, -1, GET)); } } TEST_CASE("Caller::rx_threads", "[.cmdcall][.rx]") { Detector det; Caller caller(&det); - std::ostringstream oss; - REQUIRE_NOTHROW(caller.call("rx_threads", {}, -1, GET, oss)); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + std::ostringstream oss; + REQUIRE_NOTHROW(caller.call("rx_threads", {}, -1, GET, oss)); + } else { + REQUIRE_THROWS(caller.call("rx_threads", {}, -1, GET)); + } } TEST_CASE("Caller::rx_arping", "[.cmdcall][.rx]") { Detector det; Caller caller(&det); - auto prev_val = det.getRxArping(); - { - std::ostringstream oss; - caller.call("rx_arping", {"1"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_arping 1\n"); - } - { - std::ostringstream oss; - caller.call("rx_arping", {}, -1, GET, oss); - REQUIRE(oss.str() == "rx_arping 1\n"); - } - { - std::ostringstream oss; - caller.call("rx_arping", {"0"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_arping 0\n"); - } - for (int i = 0; i != det.size(); ++i) { - det.setRxArping(prev_val[i], {i}); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getRxArping(); + { + std::ostringstream oss; + caller.call("rx_arping", {"1"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_arping 1\n"); + } + { + std::ostringstream oss; + caller.call("rx_arping", {}, -1, GET, oss); + REQUIRE(oss.str() == "rx_arping 1\n"); + } + { + std::ostringstream oss; + caller.call("rx_arping", {"0"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_arping 0\n"); + } + for (int i = 0; i != det.size(); ++i) { + det.setRxArping(prev_val[i], {i}); + } + } else { + REQUIRE_THROWS(caller.call("rx_arping", {}, -1, GET)); } } @@ -468,61 +564,64 @@ TEST_CASE("Caller::rx_roi", "[.cmdcall]") { Detector det; Caller caller(&det); auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + if (det_type == defs::CHIPTESTBOARD) { + REQUIRE_THROWS(caller.call("rx_roi", {"5", "10"}, -1, PUT)); + } else { + auto prev_val = det.getRxROI(); + defs::xy detsize = det.getDetectorSize(); - if (det_type == defs::CHIPTESTBOARD) { - REQUIRE_THROWS(caller.call("rx_roi", {"5", "10"}, -1, PUT)); + // 1d + if (det_type == defs::GOTTHARD || det_type == defs::GOTTHARD2 || + det_type == defs::MYTHEN3) { + { + std::ostringstream oss; + caller.call("rx_roi", {"5", "10"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_roi [5, 10]\n"); + } + { + std::ostringstream oss; + caller.call("rx_roi", {"10", "15"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_roi [10, 15]\n"); + } + REQUIRE_THROWS(caller.call("rx_roi", {"-1", "-1"}, -1, PUT)); + REQUIRE_THROWS( + caller.call("rx_roi", {"10", "15", "25", "30"}, -1, PUT)); + } + // 2d + else { + { + std::ostringstream oss; + caller.call("rx_roi", {"10", "15", "1", "5"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_roi [10, 15, 1, 5]\n"); + } + { + std::ostringstream oss; + caller.call("rx_roi", {"10", "22", "18", "19"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_roi [10, 22, 18, 19]\n"); + } + { + std::ostringstream oss; + caller.call("rx_roi", + {"1", std::to_string(detsize.x - 5), "1", + std::to_string(detsize.y - 5)}, + -1, PUT, oss); + REQUIRE(oss.str() == std::string("rx_roi [1, ") + + std::to_string(detsize.x - 5) + + std::string(", 1, ") + + std::to_string(detsize.y - 5) + + std::string("]\n")); + } + REQUIRE_THROWS( + caller.call("rx_roi", {"-1", "-1", "-1", "-1"}, -1, PUT)); + } + + for (int i = 0; i != det.size(); ++i) { + det.setRxROI(prev_val); + } + } } else { - auto prev_val = det.getRxROI(); - defs::xy detsize = det.getDetectorSize(); - - // 1d - if (det_type == defs::GOTTHARD || det_type == defs::GOTTHARD2 || - det_type == defs::MYTHEN3) { - { - std::ostringstream oss; - caller.call("rx_roi", {"5", "10"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_roi [5, 10]\n"); - } - { - std::ostringstream oss; - caller.call("rx_roi", {"10", "15"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_roi [10, 15]\n"); - } - REQUIRE_THROWS(caller.call("rx_roi", {"-1", "-1"}, -1, PUT)); - REQUIRE_THROWS( - caller.call("rx_roi", {"10", "15", "25", "30"}, -1, PUT)); - } - // 2d - else { - { - std::ostringstream oss; - caller.call("rx_roi", {"10", "15", "1", "5"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_roi [10, 15, 1, 5]\n"); - } - { - std::ostringstream oss; - caller.call("rx_roi", {"10", "22", "18", "19"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_roi [10, 22, 18, 19]\n"); - } - { - std::ostringstream oss; - caller.call("rx_roi", - {"1", std::to_string(detsize.x - 5), "1", - std::to_string(detsize.y - 5)}, - -1, PUT, oss); - REQUIRE(oss.str() == std::string("rx_roi [1, ") + - std::to_string(detsize.x - 5) + - std::string(", 1, ") + - std::to_string(detsize.y - 5) + - std::string("]\n")); - } - REQUIRE_THROWS( - caller.call("rx_roi", {"-1", "-1", "-1", "-1"}, -1, PUT)); - } - - for (int i = 0; i != det.size(); ++i) { - det.setRxROI(prev_val); - } + REQUIRE_THROWS(caller.call("rx_roi", {}, -1, GET)); } } @@ -530,19 +629,22 @@ TEST_CASE("Caller::rx_clearroi", "[.cmdcall]") { Detector det; Caller caller(&det); auto det_type = det.getDetectorType().squash(); - - if (det_type == defs::CHIPTESTBOARD) { - REQUIRE_THROWS(caller.call("rx_clearroi", {}, -1, PUT)); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + if (det_type == defs::CHIPTESTBOARD) { + REQUIRE_THROWS(caller.call("rx_clearroi", {}, -1, PUT)); + } else { + auto prev_val = det.getRxROI(); + { + std::ostringstream oss; + caller.call("rx_clearroi", {}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_clearroi successful\n"); + } + for (int i = 0; i != det.size(); ++i) { + det.setRxROI(prev_val); + } + } } else { - auto prev_val = det.getRxROI(); - { - std::ostringstream oss; - caller.call("rx_clearroi", {}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_clearroi successful\n"); - } - for (int i = 0; i != det.size(); ++i) { - det.setRxROI(prev_val); - } + REQUIRE_THROWS(caller.call("rx_clearroi", {}, -1, PUT)); } } @@ -551,188 +653,228 @@ TEST_CASE("Caller::rx_clearroi", "[.cmdcall]") { TEST_CASE("Caller::fformat", "[.cmdcall]") { Detector det; Caller caller(&det); - auto prev_val = det.getFileFormat(); - { - std::ostringstream oss; - caller.call("fformat", {"binary"}, -1, PUT, oss); - REQUIRE(oss.str() == "fformat binary\n"); - } - { - std::ostringstream oss; - caller.call("fformat", {}, -1, GET, oss); - REQUIRE(oss.str() == "fformat binary\n"); - } - for (int i = 0; i != det.size(); ++i) { - det.setFileFormat(prev_val[i], {i}); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getFileFormat(); + { + std::ostringstream oss; + caller.call("fformat", {"binary"}, -1, PUT, oss); + REQUIRE(oss.str() == "fformat binary\n"); + } + { + std::ostringstream oss; + caller.call("fformat", {}, -1, GET, oss); + REQUIRE(oss.str() == "fformat binary\n"); + } + for (int i = 0; i != det.size(); ++i) { + det.setFileFormat(prev_val[i], {i}); + } + } else { + REQUIRE_THROWS(caller.call("fformat", {}, -1, GET)); } } TEST_CASE("Caller::fpath", "[.cmdcall]") { Detector det; Caller caller(&det); - auto prev_val = det.getFilePath(); - { - std::ostringstream oss; - caller.call("fpath", {"/tmp"}, -1, PUT, oss); - REQUIRE(oss.str() == "fpath /tmp\n"); - } - { - std::ostringstream oss; - caller.call("fpath", {}, -1, GET, oss); - REQUIRE(oss.str() == "fpath /tmp\n"); - } - for (int i = 0; i != det.size(); ++i) { - det.setFilePath(prev_val[i], {i}); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getFilePath(); + { + std::ostringstream oss; + caller.call("fpath", {"/tmp"}, -1, PUT, oss); + REQUIRE(oss.str() == "fpath /tmp\n"); + } + { + std::ostringstream oss; + caller.call("fpath", {}, -1, GET, oss); + REQUIRE(oss.str() == "fpath /tmp\n"); + } + for (int i = 0; i != det.size(); ++i) { + det.setFilePath(prev_val[i], {i}); + } + } else { + REQUIRE_THROWS(caller.call("fpath", {}, -1, GET)); } } TEST_CASE("Caller::fname", "[.cmdcall]") { Detector det; Caller caller(&det); - auto prev_val = det.getFileNamePrefix(); - { - std::ostringstream oss; - caller.call("fname", {"somename"}, -1, PUT, oss); - REQUIRE(oss.str() == "fname somename\n"); - } - { - std::ostringstream oss; - caller.call("fname", {}, -1, GET, oss); - REQUIRE(oss.str() == "fname somename\n"); - } - { - std::ostringstream oss; - caller.call("fname", {"run"}, -1, PUT, oss); - REQUIRE(oss.str() == "fname run\n"); - } - REQUIRE_THROWS(caller.call("fname", {"fdf/dfd"}, -1, PUT)); - REQUIRE_THROWS(caller.call("fname", {"fdf dfd"}, -1, PUT)); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getFileNamePrefix(); + { + std::ostringstream oss; + caller.call("fname", {"somename"}, -1, PUT, oss); + REQUIRE(oss.str() == "fname somename\n"); + } + { + std::ostringstream oss; + caller.call("fname", {}, -1, GET, oss); + REQUIRE(oss.str() == "fname somename\n"); + } + { + std::ostringstream oss; + caller.call("fname", {"run"}, -1, PUT, oss); + REQUIRE(oss.str() == "fname run\n"); + } + REQUIRE_THROWS(caller.call("fname", {"fdf/dfd"}, -1, PUT)); + REQUIRE_THROWS(caller.call("fname", {"fdf dfd"}, -1, PUT)); - for (int i = 0; i != det.size(); ++i) { - det.setFileNamePrefix(prev_val[i], {i}); + for (int i = 0; i != det.size(); ++i) { + det.setFileNamePrefix(prev_val[i], {i}); + } + } else { + REQUIRE_THROWS(caller.call("fname", {}, -1, GET)); } } TEST_CASE("Caller::findex", "[.cmdcall]") { Detector det; Caller caller(&det); - auto prev_val = det.getAcquisitionIndex(); - { - std::ostringstream oss; - caller.call("findex", {"57"}, -1, PUT, oss); - REQUIRE(oss.str() == "findex 57\n"); - } - { - std::ostringstream oss; - caller.call("findex", {}, -1, GET, oss); - REQUIRE(oss.str() == "findex 57\n"); - } - { - std::ostringstream oss; - caller.call("findex", {"0"}, -1, PUT, oss); - REQUIRE(oss.str() == "findex 0\n"); - } - for (int i = 0; i != det.size(); ++i) { - det.setAcquisitionIndex(prev_val[i], {i}); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getAcquisitionIndex(); + { + std::ostringstream oss; + caller.call("findex", {"57"}, -1, PUT, oss); + REQUIRE(oss.str() == "findex 57\n"); + } + { + std::ostringstream oss; + caller.call("findex", {}, -1, GET, oss); + REQUIRE(oss.str() == "findex 57\n"); + } + { + std::ostringstream oss; + caller.call("findex", {"0"}, -1, PUT, oss); + REQUIRE(oss.str() == "findex 0\n"); + } + for (int i = 0; i != det.size(); ++i) { + det.setAcquisitionIndex(prev_val[i], {i}); + } + } else { + REQUIRE_THROWS(caller.call("findex", {}, -1, GET)); } } TEST_CASE("Caller::fwrite", "[.cmdcall]") { Detector det; Caller caller(&det); - auto prev_val = det.getFileWrite(); - { - std::ostringstream oss; - caller.call("fwrite", {"1"}, -1, PUT, oss); - REQUIRE(oss.str() == "fwrite 1\n"); - } - { - std::ostringstream oss; - caller.call("fwrite", {}, -1, GET, oss); - REQUIRE(oss.str() == "fwrite 1\n"); - } - { - std::ostringstream oss; - caller.call("fwrite", {"0"}, -1, PUT, oss); - REQUIRE(oss.str() == "fwrite 0\n"); - } - for (int i = 0; i != det.size(); ++i) { - det.setFileWrite(prev_val[i], {i}); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getFileWrite(); + { + std::ostringstream oss; + caller.call("fwrite", {"1"}, -1, PUT, oss); + REQUIRE(oss.str() == "fwrite 1\n"); + } + { + std::ostringstream oss; + caller.call("fwrite", {}, -1, GET, oss); + REQUIRE(oss.str() == "fwrite 1\n"); + } + { + std::ostringstream oss; + caller.call("fwrite", {"0"}, -1, PUT, oss); + REQUIRE(oss.str() == "fwrite 0\n"); + } + for (int i = 0; i != det.size(); ++i) { + det.setFileWrite(prev_val[i], {i}); + } + } else { + REQUIRE_THROWS(caller.call("fwrite", {}, -1, GET)); } } TEST_CASE("Caller::fmaster", "[.cmdcall]") { Detector det; Caller caller(&det); - auto prev_val = det.getMasterFileWrite(); - { - std::ostringstream oss; - caller.call("fmaster", {"0"}, -1, PUT, oss); - REQUIRE(oss.str() == "fmaster 0\n"); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getMasterFileWrite(); + { + std::ostringstream oss; + caller.call("fmaster", {"0"}, -1, PUT, oss); + REQUIRE(oss.str() == "fmaster 0\n"); + } + { + std::ostringstream oss; + caller.call("fmaster", {}, -1, GET, oss); + REQUIRE(oss.str() == "fmaster 0\n"); + } + { + std::ostringstream oss; + caller.call("fmaster", {"1"}, -1, PUT, oss); + REQUIRE(oss.str() == "fmaster 1\n"); + } + det.setMasterFileWrite(prev_val); + } else { + REQUIRE_THROWS(caller.call("fmaster", {}, -1, GET)); } - { - std::ostringstream oss; - caller.call("fmaster", {}, -1, GET, oss); - REQUIRE(oss.str() == "fmaster 0\n"); - } - { - std::ostringstream oss; - caller.call("fmaster", {"1"}, -1, PUT, oss); - REQUIRE(oss.str() == "fmaster 1\n"); - } - det.setMasterFileWrite(prev_val); } TEST_CASE("Caller::foverwrite", "[.cmdcall]") { Detector det; Caller caller(&det); - auto prev_val = det.getFileOverWrite(); - { - std::ostringstream oss; - caller.call("foverwrite", {"1"}, -1, PUT, oss); - REQUIRE(oss.str() == "foverwrite 1\n"); - } - { - std::ostringstream oss; - caller.call("foverwrite", {}, -1, GET, oss); - REQUIRE(oss.str() == "foverwrite 1\n"); - } - { - std::ostringstream oss; - caller.call("foverwrite", {"0"}, -1, PUT, oss); - REQUIRE(oss.str() == "foverwrite 0\n"); - } - for (int i = 0; i != det.size(); ++i) { - det.setFileOverWrite(prev_val[i], {i}); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getFileOverWrite(); + { + std::ostringstream oss; + caller.call("foverwrite", {"1"}, -1, PUT, oss); + REQUIRE(oss.str() == "foverwrite 1\n"); + } + { + std::ostringstream oss; + caller.call("foverwrite", {}, -1, GET, oss); + REQUIRE(oss.str() == "foverwrite 1\n"); + } + { + std::ostringstream oss; + caller.call("foverwrite", {"0"}, -1, PUT, oss); + REQUIRE(oss.str() == "foverwrite 0\n"); + } + for (int i = 0; i != det.size(); ++i) { + det.setFileOverWrite(prev_val[i], {i}); + } + } else { + REQUIRE_THROWS(caller.call("foverwrite", {}, -1, GET)); } } TEST_CASE("Caller::rx_framesperfile", "[.cmdcall][.rx]") { Detector det; Caller caller(&det); - auto prev_val = det.getFramesPerFile(); - { - std::ostringstream oss; - caller.call("rx_framesperfile", {"50"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_framesperfile 50\n"); - } - { - std::ostringstream oss; - caller.call("rx_framesperfile", {}, -1, GET, oss); - REQUIRE(oss.str() == "rx_framesperfile 50\n"); - } - { - std::ostringstream oss; - caller.call("rx_framesperfile", {"10000"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_framesperfile 10000\n"); - } - { - std::ostringstream oss; - caller.call("rx_framesperfile", {"0"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_framesperfile 0\n"); - } - for (int i = 0; i != det.size(); ++i) { - det.setFramesPerFile(prev_val[i], {i}); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getFramesPerFile(); + { + std::ostringstream oss; + caller.call("rx_framesperfile", {"50"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_framesperfile 50\n"); + } + { + std::ostringstream oss; + caller.call("rx_framesperfile", {}, -1, GET, oss); + REQUIRE(oss.str() == "rx_framesperfile 50\n"); + } + { + std::ostringstream oss; + caller.call("rx_framesperfile", {"10000"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_framesperfile 10000\n"); + } + { + std::ostringstream oss; + caller.call("rx_framesperfile", {"0"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_framesperfile 0\n"); + } + for (int i = 0; i != det.size(); ++i) { + det.setFramesPerFile(prev_val[i], {i}); + } + } else { + REQUIRE_THROWS(caller.call("rx_framesperfile", {}, -1, GET)); } } @@ -741,171 +883,202 @@ TEST_CASE("Caller::rx_framesperfile", "[.cmdcall][.rx]") { TEST_CASE("Caller::rx_zmqstream", "[.cmdcall][.rx]") { Detector det; Caller caller(&det); - auto prev_val = det.getRxZmqDataStream(); - { - std::ostringstream oss; - caller.call("rx_zmqstream", {"1"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_zmqstream 1\n"); - REQUIRE(det.getRxZmqDataStream().squash() == true); - } - { - std::ostringstream oss; - caller.call("rx_zmqstream", {}, -1, GET, oss); - REQUIRE(oss.str() == "rx_zmqstream 1\n"); - } - { - std::ostringstream oss; - caller.call("rx_zmqstream", {"0"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_zmqstream 0\n"); - REQUIRE(det.getRxZmqDataStream().squash() == false); - } - for (int i = 0; i != det.size(); ++i) { - det.setRxZmqDataStream(prev_val[i], {i}); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getRxZmqDataStream(); + { + std::ostringstream oss; + caller.call("rx_zmqstream", {"1"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_zmqstream 1\n"); + REQUIRE(det.getRxZmqDataStream().squash() == true); + } + { + std::ostringstream oss; + caller.call("rx_zmqstream", {}, -1, GET, oss); + REQUIRE(oss.str() == "rx_zmqstream 1\n"); + } + { + std::ostringstream oss; + caller.call("rx_zmqstream", {"0"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_zmqstream 0\n"); + REQUIRE(det.getRxZmqDataStream().squash() == false); + } + for (int i = 0; i != det.size(); ++i) { + det.setRxZmqDataStream(prev_val[i], {i}); + } + } else { + REQUIRE_THROWS(caller.call("rx_zmqstream", {}, -1, GET)); } } TEST_CASE("Caller::rx_zmqfreq", "[.cmdcall][.rx]") { Detector det; Caller caller(&det); - auto prev_val = det.getRxZmqFrequency(); - { - std::ostringstream oss; - caller.call("rx_zmqfreq", {"1"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_zmqfreq 1\n"); - } - { - std::ostringstream oss; - caller.call("rx_zmqfreq", {}, -1, GET, oss); - REQUIRE(oss.str() == "rx_zmqfreq 1\n"); - } - { - std::ostringstream oss; - caller.call("rx_zmqfreq", {"0"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_zmqfreq 0\n"); - } - for (int i = 0; i != det.size(); ++i) { - det.setRxZmqFrequency(prev_val[i], {i}); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getRxZmqFrequency(); + { + std::ostringstream oss; + caller.call("rx_zmqfreq", {"1"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_zmqfreq 1\n"); + } + { + std::ostringstream oss; + caller.call("rx_zmqfreq", {}, -1, GET, oss); + REQUIRE(oss.str() == "rx_zmqfreq 1\n"); + } + { + std::ostringstream oss; + caller.call("rx_zmqfreq", {"0"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_zmqfreq 0\n"); + } + for (int i = 0; i != det.size(); ++i) { + det.setRxZmqFrequency(prev_val[i], {i}); + } + } else { + REQUIRE_THROWS(caller.call("rx_zmqfreq", {}, -1, GET)); } } TEST_CASE("Caller::rx_zmqstartfnum", "[.cmdcall][.rx]") { Detector det; Caller caller(&det); - auto prev_val = det.getRxZmqStartingFrame(); - { - std::ostringstream oss; - caller.call("rx_zmqstartfnum", {"5"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_zmqstartfnum 5\n"); - } - { - std::ostringstream oss; - caller.call("rx_zmqstartfnum", {}, -1, GET, oss); - REQUIRE(oss.str() == "rx_zmqstartfnum 5\n"); - } - { - std::ostringstream oss; - caller.call("rx_zmqstartfnum", {"0"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_zmqstartfnum 0\n"); - } - for (int i = 0; i != det.size(); ++i) { - det.setRxZmqStartingFrame(prev_val[i], {i}); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getRxZmqStartingFrame(); + { + std::ostringstream oss; + caller.call("rx_zmqstartfnum", {"5"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_zmqstartfnum 5\n"); + } + { + std::ostringstream oss; + caller.call("rx_zmqstartfnum", {}, -1, GET, oss); + REQUIRE(oss.str() == "rx_zmqstartfnum 5\n"); + } + { + std::ostringstream oss; + caller.call("rx_zmqstartfnum", {"0"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_zmqstartfnum 0\n"); + } + for (int i = 0; i != det.size(); ++i) { + det.setRxZmqStartingFrame(prev_val[i], {i}); + } + } else { + REQUIRE_THROWS(caller.call("rx_zmqstartfnum", {}, -1, GET)); + } } TEST_CASE("Caller::rx_zmqport", "[.cmdcall][.rx]") { Detector det; Caller caller(&det); - auto prev_val_zmqport = det.getRxZmqPort(); - auto prev_val_numinterfaces = det.getNumberofUDPInterfaces().tsquash( - "inconsistent number of udp interfaces to test"); - - int socketsperdetector = 1; auto det_type = det.getDetectorType().squash(); - if (det_type == defs::EIGER) { - socketsperdetector *= 2; - } else if (det_type == defs::JUNGFRAU || det_type == defs::MOENCH) { - caller.call("numinterfaces", {"2"}, -1, PUT); - socketsperdetector *= 2; - } - uint16_t port = 3500; - caller.call("rx_zmqport", {std::to_string(port)}, -1, PUT); - for (int i = 0; i != det.size(); ++i) { - std::ostringstream oss; - caller.call("rx_zmqport", {}, i, GET, oss); - REQUIRE(oss.str() == "rx_zmqport " + - std::to_string(port + i * socketsperdetector) + - '\n'); - } - port = 30001; - caller.call("rx_zmqport", {std::to_string(port)}, -1, PUT); - for (int i = 0; i != det.size(); ++i) { - std::ostringstream oss; - caller.call("rx_zmqport", {}, i, GET, oss); - REQUIRE(oss.str() == "rx_zmqport " + - std::to_string(port + i * socketsperdetector) + - '\n'); - } - test_valid_port_caller("rx_zmqport", {}, -1, PUT); - test_valid_port_caller("rx_zmqport", {}, 0, PUT); - // should fail for the second module - if (det.size() > 1) { - REQUIRE_THROWS(caller.call("rx_zmqport", {"65535"}, -1, PUT)); - } + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val_zmqport = det.getRxZmqPort(); + auto prev_val_numinterfaces = det.getNumberofUDPInterfaces().tsquash( + "inconsistent number of udp interfaces to test"); - for (int i = 0; i != det.size(); ++i) { - det.setRxZmqPort(prev_val_zmqport[i], i); - } - if (det_type == defs::JUNGFRAU || det_type == defs::MOENCH) { - det.setNumberofUDPInterfaces(prev_val_numinterfaces); + int socketsperdetector = 1; + auto det_type = det.getDetectorType().squash(); + if (det_type == defs::EIGER) { + socketsperdetector *= 2; + } else if (det_type == defs::JUNGFRAU || det_type == defs::MOENCH) { + caller.call("numinterfaces", {"2"}, -1, PUT); + socketsperdetector *= 2; + } + uint16_t port = 3500; + caller.call("rx_zmqport", {std::to_string(port)}, -1, PUT); + for (int i = 0; i != det.size(); ++i) { + std::ostringstream oss; + caller.call("rx_zmqport", {}, i, GET, oss); + REQUIRE(oss.str() == "rx_zmqport " + + std::to_string(port + i * socketsperdetector) + + '\n'); + } + port = 30001; + caller.call("rx_zmqport", {std::to_string(port)}, -1, PUT); + for (int i = 0; i != det.size(); ++i) { + std::ostringstream oss; + caller.call("rx_zmqport", {}, i, GET, oss); + REQUIRE(oss.str() == "rx_zmqport " + + std::to_string(port + i * socketsperdetector) + + '\n'); + } + test_valid_port_caller("rx_zmqport", {}, -1, PUT); + test_valid_port_caller("rx_zmqport", {}, 0, PUT); + // should fail for the second module + if (det.size() > 1) { + REQUIRE_THROWS(caller.call("rx_zmqport", {"65535"}, -1, PUT)); + } + + for (int i = 0; i != det.size(); ++i) { + det.setRxZmqPort(prev_val_zmqport[i], i); + } + if (det_type == defs::JUNGFRAU || det_type == defs::MOENCH) { + det.setNumberofUDPInterfaces(prev_val_numinterfaces); + } + } else { + REQUIRE_THROWS(caller.call("rx_zmqport", {}, -1, GET)); } } TEST_CASE("Caller::rx_zmqip", "[.cmdcall][.rx]") { Detector det; Caller caller(&det); - auto prev_val = det.getRxZmqIP(); - { - std::ostringstream oss; - caller.call("rx_zmqip", {"127.0.0.1"}, 0, PUT, oss); - REQUIRE(oss.str() == "rx_zmqip 127.0.0.1\n"); - std::cout << "ZMQIP: " << det.getRxZmqIP() << '\n'; - } - { - std::ostringstream oss; - caller.call("rx_zmqip", {}, 0, GET, oss); - REQUIRE(oss.str() == "rx_zmqip 127.0.0.1\n"); - } - for (int i = 0; i != det.size(); ++i) { - det.setRxZmqIP(prev_val[i], {i}); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getRxZmqIP(); + { + std::ostringstream oss; + caller.call("rx_zmqip", {"127.0.0.1"}, 0, PUT, oss); + REQUIRE(oss.str() == "rx_zmqip 127.0.0.1\n"); + std::cout << "ZMQIP: " << det.getRxZmqIP() << '\n'; + } + { + std::ostringstream oss; + caller.call("rx_zmqip", {}, 0, GET, oss); + REQUIRE(oss.str() == "rx_zmqip 127.0.0.1\n"); + } + for (int i = 0; i != det.size(); ++i) { + det.setRxZmqIP(prev_val[i], {i}); + } + } else { + REQUIRE_THROWS(caller.call("rx_zmqip", {}, -1, GET)); } } TEST_CASE("Caller::rx_zmqhwm", "[.cmdcall]") { Detector det; Caller caller(&det); - auto prev_val = - det.getRxZmqHwm().tsquash("Inconsistent values for rx_zmqhwm to test"); - { - std::ostringstream oss; - caller.call("rx_zmqhwm", {"50"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_zmqhwm 50\n"); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val = + det.getRxZmqHwm().tsquash("Inconsistent values for rx_zmqhwm to test"); + { + std::ostringstream oss; + caller.call("rx_zmqhwm", {"50"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_zmqhwm 50\n"); + } + { + std::ostringstream oss; + caller.call("rx_zmqhwm", {}, -1, GET, oss); + REQUIRE(oss.str() == "rx_zmqhwm 50\n"); + } + { + std::ostringstream oss; + caller.call("rx_zmqhwm", {"0"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_zmqhwm 0\n"); + } + { + std::ostringstream oss; + caller.call("rx_zmqhwm", {"-1"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_zmqhwm -1\n"); + } + det.setRxZmqHwm(prev_val); + } else { + REQUIRE_THROWS(caller.call("rx_zmqhwm", {}, -1, GET)); } - { - std::ostringstream oss; - caller.call("rx_zmqhwm", {}, -1, GET, oss); - REQUIRE(oss.str() == "rx_zmqhwm 50\n"); - } - { - std::ostringstream oss; - caller.call("rx_zmqhwm", {"0"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_zmqhwm 0\n"); - } - { - std::ostringstream oss; - caller.call("rx_zmqhwm", {"-1"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_zmqhwm -1\n"); - } - det.setRxZmqHwm(prev_val); } /* CTB Specific */ @@ -976,56 +1149,66 @@ TEST_CASE("Caller::rx_dbitoffset", "[.cmdcall][.rx]") { TEST_CASE("Caller::rx_jsonaddheader", "[.cmdcall][.rx]") { Detector det; Caller caller(&det); - auto prev_val = det.getAdditionalJsonHeader(); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getAdditionalJsonHeader(); - { - std::ostringstream oss; - caller.call("rx_jsonaddheader", {"key1", "value1", "key2", "value2"}, - -1, PUT, oss); - REQUIRE(oss.str() == "rx_jsonaddheader {key1: value1, key2: value2}\n"); - } - { - std::ostringstream oss; - caller.call("rx_jsonaddheader", {}, -1, GET, oss); - REQUIRE(oss.str() == "rx_jsonaddheader {key1: value1, key2: value2}\n"); - } - { - std::ostringstream oss; - caller.call("rx_jsonaddheader", {}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_jsonaddheader {}\n"); - } - for (int i = 0; i != det.size(); ++i) { - det.setAdditionalJsonHeader(prev_val[i], {i}); + { + std::ostringstream oss; + caller.call("rx_jsonaddheader", {"key1", "value1", "key2", "value2"}, + -1, PUT, oss); + REQUIRE(oss.str() == "rx_jsonaddheader {key1: value1, key2: value2}\n"); + } + { + std::ostringstream oss; + caller.call("rx_jsonaddheader", {}, -1, GET, oss); + REQUIRE(oss.str() == "rx_jsonaddheader {key1: value1, key2: value2}\n"); + } + { + std::ostringstream oss; + caller.call("rx_jsonaddheader", {}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_jsonaddheader {}\n"); + } + for (int i = 0; i != det.size(); ++i) { + det.setAdditionalJsonHeader(prev_val[i], {i}); + } + } else { + REQUIRE_THROWS(caller.call("rx_jsonaddheader", {}, -1, GET)); } } TEST_CASE("Caller::rx_jsonpara", "[.cmdcall][.rx]") { Detector det; Caller caller(&det); - auto prev_val = det.getAdditionalJsonHeader(); - { - std::ostringstream oss; - caller.call("rx_jsonpara", {"key1", "value1"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_jsonpara {key1: value1}\n"); - } - { - std::ostringstream oss; - caller.call("rx_jsonpara", {"key1", "value2"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_jsonpara {key1: value2}\n"); - } - { - std::ostringstream oss; - caller.call("rx_jsonpara", {"key1"}, -1, GET, oss); - REQUIRE(oss.str() == "rx_jsonpara value2\n"); - } - { - std::ostringstream oss; - caller.call("rx_jsonpara", {"key1"}, -1, PUT, oss); - REQUIRE(oss.str() == "rx_jsonpara key1 deleted\n"); - } - REQUIRE_THROWS(caller.call("rx_jsonpara", {"key1"}, -1, GET)); - for (int i = 0; i != det.size(); ++i) { - det.setAdditionalJsonHeader(prev_val[i], {i}); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getAdditionalJsonHeader(); + { + std::ostringstream oss; + caller.call("rx_jsonpara", {"key1", "value1"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_jsonpara {key1: value1}\n"); + } + { + std::ostringstream oss; + caller.call("rx_jsonpara", {"key1", "value2"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_jsonpara {key1: value2}\n"); + } + { + std::ostringstream oss; + caller.call("rx_jsonpara", {"key1"}, -1, GET, oss); + REQUIRE(oss.str() == "rx_jsonpara value2\n"); + } + { + std::ostringstream oss; + caller.call("rx_jsonpara", {"key1"}, -1, PUT, oss); + REQUIRE(oss.str() == "rx_jsonpara key1 deleted\n"); + } + REQUIRE_THROWS(caller.call("rx_jsonpara", {"key1"}, -1, GET)); + for (int i = 0; i != det.size(); ++i) { + det.setAdditionalJsonHeader(prev_val[i], {i}); + } + } else { + REQUIRE_THROWS(caller.call("rx_jsonpara", {}, -1, GET)); } } diff --git a/slsDetectorSoftware/tests/Caller/test-Caller.cpp b/slsDetectorSoftware/tests/Caller/test-Caller.cpp index b764e7adb..e1a31e239 100644 --- a/slsDetectorSoftware/tests/Caller/test-Caller.cpp +++ b/slsDetectorSoftware/tests/Caller/test-Caller.cpp @@ -27,30 +27,6 @@ TEST_CASE("CALLER::Caller::Calling help doesn't throw or cause segfault") { caller.call(cmd, {}, -1, slsDetectorDefs::HELP_ACTION, os)); } -TEST_CASE("CALLER::Caller::period", "[.cmdcall]") { - Detector det; - Caller caller(&det); - auto prev_val = det.getPeriod(); - { - std::ostringstream oss; - caller.call("period", {"1.25s"}, -1, PUT, oss); - REQUIRE(oss.str() == "period 1.25s\n"); - } - { - std::ostringstream oss; - caller.call("period", {}, -1, GET, oss); - REQUIRE(oss.str() == "period 1.25s\n"); - } - { - std::ostringstream oss; - caller.call("period", {"0"}, -1, PUT, oss); - REQUIRE(oss.str() == "period 0\n"); - } - for (int i = 0; i != det.size(); ++i) { - det.setPeriod(prev_val[i], {i}); - } -} - TEST_CASE("CALLER::Unknown command", "[.cmdcall]") { Detector det; Caller caller(&det); @@ -111,8 +87,13 @@ TEST_CASE("CALLER::virtual", "[.cmdcall]") { TEST_CASE("CALLER::versions", "[.cmdcall]") { Detector det; Caller caller(&det); - REQUIRE_NOTHROW(caller.call("versions", {}, -1, GET)); - REQUIRE_THROWS(caller.call("versions", {"0"}, -1, PUT)); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + REQUIRE_NOTHROW(caller.call("versions", {}, -1, GET)); + REQUIRE_THROWS(caller.call("versions", {"0"}, -1, PUT)); + } else { + REQUIRE_THROWS(caller.call("versions", {}, -1, GET)); + } } TEST_CASE("CALLER::packageversion", "[.cmdcall]") { @@ -146,22 +127,32 @@ TEST_CASE("CALLER::detectorserverversion", "[.cmdcall]") { TEST_CASE("CALLER::hardwareversion", "[.cmdcall]") { Detector det; Caller caller(&det); - REQUIRE_NOTHROW(caller.call("hardwareversion", {}, -1, GET)); - REQUIRE_THROWS(caller.call("hardwareversion", {"0"}, -1, PUT)); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + REQUIRE_NOTHROW(caller.call("hardwareversion", {}, -1, GET)); + REQUIRE_THROWS(caller.call("hardwareversion", {"0"}, -1, PUT)); + } else { + REQUIRE_THROWS(caller.call("hardwareversion", {}, -1, GET)); + } } TEST_CASE("CALLER::kernelversion", "[.cmdcall]") { Detector det; Caller caller(&det); - REQUIRE_NOTHROW(caller.call("kernelversion", {}, -1, GET)); - REQUIRE_THROWS(caller.call("kernelversion", {"0"}, -1, PUT)); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + REQUIRE_NOTHROW(caller.call("kernelversion", {}, -1, GET)); + REQUIRE_THROWS(caller.call("kernelversion", {"0"}, -1, PUT)); + } else { + REQUIRE_THROWS(caller.call("kernelversion", {}, -1, GET)); + } } TEST_CASE("CALLER::serialnumber", "[.cmdcall]") { Detector det; Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type == defs::EIGER) { + if (det_type == defs::EIGER || det_type == defs::XILINX_CHIPTESTBOARD) { REQUIRE_THROWS(caller.call("serialnumber", {}, -1, GET)); } else { REQUIRE_NOTHROW(caller.call("serialnumber", {}, -1, GET)); @@ -203,7 +194,7 @@ TEST_CASE("CALLER::settingslist", "[.cmdcall]") { Detector det; Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type == defs::CHIPTESTBOARD) { + if (det_type == defs::CHIPTESTBOARD || det_type == defs::XILINX_CHIPTESTBOARD) { REQUIRE_THROWS(caller.call("settingslist", {}, -1, GET)); } else { REQUIRE_NOTHROW(caller.call("settingslist", {}, -1, GET)); @@ -848,73 +839,82 @@ TEST_CASE("CALLER::exptime", "[.cmdcall][.time]") { Detector det; Caller caller(&det); auto det_type = det.getDetectorType().squash(); - std::chrono::nanoseconds prev_val; - if (det_type != defs::MYTHEN3) { - prev_val = det.getExptime().tsquash("inconsistent exptime to test"); - } else { - auto t = - det.getExptimeForAllGates().tsquash("inconsistent exptime to test"); - if (t[0] != t[1] || t[1] != t[2]) { - throw RuntimeError("inconsistent exptime for all gates"); - } - prev_val = t[0]; - } - { - std::ostringstream oss; - caller.call("exptime", {"0.05"}, -1, PUT, oss); - REQUIRE(oss.str() == "exptime 0.05\n"); - } - if (det_type != defs::MYTHEN3) { - std::ostringstream oss; - caller.call("exptime", {}, -1, GET, oss); - REQUIRE(oss.str() == "exptime 50ms\n"); - } - { - std::ostringstream oss; - caller.call("exptime", {"1s"}, -1, PUT, oss); - REQUIRE(oss.str() == "exptime 1s\n"); - } - if (det_type != defs::JUNGFRAU && det_type != defs::MOENCH) { - { - std::ostringstream oss; - caller.call("exptime", {"0"}, -1, PUT, oss); - REQUIRE(oss.str() == "exptime 0\n"); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + std::chrono::nanoseconds prev_val; + if (det_type != defs::MYTHEN3) { + prev_val = det.getExptime().tsquash("inconsistent exptime to test"); + } else { + auto t = + det.getExptimeForAllGates().tsquash("inconsistent exptime to test"); + if (t[0] != t[1] || t[1] != t[2]) { + throw RuntimeError("inconsistent exptime for all gates"); + } + prev_val = t[0]; } { - // Get exptime of single module std::ostringstream oss; - caller.call("exptime", {}, 0, GET, oss); - if (det_type == defs::MYTHEN3) { - REQUIRE(oss.str() == "exptime [0ns, 0ns, 0ns]\n"); - } else { - REQUIRE(oss.str() == "exptime 0ns\n"); + caller.call("exptime", {"0.05"}, -1, PUT, oss); + REQUIRE(oss.str() == "exptime 0.05\n"); + } + if (det_type != defs::MYTHEN3) { + std::ostringstream oss; + caller.call("exptime", {}, -1, GET, oss); + REQUIRE(oss.str() == "exptime 50ms\n"); + } + { + std::ostringstream oss; + caller.call("exptime", {"1s"}, -1, PUT, oss); + REQUIRE(oss.str() == "exptime 1s\n"); + } + if (det_type != defs::JUNGFRAU && det_type != defs::MOENCH) { + { + std::ostringstream oss; + caller.call("exptime", {"0"}, -1, PUT, oss); + REQUIRE(oss.str() == "exptime 0\n"); + } + { + // Get exptime of single module + std::ostringstream oss; + caller.call("exptime", {}, 0, GET, oss); + if (det_type == defs::MYTHEN3) { + REQUIRE(oss.str() == "exptime [0ns, 0ns, 0ns]\n"); + } else { + REQUIRE(oss.str() == "exptime 0ns\n"); + } } } + det.setExptime(-1, prev_val); + } else { + REQUIRE_THROWS(caller.call("exptime", {}, -1, GET)); } - det.setExptime(-1, prev_val); } TEST_CASE("CALLER::period", "[.cmdcall]") { Detector det; Caller caller(&det); - auto prev_val = det.getPeriod(); - { - std::ostringstream oss; - caller.call("period", {"1.25s"}, -1, PUT, oss); - REQUIRE(oss.str() == "period 1.25s\n"); - } - { - std::ostringstream oss; - caller.call("period", {}, -1, GET, oss); - REQUIRE(oss.str() == "period 1.25s\n"); - } - { - std::ostringstream oss; - caller.call("period", {"0"}, -1, PUT, oss); - REQUIRE(oss.str() == "period 0\n"); - } - for (int i = 0; i != det.size(); ++i) { - det.setPeriod(prev_val[i], {i}); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getPeriod(); + { + std::ostringstream oss; + caller.call("period", {"1.25s"}, -1, PUT, oss); + REQUIRE(oss.str() == "period 1.25s\n"); + } + { + std::ostringstream oss; + caller.call("period", {}, -1, GET, oss); + REQUIRE(oss.str() == "period 1.25s\n"); + } + { + std::ostringstream oss; + caller.call("period", {"0"}, -1, PUT, oss); + REQUIRE(oss.str() == "period 0\n"); + } + for (int i = 0; i != det.size(); ++i) { + det.setPeriod(prev_val[i], {i}); + } + } else { + REQUIRE_THROWS(caller.call("period", {}, -1, GET)); } } @@ -922,32 +922,36 @@ TEST_CASE("CALLER::delay", "[.cmdcall]") { Detector det; Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type == defs::EIGER) { - REQUIRE_THROWS(caller.call("delay", {"1"}, -1, PUT)); - REQUIRE_THROWS(caller.call("delay", {}, -1, GET)); - } else if (det_type == defs::GOTTHARD) { - // extra delays for master (can throw when setting) - REQUIRE_NOTHROW(caller.call("delay", {}, -1, GET)); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + if (det_type == defs::EIGER) { + REQUIRE_THROWS(caller.call("delay", {"1"}, -1, PUT)); + REQUIRE_THROWS(caller.call("delay", {}, -1, GET)); + } else if (det_type == defs::GOTTHARD) { + // extra delays for master (can throw when setting) + REQUIRE_NOTHROW(caller.call("delay", {}, -1, GET)); + } else { + auto prev_val = det.getDelayAfterTrigger(); + { + std::ostringstream oss; + caller.call("delay", {"1.25s"}, -1, PUT, oss); + REQUIRE(oss.str() == "delay 1.25s\n"); + } + { + std::ostringstream oss; + caller.call("delay", {}, -1, GET, oss); + REQUIRE(oss.str() == "delay 1.25s\n"); + } + { + std::ostringstream oss; + caller.call("delay", {"0s"}, -1, PUT, oss); + REQUIRE(oss.str() == "delay 0s\n"); + } + for (int i = 0; i != det.size(); ++i) { + det.setDelayAfterTrigger(prev_val[i], {i}); + } + } } else { - auto prev_val = det.getDelayAfterTrigger(); - { - std::ostringstream oss; - caller.call("delay", {"1.25s"}, -1, PUT, oss); - REQUIRE(oss.str() == "delay 1.25s\n"); - } - { - std::ostringstream oss; - caller.call("delay", {}, -1, GET, oss); - REQUIRE(oss.str() == "delay 1.25s\n"); - } - { - std::ostringstream oss; - caller.call("delay", {"0s"}, -1, PUT, oss); - REQUIRE(oss.str() == "delay 0s\n"); - } - for (int i = 0; i != det.size(); ++i) { - det.setDelayAfterTrigger(prev_val[i], {i}); - } + REQUIRE_THROWS(caller.call("delay", {}, -1, GET)); } } @@ -955,7 +959,7 @@ TEST_CASE("CALLER::framesl", "[.cmdcall]") { Detector det; Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type == defs::EIGER) { + if (det_type == defs::EIGER || det_type == defs::XILINX_CHIPTESTBOARD) { REQUIRE_THROWS(caller.call("framesl", {}, -1, GET)); } else { REQUIRE_NOTHROW(caller.call("framesl", {}, -1, GET)); @@ -966,7 +970,7 @@ TEST_CASE("CALLER::triggersl", "[.cmdcall]") { Detector det; Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type == defs::EIGER) { + if (det_type == defs::EIGER || det_type == defs::XILINX_CHIPTESTBOARD) { REQUIRE_THROWS(caller.call("triggersl", {}, -1, GET)); } else { REQUIRE_NOTHROW(caller.call("triggersl", {}, -1, GET)); @@ -980,6 +984,7 @@ TEST_CASE("CALLER::delayl", "[.cmdcall]") { switch (det_type) { case defs::EIGER: case defs::CHIPTESTBOARD: + case defs::XILINX_CHIPTESTBOARD: case defs::GOTTHARD2: case defs::MYTHEN3: REQUIRE_THROWS(caller.call("delayl", {}, -1, GET)); @@ -997,6 +1002,7 @@ TEST_CASE("CALLER::periodl", "[.cmdcall]") { switch (det_type) { case defs::EIGER: case defs::CHIPTESTBOARD: + case defs::XILINX_CHIPTESTBOARD: case defs::GOTTHARD2: case defs::MYTHEN3: REQUIRE_THROWS(caller.call("periodl", {}, -1, GET)); @@ -1011,41 +1017,45 @@ TEST_CASE("CALLER::dr", "[.cmdcall]") { Detector det; Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type == defs::EIGER) { - auto dr = det.getDynamicRange().squash(); - std::array vals{4, 8, 16, 32}; - for (const auto val : vals) { - std::ostringstream oss1, oss2; - caller.call("dr", {std::to_string(val)}, -1, PUT, oss1); - REQUIRE(oss1.str() == "dr " + std::to_string(val) + '\n'); - caller.call("dr", {}, -1, GET, oss2); - REQUIRE(oss2.str() == "dr " + std::to_string(val) + '\n'); - } - det.setDynamicRange(dr); - } else if (det_type == defs::MYTHEN3) { - auto dr = det.getDynamicRange().squash(); - // not updated in firmware to support dr 1 - std::array vals{8, 16, 32}; - for (const auto val : vals) { - std::ostringstream oss1, oss2; - caller.call("dr", {std::to_string(val)}, -1, PUT, oss1); - REQUIRE(oss1.str() == "dr " + std::to_string(val) + '\n'); - caller.call("dr", {}, -1, GET, oss2); - REQUIRE(oss2.str() == "dr " + std::to_string(val) + '\n'); - } - det.setDynamicRange(dr); - } else { - // For the other detectors we should get an error message - // except for dr 16 - REQUIRE_THROWS(caller.call("dr", {"4"}, -1, PUT)); - REQUIRE_THROWS(caller.call("dr", {"8"}, -1, PUT)); - REQUIRE_THROWS(caller.call("dr", {"32"}, -1, PUT)); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + if (det_type == defs::EIGER) { + auto dr = det.getDynamicRange().squash(); + std::array vals{4, 8, 16, 32}; + for (const auto val : vals) { + std::ostringstream oss1, oss2; + caller.call("dr", {std::to_string(val)}, -1, PUT, oss1); + REQUIRE(oss1.str() == "dr " + std::to_string(val) + '\n'); + caller.call("dr", {}, -1, GET, oss2); + REQUIRE(oss2.str() == "dr " + std::to_string(val) + '\n'); + } + det.setDynamicRange(dr); + } else if (det_type == defs::MYTHEN3) { + auto dr = det.getDynamicRange().squash(); + // not updated in firmware to support dr 1 + std::array vals{8, 16, 32}; + for (const auto val : vals) { + std::ostringstream oss1, oss2; + caller.call("dr", {std::to_string(val)}, -1, PUT, oss1); + REQUIRE(oss1.str() == "dr " + std::to_string(val) + '\n'); + caller.call("dr", {}, -1, GET, oss2); + REQUIRE(oss2.str() == "dr " + std::to_string(val) + '\n'); + } + det.setDynamicRange(dr); + } else { + // For the other detectors we should get an error message + // except for dr 16 + REQUIRE_THROWS(caller.call("dr", {"4"}, -1, PUT)); + REQUIRE_THROWS(caller.call("dr", {"8"}, -1, PUT)); + REQUIRE_THROWS(caller.call("dr", {"32"}, -1, PUT)); - std::ostringstream oss1, oss2; - caller.call("dr", {"16"}, -1, PUT, oss1); - REQUIRE(oss1.str() == "dr 16\n"); - caller.call("dr", {"16"}, -1, PUT, oss2); - REQUIRE(oss2.str() == "dr 16\n"); + std::ostringstream oss1, oss2; + caller.call("dr", {"16"}, -1, PUT, oss1); + REQUIRE(oss1.str() == "dr 16\n"); + caller.call("dr", {"16"}, -1, PUT, oss2); + REQUIRE(oss2.str() == "dr 16\n"); + } + } else { + REQUIRE_THROWS(caller.call("dr", {}, -1, GET)); } } @@ -1059,62 +1069,67 @@ TEST_CASE("CALLER::drlist", "[.cmdcall]") { TEST_CASE("CALLER::timing", "[.cmdcall]") { Detector det; Caller caller(&det); - auto prev_val = det.getTimingMode(); - det.setTimingMode(defs::AUTO_TIMING); - { - std::ostringstream oss1, oss2; - caller.call("timing", {"auto"}, -1, PUT, oss1); - REQUIRE(oss1.str() == "timing auto\n"); - caller.call("timing", {}, -1, GET, oss2); - REQUIRE(oss2.str() == "timing auto\n"); - } - { - std::ostringstream oss1, oss2; - caller.call("timing", {"trigger"}, -1, PUT, oss1); - REQUIRE(oss1.str() == "timing trigger\n"); - caller.call("timing", {}, -1, GET, oss2); - REQUIRE(oss2.str() == "timing trigger\n"); - } auto det_type = det.getDetectorType().squash(); - if (det_type == defs::EIGER) { + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getTimingMode(); + det.setTimingMode(defs::AUTO_TIMING); { std::ostringstream oss1, oss2; - caller.call("timing", {"gating"}, -1, PUT, oss1); - REQUIRE(oss1.str() == "timing gating\n"); + caller.call("timing", {"auto"}, -1, PUT, oss1); + REQUIRE(oss1.str() == "timing auto\n"); caller.call("timing", {}, -1, GET, oss2); - REQUIRE(oss2.str() == "timing gating\n"); + REQUIRE(oss2.str() == "timing auto\n"); } { std::ostringstream oss1, oss2; - caller.call("timing", {"burst_trigger"}, -1, PUT, oss1); - REQUIRE(oss1.str() == "timing burst_trigger\n"); + caller.call("timing", {"trigger"}, -1, PUT, oss1); + REQUIRE(oss1.str() == "timing trigger\n"); caller.call("timing", {}, -1, GET, oss2); - REQUIRE(oss2.str() == "timing burst_trigger\n"); + REQUIRE(oss2.str() == "timing trigger\n"); } - REQUIRE_THROWS(caller.call("timing", {"trigger_gating"}, -1, PUT)); - } else if (det_type == defs::MYTHEN3) { - { - std::ostringstream oss1, oss2; - caller.call("timing", {"gating"}, -1, PUT, oss1); - REQUIRE(oss1.str() == "timing gating\n"); - caller.call("timing", {}, -1, GET, oss2); - REQUIRE(oss2.str() == "timing gating\n"); + if (det_type == defs::EIGER) { + { + std::ostringstream oss1, oss2; + caller.call("timing", {"gating"}, -1, PUT, oss1); + REQUIRE(oss1.str() == "timing gating\n"); + caller.call("timing", {}, -1, GET, oss2); + REQUIRE(oss2.str() == "timing gating\n"); + } + { + std::ostringstream oss1, oss2; + caller.call("timing", {"burst_trigger"}, -1, PUT, oss1); + REQUIRE(oss1.str() == "timing burst_trigger\n"); + caller.call("timing", {}, -1, GET, oss2); + REQUIRE(oss2.str() == "timing burst_trigger\n"); + } + REQUIRE_THROWS(caller.call("timing", {"trigger_gating"}, -1, PUT)); + } else if (det_type == defs::MYTHEN3) { + { + std::ostringstream oss1, oss2; + caller.call("timing", {"gating"}, -1, PUT, oss1); + REQUIRE(oss1.str() == "timing gating\n"); + caller.call("timing", {}, -1, GET, oss2); + REQUIRE(oss2.str() == "timing gating\n"); + } + { + std::ostringstream oss1, oss2; + caller.call("timing", {"trigger_gating"}, -1, PUT, oss1); + REQUIRE(oss1.str() == "timing trigger_gating\n"); + caller.call("timing", {}, -1, GET, oss2); + REQUIRE(oss2.str() == "timing trigger_gating\n"); + } + REQUIRE_THROWS(caller.call("timing", {"burst_trigger"}, -1, PUT)); + } else { + REQUIRE_THROWS(caller.call("timing", {"gating"}, -1, PUT)); + REQUIRE_THROWS(caller.call("timing", {"burst_trigger"}, -1, PUT)); + REQUIRE_THROWS(caller.call("timing", {"trigger_gating"}, -1, PUT)); } - { - std::ostringstream oss1, oss2; - caller.call("timing", {"trigger_gating"}, -1, PUT, oss1); - REQUIRE(oss1.str() == "timing trigger_gating\n"); - caller.call("timing", {}, -1, GET, oss2); - REQUIRE(oss2.str() == "timing trigger_gating\n"); + for (int i = 0; i != det.size(); ++i) { + det.setTimingMode(prev_val[i], {i}); } - REQUIRE_THROWS(caller.call("timing", {"burst_trigger"}, -1, PUT)); } else { - REQUIRE_THROWS(caller.call("timing", {"gating"}, -1, PUT)); - REQUIRE_THROWS(caller.call("timing", {"burst_trigger"}, -1, PUT)); - REQUIRE_THROWS(caller.call("timing", {"trigger_gating"}, -1, PUT)); - } - for (int i = 0; i != det.size(); ++i) { - det.setTimingMode(prev_val[i], {i}); + REQUIRE_THROWS(caller.call("timing", {}, -1, GET)); + } } @@ -1417,97 +1432,102 @@ TEST_CASE("CALLER::highvoltage", "[.cmdcall]") { Detector det; Caller caller(&det); auto det_type = det.getDetectorType().squash(); - auto prev_val = det.getHighVoltage(); - // selected values - if (det_type == defs::GOTTHARD) { - REQUIRE_THROWS(caller.call("highvoltage", {"50"}, -1, PUT)); - { - std::ostringstream oss1, oss2; - caller.call("highvoltage", {"90"}, -1, PUT, oss1); - REQUIRE(oss1.str() == "highvoltage 90\n"); - caller.call("highvoltage", {}, -1, GET, oss2); - REQUIRE(oss2.str() == "highvoltage 90\n"); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getHighVoltage(); + // selected values + if (det_type == defs::GOTTHARD) { + REQUIRE_THROWS(caller.call("highvoltage", {"50"}, -1, PUT)); + { + std::ostringstream oss1, oss2; + caller.call("highvoltage", {"90"}, -1, PUT, oss1); + REQUIRE(oss1.str() == "highvoltage 90\n"); + caller.call("highvoltage", {}, -1, GET, oss2); + REQUIRE(oss2.str() == "highvoltage 90\n"); + } + { + std::ostringstream oss1, oss2; + caller.call("highvoltage", {"0"}, -1, PUT, oss1); + REQUIRE(oss1.str() == "highvoltage 0\n"); + caller.call("highvoltage", {}, -1, GET, oss2); + REQUIRE(oss2.str() == "highvoltage 0\n"); + } } - { - std::ostringstream oss1, oss2; - caller.call("highvoltage", {"0"}, -1, PUT, oss1); - REQUIRE(oss1.str() == "highvoltage 0\n"); - caller.call("highvoltage", {}, -1, GET, oss2); - REQUIRE(oss2.str() == "highvoltage 0\n"); + // range 0, 60 - 200 + else if (det_type == defs::JUNGFRAU || det_type == defs::MOENCH || + det_type == defs::CHIPTESTBOARD) { + REQUIRE_THROWS(caller.call("highvoltage", {"50"}, -1, PUT)); + { + std::ostringstream oss1, oss2; + caller.call("highvoltage", {"90"}, -1, PUT, oss1); + REQUIRE(oss1.str() == "highvoltage 90\n"); + caller.call("highvoltage", {}, -1, GET, oss2); + REQUIRE(oss2.str() == "highvoltage 90\n"); + } + { + std::ostringstream oss1, oss2; + caller.call("highvoltage", {"0"}, -1, PUT, oss1); + REQUIRE(oss1.str() == "highvoltage 0\n"); + caller.call("highvoltage", {}, -1, GET, oss2); + REQUIRE(oss2.str() == "highvoltage 0\n"); + } } - } - // range 0, 60 - 200 - else if (det_type == defs::JUNGFRAU || det_type == defs::MOENCH || - det_type == defs::CHIPTESTBOARD) { - REQUIRE_THROWS(caller.call("highvoltage", {"50"}, -1, PUT)); - { - std::ostringstream oss1, oss2; - caller.call("highvoltage", {"90"}, -1, PUT, oss1); - REQUIRE(oss1.str() == "highvoltage 90\n"); - caller.call("highvoltage", {}, -1, GET, oss2); - REQUIRE(oss2.str() == "highvoltage 90\n"); + // full range 0 - 200 (get needs to wait) + else if (det_type == defs::EIGER) { + { + std::ostringstream oss1, oss2; + caller.call("highvoltage", {"50"}, 0, PUT, oss1); + REQUIRE(oss1.str() == "highvoltage 50\n"); + std::this_thread::sleep_for(std::chrono::seconds(2)); + caller.call("highvoltage", {}, 0, GET, oss2); + REQUIRE(oss2.str() == "highvoltage 50\n"); + } + { + std::ostringstream oss1, oss2; + caller.call("highvoltage", {"120"}, 0, PUT, oss1); + REQUIRE(oss1.str() == "highvoltage 120\n"); + std::this_thread::sleep_for(std::chrono::seconds(2)); + caller.call("highvoltage", {}, 0, GET, oss2); + REQUIRE(oss2.str() == "highvoltage 120\n"); + } + { + std::ostringstream oss1, oss2; + caller.call("highvoltage", {"0"}, 0, PUT, oss1); + REQUIRE(oss1.str() == "highvoltage 0\n"); + std::this_thread::sleep_for(std::chrono::seconds(2)); + caller.call("highvoltage", {}, 0, GET, oss2); + REQUIRE(oss2.str() == "highvoltage 0\n"); + } } - { - std::ostringstream oss1, oss2; - caller.call("highvoltage", {"0"}, -1, PUT, oss1); - REQUIRE(oss1.str() == "highvoltage 0\n"); - caller.call("highvoltage", {}, -1, GET, oss2); - REQUIRE(oss2.str() == "highvoltage 0\n"); + // full range 0 - 200 + else { + { + std::ostringstream oss1, oss2; + caller.call("highvoltage", {"50"}, -1, PUT, oss1); + REQUIRE(oss1.str() == "highvoltage 50\n"); + caller.call("highvoltage", {}, -1, GET, oss2); + REQUIRE(oss2.str() == "highvoltage 50\n"); + } + { + std::ostringstream oss1, oss2; + caller.call("highvoltage", {"120"}, -1, PUT, oss1); + REQUIRE(oss1.str() == "highvoltage 120\n"); + caller.call("highvoltage", {}, -1, GET, oss2); + REQUIRE(oss2.str() == "highvoltage 120\n"); + } + { + std::ostringstream oss1, oss2; + caller.call("highvoltage", {"0"}, -1, PUT, oss1); + REQUIRE(oss1.str() == "highvoltage 0\n"); + caller.call("highvoltage", {}, -1, GET, oss2); + REQUIRE(oss2.str() == "highvoltage 0\n"); + } } - } - // full range 0 - 200 (get needs to wait) - else if (det_type == defs::EIGER) { - { - std::ostringstream oss1, oss2; - caller.call("highvoltage", {"50"}, 0, PUT, oss1); - REQUIRE(oss1.str() == "highvoltage 50\n"); - std::this_thread::sleep_for(std::chrono::seconds(2)); - caller.call("highvoltage", {}, 0, GET, oss2); - REQUIRE(oss2.str() == "highvoltage 50\n"); + for (int i = 0; i != det.size(); ++i) { + det.setHighVoltage(prev_val[i], {i}); } - { - std::ostringstream oss1, oss2; - caller.call("highvoltage", {"120"}, 0, PUT, oss1); - REQUIRE(oss1.str() == "highvoltage 120\n"); - std::this_thread::sleep_for(std::chrono::seconds(2)); - caller.call("highvoltage", {}, 0, GET, oss2); - REQUIRE(oss2.str() == "highvoltage 120\n"); - } - { - std::ostringstream oss1, oss2; - caller.call("highvoltage", {"0"}, 0, PUT, oss1); - REQUIRE(oss1.str() == "highvoltage 0\n"); - std::this_thread::sleep_for(std::chrono::seconds(2)); - caller.call("highvoltage", {}, 0, GET, oss2); - REQUIRE(oss2.str() == "highvoltage 0\n"); - } - } - // full range 0 - 200 - else { - { - std::ostringstream oss1, oss2; - caller.call("highvoltage", {"50"}, -1, PUT, oss1); - REQUIRE(oss1.str() == "highvoltage 50\n"); - caller.call("highvoltage", {}, -1, GET, oss2); - REQUIRE(oss2.str() == "highvoltage 50\n"); - } - { - std::ostringstream oss1, oss2; - caller.call("highvoltage", {"120"}, -1, PUT, oss1); - REQUIRE(oss1.str() == "highvoltage 120\n"); - caller.call("highvoltage", {}, -1, GET, oss2); - REQUIRE(oss2.str() == "highvoltage 120\n"); - } - { - std::ostringstream oss1, oss2; - caller.call("highvoltage", {"0"}, -1, PUT, oss1); - REQUIRE(oss1.str() == "highvoltage 0\n"); - caller.call("highvoltage", {}, -1, GET, oss2); - REQUIRE(oss2.str() == "highvoltage 0\n"); - } - } - for (int i = 0; i != det.size(); ++i) { - det.setHighVoltage(prev_val[i], {i}); + } else { + REQUIRE_THROWS(caller.call("highvoltage", {"0"}, -1, PUT)); + REQUIRE_THROWS(caller.call("highvoltage", {}, -1, GET)); } } @@ -2005,7 +2025,7 @@ TEST_CASE("CALLER::temp_fpga", "[.cmdcall]") { Detector det; Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type != defs::CHIPTESTBOARD) { + if (det_type != defs::CHIPTESTBOARD && det_type != defs::XILINX_CHIPTESTBOARD) { REQUIRE_NOTHROW(caller.call("temp_fpga", {}, -1, GET)); std::ostringstream oss; REQUIRE_NOTHROW(caller.call("temp_fpga", {}, 0, GET, oss)); @@ -2056,15 +2076,21 @@ TEST_CASE("CALLER::daclist", "[.cmdcall]") { TEST_CASE("CALLER::dacvalues", "[.cmdcall]") { Detector det; Caller caller(&det); - REQUIRE_NOTHROW(caller.call("dacvalues", {}, -1, GET)); - REQUIRE_THROWS(caller.call("dacvalues", {}, -1, PUT)); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + REQUIRE_NOTHROW(caller.call("dacvalues", {}, -1, GET)); + REQUIRE_THROWS(caller.call("dacvalues", {}, -1, PUT)); + } else { + REQUIRE_THROWS(caller.call("dacvalues", {}, -1, GET)); + + } } TEST_CASE("CALLER::defaultdac", "[.cmdcall]") { Detector det; Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type != defs::CHIPTESTBOARD) { + if (det_type != defs::CHIPTESTBOARD && det_type != defs::XILINX_CHIPTESTBOARD) { REQUIRE_THROWS(caller.call("defaultdac", {}, -1, GET)); REQUIRE_THROWS(caller.call("defaultdac", {"blabla"}, -1, PUT)); auto daclist = det.getDacList(); @@ -2123,7 +2149,7 @@ TEST_CASE("CALLER::resetdacs", "[.cmdcall]") { Detector det; Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type != defs::CHIPTESTBOARD) { + if (det_type != defs::CHIPTESTBOARD && det_type != defs::XILINX_CHIPTESTBOARD) { auto prev_val = det.getSettings(); REQUIRE_THROWS(caller.call("resetdacs", {}, -1, GET)); @@ -2241,124 +2267,138 @@ TEST_CASE("CALLER::clearbusy", "[.cmdcall]") { TEST_CASE("CALLER::start", "[.cmdcall]") { Detector det; Caller caller(&det); - // PUT only command - REQUIRE_THROWS(caller.call("start", {}, -1, GET)); auto det_type = det.getDetectorType().squash(); - std::chrono::nanoseconds prev_val; - if (det_type != defs::MYTHEN3) { - prev_val = det.getExptime().tsquash("inconsistent exptime to test"); - } else { - auto t = - det.getExptimeForAllGates().tsquash("inconsistent exptime to test"); - if (t[0] != t[1] || t[1] != t[2]) { - throw RuntimeError("inconsistent exptime for all gates"); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + // PUT only command + REQUIRE_THROWS(caller.call("start", {}, -1, GET)); + auto det_type = det.getDetectorType().squash(); + std::chrono::nanoseconds prev_val; + if (det_type != defs::MYTHEN3) { + prev_val = det.getExptime().tsquash("inconsistent exptime to test"); + } else { + auto t = + det.getExptimeForAllGates().tsquash("inconsistent exptime to test"); + if (t[0] != t[1] || t[1] != t[2]) { + throw RuntimeError("inconsistent exptime for all gates"); + } + prev_val = t[0]; } - prev_val = t[0]; + auto prev_frames = + det.getNumberOfFrames().tsquash("inconsistent #frames in test"); + auto prev_period = det.getPeriod().tsquash("inconsistent period in test"); + det.setExptime(-1, std::chrono::microseconds(200)); + det.setPeriod(std::chrono::milliseconds(1)); + det.setNumberOfFrames(2000); + { + std::ostringstream oss; + caller.call("start", {}, -1, PUT, oss); + REQUIRE(oss.str() == "start successful\n"); + } + if (det_type != defs::CHIPTESTBOARD && det_type != defs::MOENCH) { + std::ostringstream oss; + caller.call("status", {}, -1, GET, oss); + REQUIRE(oss.str() == "status running\n"); + } + det.stopDetector(); + det.setExptime(-1, prev_val); + det.setPeriod(prev_period); + det.setNumberOfFrames(prev_frames); + } else { + REQUIRE_THROWS(caller.call("start", {}, -1, GET)); } - auto prev_frames = - det.getNumberOfFrames().tsquash("inconsistent #frames in test"); - auto prev_period = det.getPeriod().tsquash("inconsistent period in test"); - det.setExptime(-1, std::chrono::microseconds(200)); - det.setPeriod(std::chrono::milliseconds(1)); - det.setNumberOfFrames(2000); - { - std::ostringstream oss; - caller.call("start", {}, -1, PUT, oss); - REQUIRE(oss.str() == "start successful\n"); - } - if (det_type != defs::CHIPTESTBOARD && det_type != defs::MOENCH) { - std::ostringstream oss; - caller.call("status", {}, -1, GET, oss); - REQUIRE(oss.str() == "status running\n"); - } - det.stopDetector(); - det.setExptime(-1, prev_val); - det.setPeriod(prev_period); - det.setNumberOfFrames(prev_frames); } TEST_CASE("CALLER::stop", "[.cmdcall]") { Detector det; Caller caller(&det); - // PUT only command - REQUIRE_THROWS(caller.call("stop", {}, -1, GET)); auto det_type = det.getDetectorType().squash(); - std::chrono::nanoseconds prev_val; - if (det_type != defs::MYTHEN3) { - prev_val = det.getExptime().tsquash("inconsistent exptime to test"); - } else { - auto t = - det.getExptimeForAllGates().tsquash("inconsistent exptime to test"); - if (t[0] != t[1] || t[1] != t[2]) { - throw RuntimeError("inconsistent exptime for all gates"); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + // PUT only command + REQUIRE_THROWS(caller.call("stop", {}, -1, GET)); + auto det_type = det.getDetectorType().squash(); + std::chrono::nanoseconds prev_val; + if (det_type != defs::MYTHEN3) { + prev_val = det.getExptime().tsquash("inconsistent exptime to test"); + } else { + auto t = + det.getExptimeForAllGates().tsquash("inconsistent exptime to test"); + if (t[0] != t[1] || t[1] != t[2]) { + throw RuntimeError("inconsistent exptime for all gates"); + } + prev_val = t[0]; } - prev_val = t[0]; + auto prev_frames = + det.getNumberOfFrames().tsquash("inconsistent #frames in test"); + auto prev_period = det.getPeriod().tsquash("inconsistent period in test"); + det.setExptime(-1, std::chrono::microseconds(200)); + det.setPeriod(std::chrono::milliseconds(1)); + det.setNumberOfFrames(2000); + det.startDetector(); + if (det_type != defs::CHIPTESTBOARD && det_type != defs::MOENCH) { + std::ostringstream oss; + caller.call("status", {}, -1, GET, oss); + REQUIRE(oss.str() == "status running\n"); + } + { + std::ostringstream oss; + caller.call("stop", {}, -1, PUT, oss); + REQUIRE(oss.str() == "stop successful\n"); + } + { + std::ostringstream oss; + caller.call("status", {}, -1, GET, oss); + REQUIRE(((oss.str() == "status stopped\n") || + (oss.str() == "status idle\n"))); + } + det.setExptime(-1, prev_val); + det.setPeriod(prev_period); + det.setNumberOfFrames(prev_frames); + } else { + REQUIRE_THROWS(caller.call("stop", {}, -1, GET)); } - auto prev_frames = - det.getNumberOfFrames().tsquash("inconsistent #frames in test"); - auto prev_period = det.getPeriod().tsquash("inconsistent period in test"); - det.setExptime(-1, std::chrono::microseconds(200)); - det.setPeriod(std::chrono::milliseconds(1)); - det.setNumberOfFrames(2000); - det.startDetector(); - if (det_type != defs::CHIPTESTBOARD && det_type != defs::MOENCH) { - std::ostringstream oss; - caller.call("status", {}, -1, GET, oss); - REQUIRE(oss.str() == "status running\n"); - } - { - std::ostringstream oss; - caller.call("stop", {}, -1, PUT, oss); - REQUIRE(oss.str() == "stop successful\n"); - } - { - std::ostringstream oss; - caller.call("status", {}, -1, GET, oss); - REQUIRE(((oss.str() == "status stopped\n") || - (oss.str() == "status idle\n"))); - } - det.setExptime(-1, prev_val); - det.setPeriod(prev_period); - det.setNumberOfFrames(prev_frames); } TEST_CASE("CALLER::status", "[.cmdcall]") { Detector det; Caller caller(&det); auto det_type = det.getDetectorType().squash(); - std::chrono::nanoseconds prev_val; - if (det_type != defs::MYTHEN3) { - prev_val = det.getExptime().tsquash("inconsistent exptime to test"); - } else { - auto t = - det.getExptimeForAllGates().tsquash("inconsistent exptime to test"); - if (t[0] != t[1] || t[1] != t[2]) { - throw RuntimeError("inconsistent exptime for all gates"); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + std::chrono::nanoseconds prev_val; + if (det_type != defs::MYTHEN3) { + prev_val = det.getExptime().tsquash("inconsistent exptime to test"); + } else { + auto t = + det.getExptimeForAllGates().tsquash("inconsistent exptime to test"); + if (t[0] != t[1] || t[1] != t[2]) { + throw RuntimeError("inconsistent exptime for all gates"); + } + prev_val = t[0]; } - prev_val = t[0]; + auto prev_frames = + det.getNumberOfFrames().tsquash("inconsistent #frames in test"); + auto prev_period = det.getPeriod().tsquash("inconsistent period in test"); + det.setExptime(-1, std::chrono::microseconds(200)); + det.setPeriod(std::chrono::milliseconds(1)); + det.setNumberOfFrames(2000); + det.startDetector(); + if (det_type != defs::CHIPTESTBOARD && det_type != defs::MOENCH) { + std::ostringstream oss; + caller.call("status", {}, -1, GET, oss); + REQUIRE(oss.str() == "status running\n"); + } + det.stopDetector(); + { + std::ostringstream oss; + caller.call("status", {}, -1, GET, oss); + REQUIRE(((oss.str() == "status stopped\n") || + (oss.str() == "status idle\n"))); + } + det.setExptime(-1, prev_val); + det.setPeriod(prev_period); + det.setNumberOfFrames(prev_frames); + } else { + REQUIRE_THROWS(caller.call("status", {}, -1, GET)); } - auto prev_frames = - det.getNumberOfFrames().tsquash("inconsistent #frames in test"); - auto prev_period = det.getPeriod().tsquash("inconsistent period in test"); - det.setExptime(-1, std::chrono::microseconds(200)); - det.setPeriod(std::chrono::milliseconds(1)); - det.setNumberOfFrames(2000); - det.startDetector(); - if (det_type != defs::CHIPTESTBOARD && det_type != defs::MOENCH) { - std::ostringstream oss; - caller.call("status", {}, -1, GET, oss); - REQUIRE(oss.str() == "status running\n"); - } - det.stopDetector(); - { - std::ostringstream oss; - caller.call("status", {}, -1, GET, oss); - REQUIRE(((oss.str() == "status stopped\n") || - (oss.str() == "status idle\n"))); - } - det.setExptime(-1, prev_val); - det.setPeriod(prev_period); - det.setNumberOfFrames(prev_frames); } TEST_CASE("CALLER::nextframenumber", "[.cmdcall]") { @@ -2433,126 +2473,130 @@ TEST_CASE("CALLER::scan", "[.cmdcall]") { defs::dacIndex ind = defs::DAC_0; defs::dacIndex notImplementedInd = defs::DAC_0; auto det_type = det.getDetectorType().squash(); - switch (det_type) { - case defs::CHIPTESTBOARD: - ind = defs::DAC_0; - notImplementedInd = defs::VSVP; - break; - case defs::EIGER: - ind = defs::VCMP_LL; - notImplementedInd = defs::VCASCP_PB; - break; - case defs::JUNGFRAU: - ind = defs::VB_COMP; - notImplementedInd = defs::VSVP; - break; - case defs::MOENCH: - ind = defs::VIN_CM; - notImplementedInd = defs::VSVP; - break; - case defs::GOTTHARD: - ind = defs::VREF_DS; - notImplementedInd = defs::VSVP; - break; - case defs::GOTTHARD2: - ind = defs::VB_COMP_FE; - notImplementedInd = defs::VSVP; - break; - case defs::MYTHEN3: - ind = defs::VTH2; - notImplementedInd = defs::VSVP; - break; - default: - break; - } + if (det_type != defs::XILINX_CHIPTESTBOARD) { + switch (det_type) { + case defs::CHIPTESTBOARD: + ind = defs::DAC_0; + notImplementedInd = defs::VSVP; + break; + case defs::EIGER: + ind = defs::VCMP_LL; + notImplementedInd = defs::VCASCP_PB; + break; + case defs::JUNGFRAU: + ind = defs::VB_COMP; + notImplementedInd = defs::VSVP; + break; + case defs::MOENCH: + ind = defs::VIN_CM; + notImplementedInd = defs::VSVP; + break; + case defs::GOTTHARD: + ind = defs::VREF_DS; + notImplementedInd = defs::VSVP; + break; + case defs::GOTTHARD2: + ind = defs::VB_COMP_FE; + notImplementedInd = defs::VSVP; + break; + case defs::MYTHEN3: + ind = defs::VTH2; + notImplementedInd = defs::VSVP; + break; + default: + break; + } - // when taking acquisition - // auto previous = det.getDAC(ind, false); - // auto notImplementedPrevious = det.getDAC(notImplementedInd, false); + // when taking acquisition + // auto previous = det.getDAC(ind, false); + // auto notImplementedPrevious = det.getDAC(notImplementedInd, false); - if (det_type == defs::MYTHEN3 && det.size() > 1) { - ; // scan only allowed for single module due to sync - } else { - { - std::ostringstream oss; - caller.call("scan", {ToString(ind), "500", "1500", "500"}, -1, PUT, - oss); - CHECK(oss.str() == - "scan [" + ToString(ind) + ", 500, 1500, 500]\n"); - } - { - std::ostringstream oss; - caller.call("scan", {}, -1, GET, oss); - CHECK(oss.str() == "scan [enabled\ndac " + ToString(ind) + - "\nstart 500\nstop 1500\nstep " - "500\nsettleTime 1ms\n]\n"); - } - { - std::ostringstream oss; - caller.call("scan", {ToString(ind), "500", "1500", "500", "2s"}, -1, - PUT, oss); - CHECK(oss.str() == - "scan [" + ToString(ind) + ", 500, 1500, 500, 2s]\n"); - } - { - std::ostringstream oss; - caller.call("scan", {}, -1, GET, oss); - CHECK(oss.str() == "scan [enabled\ndac " + ToString(ind) + - "\nstart 500\nstop 1500\nstep " - "500\nsettleTime 2s\n]\n"); - } - { - std::ostringstream oss; - caller.call("scan", {"0"}, -1, PUT, oss); - CHECK(oss.str() == "scan [0]\n"); - } - { - std::ostringstream oss; - caller.call("scan", {}, -1, GET, oss); - CHECK(oss.str() == "scan [disabled]\n"); - } - { - std::ostringstream oss; - caller.call("scan", {ToString(ind), "1500", "500", "-500"}, -1, PUT, - oss); - CHECK(oss.str() == - "scan [" + ToString(ind) + ", 1500, 500, -500]\n"); - } - CHECK_THROWS(caller.call( - "scan", {ToString(notImplementedInd), "500", "1500", "500"}, -1, - PUT)); - CHECK_THROWS(caller.call("scan", {ToString(ind), "500", "1500", "-500"}, - -1, PUT)); - CHECK_THROWS(caller.call("scan", {ToString(ind), "1500", "500", "500"}, - -1, PUT)); - - if (det_type == defs::MYTHEN3 || defs::EIGER) { + if (det_type == defs::MYTHEN3 && det.size() > 1) { + ; // scan only allowed for single module due to sync + } else { { std::ostringstream oss; - caller.call("scan", {"trimbits", "0", "63", "16", "2s"}, -1, - PUT, oss); - CHECK(oss.str() == "scan [trimbits, 0, 63, 16, 2s]\n"); + caller.call("scan", {ToString(ind), "500", "1500", "500"}, -1, PUT, + oss); + CHECK(oss.str() == + "scan [" + ToString(ind) + ", 500, 1500, 500]\n"); } { std::ostringstream oss; caller.call("scan", {}, -1, GET, oss); - CHECK(oss.str() == - "scan [enabled\ndac trimbits\nstart 0\nstop 48\nstep " - "16\nsettleTime 2s\n]\n"); + CHECK(oss.str() == "scan [enabled\ndac " + ToString(ind) + + "\nstart 500\nstop 1500\nstep " + "500\nsettleTime 1ms\n]\n"); } + { + std::ostringstream oss; + caller.call("scan", {ToString(ind), "500", "1500", "500", "2s"}, -1, + PUT, oss); + CHECK(oss.str() == + "scan [" + ToString(ind) + ", 500, 1500, 500, 2s]\n"); + } + { + std::ostringstream oss; + caller.call("scan", {}, -1, GET, oss); + CHECK(oss.str() == "scan [enabled\ndac " + ToString(ind) + + "\nstart 500\nstop 1500\nstep " + "500\nsettleTime 2s\n]\n"); + } + { + std::ostringstream oss; + caller.call("scan", {"0"}, -1, PUT, oss); + CHECK(oss.str() == "scan [0]\n"); + } + { + std::ostringstream oss; + caller.call("scan", {}, -1, GET, oss); + CHECK(oss.str() == "scan [disabled]\n"); + } + { + std::ostringstream oss; + caller.call("scan", {ToString(ind), "1500", "500", "-500"}, -1, PUT, + oss); + CHECK(oss.str() == + "scan [" + ToString(ind) + ", 1500, 500, -500]\n"); + } + CHECK_THROWS(caller.call( + "scan", {ToString(notImplementedInd), "500", "1500", "500"}, -1, + PUT)); + CHECK_THROWS(caller.call("scan", {ToString(ind), "500", "1500", "-500"}, + -1, PUT)); + CHECK_THROWS(caller.call("scan", {ToString(ind), "1500", "500", "500"}, + -1, PUT)); + + if (det_type == defs::MYTHEN3 || defs::EIGER) { + { + std::ostringstream oss; + caller.call("scan", {"trimbits", "0", "63", "16", "2s"}, -1, + PUT, oss); + CHECK(oss.str() == "scan [trimbits, 0, 63, 16, 2s]\n"); + } + { + std::ostringstream oss; + caller.call("scan", {}, -1, GET, oss); + CHECK(oss.str() == + "scan [enabled\ndac trimbits\nstart 0\nstop 48\nstep " + "16\nsettleTime 2s\n]\n"); + } + } + + // Switch off scan for future tests + det.setScan(defs::scanParameters()); + // acquire for each? + + // when taking acquisition + // Reset all dacs to previous value + // for (int i = 0; i != det.size(); ++i) { + // det.setDAC(ind, previous[i], false, {i}); + // det.setDAC(notImplementedInd, notImplementedPrevious[i], false, + // {i}); + // } } - - // Switch off scan for future tests - det.setScan(defs::scanParameters()); - // acquire for each? - - // when taking acquisition - // Reset all dacs to previous value - // for (int i = 0; i != det.size(); ++i) { - // det.setDAC(ind, previous[i], false, {i}); - // det.setDAC(notImplementedInd, notImplementedPrevious[i], false, - // {i}); - // } + } else { + REQUIRE_THROWS(caller.call("scan", {ToString(defs::DAC_0), "500", "1500", "500"}, -1, PUT)); } } @@ -2608,15 +2652,20 @@ TEST_CASE("CALLER::numinterfaces", "[.cmdcall]") { TEST_CASE("CALLER::udp_srcip", "[.cmdcall]") { Detector det; Caller caller(&det); - auto prev_val = det.getSourceUDPIP(); - REQUIRE_THROWS(caller.call("udp_srcip", {"0.0.0.0"}, -1, PUT)); - { - std::ostringstream oss; - caller.call("udp_srcip", {"129.129.205.12"}, -1, PUT, oss); - REQUIRE(oss.str() == "udp_srcip 129.129.205.12\n"); - } - for (int i = 0; i != det.size(); ++i) { - det.setSourceUDPIP(prev_val[i], {i}); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getSourceUDPIP(); + REQUIRE_THROWS(caller.call("udp_srcip", {"0.0.0.0"}, -1, PUT)); + { + std::ostringstream oss; + caller.call("udp_srcip", {"129.129.205.12"}, -1, PUT, oss); + REQUIRE(oss.str() == "udp_srcip 129.129.205.12\n"); + } + for (int i = 0; i != det.size(); ++i) { + det.setSourceUDPIP(prev_val[i], {i}); + } + } else { + REQUIRE_THROWS(caller.call("udp_srcip", {}, -1, GET)); } } @@ -2652,9 +2701,15 @@ TEST_CASE("CALLER::udp_numdst", "[.cmdcall]") { TEST_CASE("CALLER::udp_cleardst", "[.cmdcall]") { Detector det; Caller caller(&det); - REQUIRE_THROWS(caller.call("udp_cleardst", {}, -1, GET)); - /* dont clear all udp destinations */ - /*REQUIRE_NOTHROW(caller.call("udp_cleardst", {}, -1, PUT));*/ + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + REQUIRE_THROWS(caller.call("udp_cleardst", {}, -1, GET)); + /* dont clear all udp destinations */ + /*REQUIRE_NOTHROW(caller.call("udp_cleardst", {}, -1, PUT));*/ + } else { + REQUIRE_THROWS(caller.call("udp_cleardst", {}, -1, PUT)); + + } } TEST_CASE("CALLER::udp_firstdst", "[.cmdcall]") { @@ -2700,17 +2755,22 @@ TEST_CASE("CALLER::udp_dstip", "[.cmdcall]") { TEST_CASE("CALLER::udp_srcmac", "[.cmdcall]") { Detector det; Caller caller(&det); - auto prev_val = det.getSourceUDPMAC(); - REQUIRE_THROWS(caller.call("udp_srcmac", {"00:00:00:00:00:00"}, -1, PUT)); - { - std::ostringstream oss; - caller.call("udp_srcmac", {"00:50:c2:42:34:12"}, -1, PUT, oss); - REQUIRE(oss.str() == "udp_srcmac 00:50:c2:42:34:12\n"); - } - for (int i = 0; i != det.size(); ++i) { - if (prev_val[i].str() != "00:00:00:00:00:00") { - det.setSourceUDPMAC(prev_val[i], {i}); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getSourceUDPMAC(); + REQUIRE_THROWS(caller.call("udp_srcmac", {"00:00:00:00:00:00"}, -1, PUT)); + { + std::ostringstream oss; + caller.call("udp_srcmac", {"00:50:c2:42:34:12"}, -1, PUT, oss); + REQUIRE(oss.str() == "udp_srcmac 00:50:c2:42:34:12\n"); } + for (int i = 0; i != det.size(); ++i) { + if (prev_val[i].str() != "00:00:00:00:00:00") { + det.setSourceUDPMAC(prev_val[i], {i}); + } + } + } else { + REQUIRE_THROWS(caller.call("udp_srcmac", {}, -1, GET)); } } @@ -2723,21 +2783,26 @@ TEST_CASE("CALLER::udp_dstmac", "[.cmdcall]") { TEST_CASE("CALLER::udp_dstport", "[.cmdcall]") { Detector det; Caller caller(&det); - auto prev_val = det.getDestinationUDPPort(); - { - std::ostringstream oss; - caller.call("udp_dstport", {"50084"}, -1, PUT, oss); - REQUIRE(oss.str() == "udp_dstport 50084\n"); - } - test_valid_port_caller("udp_dstport", {}, -1, PUT); - test_valid_port_caller("udp_dstport", {}, 0, PUT); - // should fail for the second module - if (det.size() > 1) { - REQUIRE_THROWS(caller.call("udp_dstport", {"65535"}, -1, PUT)); - } + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + auto prev_val = det.getDestinationUDPPort(); + { + std::ostringstream oss; + caller.call("udp_dstport", {"50084"}, -1, PUT, oss); + REQUIRE(oss.str() == "udp_dstport 50084\n"); + } + test_valid_port_caller("udp_dstport", {}, -1, PUT); + test_valid_port_caller("udp_dstport", {}, 0, PUT); + // should fail for the second module + if (det.size() > 1) { + REQUIRE_THROWS(caller.call("udp_dstport", {"65535"}, -1, PUT)); + } - for (int i = 0; i != det.size(); ++i) { - det.setDestinationUDPPort(prev_val[i], {i}); + for (int i = 0; i != det.size(); ++i) { + det.setDestinationUDPPort(prev_val[i], {i}); + } + } else { + REQUIRE_THROWS(caller.call("udp_dstport", {}, -1, GET)); } } @@ -2844,15 +2909,26 @@ TEST_CASE("CALLER::udp_dstport2", "[.cmdcall]") { TEST_CASE("CALLER::udp_reconfigure", "[.cmdcall]") { Detector det; Caller caller(&det); - REQUIRE_THROWS(caller.call("udp_reconfigure", {}, -1, GET)); - REQUIRE_NOTHROW(caller.call("udp_reconfigure", {}, -1, PUT)); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + REQUIRE_THROWS(caller.call("udp_reconfigure", {}, -1, GET)); + REQUIRE_NOTHROW(caller.call("udp_reconfigure", {}, -1, PUT)); + } else { + REQUIRE_THROWS(caller.call("udp_reconfigure", {}, -1, PUT)); + } } TEST_CASE("CALLER::udp_validate", "[.cmdcall]") { Detector det; Caller caller(&det); - REQUIRE_THROWS(caller.call("udp_validate", {}, -1, GET)); - REQUIRE_NOTHROW(caller.call("udp_validate", {}, -1, PUT)); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + REQUIRE_THROWS(caller.call("udp_validate", {}, -1, GET)); + REQUIRE_NOTHROW(caller.call("udp_validate", {}, -1, PUT)); + } else { + REQUIRE_THROWS(caller.call("udp_validate", {}, -1, PUT)); + + } } TEST_CASE("CALLER::tengiga", "[.cmdcall]") { @@ -3072,16 +3148,19 @@ TEST_CASE("CALLER::zmqport", "[.cmdcall]") { TEST_CASE("CALLER::zmqip", "[.cmdcall]") { Detector det; Caller caller(&det); - std::ostringstream oss1, oss2; - auto zmqip = det.getClientZmqIp(); - caller.call("zmqip", {}, 0, GET, oss1); - REQUIRE(oss1.str() == "zmqip " + zmqip[0].str() + '\n'); + auto det_type = det.getDetectorType().squash(); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + std::ostringstream oss1, oss2; + auto zmqip = det.getClientZmqIp(); + caller.call("zmqip", {}, 0, GET, oss1); + REQUIRE(oss1.str() == "zmqip " + zmqip[0].str() + '\n'); - caller.call("zmqip", {zmqip[0].str()}, 0, PUT, oss2); - REQUIRE(oss2.str() == "zmqip " + zmqip[0].str() + '\n'); + caller.call("zmqip", {zmqip[0].str()}, 0, PUT, oss2); + REQUIRE(oss2.str() == "zmqip " + zmqip[0].str() + '\n'); - for (int i = 0; i != det.size(); ++i) { - det.setRxZmqIP(zmqip[i], {i}); + for (int i = 0; i != det.size(); ++i) { + det.setRxZmqIP(zmqip[i], {i}); + } } } @@ -3238,24 +3317,28 @@ TEST_CASE("CALLER::reg", "[.cmdcall]") { Detector det; Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type != defs::EIGER) { - uint32_t addr = 0x64; - std::string saddr = ToStringHex(addr); - auto prev_val = det.readRegister(addr); - { - std::ostringstream oss1, oss2; - caller.call("reg", {saddr, "0x5"}, -1, PUT, oss1); - REQUIRE(oss1.str() == "reg [" + saddr + ", 0x5]\n"); - caller.call("reg", {saddr}, -1, GET, oss2); - REQUIRE(oss2.str() == "reg 0x5\n"); + if (det_type != defs::XILINX_CHIPTESTBOARD) { + if (det_type != defs::EIGER) { + uint32_t addr = 0x64; + std::string saddr = ToStringHex(addr); + auto prev_val = det.readRegister(addr); + { + std::ostringstream oss1, oss2; + caller.call("reg", {saddr, "0x5"}, -1, PUT, oss1); + REQUIRE(oss1.str() == "reg [" + saddr + ", 0x5]\n"); + caller.call("reg", {saddr}, -1, GET, oss2); + REQUIRE(oss2.str() == "reg 0x5\n"); + } + for (int i = 0; i != det.size(); ++i) { + det.writeRegister(addr, prev_val[i], {i}); + } } - for (int i = 0; i != det.size(); ++i) { - det.writeRegister(addr, prev_val[i], {i}); + // cannot check for eiger virtual server + else { + REQUIRE_NOTHROW(caller.call("reg", {"0x64"}, -1, GET)); } - } - // cannot check for eiger virtual server - else { - REQUIRE_NOTHROW(caller.call("reg", {"0x64"}, -1, GET)); + } else { + REQUIRE_THROWS(caller.call("reg", {}, -1, GET)); } } @@ -3281,7 +3364,7 @@ TEST_CASE("CALLER::setbit", "[.cmdcall]") { Detector det; Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type != defs::EIGER) { + if (det_type != defs::EIGER && det_type != defs::XILINX_CHIPTESTBOARD) { uint32_t addr = 0x64; std::string saddr = ToStringHex(addr); auto prev_val = det.readRegister(addr); @@ -3303,7 +3386,7 @@ TEST_CASE("CALLER::clearbit", "[.cmdcall]") { Detector det; Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type != defs::EIGER) { + if (det_type != defs::EIGER && det_type != defs::XILINX_CHIPTESTBOARD) { uint32_t addr = 0x64; std::string saddr = ToStringHex(addr); auto prev_val = det.readRegister(addr); @@ -3325,7 +3408,9 @@ TEST_CASE("CALLER::getbit", "[.cmdcall]") { Detector det; Caller caller(&det); auto det_type = det.getDetectorType().squash(); - if (det_type != defs::EIGER) { + if (det_type == defs::XILINX_CHIPTESTBOARD) { + REQUIRE_THROWS(caller.call("getbit", {"0x64", "1"}, -1, GET)); + } else if (det_type != defs::EIGER) { uint32_t addr = 0x64; std::string saddr = ToStringHex(addr); auto prev_val = det.readRegister(addr); diff --git a/slsSupportLib/include/sls/versionAPI.h b/slsSupportLib/include/sls/versionAPI.h index fbb726e37..f14a99937 100644 --- a/slsSupportLib/include/sls/versionAPI.h +++ b/slsSupportLib/include/sls/versionAPI.h @@ -4,11 +4,11 @@ #define RELEASE "developer" #define APILIB "developer 0x230224" #define APIRECEIVER "developer 0x230224" -#define APIXILINXCTB "developer 0x240104" -#define APICTB "developer 0x240104" -#define APIGOTTHARD "developer 0x240104" -#define APIGOTTHARD2 "developer 0x240104" -#define APIJUNGFRAU "developer 0x240104" -#define APIMYTHEN3 "developer 0x240104" -#define APIMOENCH "developer 0x240104" -#define APIEIGER "developer 0x240104" +#define APIXILINXCTB "developer 0x240109" +#define APICTB "developer 0x240109" +#define APIGOTTHARD "developer 0x240109" +#define APIGOTTHARD2 "developer 0x240109" +#define APIJUNGFRAU "developer 0x240109" +#define APIMYTHEN3 "developer 0x240109" +#define APIMOENCH "developer 0x240109" +#define APIEIGER "developer 0x240109" diff --git a/tests/scripts/test_simulators.py b/tests/scripts/test_simulators.py index 2a40ba1a3..1d26c96e7 100644 --- a/tests/scripts/test_simulators.py +++ b/tests/scripts/test_simulators.py @@ -99,7 +99,9 @@ def loadConfig(name, rx_hostname, settingsdir): Log(Fore.GREEN, 'Loading config') try: d = Detector() - if name == 'eiger': + if name == 'xilinx_ctb': + d.hostname = 'localhost' + elif name == 'eiger': d.hostname = 'localhost:' + str(DEFAULT_TCP_CNTRL_PORTNO) + '+localhost:' + str(HALFMOD2_TCP_CNTRL_PORTNO) #d.udp_dstport = {2: 50003} # will set up for every module @@ -174,6 +176,7 @@ if args.servers is None: 'gotthard', 'ctb', 'moench', + 'xilinx_ctb' ] else: servers = args.servers