merge from 7.0.0

This commit is contained in:
2023-02-24 10:39:51 +01:00
101 changed files with 4009 additions and 2128 deletions

View File

@ -31,6 +31,11 @@ namespace sls {
// #define ZMQ_DETAIL
#define ROIVERBOSITY
// high water mark for gui
#define DEFFAULT_LOW_ZMQ_HWM (25)
#define DEFAULT_LOW_ZMQ_HWM_BUFFERSIZE (1024 * 1024) // 1MB
#define DEFAULT_ZMQ_BUFFERSIZE (-1) // os default
/** zmq header structure */
struct zmqHeader {
/** true if incoming data, false if end of acquisition */
@ -108,15 +113,29 @@ class ZmqSocket {
/** Returns high water mark for outbound messages */
int GetSendHighWaterMark();
/** Sets high water mark for outbound messages. Default 1000 (zmqlib) */
/** Sets high water mark for outbound messages. Default 1000 (zmqlib). Also
* changes send buffer size depending on hwm. Must rebind. */
void SetSendHighWaterMark(int limit);
/** Returns high water mark for inbound messages */
int GetReceiveHighWaterMark();
/** Sets high water mark for inbound messages. Default 1000 (zmqlib) */
/** Sets high water mark for inbound messages. Default 1000 (zmqlib). Also
* changes receiver buffer size depending on hwm. Must reconnect */
void SetReceiveHighWaterMark(int limit);
/** Gets kernel buffer for outbound messages. Default 0 (os) */
int GetSendBuffer();
/** Sets kernel buffer for outbound messages. Default 0 (os) */
void SetSendBuffer(int limit);
/** Gets kernel buffer for inbound messages. Default 0 (os) */
int GetReceiveBuffer();
/** Sets kernel buffer for inbound messages. Default 0 (os) */
void SetReceiveBuffer(int limit);
/**
* Returns Port Number
* @returns Port Number
@ -129,6 +148,9 @@ class ZmqSocket {
*/
std::string GetZmqServerAddress() { return sockfd.serverAddress; }
/** unbinds and rebind, to apply changes of HWM */
void Rebind();
/**
* Connect client socket to server socket
* @returns 1 for fail, 0 for success

View File

@ -148,6 +148,18 @@ Squash(const Container &c, typename Container::value_type default_value = {}) {
return default_value;
}
template <typename T>
typename std::enable_if<is_container<T>::value, bool>::type
removeDuplicates(T &c) {
auto containerSize = c.size();
std::sort(c.begin(), c.end());
c.erase(std::unique(c.begin(), c.end()), c.end());
if (c.size() != containerSize) {
return true;
}
return false;
}
} // namespace sls
#endif // CONTAINER_UTILS_H

View File

@ -50,6 +50,8 @@ ssize_t getFileSize(FILE *fd, const std::string &prependErrorString);
std::string getFileNameFromFilePath(const std::string &fpath);
std::vector<int> getChannelsFromStringList(const std::vector<std::string> list);
/** File can have # for comments.
* Channels can be separated by spaces, commas
* and ranges provided using ':', eg. 23:29

View File

@ -10,6 +10,8 @@
*@short functions indices to call on server (detector/receiver)
*/
#define UNRECOGNIZED_FNUM_ENUM "Unrecognized Function enum"
enum detFuncs {
F_EXEC_COMMAND = 0,
F_GET_DETECTOR_TYPE,

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
/** API versions */
<<<<<<< HEAD
#define RELEASE "developer"
#define APILIB "developer 0x221213"
#define APIRECEIVER "developer 0x221213"
@ -11,3 +12,15 @@
#define APIMOENCH "developer 0x221215"
#define APIGOTTHARD "developer 0x230117"
#define APIMYTHEN3 "developer 0x230117"
=======
#define RELEASE "7.0.0"
#define APICTB "7.0.0 0x230222"
#define APIGOTTHARD "7.0.0 0x230222"
#define APIGOTTHARD2 "7.0.0 0x230222"
#define APIJUNGFRAU "7.0.0 0x230222"
#define APIMYTHEN3 "7.0.0 0x230222"
#define APIMOENCH "7.0.0 0x230222"
#define APIEIGER "7.0.0 0x230222"
#define APILIB "7.0.0 0x230223"
#define APIRECEIVER "7.0.0 0x230222"
>>>>>>> 7.0.0.rc

View File

@ -4,6 +4,7 @@
#include "sls/logger.h"
#include "sls/sls_detector_defs.h"
#include "sls/sls_detector_exceptions.h"
#include "sls/sls_detector_funcs.h"
#include <arpa/inet.h>
#include <cassert>
#include <cstring>
@ -76,9 +77,7 @@ void ClientSocket::readReply(int &ret, void *retval, size_t retval_size) {
try {
Receive(&ret, sizeof(ret));
if (ret == slsDetectorDefs::FAIL) {
char mess[MAX_STR_LENGTH]{};
// get error message
Receive(mess, sizeof(mess));
std::string mess = readErrorMessage();
// Do we need to know hostname here?
// In that case save it???
if (socketType == "Receiver") {
@ -107,6 +106,9 @@ void ClientSocket::readReply(int &ret, void *retval, size_t retval_size) {
std::string ClientSocket::readErrorMessage() {
std::string error_msg(MAX_STR_LENGTH, '\0');
Receive(&error_msg[0], error_msg.size());
if (error_msg.find(UNRECOGNIZED_FNUM_ENUM) != std::string::npos) {
error_msg.insert(0, "Software version mismatch. ");
}
return error_msg;
}

View File

@ -27,15 +27,18 @@ UdpRxSocket::UdpRxSocket(int port, ssize_t packet_size, const char *hostname,
const std::string portname = std::to_string(port);
if (getaddrinfo(hostname, portname.c_str(), &hints, &res)) {
throw RuntimeError("Failed at getaddrinfo with " +
std::string(hostname));
std::string(hostname) + " [" +
std::string(strerror(errno)) + ']');
}
sockfd_ = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sockfd_ == -1) {
throw RuntimeError("Failed to create UDP RX socket");
throw RuntimeError("Failed to create UDP RX socket [" +
std::string(strerror(errno)) + ']');
}
if (bind(sockfd_, res->ai_addr, res->ai_addrlen) == -1) {
close(sockfd_);
throw RuntimeError("Failed to bind UDP RX socket");
throw RuntimeError("Failed to bind UDP RX socket [" +
std::string(strerror(errno)) + ']');
}
freeaddrinfo(res);
@ -74,13 +77,15 @@ int UdpRxSocket::getBufferSize() const {
int ret = 0;
socklen_t optlen = sizeof(ret);
if (getsockopt(sockfd_, SOL_SOCKET, SO_RCVBUF, &ret, &optlen) == -1)
throw RuntimeError("Could not get socket buffer size");
throw RuntimeError("Could not get socket buffer size [" +
std::string(strerror(errno)) + ']');
return ret;
}
void UdpRxSocket::setBufferSize(int size) {
if (setsockopt(sockfd_, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)))
throw RuntimeError("Could not set socket buffer size");
throw RuntimeError("Could not set socket buffer size [" +
std::string(strerror(errno)) + ']');
}
void UdpRxSocket::Shutdown() {

View File

@ -102,6 +102,16 @@ void ZmqSocket::SetSendHighWaterMark(int limit) {
PrintError();
throw ZmqSocketError("Could not set ZMQ_SNDHWM");
}
if (GetSendHighWaterMark() != limit) {
throw ZmqSocketError("Could not set ZMQ_SNDHWM to " +
std::to_string(limit));
}
int bufsize = DEFAULT_ZMQ_BUFFERSIZE;
if (limit < DEFFAULT_LOW_ZMQ_HWM) {
bufsize = DEFAULT_LOW_ZMQ_HWM_BUFFERSIZE;
}
SetSendBuffer(bufsize);
}
int ZmqSocket::GetReceiveHighWaterMark() {
@ -110,7 +120,7 @@ int ZmqSocket::GetReceiveHighWaterMark() {
if (zmq_getsockopt(sockfd.socketDescriptor, ZMQ_RCVHWM, &value,
&value_size)) {
PrintError();
throw ZmqSocketError("Could not get ZMQ_SNDHWM");
throw ZmqSocketError("Could not get ZMQ_RCVHWM");
}
return value;
}
@ -119,7 +129,77 @@ void ZmqSocket::SetReceiveHighWaterMark(int limit) {
if (zmq_setsockopt(sockfd.socketDescriptor, ZMQ_RCVHWM, &limit,
sizeof(limit))) {
PrintError();
throw ZmqSocketError("Could not set ZMQ_SNDHWM");
throw ZmqSocketError("Could not set ZMQ_RCVHWM");
}
if (GetReceiveHighWaterMark() != limit) {
throw ZmqSocketError("Could not set ZMQ_RCVHWM to " +
std::to_string(limit));
}
int bufsize = DEFAULT_ZMQ_BUFFERSIZE;
if (limit < DEFFAULT_LOW_ZMQ_HWM) {
bufsize = DEFAULT_LOW_ZMQ_HWM_BUFFERSIZE;
}
SetReceiveBuffer(bufsize);
}
int ZmqSocket::GetSendBuffer() {
int value = 0;
size_t value_size = sizeof(value);
if (zmq_getsockopt(sockfd.socketDescriptor, ZMQ_SNDBUF, &value,
&value_size)) {
PrintError();
throw ZmqSocketError("Could not get ZMQ_SNDBUF");
}
return value;
}
void ZmqSocket::SetSendBuffer(int limit) {
if (zmq_setsockopt(sockfd.socketDescriptor, ZMQ_SNDBUF, &limit,
sizeof(limit))) {
PrintError();
throw ZmqSocketError("Could not set ZMQ_SNDBUF");
}
if (GetSendBuffer() != limit) {
throw ZmqSocketError("Could not set ZMQ_SNDBUF to " +
std::to_string(limit));
}
}
int ZmqSocket::GetReceiveBuffer() {
int value = 0;
size_t value_size = sizeof(value);
if (zmq_getsockopt(sockfd.socketDescriptor, ZMQ_RCVBUF, &value,
&value_size)) {
PrintError();
throw ZmqSocketError("Could not get ZMQ_RCVBUF");
}
return value;
}
void ZmqSocket::SetReceiveBuffer(int limit) {
if (zmq_setsockopt(sockfd.socketDescriptor, ZMQ_RCVBUF, &limit,
sizeof(limit))) {
PrintError();
throw ZmqSocketError("Could not set ZMQ_RCVBUF");
}
if (GetReceiveBuffer() != limit) {
throw ZmqSocketError("Could not set ZMQ_RCVBUF to " +
std::to_string(limit));
}
}
void ZmqSocket::Rebind() { // the purpose is to apply HWL changes, which are
// frozen at bind, which is in the constructor.
// unbbind
if (zmq_unbind(sockfd.socketDescriptor, sockfd.serverAddress.c_str())) {
PrintError();
throw ZmqSocketError("Could not unbind socket");
}
// bind address
if (zmq_bind(sockfd.socketDescriptor, sockfd.serverAddress.c_str())) {
PrintError();
throw ZmqSocketError("Could not bind socket");
}
}

View File

@ -2,6 +2,7 @@
// Copyright (C) 2021 Contributors to the SLS Detector Package
#include "sls/file_utils.h"
#include "sls/ToString.h"
#include "sls/container_utils.h"
#include "sls/logger.h"
#include "sls/sls_detector_exceptions.h"
@ -165,6 +166,63 @@ ssize_t getFileSize(FILE *fd, const std::string &prependErrorString) {
return fileSize;
}
std::vector<int>
getChannelsFromStringList(const std::vector<std::string> list) {
std::vector<int> channels;
for (auto line : list) {
// replace comma with space
std::replace_if(
begin(line), end(line), [](char c) { return (c == ','); }, ' ');
// split line (delim space)
std::vector<std::string> vec = split(line, ' ');
// for every channel separated by space
for (auto it : vec) {
// find range and replace with sequence of x to y
auto result = it.find(':');
if (result != std::string::npos) {
try {
int istart = StringTo<int>(it.substr(0, result));
int istop = StringTo<int>(
it.substr(result + 1, it.length() - result - 1));
LOG(logDEBUG1) << "istart:" << istart << " istop:" << istop;
std::vector<int> range(istop - istart);
std::generate(range.begin(), range.end(),
[n = istart]() mutable { return n++; });
for (auto range_it : range) {
channels.push_back(range_it);
}
} catch (std::exception &e) {
throw RuntimeError(
"Could not load channels. Invalid channel range: " +
it);
}
}
// else convert to int
else {
int ival = 0;
try {
ival = StringTo<int>(it);
} catch (std::exception &e) {
throw RuntimeError(
"Could not load channels. Invalid channel number: " +
it);
}
channels.push_back(ival);
}
}
}
if (removeDuplicates(channels)) {
LOG(logWARNING) << "Removed duplicates from channel file";
}
LOG(logDEBUG1) << "list:" << ToString(channels);
return channels;
}
std::vector<int> getChannelsFromFile(const std::string &fname) {
// read bad channels file
std::ifstream input_file(fname);
@ -172,73 +230,19 @@ std::vector<int> getChannelsFromFile(const std::string &fname) {
throw RuntimeError("Could not open bad channels file " + fname +
" for reading");
}
std::vector<int> list;
std::vector<std::string> lines;
for (std::string line; std::getline(input_file, line);) {
// ignore comments
if (line.find('#') != std::string::npos) {
line.erase(line.find('#'));
}
// replace comma with space
std::replace_if(
begin(line), end(line), [](char c) { return (c == ','); }, ' ');
// replace x:y with a sequence of x to y
auto result = line.find(':');
while (result != std::string::npos) {
auto start = line.rfind(' ', result);
if (start == std::string::npos) {
start = 0;
} else
++start;
int istart = StringTo<int>(line.substr(start, result - start));
auto stop = line.find(' ', result);
if (stop == std::string::npos) {
stop = line.length();
}
int istop =
StringTo<int>(line.substr(result + 1, stop - result - 1));
std::vector<int> v(istop - istart);
std::generate(v.begin(), v.end(),
[n = istart]() mutable { return n++; });
line.replace(start, stop - start, ToString(v));
LOG(logDEBUG1) << line;
result = line.find(':');
}
// remove punctuations including [ and ]
line.erase(std::remove_if(begin(line), end(line), ispunct), end(line));
LOG(logDEBUG) << "\nline: [" << line << ']';
// split line (delim space) and push to list
std::vector<std::string> vec = split(line, ' ');
for (auto it : vec) {
int ival = 0;
try {
ival = StringTo<int>(it);
} catch (std::exception &e) {
throw RuntimeError("Could not load channels from file. Invalid "
"channel number: " +
it);
}
list.push_back(ival);
// ignore empty lines
if (line.empty()) {
continue;
}
lines.push_back(line);
}
// remove duplicates from list
auto listSize = list.size();
std::sort(list.begin(), list.end());
list.erase(unique(list.begin(), list.end()), list.end());
if (list.size() != listSize) {
LOG(logWARNING) << "Removed duplicates from channel file";
}
LOG(logDEBUG1) << "list:" << ToString(list);
return list;
return getChannelsFromStringList(lines);
}
std::string getAbsolutePathFromCurrentProcess(const std::string &fname) {

View File

@ -136,4 +136,18 @@ TEST_CASE("compare a vector of arrays", "[support]") {
CHECK(minusOneIfDifferent(vec1) == arr);
}
TEST_CASE("remove duplicates from vector") {
std::vector<int> v{5, 6, 5, 3};
auto r = removeDuplicates(v);
CHECK(r == true); // did indeed remove elements
CHECK(v == std::vector<int>{3, 5, 6});
}
TEST_CASE("remove duplicated empty vector") {
std::vector<int> v;
auto r = removeDuplicates(v);
CHECK(r == false); // no elements to remove
CHECK(v == std::vector<int>{});
}
} // namespace sls