mirror of
https://github.com/slsdetectorgroup/slsDetectorPackage.git
synced 2025-04-21 03:10:02 +02:00
parent
7394833710
commit
71489b7106
@ -1682,6 +1682,30 @@ class Detector(CppDetectorApi):
|
||||
def badchannels(self, value):
|
||||
ut.set_using_dict(self.setBadChannels, value)
|
||||
|
||||
@property
|
||||
@element
|
||||
def row(self):
|
||||
"""
|
||||
Set Detector row (udp header) to value. Gui uses it to rearrange for complete image.
|
||||
"""
|
||||
return self.getRow()
|
||||
|
||||
@row.setter
|
||||
def row(self, value):
|
||||
ut.set_using_dict(self.setRow, value)
|
||||
|
||||
@property
|
||||
@element
|
||||
def column(self):
|
||||
"""
|
||||
Set Detector column (udp header) to value. Gui uses it to rearrange for complete image.
|
||||
"""
|
||||
return self.getColumn()
|
||||
|
||||
@column.setter
|
||||
def column(self, value):
|
||||
ut.set_using_dict(self.setColumn, value)
|
||||
|
||||
@property
|
||||
@element
|
||||
def lock(self):
|
||||
|
@ -239,6 +239,22 @@ void init_det(py::module &m) {
|
||||
(void (Detector::*)(const std::vector<std::vector<int>>)) &
|
||||
Detector::setBadChannels,
|
||||
py::arg());
|
||||
CppDetectorApi.def("getRow",
|
||||
(Result<int>(Detector::*)(sls::Positions) const) &
|
||||
Detector::getRow,
|
||||
py::arg() = Positions{});
|
||||
CppDetectorApi.def("setRow",
|
||||
(void (Detector::*)(const int, sls::Positions)) &
|
||||
Detector::setRow,
|
||||
py::arg(), py::arg() = Positions{});
|
||||
CppDetectorApi.def("getColumn",
|
||||
(Result<int>(Detector::*)(sls::Positions) const) &
|
||||
Detector::getColumn,
|
||||
py::arg() = Positions{});
|
||||
CppDetectorApi.def("setColumn",
|
||||
(void (Detector::*)(const int, sls::Positions)) &
|
||||
Detector::setColumn,
|
||||
py::arg(), py::arg() = Positions{});
|
||||
CppDetectorApi.def("isVirtualDetectorServer",
|
||||
(Result<bool>(Detector::*)(sls::Positions) const) &
|
||||
Detector::isVirtualDetectorServer,
|
||||
|
@ -2605,8 +2605,8 @@ int readSample(int ns) {
|
||||
// if channel is in enable mask
|
||||
if ((1 << ich) & (transceiverMask)) {
|
||||
|
||||
int offset = FIFO_TIN_STATUS_FIFO_EMPTY_1_OFST + ich;
|
||||
uint32_t mask = (1 << offset);
|
||||
// int offset = FIFO_TIN_STATUS_FIFO_EMPTY_1_OFST + ich;
|
||||
// uint32_t mask = (1 << offset);
|
||||
// int empty = ((bus_r(tStatusAddr) & mask) >> offset);
|
||||
|
||||
// if fifo not empty
|
||||
|
@ -1485,7 +1485,8 @@ int setReadoutSpeed(int val) {
|
||||
return FAIL;
|
||||
}
|
||||
if (isHardwareVersion_1_0()) {
|
||||
LOG(logERROR, ("Cannot set full speed. Not implemented for this pcb version (1.0)\n"));
|
||||
LOG(logERROR, ("Cannot set full speed. Not implemented for this pcb "
|
||||
"version (1.0)\n"));
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
|
@ -319,3 +319,11 @@ int get_num_transceiver_samples(int);
|
||||
int set_num_transceiver_samples(int);
|
||||
int get_transceiver_enable(int);
|
||||
int set_transceiver_enable(int);
|
||||
int get_row(int);
|
||||
int set_row(int);
|
||||
int get_column(int);
|
||||
int set_column(int);
|
||||
int getRow();
|
||||
int setRow(int);
|
||||
int getColumn();
|
||||
int setColumn(int);
|
||||
|
@ -482,6 +482,11 @@ void function_table() {
|
||||
flist[F_SET_NUM_TRANSCEIVER_SAMPLES] = &set_num_transceiver_samples;
|
||||
flist[F_GET_TRANSCEIVER_ENABLE_MASK] = &get_transceiver_enable;
|
||||
flist[F_SET_TRANSCEIVER_ENABLE_MASK] = &set_transceiver_enable;
|
||||
flist[F_GET_ROW] = &get_row;
|
||||
flist[F_SET_ROW] = &set_row;
|
||||
flist[F_GET_COLUMN] = &get_column;
|
||||
flist[F_SET_COLUMN] = &set_column;
|
||||
|
||||
// check
|
||||
if (NUM_DET_FUNCTIONS >= RECEIVER_ENUM_START) {
|
||||
LOG(logERROR, ("The last detector function enum has reached its "
|
||||
@ -10582,3 +10587,127 @@ int get_transceiver_enable(int file_des) {
|
||||
#endif
|
||||
return Server_SendResult(file_des, INT32, &retval, sizeof(retval));
|
||||
}
|
||||
|
||||
int get_row(int file_des) {
|
||||
ret = OK;
|
||||
memset(mess, 0, sizeof(mess));
|
||||
int retval = -1;
|
||||
|
||||
LOG(logDEBUG1, ("Getting row\n"));
|
||||
// get only
|
||||
retval = getRow();
|
||||
LOG(logDEBUG1, ("row retval: %u\n", retval));
|
||||
|
||||
return Server_SendResult(file_des, INT32, &retval, sizeof(retval));
|
||||
}
|
||||
|
||||
int set_row(int file_des) {
|
||||
ret = OK;
|
||||
memset(mess, 0, sizeof(mess));
|
||||
int arg = 0;
|
||||
|
||||
if (receiveData(file_des, &arg, sizeof(arg), INT32) < 0)
|
||||
return printSocketReadError();
|
||||
LOG(logINFO, ("Setting row: %u\n", arg));
|
||||
|
||||
// only set
|
||||
if (Server_VerifyLock() == OK) {
|
||||
if (arg < 0) {
|
||||
ret = FAIL;
|
||||
sprintf(
|
||||
mess,
|
||||
"Could not set row. Invalid value %d. Must be greater than 0\n",
|
||||
arg);
|
||||
LOG(logERROR, (mess));
|
||||
} else {
|
||||
ret = setRow(arg);
|
||||
if (ret == FAIL) {
|
||||
sprintf(mess, "Could not set row\n");
|
||||
LOG(logERROR, (mess));
|
||||
} else {
|
||||
int retval = getRow();
|
||||
LOG(logDEBUG1, ("gain retval: %u\n", retval));
|
||||
validate(&ret, mess, arg, retval, "set row", DEC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Server_SendResult(file_des, INT32, NULL, 0);
|
||||
}
|
||||
|
||||
int get_column(int file_des) {
|
||||
ret = OK;
|
||||
memset(mess, 0, sizeof(mess));
|
||||
int retval = -1;
|
||||
|
||||
LOG(logDEBUG1, ("Getting column\n"));
|
||||
// get only
|
||||
retval = getColumn();
|
||||
LOG(logDEBUG1, ("column retval: %u\n", retval));
|
||||
|
||||
return Server_SendResult(file_des, INT32, &retval, sizeof(retval));
|
||||
}
|
||||
|
||||
int set_column(int file_des) {
|
||||
ret = OK;
|
||||
memset(mess, 0, sizeof(mess));
|
||||
int arg = 0;
|
||||
|
||||
if (receiveData(file_des, &arg, sizeof(arg), INT32) < 0)
|
||||
return printSocketReadError();
|
||||
LOG(logINFO, ("Setting column: %u\n", arg));
|
||||
|
||||
// only set
|
||||
if (Server_VerifyLock() == OK) {
|
||||
if (arg < 0) {
|
||||
ret = FAIL;
|
||||
sprintf(mess,
|
||||
"Could not set column. Invalid value %d. Must be greater "
|
||||
"than 0\n",
|
||||
arg);
|
||||
LOG(logERROR, (mess));
|
||||
} else {
|
||||
ret = setColumn(arg);
|
||||
if (ret == FAIL) {
|
||||
sprintf(mess, "Could not set column\n");
|
||||
LOG(logERROR, (mess));
|
||||
} else {
|
||||
int retval = getColumn();
|
||||
LOG(logDEBUG1, ("gain retval: %u\n", retval));
|
||||
validate(&ret, mess, arg, retval, "set column", DEC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Server_SendResult(file_des, INT32, NULL, 0);
|
||||
}
|
||||
|
||||
int getRow() {
|
||||
#if defined(JUNGFRAUD) || defined(MOENCHD)
|
||||
// inner (top) position (0, 1) might be incremented if 2 interfaces
|
||||
return getDetectorPosition()[Y + 2];
|
||||
#endif
|
||||
return getDetectorPosition()[Y];
|
||||
}
|
||||
|
||||
int setRow(int value) {
|
||||
int pos[2] = {0, 0};
|
||||
memcpy(pos, getDetectorPosition(), sizeof(pos));
|
||||
pos[Y] = value;
|
||||
return setDetectorPosition(pos);
|
||||
}
|
||||
|
||||
int getColumn() {
|
||||
#if defined(JUNGFRAUD) || defined(MOENCHD)
|
||||
// inner (top) position (0, 1) might be incremented if 2 interfaces
|
||||
return getDetectorPosition()[X + 2];
|
||||
#endif
|
||||
return getDetectorPosition()[X];
|
||||
}
|
||||
|
||||
int setColumn(int value) {
|
||||
int pos[2] = {0, 0};
|
||||
memcpy(pos, getDetectorPosition(), sizeof(pos));
|
||||
pos[X] = value;
|
||||
return setDetectorPosition(pos);
|
||||
}
|
@ -238,6 +238,16 @@ class Detector {
|
||||
* channel list. */
|
||||
void setBadChannels(const std::vector<std::vector<int>> list);
|
||||
|
||||
Result<int> getRow(Positions pos = {}) const;
|
||||
|
||||
/** Set it in udp header. Gui uses it to rearrange for complete image */
|
||||
void setRow(const int value, Positions pos = {});
|
||||
|
||||
Result<int> getColumn(Positions pos = {}) const;
|
||||
|
||||
/** Set it in udp header. Gui uses it to rearrange for complete image */
|
||||
void setColumn(const int value, Positions pos = {});
|
||||
|
||||
Result<bool> isVirtualDetectorServer(Positions pos = {}) const;
|
||||
///@}
|
||||
|
||||
|
@ -992,6 +992,8 @@ class CmdProxy {
|
||||
{"master", &CmdProxy::master},
|
||||
{"sync", &CmdProxy::sync},
|
||||
{"badchannels", &CmdProxy::BadChannels},
|
||||
{"row", &CmdProxy::row},
|
||||
{"column", &CmdProxy::column},
|
||||
|
||||
/* acquisition parameters */
|
||||
{"acquire", &CmdProxy::Acquire},
|
||||
@ -1542,6 +1544,15 @@ class CmdProxy {
|
||||
"[0, 1]\n\t[Jungfrau][Moench] Enables or disables "
|
||||
"synchronization between modules.");
|
||||
|
||||
INTEGER_COMMAND_VEC_ID(row, getRow, setRow, StringTo<int>,
|
||||
"[value]\n\tSet Detector row (udp header) to value. "
|
||||
"\n\tGui uses it to rearrange for complete image");
|
||||
|
||||
INTEGER_COMMAND_VEC_ID(
|
||||
column, getColumn, setColumn, StringTo<int>,
|
||||
"[value]\n\tSet Detector column (udp header) to value. \n\tGui uses it "
|
||||
"to rearrange for complete image");
|
||||
|
||||
/* acquisition parameters */
|
||||
|
||||
INTEGER_COMMAND_SET_NOID_GET_ID(
|
||||
|
@ -379,6 +379,22 @@ void Detector::setBadChannels(const std::vector<int> list, Positions pos) {
|
||||
pimpl->setBadChannels(list, pos);
|
||||
}
|
||||
|
||||
Result<int> Detector::getRow(Positions pos) const {
|
||||
return pimpl->Parallel(&Module::getRow, pos);
|
||||
}
|
||||
|
||||
void Detector::setRow(const int value, Positions pos) {
|
||||
pimpl->Parallel(&Module::setRow, pos, value);
|
||||
}
|
||||
|
||||
Result<int> Detector::getColumn(Positions pos) const {
|
||||
return pimpl->Parallel(&Module::getColumn, pos);
|
||||
}
|
||||
|
||||
void Detector::setColumn(const int value, Positions pos) {
|
||||
pimpl->Parallel(&Module::setColumn, pos, value);
|
||||
}
|
||||
|
||||
Result<bool> Detector::isVirtualDetectorServer(Positions pos) const {
|
||||
return pimpl->Parallel(&Module::isVirtualDetectorServer, pos);
|
||||
}
|
||||
|
@ -589,6 +589,24 @@ void Module::setBadChannels(std::vector<int> list) {
|
||||
}
|
||||
}
|
||||
|
||||
int Module::getRow() const { return sendToDetector<int>(F_GET_ROW); }
|
||||
|
||||
void Module::setRow(int value) {
|
||||
sendToDetector(F_SET_ROW, value, nullptr);
|
||||
if (shm()->useReceiverFlag) {
|
||||
sendToReceiver(F_RECEIVER_SET_ROW, value, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
int Module::getColumn() const { return sendToDetector<int>(F_GET_COLUMN); }
|
||||
|
||||
void Module::setColumn(int value) {
|
||||
sendToDetector(F_SET_COLUMN, value, nullptr);
|
||||
if (shm()->useReceiverFlag) {
|
||||
sendToReceiver(F_RECEIVER_SET_COLUMN, value, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
bool Module::isVirtualDetectorServer() const {
|
||||
return sendToDetector<int>(F_IS_VIRTUAL);
|
||||
}
|
||||
|
@ -134,6 +134,10 @@ class Module : public virtual slsDetectorDefs {
|
||||
void setSynchronization(const bool value);
|
||||
std::vector<int> getBadChannels() const;
|
||||
void setBadChannels(std::vector<int> list);
|
||||
int getRow() const;
|
||||
void setRow(const int value);
|
||||
int getColumn() const;
|
||||
void setColumn(const int value);
|
||||
|
||||
bool isVirtualDetectorServer() const;
|
||||
|
||||
|
@ -715,6 +715,52 @@ TEST_CASE("badchannels", "[.cmd]") {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("row", "[.cmd]") {
|
||||
Detector det;
|
||||
CmdProxy proxy(&det);
|
||||
auto prev_val = det.getRow()[0];
|
||||
{
|
||||
std::ostringstream oss;
|
||||
proxy.Call("row", {"1"}, 0, PUT, oss);
|
||||
REQUIRE(oss.str() == "row 1\n");
|
||||
}
|
||||
{
|
||||
std::ostringstream oss;
|
||||
proxy.Call("row", {}, 0, GET, oss);
|
||||
REQUIRE(oss.str() == "row 1\n");
|
||||
}
|
||||
{
|
||||
std::ostringstream oss;
|
||||
proxy.Call("row", {"0"}, 0, PUT, oss);
|
||||
REQUIRE(oss.str() == "row 0\n");
|
||||
}
|
||||
REQUIRE_THROWS(proxy.Call("row", {"-5"}, -1, PUT));
|
||||
det.setRow(prev_val, {0});
|
||||
}
|
||||
|
||||
TEST_CASE("column", "[.cmd]") {
|
||||
Detector det;
|
||||
CmdProxy proxy(&det);
|
||||
auto prev_val = det.getColumn()[0];
|
||||
{
|
||||
std::ostringstream oss;
|
||||
proxy.Call("column", {"1"}, 0, PUT, oss);
|
||||
REQUIRE(oss.str() == "column 1\n");
|
||||
}
|
||||
{
|
||||
std::ostringstream oss;
|
||||
proxy.Call("column", {}, 0, GET, oss);
|
||||
REQUIRE(oss.str() == "column 1\n");
|
||||
}
|
||||
{
|
||||
std::ostringstream oss;
|
||||
proxy.Call("column", {"0"}, 0, PUT, oss);
|
||||
REQUIRE(oss.str() == "column 0\n");
|
||||
}
|
||||
REQUIRE_THROWS(proxy.Call("column", {"-5"}, -1, PUT));
|
||||
det.setColumn(prev_val, {0});
|
||||
}
|
||||
|
||||
/* acquisition parameters */
|
||||
|
||||
// acquire: not testing
|
||||
|
@ -222,6 +222,9 @@ int ClientInterface::functionTable(){
|
||||
flist[F_RECEIVER_SET_RECEIVER_ROI_METADATA] = &ClientInterface::set_receiver_roi_metadata;
|
||||
flist[F_RECEIVER_SET_NUM_TRANSCEIVER_SAMPLES] = &ClientInterface::set_num_transceiver_samples;
|
||||
flist[F_RECEIVER_SET_TRANSCEIVER_MASK] = &ClientInterface::set_transceiver_mask;
|
||||
flist[F_RECEIVER_SET_ROW] = &ClientInterface::set_row;
|
||||
flist[F_RECEIVER_SET_COLUMN] = &ClientInterface::set_column;
|
||||
|
||||
|
||||
for (int i = NUM_DET_FUNCTIONS + 1; i < NUM_REC_FUNCTIONS ; i++) {
|
||||
LOG(logDEBUG1) << "function fnum: " << i << " (" <<
|
||||
@ -1799,4 +1802,26 @@ int ClientInterface::set_transceiver_mask(Interface &socket) {
|
||||
return socket.sendResult(retval);
|
||||
}
|
||||
|
||||
int ClientInterface::set_row(Interface &socket) {
|
||||
auto value = socket.Receive<int>();
|
||||
if (value < 0) {
|
||||
throw RuntimeError("Invalid row " + std::to_string(value));
|
||||
}
|
||||
verifyIdle(socket);
|
||||
LOG(logDEBUG1) << "Setting num rows to " << value;
|
||||
impl()->setRow(value);
|
||||
return socket.Send(OK);
|
||||
}
|
||||
|
||||
int ClientInterface::set_column(Interface &socket) {
|
||||
auto value = socket.Receive<int>();
|
||||
if (value < 0) {
|
||||
throw RuntimeError("Invalid column " + std::to_string(value));
|
||||
}
|
||||
verifyIdle(socket);
|
||||
LOG(logDEBUG1) << "Setting column to " << value;
|
||||
impl()->setColumn(value);
|
||||
return socket.Send(OK);
|
||||
}
|
||||
|
||||
} // namespace sls
|
||||
|
@ -172,6 +172,8 @@ class ClientInterface : private virtual slsDetectorDefs {
|
||||
int set_receiver_roi_metadata(ServerInterface &socket);
|
||||
int set_num_transceiver_samples(ServerInterface &socket);
|
||||
int set_transceiver_mask(ServerInterface &socket);
|
||||
int set_row(ServerInterface &socket);
|
||||
int set_column(ServerInterface &socket);
|
||||
|
||||
Implementation *impl() {
|
||||
if (receiver != nullptr) {
|
||||
|
@ -284,6 +284,20 @@ void Implementation::setModulePositionId(const int id) {
|
||||
}
|
||||
}
|
||||
|
||||
void Implementation::setRow(const int value) {
|
||||
for (unsigned int i = 0; i < listener.size(); ++i) {
|
||||
int col = listener[i]->GetHardCodedPosition().second;
|
||||
listener[i]->SetHardCodedPosition(value, col);
|
||||
}
|
||||
}
|
||||
|
||||
void Implementation::setColumn(const int value) {
|
||||
for (unsigned int i = 0; i < listener.size(); ++i) {
|
||||
int row = listener[i]->GetHardCodedPosition().first;
|
||||
listener[i]->SetHardCodedPosition(row, value);
|
||||
}
|
||||
}
|
||||
|
||||
std::string Implementation::getDetectorHostname() const { return detHostname; }
|
||||
|
||||
void Implementation::setDetectorHostname(const std::string &c) {
|
||||
|
@ -41,6 +41,8 @@ class Implementation : private virtual slsDetectorDefs {
|
||||
void setDetectorSize(const xy size);
|
||||
int getModulePositionId() const;
|
||||
void setModulePositionId(const int id);
|
||||
void setRow(const int value);
|
||||
void setColumn(const int value);
|
||||
std::string getDetectorHostname() const;
|
||||
void setDetectorHostname(const std::string &c);
|
||||
bool getSilentMode() const;
|
||||
|
@ -251,6 +251,10 @@ void Listener::SetHardCodedPosition(uint16_t r, uint16_t c) {
|
||||
<< "] (row: " << row << ", col: " << column << ")";
|
||||
}
|
||||
|
||||
std::pair<uint16_t, uint16_t> Listener::GetHardCodedPosition() {
|
||||
return std::make_pair(row, column);
|
||||
}
|
||||
|
||||
void Listener::ThreadExecution() {
|
||||
char *buffer;
|
||||
fifo->GetNewAddress(buffer);
|
||||
|
@ -61,6 +61,7 @@ class Listener : private virtual slsDetectorDefs, public ThreadObject {
|
||||
* packets/deactivated) c when used is in 2d
|
||||
*/
|
||||
void SetHardCodedPosition(uint16_t r, uint16_t c);
|
||||
std::pair<uint16_t, uint16_t> GetHardCodedPosition();
|
||||
|
||||
private:
|
||||
void RecordFirstIndex(uint64_t fnum);
|
||||
|
@ -286,6 +286,10 @@ enum detFuncs {
|
||||
F_SET_NUM_TRANSCEIVER_SAMPLES,
|
||||
F_GET_TRANSCEIVER_ENABLE_MASK,
|
||||
F_SET_TRANSCEIVER_ENABLE_MASK,
|
||||
F_GET_ROW,
|
||||
F_SET_ROW,
|
||||
F_GET_COLUMN,
|
||||
F_SET_COLUMN,
|
||||
|
||||
NUM_DET_FUNCTIONS,
|
||||
RECEIVER_ENUM_START = 512, /**< detector function should not exceed this
|
||||
@ -395,6 +399,8 @@ enum detFuncs {
|
||||
F_RECEIVER_SET_RECEIVER_ROI_METADATA,
|
||||
F_RECEIVER_SET_NUM_TRANSCEIVER_SAMPLES,
|
||||
F_RECEIVER_SET_TRANSCEIVER_MASK,
|
||||
F_RECEIVER_SET_ROW,
|
||||
F_RECEIVER_SET_COLUMN,
|
||||
|
||||
NUM_REC_FUNCTIONS
|
||||
};
|
||||
@ -677,6 +683,10 @@ const char* getFunctionNameFromEnum(enum detFuncs func) {
|
||||
case F_SET_NUM_TRANSCEIVER_SAMPLES: return "F_SET_NUM_TRANSCEIVER_SAMPLES";
|
||||
case F_GET_TRANSCEIVER_ENABLE_MASK: return "F_GET_TRANSCEIVER_ENABLE_MASK";
|
||||
case F_SET_TRANSCEIVER_ENABLE_MASK: return "F_SET_TRANSCEIVER_ENABLE_MASK";
|
||||
case F_GET_ROW: return "F_GET_ROW";
|
||||
case F_SET_ROW: return "F_SET_ROW";
|
||||
case F_GET_COLUMN: return "F_GET_COLUMN";
|
||||
case F_SET_COLUMN: return "F_SET_COLUMN";
|
||||
|
||||
case NUM_DET_FUNCTIONS: return "NUM_DET_FUNCTIONS";
|
||||
case RECEIVER_ENUM_START: return "RECEIVER_ENUM_START";
|
||||
@ -786,6 +796,9 @@ const char* getFunctionNameFromEnum(enum detFuncs func) {
|
||||
case F_RECEIVER_SET_RECEIVER_ROI_METADATA: return "F_RECEIVER_SET_RECEIVER_ROI_METADATA";
|
||||
case F_RECEIVER_SET_NUM_TRANSCEIVER_SAMPLES: return "F_RECEIVER_SET_NUM_TRANSCEIVER_SAMPLES";
|
||||
case F_RECEIVER_SET_TRANSCEIVER_MASK: return "F_RECEIVER_SET_TRANSCEIVER_MASK";
|
||||
case F_RECEIVER_SET_ROW: return "F_RECEIVER_SET_ROW";
|
||||
case F_RECEIVER_SET_COLUMN: return "F_RECEIVER_SET_COLUMN";
|
||||
|
||||
|
||||
case NUM_REC_FUNCTIONS: return "NUM_REC_FUNCTIONS";
|
||||
default: return "Unknown Function";
|
||||
|
Loading…
x
Reference in New Issue
Block a user