diff --git a/python/src/detector.cpp b/python/src/detector.cpp index 82acb1eef..7677fbae4 100644 --- a/python/src/detector.cpp +++ b/python/src/detector.cpp @@ -1520,11 +1520,11 @@ void init_det(py::module &m) { (void (Detector::*)(const std::string &, const std::string &, sls::Positions)) & Detector::copyDetectorServer, - py::arg(), py::arg(), py::arg() = Positions{}) + py::arg(), py::arg(), py::arg() = Positions{}) .def("updateDetectorServer", (void (Detector::*)(const std::string &, sls::Positions)) & Detector::updateDetectorServer, - py::arg(), py::arg() = Positions{}) + py::arg(), py::arg() = Positions{}) .def("updateKernel", (void (Detector::*)(const std::string &, sls::Positions)) & Detector::updateKernel, @@ -1542,6 +1542,14 @@ void init_det(py::module &m) { sls::Positions)) & Detector::updateFirmwareAndServer, py::arg(), py::arg(), py::arg() = Positions{}) + .def("getUpdateMode", + (Result(Detector::*)(sls::Positions) const) & + Detector::getUpdateMode, + py::arg() = Positions{}) + .def("setUpdateMode", + (void (Detector::*)(bool, sls::Positions)) & + Detector::setUpdateMode, + py::arg(), py::arg() = Positions{}) .def("readRegister", (Result(Detector::*)(uint32_t, sls::Positions) const) & Detector::readRegister, diff --git a/slsDetectorServers/eigerDetectorServer/slsDetectorServer_defs.h b/slsDetectorServers/eigerDetectorServer/slsDetectorServer_defs.h index 2711a76b5..3f0e5a288 100644 --- a/slsDetectorServers/eigerDetectorServer/slsDetectorServer_defs.h +++ b/slsDetectorServers/eigerDetectorServer/slsDetectorServer_defs.h @@ -3,7 +3,7 @@ #pragma once #include "sls/sls_detector_defs.h" -#define LINKED_SERVER_NAME "/home/root/executables/eigerDetectorServer" +#define LINKED_SERVER_NAME "eigerDetectorServer" #define REQUIRED_FIRMWARE_VERSION (29) // virtual ones renamed for consistency diff --git a/slsDetectorServers/slsDetectorServer/include/common.h b/slsDetectorServers/slsDetectorServer/include/common.h index 77b567423..ade91d545 100644 --- a/slsDetectorServers/slsDetectorServer/include/common.h +++ b/slsDetectorServers/slsDetectorServer/include/common.h @@ -10,9 +10,11 @@ #ifdef VIRTUAL #define TEMP_PROG_FOLDER_NAME "/tmp/" +#define UPDATE_FILE "/tmp/slsdet_udpate" #else #define TEMP_PROG_FOLDER_NAME "/var/tmp/" #define TEMP_PROG_FOLDER_NAME_ALL_FILES "/var/tmp/*" +#define UPDATE_FILE "udpate.txt" #endif #define TEMP_PROG_FILE_NAME TEMP_PROG_FOLDER_NAME "tmp.rawbin" @@ -62,3 +64,6 @@ int writeBinaryFile(char *mess, char *fname, char *buffer, const uint64_t filesize, char *errorPrefix); int moveBinaryFile(char *mess, char *dest, char *src, char *errorPrefix); + +int createEmptyFile(char *mess, char *fname, char *errorPrefix); +int deleteFile(char *mess, char *fname, char *errorPrefix); diff --git a/slsDetectorServers/slsDetectorServer/include/slsDetectorServer_funcs.h b/slsDetectorServers/slsDetectorServer/include/slsDetectorServer_funcs.h index 23bd0e51e..8948e19d4 100644 --- a/slsDetectorServers/slsDetectorServer/include/slsDetectorServer_funcs.h +++ b/slsDetectorServers/slsDetectorServer/include/slsDetectorServer_funcs.h @@ -287,4 +287,6 @@ void receive_program_via_blackfin(int file_des, enum PROGRAM_INDEX index, char *checksum, char *serverName); void receive_program_default(int file_des, enum PROGRAM_INDEX index, char *functionType, uint64_t filesize, - char *checksum, char *serverName); \ No newline at end of file + char *checksum, char *serverName); +int get_update_mode(int); +int set_update_mode(int); \ No newline at end of file diff --git a/slsDetectorServers/slsDetectorServer/src/common.c b/slsDetectorServers/slsDetectorServer/src/common.c index ac3be1db7..dda73cd4a 100644 --- a/slsDetectorServers/slsDetectorServer/src/common.c +++ b/slsDetectorServers/slsDetectorServer/src/common.c @@ -434,11 +434,17 @@ int setupDetectorServer(char *mess, char *sname) { LOG(logINFO, ("\tPermissions modified\n")); // symbolic link - char linkname[MAX_STR_LENGTH] = {0}; - strcpy(linkname, LINKED_SERVER_NAME); -#ifdef VIRTUAL - sprintf(linkname, "%s%s", TEMP_PROG_FOLDER_NAME, LINKED_SERVER_NAME); -#endif + const int fileNameSize = 128; + char linkname[fileNameSize]; + if (getAbsPath(linkname, fileNameSize, LINKED_SERVER_NAME) == FAIL) { + sprintf( + mess, + "Could not copy detector server. Could not get abs path of current " + "process\n"); + LOG(logERROR, (mess)); + return FAIL; + } + if (snprintf(cmd, MAX_STR_LENGTH, "ln -sf %s %s", sname, linkname) >= MAX_STR_LENGTH) { strcpy(mess, "Could not copy detector server. Command to " @@ -472,8 +478,7 @@ int setupDetectorServer(char *mess, char *sname) { // add new link name to /etc/inittab char *format = "echo 'ttyS0::respawn:/./%s' >> /etc/inittab"; - if (snprintf(cmd, MAX_STR_LENGTH, format, LINKED_SERVER_NAME) >= - MAX_STR_LENGTH) { + if (snprintf(cmd, MAX_STR_LENGTH, format, linkname) >= MAX_STR_LENGTH) { strcpy(mess, "Could not copy detector server. Command " "to add new server for spawning is too long\n"); LOG(logERROR, (mess)); @@ -506,12 +511,23 @@ int writeBinaryFile(char *mess, char *fname, char *buffer, const uint64_t filesize, char *errorPrefix) { LOG(logINFO, ("\tWriting Detector Server Binary...\n")); - FILE *fp = fopen(fname, "wb"); + const int fileNameSize = 128; + char fullname[fileNameSize]; + if (getAbsPath(fullname, fileNameSize, fname) == FAIL) { + sprintf(mess, + "Could not %s. Could not get abs path of current " + "process\n", + errorPrefix); + LOG(logERROR, (mess)); + return FAIL; + } + + FILE *fp = fopen(fullname, "wb"); if (fp == NULL) { sprintf(mess, "Could not %s. (opening file to write(%s). " "Maybe it is being used? Try another name?\n", - errorPrefix, fname); + errorPrefix, fullname); LOG(logERROR, (mess)); return FAIL; } @@ -555,12 +571,13 @@ int writeBinaryFile(char *mess, char *fname, char *buffer, LOG(logERROR, (mess)); return FAIL; } - LOG(logINFO, ("\tWritten binary to %s (%lu bytes)\n", fname, + LOG(logINFO, ("\tWritten binary to %s (%lu bytes)\n", fullname, (long unsigned int)bytesWritten)); return OK; } int moveBinaryFile(char *mess, char *dest, char *src, char *errorPrefix) { + char cmd[MAX_STR_LENGTH] = {0}; char retvals[MAX_STR_LENGTH] = {0}; @@ -584,3 +601,76 @@ int moveBinaryFile(char *mess, char *dest, char *src, char *errorPrefix) { LOG(logINFO, ("\tMoved file from %s to %s\n", src, dest)); return OK; } + +int createEmptyFile(char *mess, char *fname, char *errorPrefix) { + const int fileNameSize = 128; + char fullname[fileNameSize]; + if (getAbsPath(fullname, fileNameSize, fname) == FAIL) { + sprintf(mess, + "Could not %s. Could not get abs path of current " + "process\n", + errorPrefix); + LOG(logERROR, (mess)); + return FAIL; + } + + char cmd[MAX_STR_LENGTH] = {0}; + char retvals[MAX_STR_LENGTH] = {0}; + + char *format = "touch %s"; + if (snprintf(cmd, MAX_STR_LENGTH, format, fullname) >= MAX_STR_LENGTH) { + sprintf(mess, "Could not %s. Command to create is too long\n", + errorPrefix); + LOG(logERROR, (mess)); + return FAIL; + } + + if (executeCommand(cmd, retvals, logDEBUG1) == FAIL) { + snprintf(mess, MAX_STR_LENGTH, + "Could not %s. (creating empty file %s): %s\n", errorPrefix, + fullname, retvals); + LOG(logERROR, (mess)); + return FAIL; + } + LOG(logINFO, ("\tEmpty file created: %s (%s)\n", fullname, errorPrefix)); + return OK; +} + +int deleteFile(char *mess, char *fname, char *errorPrefix) { + const int fileNameSize = 128; + char fullname[fileNameSize]; + if (getAbsPath(fullname, fileNameSize, fname) == FAIL) { + sprintf(mess, + "Could not %s. Could not get abs path of current " + "process\n", + errorPrefix); + LOG(logERROR, (mess)); + return FAIL; + } + + if (access(fullname, F_OK) == 0) { + char cmd[MAX_STR_LENGTH] = {0}; + char retvals[MAX_STR_LENGTH] = {0}; + char *format = "rm %s"; + + if (snprintf(cmd, MAX_STR_LENGTH, format, fullname) >= MAX_STR_LENGTH) { + sprintf(mess, "Could not %s. Command to delete is too long\n", + errorPrefix); + LOG(logERROR, (mess)); + return FAIL; + } + + if (executeCommand(cmd, retvals, logDEBUG1) == FAIL) { + snprintf(mess, MAX_STR_LENGTH, + "Could not %s. (deleting file %s). %s\n", errorPrefix, + fullname, retvals); + LOG(logERROR, (mess)); + return FAIL; + } + LOG(logINFO, ("\tDeleted file: %s (%s)\n", fullname, errorPrefix)); + } else { + LOG(logINFO, + ("\tFile does not exist anyway: %s (%s)\n", fullname, errorPrefix)); + } + return OK; +} \ No newline at end of file diff --git a/slsDetectorServers/slsDetectorServer/src/slsDetectorServer.c b/slsDetectorServers/slsDetectorServer/src/slsDetectorServer.c index 0b8ada232..dbe7120ca 100644 --- a/slsDetectorServers/slsDetectorServer/src/slsDetectorServer.c +++ b/slsDetectorServers/slsDetectorServer/src/slsDetectorServer.c @@ -4,6 +4,7 @@ The port number is passed as an argument */ #include "clogger.h" +#include "common.h" #include "communication_funcs.h" #include "sharedMemory.h" #include "sls/sls_detector_defs.h" @@ -48,6 +49,18 @@ int main(int argc, char *argv[]) { checkModuleFlag = 1; int version = 0; + // update flag if update file exists (command line arg overwrites) + const int fileNameSize = 128; + char fname[fileNameSize]; + if (getAbsPath(fname, fileNameSize, UPDATE_FILE) == FAIL) { + LOG(logERROR, ("Could not get abs path to check if update file exists. " + "Will try current folder instead.\n")); + strcpy(fname, UPDATE_FILE); + } + if (access(fname, F_OK) == 0) { + updateFlag = 1; + } + // help message char helpMessage[MAX_STR_LENGTH]; memset(helpMessage, 0, MAX_STR_LENGTH); diff --git a/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c b/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c index e11abdbd7..add17a247 100644 --- a/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c +++ b/slsDetectorServers/slsDetectorServer/src/slsDetectorServer_funcs.c @@ -95,7 +95,9 @@ int updateModeAllowedFunction(int file_des) { F_REBOOT_CONTROLLER, F_GET_KERNEL_VERSION, F_UPDATE_KERNEL, - F_UPDATE_DETECTOR_SERVER}; + F_UPDATE_DETECTOR_SERVER, + F_GET_UPDATE_MODE, + F_SET_UPDATE_MODE}; for (unsigned int i = 0; i < listsize; ++i) { if ((unsigned int)fnum == list[i]) { return OK; @@ -457,6 +459,8 @@ void function_table() { flist[F_GET_KERNEL_VERSION] = &get_kernel_version; flist[F_UPDATE_KERNEL] = &update_kernel; flist[F_UPDATE_DETECTOR_SERVER] = &update_detector_server; + flist[F_GET_UPDATE_MODE] = &get_update_mode; + flist[F_SET_UPDATE_MODE] = &set_update_mode; // check if (NUM_DET_FUNCTIONS >= RECEIVER_ENUM_START) { @@ -9312,24 +9316,36 @@ int receive_program(int file_des, enum PROGRAM_INDEX index) { if (index == PROGRAM_SERVER) { if (receiveData(file_des, serverName, MAX_STR_LENGTH, OTHER) < 0) return printSocketReadError(); -#ifdef VIRTUAL - // writing to a temp folder - { - char temp[MAX_STR_LENGTH] = {0}; - sprintf(temp, "%s%s", TEMP_PROG_FOLDER_NAME, serverName); - strcpy(serverName, temp); - } -#endif LOG(logINFO, ("\tServer Name: %s\n", serverName)); } + // in same folder as current process (will also work for virtual then + // with write permissions) + { + const int fileNameSize = 128; + char fname[fileNameSize]; + if (getAbsPath(fname, fileNameSize, serverName) == FAIL) { + ret = FAIL; + sprintf(mess, + "Could not %s. Could not get abs path of current " + "process\n", + functionType); + LOG(logERROR, (mess)); + Server_SendResult(file_des, INT32, NULL, 0); + } else { + strcpy(serverName, fname); + } + } + + if (ret == OK) { #if defined(GOTTHARD2D) || defined(MYTHEN3D) || defined(EIGERD) - receive_program_default(file_des, index, functionType, filesize, - checksum, serverName); + receive_program_default(file_des, index, functionType, filesize, + checksum, serverName); #else - receive_program_via_blackfin(file_des, index, functionType, filesize, - checksum, serverName); + receive_program_via_blackfin(file_des, index, functionType, + filesize, checksum, serverName); #endif + } if (ret == OK) { LOG(logINFOGREEN, ("%s completed successfully\n", functionType)); @@ -9527,20 +9543,16 @@ void receive_program_default(int file_des, enum PROGRAM_INDEX index, "update detector server"); // extra step to write to temp and move to real file as // fopen will give text busy if opening same name as process name - char dest[MAX_STR_LENGTH] = {0}; - sprintf(dest, "%s%s", - (myDetectorType == EIGER ? "/home/root/executables/" : ""), - serverName); - if (ret == OK) { - ret = moveBinaryFile(mess, dest, TEMP_PROG_FILE_NAME, + ret = moveBinaryFile(mess, serverName, TEMP_PROG_FILE_NAME, "update detector server"); } if (ret == OK) { - ret = verifyChecksumFromFile(mess, functionType, checksum, dest); + ret = verifyChecksumFromFile(mess, functionType, checksum, + serverName); } if (ret == OK) { - ret = setupDetectorServer(mess, dest); + ret = setupDetectorServer(mess, serverName); } break; #endif @@ -9554,4 +9566,42 @@ void receive_program_default(int file_des, enum PROGRAM_INDEX index, // free resources free(src); #endif +} + +int get_update_mode(int file_des) { + ret = OK; + memset(mess, 0, sizeof(mess)); + int retval = -1; + LOG(logDEBUG1, ("Getting update mode\n")); + + retval = updateFlag; + LOG(logDEBUG1, ("update mode retval: %d\n", retval)); + + return Server_SendResult(file_des, INT32, &retval, sizeof(retval)); +} + +int set_update_mode(int file_des) { + ret = OK; + memset(mess, 0, sizeof(mess)); + int arg = -1; + + if (receiveData(file_des, &arg, sizeof(arg), INT32) < 0) + return printSocketReadError(); + LOG(logDEBUG1, ("Setting update mode to \n", arg)); + + switch (arg) { + case 0: + ret = deleteFile(mess, UPDATE_FILE, "unset update mode"); + break; + case 1: + ret = createEmptyFile(mess, UPDATE_FILE, "set update mode"); + break; + default: + ret = FAIL; + sprintf(mess, "Could not set updatemode. Options: 0 or 1\n"); + LOG(logERROR, (mess)); + break; + } + + return Server_SendResult(file_des, INT32, NULL, 0); } \ No newline at end of file diff --git a/slsDetectorSoftware/include/sls/Detector.h b/slsDetectorSoftware/include/sls/Detector.h index 389fec128..b617eb33a 100644 --- a/slsDetectorSoftware/include/sls/Detector.h +++ b/slsDetectorSoftware/include/sls/Detector.h @@ -1733,8 +1733,8 @@ class Detector { /** [Jungfrau][CTB][Moench] Advanced user Function! */ void resetFPGA(Positions pos = {}); - /** [[deprecated ("Replaced by updateDetectorServer, which does not require tftp")]] - * [Jungfrau][Eiger][Gotthard][CTB][Moench][Mythen3][Gotthard2] + /** [[deprecated ("Replaced by updateDetectorServer, which does not require + * tftp")]] [Jungfrau][Eiger][Gotthard][CTB][Moench][Mythen3][Gotthard2] * Advanced user Function! \n * Copy detector server fname from tftp folder of hostname to detector. Also * creates a symbolic link to a shorter name (without vx.x.x). Then the @@ -1764,13 +1764,14 @@ class Detector { * Function! */ void rebootController(Positions pos = {}); - /** [[deprecated ("Replaced by overloaded updateDetectorServer, which does not require tftp and has one less argument")]] - * Advanced user Function!\n [Jungfrau][Gotthard][CTB][Moench] Updates the - * firmware, detector server, make a soft link and then reboots detector - * controller. \n [Mythen3][Gotthard2] Will require a script to start up the - * shorter named server link at start up \n sname is name of detector - * server binary found on tftp folder of host pc \n hostname is name of pc - * to tftp from \n fname is programming file name with full path to it + /** [[deprecated ("Replaced by overloaded updateDetectorServer, which does + * not require tftp and has one less argument")]] Advanced user Function!\n + * [Jungfrau][Gotthard][CTB][Moench] Updates the firmware, detector server, + * make a soft link and then reboots detector controller. \n + * [Mythen3][Gotthard2] Will require a script to start up the shorter named + * server link at start up \n sname is name of detector server binary found + * on tftp folder of host pc \n hostname is name of pc to tftp from \n fname + * is programming file name with full path to it */ void updateFirmwareAndServer(const std::string &sname, const std::string &hostname, @@ -1780,12 +1781,19 @@ class Detector { * Advanced user Function!\n [Jungfrau][Gotthard][CTB][Moench] Updates the * firmware, detector server, make a soft link and then reboots detector * controller. \n [Mythen3][Gotthard2] Will require a script to start up the - * shorter named server link at start up \n sname is full path name of detector - * server \n fname is programming file name with full path to it + * shorter named server link at start up \n sname is full path name of + * detector server \n fname is programming file name with full path to it */ void updateFirmwareAndServer(const std::string &sname, const std::string &fname, Positions pos = {}); + Result getUpdateMode(Positions pos = {}); + + /** Restarts detector server in update mode. This is useful when + * server-firmware compatibility is at its worst and server cannot start up + * normally */ + void setUpdateMode(const bool updatemode, Positions pos = {}); + /** Advanced user Function! \n * Goes to stop server. Hence, can be called while calling blocking * acquire(). \n [Eiger] Address is +0x100 for only left, +0x200 for only diff --git a/slsDetectorSoftware/src/CmdProxy.h b/slsDetectorSoftware/src/CmdProxy.h index 2501e2e27..70b47cd0c 100644 --- a/slsDetectorSoftware/src/CmdProxy.h +++ b/slsDetectorSoftware/src/CmdProxy.h @@ -1063,6 +1063,7 @@ class CmdProxy { {"updatekernel", &CmdProxy::UpdateKernel}, {"rebootcontroller", &CmdProxy::rebootcontroller}, {"update", &CmdProxy::UpdateFirmwareAndDetectorServer}, + {"updatemode", &CmdProxy::updatemode}, {"reg", &CmdProxy::Register}, {"adcreg", &CmdProxy::AdcRegister}, {"setbit", &CmdProxy::BitOperations}, @@ -2184,6 +2185,12 @@ class CmdProxy { "\n\t[Jungfrau][Ctb][Moench][Gotthard][Mythen3][" "Gotthard2] Reboot controller of detector."); + INTEGER_COMMAND_VEC_ID( + updatemode, getUpdateMode, setUpdateMode, StringTo, + "[0|1]\n\tRestart the detector server in update mode or not. This is " + "useful when server-firmware compatibility is at its worst and server " + "cannot start up normally"); + EXECUTE_SET_COMMAND( firmwaretest, executeFirmwareTest, "\n\t[Jungfrau][Gotthard][Mythen3][Gotthard2][Ctb][Moench] Firmware " diff --git a/slsDetectorSoftware/src/Detector.cpp b/slsDetectorSoftware/src/Detector.cpp index a8f999713..823f18c6c 100644 --- a/slsDetectorSoftware/src/Detector.cpp +++ b/slsDetectorSoftware/src/Detector.cpp @@ -2195,6 +2195,15 @@ void Detector::updateFirmwareAndServer(const std::string &sname, programFPGA(fname, pos); } +Result Detector::getUpdateMode(Positions pos) { + return pimpl->Parallel(&Module::getUpdateMode, pos); +} + +void Detector::setUpdateMode(const bool updatemode, Positions pos) { + pimpl->Parallel(&Module::setUpdateMode, pos, updatemode); + rebootController(pos); +} + Result Detector::readRegister(uint32_t addr, Positions pos) const { return pimpl->Parallel(&Module::readRegister, pos, addr); } diff --git a/slsDetectorSoftware/src/Module.cpp b/slsDetectorSoftware/src/Module.cpp index de0559d37..dfd0e2358 100644 --- a/slsDetectorSoftware/src/Module.cpp +++ b/slsDetectorSoftware/src/Module.cpp @@ -2539,8 +2539,9 @@ void Module::updateDetectorServer(std::vector buffer, "Update Detector Server (no tftp)", serverName); break; default: - throw RuntimeError("Updating DetectorServer via the package is not implemented " - "for this detector"); + throw RuntimeError( + "Updating DetectorServer via the package is not implemented " + "for this detector"); } } @@ -2567,6 +2568,14 @@ void Module::rebootController() { << "): Controller rebooted successfully!"; } +bool Module::getUpdateMode() { return sendToDetector(F_GET_UPDATE_MODE); } + +void Module::setUpdateMode(const bool updatemode) { + sendToDetector(F_SET_UPDATE_MODE, static_cast(updatemode), nullptr); + LOG(logINFO) << "Module " << moduleIndex << " (" << shm()->hostname + << "): Update Mode set to " << updatemode << "!"; +} + uint32_t Module::readRegister(uint32_t addr) const { return sendToDetectorStop(F_READ_REGISTER, addr); } diff --git a/slsDetectorSoftware/src/Module.h b/slsDetectorSoftware/src/Module.h index 0750fb941..a11de9065 100644 --- a/slsDetectorSoftware/src/Module.h +++ b/slsDetectorSoftware/src/Module.h @@ -545,6 +545,8 @@ class Module : public virtual slsDetectorDefs { const std::string &serverName); void updateKernel(std::vector buffer); void rebootController(); + bool getUpdateMode(); + void setUpdateMode(const bool updatemode); uint32_t readRegister(uint32_t addr) const; uint32_t writeRegister(uint32_t addr, uint32_t val); void setBit(uint32_t addr, int n); diff --git a/slsSupportLib/include/sls/sls_detector_funcs.h b/slsSupportLib/include/sls/sls_detector_funcs.h index 8606c5f40..a0b3f71cb 100755 --- a/slsSupportLib/include/sls/sls_detector_funcs.h +++ b/slsSupportLib/include/sls/sls_detector_funcs.h @@ -256,6 +256,8 @@ enum detFuncs { F_GET_KERNEL_VERSION, F_UPDATE_KERNEL, F_UPDATE_DETECTOR_SERVER, + F_GET_UPDATE_MODE, + F_SET_UPDATE_MODE, NUM_DET_FUNCTIONS, RECEIVER_ENUM_START = 256, /**< detector function should not exceed this @@ -613,6 +615,8 @@ const char* getFunctionNameFromEnum(enum detFuncs func) { case F_SET_READOUT_SPEED: return "F_SET_READOUT_SPEED"; case F_GET_KERNEL_VERSION: return "F_GET_KERNEL_VERSION"; case F_UPDATE_DETECTOR_SERVER: return "F_UPDATE_DETECTOR_SERVER"; + case F_GET_UPDATE_MODE: return "F_GET_UPDATE_MODE"; + case F_SET_UPDATE_MODE: return "F_SET_UPDATE_MODE"; case NUM_DET_FUNCTIONS: return "NUM_DET_FUNCTIONS"; case RECEIVER_ENUM_START: return "RECEIVER_ENUM_START";