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
This commit is contained in:
maliakal_d 2024-01-10 16:23:52 +01:00 committed by GitHub
parent 9738cb7d74
commit 9a08ecc5a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 1720 additions and 1292 deletions

View File

@ -5,6 +5,8 @@
#include <inttypes.h>
#include <sys/types.h>
int mapCSP0(void);
void bus_w(u_int32_t offset, u_int32_t data);
u_int32_t bus_r(u_int32_t offset);
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);

View File

@ -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();

View File

@ -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

View File

@ -51,14 +51,10 @@ void basictests() {
}
#ifndef VIRTUAL
/*if ((!debugflag) && (!updateFlag) &&
((validateKernelVersion(KERNEL_DATE_VRSN) == FAIL) ||
(checkType() == FAIL) || (testFpga() == FAIL) ||
(testBus() == FAIL))) {*/
if ((!debugflag) && (!updateFlag) &&
((validateKernelVersion(KERNEL_DATE_VRSN) == FAIL) ||
(checkType() == FAIL) /*|| (testFpga() == FAIL) ||
(testBus() == FAIL)*/)) {
(checkType() == FAIL) || (testFpga() == FAIL) ||
(testBus() == FAIL))) {
sprintf(initErrorMessage,
"Could not pass basic tests of FPGA and bus. Cannot proceed. "
"Check Firmware. (Firmware version:0x%lx) \n",
@ -103,6 +99,123 @@ int checkType() {
return OK;
}
int testFpga() {
#ifdef VIRTUAL
return OK;
#endif
LOG(logINFO, ("Testing FPGA:\n"));
// fixed pattern
int ret = OK;
/* TODO: FIX PATTERN not defined in firmware
uint32_t val = bus_r(FIX_PATT_REG);
if (val == FIX_PATT_VAL) {
LOG(logINFO, ("\tFixed pattern: successful match (0x%08x)\n", val));
} else {
LOG(logERROR,
("Fixed pattern does not match! Read 0x%08x, expected 0x%08x\n",
val, FIX_PATT_VAL));
ret = FAIL;
}
*/
if (ret == OK) {
// Delay LSB reg
LOG(logINFO, ("\tTesting Delay LSB Register:\n"));
uint32_t addr = DELAYINREG1;
// store previous delay value
uint32_t previousValue = bus_r(addr);
volatile uint32_t val = 0, readval = 0;
int times = 1000 * 1000;
for (int i = 0; i < times; ++i) {
val = 0x5A5A5A5A - i;
bus_w(addr, val);
readval = bus_r(addr);
if (readval != val) {
LOG(logERROR, ("1:Mismatch! Loop(%d): Wrote 0x%x, read 0x%x\n",
i, val, readval));
ret = FAIL;
break;
}
val = (i + (i << 10) + (i << 20));
bus_w(addr, val);
readval = bus_r(addr);
if (readval != val) {
LOG(logERROR, ("2:Mismatch! Loop(%d): Wrote 0x%x, read 0x%x\n",
i, val, readval));
ret = FAIL;
break;
}
val = 0x0F0F0F0F;
bus_w(addr, val);
readval = bus_r(addr);
if (readval != val) {
LOG(logERROR, ("3:Mismatch! Loop(%d): Wrote 0x%x, read 0x%x\n",
i, val, readval));
ret = FAIL;
break;
}
val = 0xF0F0F0F0;
bus_w(addr, val);
readval = bus_r(addr);
if (readval != val) {
LOG(logERROR, ("4:Mismatch! Loop(%d): Wrote 0x%x, read 0x%x\n",
i, val, readval));
ret = FAIL;
break;
}
}
// write back previous value
bus_w(addr, previousValue);
if (ret == OK) {
LOG(logINFO,
("\tSuccessfully tested FPGA Delay LSB Register %d times\n",
times));
}
}
return ret;
}
int testBus() {
#ifdef VIRTUAL
return OK;
#endif
LOG(logINFO, ("Testing Bus:\n"));
int ret = OK;
uint32_t addr = DELAYINREG1;
// store previous delay value
uint32_t previousValue = bus_r(addr);
volatile uint32_t val = 0, readval = 0;
int times = 1000 * 1000;
for (int i = 0; i < times; ++i) {
val += 0xbbbbb;
bus_w(addr, val);
readval = bus_r(addr);
if (readval != val) {
LOG(logERROR, ("Mismatch! Loop(%d): Wrote 0x%x, read 0x%x\n", i,
val, readval));
ret = FAIL;
}
}
// write back previous value
bus_w(addr, previousValue);
if (ret == OK) {
LOG(logINFO, ("\tSuccessfully tested bus %d times\n", times));
}
return ret;
}
/* Ids */
void getServerVersion(char *version) { strcpy(version, APIXILINXCTB); }
@ -194,18 +307,81 @@ void initStopServer() {
/* set up detector */
void setupDetector() {
LOG(logINFO, ("This Server is for 1 Xilinx Chip Test Board\n"));
LOG(logINFO, ("Setting up Server for 1 Xilinx Chip Test Board\n"));
#ifdef VIRTUAL
sharedMemory_setStatus(IDLE);
#endif
LOG(logINFO, ("Goodbye...\n"));
LOG(logINFOBLUE, ("Setting Default parameters\n"));
setNumFrames(DEFAULT_NUM_FRAMES);
setNumTriggers(DEFAULT_NUM_CYCLES);
}
/* parameters - timer */
void setNumFrames(int64_t val) {
if (val > 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; }
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;
}

View File

@ -16,3 +16,8 @@
enum ADCINDEX { V_PWR_IO };
enum DACINDEX { D0 };
/** Default Parameters */
#define DEFAULT_NUM_FRAMES (1)
#define DEFAULT_NUM_CYCLES (1)

View File

@ -653,7 +653,6 @@ std::vector<defs::dacIndex> Detector::getTemperatureList() const {
std::vector<defs::dacIndex> retval;
switch (getDetectorType().squash()) {
case defs::CHIPTESTBOARD:
case defs::XILINX_CHIPTESTBOARD:
return std::vector<defs::dacIndex>{defs::SLOW_ADC_TEMP};
case defs::JUNGFRAU:
case defs::MOENCH:

View File

@ -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<defs::dacIndex>(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<defs::dacIndex>(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<defs::dacIndex>(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<defs::dacIndex>(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<defs::dacIndex>(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<defs::dacIndex>(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<defs::dacIndex>(i), "dac", 0);
if (det_type == defs::CHIPTESTBOARD) {
test_dac_caller(static_cast<defs::dacIndex>(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));

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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"

View File

@ -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