Erik Fröjdh 2f2fe4dd47
Release of 5.1.0 (#237)
* Setting pattern from memory (#218)

* ToString accepts c-style arrays

* fixed patwait time bug in validation

* Introduced pattern class

* compile for servers too

* Python binding for Pattern

* added scanParameters in Python

* slsReceiver: avoid potential memory leak around Implementation::generalData

* additional constructors for scanPrameters in python

* bugfix: avoid potentital memory leak in receiver if called outside constructor context

* added scanParameters in Python

* additional constructors for scanPrameters in python

* M3defaultpattern (#227)

* default pattern for m3 and moench including Python bindings

* M3settings (#228)

* some changes to compile on RH7 and in the server to load the default chip status register at startup

* Updated mythen3DeectorServer_developer executable with correct initialization at startup

Co-authored-by: Erik Frojdh <erik.frojdh@gmail.com>
Co-authored-by: Anna Bergamaschi <anna.bergamaschi@psi.ch>

* Pattern.h as a public header files (#229)

* fixed buffer overflow but caused by using global instead of local enum

* replacing out of range trimbits with edge values

* replacing dac values that are out of range after interpolation

* updated pybind11 to 2.6.2

* Mythen3 improved synchronization (#231)

Disabling scans for multi module Mythen3, since there is no feedback of the detectors being ready
startDetector first starts the slaves then the master
acquire firs calls startDetector for the slaves then acquire on the master
getMaster to read back from hardware which one is master

* New server for JF to go with the new FW (#232)

* Modified Jungfrau speed settings for HW1.0 - FW fix version 1.1.1, compilation date 210218

* Corrected bug. DBIT clk phase is implemented in both HW version 1.0 and 2.0. Previous version did not update the DBIT phase shift on the configuration of a speed.

* fix for m3 scan with single module

* m3 fw version

* m3 server

* bugfix for bottom when setting quad

* new strategy for finding zmq based on cppzmq



Co-authored-by: Dhanya Thattil <dhanya.thattil@psi.ch>
Co-authored-by: Dhanya Thattil <33750417+thattil@users.noreply.github.com>
Co-authored-by: Alejandro Homs Puron <ahoms@esrf.fr>
Co-authored-by: Anna Bergamaschi <anna.bergamaschi@psi.ch>
Co-authored-by: Xiaoqiang Wang <xiaoqiangwang@gmail.com>
Co-authored-by: lopez_c <carlos.lopez-cuenca@psi.ch>
2021-03-22 14:43:11 +01:00

566 lines
18 KiB
C

#include "communication_funcs.h"
#include "clogger.h"
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
#include <sys/select.h>
#include <unistd.h>
#define SEND_REC_MAX_SIZE 4096
#define DEFAULT_PORTNO 1952
#define DEFAULT_BACKLOG 5
// blackfin limits
#define CPU_DRVR_SND_LMT (30000) // rough limit
#define CPU_RSND_PCKT_LOOP (10)
#define CPU_RSND_WAIT_US (1)
// Global variables from errno.h
// extern int errno;
// Variables that will be exported
int lockStatus = 0;
uint32_t lastClientIP = 0u;
uint32_t thisClientIP = 0u;
int differentClients = 0;
int isControlServer = 1;
int ret = FAIL;
int fnum = 0;
char mess[MAX_STR_LENGTH];
// Local variables
uint32_t dummyClientIP = 0u;
int myport = -1;
// socket descriptor set
fd_set readset, tempset;
// number of socket descrptor listening to
int isock = 0;
// value of socket descriptor,
// becomes max value of socket descriptor (listen) and file descriptor (accept)
int maxfd = 0;
int bindSocket(unsigned short int port_number) {
ret = FAIL;
int socketDescriptor = -1;
int i = 0;
struct sockaddr_in addressS;
// same port
if (myport == port_number) {
sprintf(
mess,
"Cannot create %s socket with port %d. Already in use before.\n",
(isControlServer ? "control" : "stop"), port_number);
LOG(logERROR, (mess));
}
// port ok
else {
// create socket
socketDescriptor = socket(AF_INET, SOCK_STREAM, 0);
// socket error
if (socketDescriptor < 0) {
sprintf(mess, "Cannot create %s socket with port %d\n",
(isControlServer ? "control" : "stop"), port_number);
LOG(logERROR, (mess));
}
// socket success
else {
i = 1;
// set port reusable
setsockopt(socketDescriptor, SOL_SOCKET, SO_REUSEADDR, &i,
sizeof(i));
// Set some fields in the serverAddress structure
addressS.sin_family = AF_INET;
addressS.sin_addr.s_addr = htonl(INADDR_ANY);
addressS.sin_port = htons(port_number);
// bind socket error
if (bind(socketDescriptor, (struct sockaddr *)&addressS,
sizeof(addressS)) < 0) {
sprintf(mess, "Cannot bind %s socket to port %d.\n",
(isControlServer ? "control" : "stop"), port_number);
LOG(logERROR, (mess));
}
// bind socket ok
else {
// listen to socket
if (listen(socketDescriptor, DEFAULT_BACKLOG) == 0) {
// clear set of descriptors. set of descriptors needed?
if (isock == 0) {
FD_ZERO(&readset);
}
// add a socket descriptor from listen
FD_SET(socketDescriptor, &readset);
isock++;
maxfd = socketDescriptor;
// success
myport = port_number;
ret = OK;
LOG(logDEBUG1,
("%s socket bound: isock=%d, port=%d, fd=%d\n",
(isControlServer ? "Control" : "Stop"), isock,
port_number, socketDescriptor));
}
// listen socket error
else {
sprintf(mess, "Cannot bind %s socket to port %d.\n",
(isControlServer ? "control" : "stop"),
port_number);
LOG(logERROR, (mess));
}
}
}
}
return socketDescriptor;
}
int acceptConnection(int socketDescriptor) {
struct sockaddr_in addressC;
int file_des = -1;
struct timeval tv;
socklen_t address_length = sizeof(struct sockaddr_in);
if (socketDescriptor < 0)
return -1;
// copy file descriptor set temporarily
memcpy(&tempset, &readset, sizeof(tempset));
// set time out as 2777.77 hours?
tv.tv_sec = 10000000;
tv.tv_usec = 0;
// monitor file descrptors
int result = select(maxfd + 1, &tempset, NULL, NULL, &tv);
// timeout
if (result == 0) {
LOG(logDEBUG3, ("%s socket select() timed out!\n",
(isControlServer ? "control" : "stop"), myport));
}
// error (not signal caught)
else if (result < 0 && errno != EINTR) {
LOG(logERROR,
("%s socket select() error: %s\n",
(isControlServer ? "control" : "stop"), myport, strerror(errno)));
}
// activity in descriptor set
else if (result > 0) {
LOG(logDEBUG3,
("%s select returned!\n", (isControlServer ? "control" : "stop")));
// loop through the file descriptor set
for (int j = 0; j < maxfd + 1; ++j) {
// checks if file descriptor part of set
if (FD_ISSET(j, &tempset)) {
LOG(logDEBUG3, ("fd %d is set\n", j));
// clear the temporary set
FD_CLR(j, &tempset);
// accept connection (if error)
if ((file_des = accept(j, (struct sockaddr *)&addressC,
&address_length)) < 0) {
LOG(logERROR,
("%s socket accept() error. Connection refused.\n",
"Error Number: %d, Message: %s\n",
(isControlServer ? "control" : "stop"), myport, errno,
strerror(errno)));
switch (errno) {
case EWOULDBLOCK:
LOG(logERROR, ("ewouldblock eagain"));
break;
case EBADF:
LOG(logERROR, ("ebadf\n"));
break;
case ECONNABORTED:
LOG(logERROR, ("econnaborted\n"));
break;
case EFAULT:
LOG(logERROR, ("efault\n"));
break;
case EINTR:
LOG(logERROR, ("eintr\n"));
break;
case EINVAL:
LOG(logERROR, ("einval\n"));
break;
case EMFILE:
LOG(logERROR, ("emfile\n"));
break;
case ENFILE:
LOG(logERROR, ("enfile\n"));
break;
case ENOTSOCK:
LOG(logERROR, ("enotsock\n"));
break;
case EOPNOTSUPP:
LOG(logERROR, ("eOPNOTSUPP\n"));
break;
case ENOBUFS:
LOG(logERROR, ("ENOBUFS\n"));
break;
case ENOMEM:
LOG(logERROR, ("ENOMEM\n"));
break;
case ENOSR:
LOG(logERROR, ("ENOSR\n"));
break;
case EPROTO:
LOG(logERROR, ("EPROTO\n"));
break;
default:
LOG(logERROR, ("unknown error\n"));
}
}
// accept success
else {
char buf[INET_ADDRSTRLEN] = "";
memset(buf, 0, INET_ADDRSTRLEN);
inet_ntop(AF_INET, &(addressC.sin_addr), buf,
INET_ADDRSTRLEN);
LOG(logDEBUG3,
("%s socket accepted connection, fd= %d\n",
(isControlServer ? "control" : "stop"), file_des));
getIpAddressFromString(buf, &dummyClientIP);
// add the file descriptor from accept
FD_SET(file_des, &readset);
maxfd = (maxfd < file_des) ? file_des : maxfd;
}
}
}
}
return file_des;
}
void closeConnection(int file_des) {
if (file_des >= 0)
close(file_des);
// remove file descriptor from set
FD_CLR(file_des, &readset);
}
void exitServer(int socketDescriptor) {
if (socketDescriptor >= 0) {
close(socketDescriptor);
}
LOG(logINFO,
("Closing %s server\n", (isControlServer ? "control" : "stop")));
FD_CLR(socketDescriptor, &readset);
isock--;
fflush(stdout);
}
void swapData(void *val, int length, intType itype) {
int16_t *c = (int16_t *)val;
int32_t *a = (int32_t *)val;
int64_t *b = (int64_t *)val;
for (int i = 0; length > 0; i++) {
switch (itype) {
case INT16:
c[i] = ((c[i] & 0x00FF) << 8) | ((c[i] & 0xFF00) >> 8);
length -= sizeof(int16_t);
break;
case INT32:
a[i] = ((a[i] << 8) & 0xFF00FF00) | ((a[i] >> 8) & 0xFF00FF);
a[i] = (a[i] << 16) | ((a[i] >> 16) & 0xFFFF);
length -= sizeof(int32_t);
break;
case INT64:
b[i] = ((b[i] << 8) & 0xFF00FF00FF00FF00ULL) |
((b[i] >> 8) & 0x00FF00FF00FF00FFULL);
b[i] = ((b[i] << 16) & 0xFFFF0000FFFF0000ULL) |
((b[i] >> 16) & 0x0000FFFF0000FFFFULL);
b[i] = (b[i] << 32) | ((b[i] >> 32) & 0xFFFFFFFFULL);
length -= sizeof(int64_t);
break;
default:
length = 0;
break;
}
}
}
int sendData(int file_des, void *buf, int length, intType itype) {
#ifndef PCCOMPILE
#ifdef EIGERD
swapData(buf, length, itype);
#endif
#endif
return sendDataOnly(file_des, buf, length);
}
int receiveData(int file_des, void *buf, int length, intType itype) {
int lret = receiveDataOnly(file_des, buf, length);
#ifndef PCCOMPILE
#ifdef EIGERD
if (lret >= 0)
swapData(buf, length, itype);
#endif
#endif
return lret;
}
int sendDataOnly(int file_des, void *buf, int length) {
if (!length)
return 0;
int bytesSent = 0;
int retry = 0; // retry index when buffer is blocked (write returns 0)
while (bytesSent < length) {
// setting a max packet size for blackfin driver (and network driver
// does not do a check if packets sent)
int bytesToSend = length - bytesSent;
if (bytesToSend > CPU_DRVR_SND_LMT)
bytesToSend = CPU_DRVR_SND_LMT;
// send
int rc =
write(file_des, (char *)((char *)buf + bytesSent), bytesToSend);
// error
if (rc < 0) {
LOG(logERROR,
("Could not write to %s socket. Possible socket crash\n",
(isControlServer ? "control" : "stop")));
return bytesSent;
}
// also error, wrote nothing, buffer blocked up, too fast sending for
// client
if (rc == 0) {
LOG(logERROR,
("Could not write to %s socket. Buffer full. Retry: %d\n",
(isControlServer ? "control" : "stop"), retry));
++retry;
// wrote nothing for many loops
if (retry >= CPU_RSND_PCKT_LOOP) {
LOG(logERROR, ("Could not write to %s socket. Buffer full! Too "
"fast! No more.\n",
(isControlServer ? "control" : "stop")));
return bytesSent;
}
usleep(CPU_RSND_WAIT_US);
}
// wrote something, reset retry
else {
retry = 0;
if (rc != bytesToSend) {
LOG(logWARNING,
("Only partial write to %s socket. Expected to write %d "
"bytes, wrote %d\n",
(isControlServer ? "control" : "stop"), bytesToSend, rc));
}
}
bytesSent += rc;
}
return bytesSent;
}
int receiveDataOnly(int file_des, void *buf, int length) {
int total_received = 0;
int nreceiving;
int nreceived;
if (file_des < 0)
return -1;
LOG(logDEBUG3, ("want to receive %d Bytes to %s server\n", length,
(isControlServer ? "control" : "stop")));
while (length > 0) {
nreceiving = (length > SEND_REC_MAX_SIZE)
? SEND_REC_MAX_SIZE
: length; // (condition) ? if_true : if_false
nreceived = read(file_des, (char *)buf + total_received, nreceiving);
if (!nreceived) {
if (!total_received) {
return -1; // to handle it
}
break;
}
length -= nreceived;
total_received += nreceived;
}
if (total_received > 0)
thisClientIP = dummyClientIP;
if (lastClientIP != thisClientIP) {
differentClients = 1;
} else
differentClients = 0;
return total_received;
}
int receiveModule(int file_des, sls_detector_module *myMod) {
enum TLogLevel level = logDEBUG1;
LOG(level, ("Receiving Module\n"));
int ts = 0, n = 0;
int nDacs = myMod->ndac;
#if defined(EIGERD) || defined(MYTHEN3D)
int nChans = myMod->nchan; // can be zero for no trimbits
LOG(level, ("nChans: %d\n", nChans));
#endif
n = receiveData(file_des, &(myMod->serialnumber),
sizeof(myMod->serialnumber), INT32);
if (!n) {
return -1;
}
ts += n;
LOG(level, ("serialno received. %d bytes. serialno: %d\n", n,
myMod->serialnumber));
n = receiveData(file_des, &(myMod->nchan), sizeof(myMod->nchan), INT32);
if (!n) {
return -1;
}
ts += n;
LOG(level, ("nchan received. %d bytes. nchan: %d\n", n, myMod->nchan));
n = receiveData(file_des, &(myMod->nchip), sizeof(myMod->nchip), INT32);
if (!n) {
return -1;
}
ts += n;
LOG(level, ("nchip received. %d bytes. nchip: %d\n", n, myMod->nchip));
n = receiveData(file_des, &(myMod->ndac), sizeof(myMod->ndac), INT32);
if (!n) {
return -1;
}
ts += n;
LOG(level, ("ndac received. %d bytes. ndac: %d\n", n, myMod->ndac));
n = receiveData(file_des, &(myMod->reg), sizeof(myMod->reg), INT32);
if (!n) {
return -1;
}
ts += n;
LOG(level, ("reg received. %d bytes. reg: %d\n", n, myMod->reg));
n = receiveData(file_des, &(myMod->iodelay), sizeof(myMod->iodelay), INT32);
if (!n) {
return -1;
}
ts += n;
LOG(level,
("iodelay received. %d bytes. iodelay: %d\n", n, myMod->iodelay));
n = receiveData(file_des, &(myMod->tau), sizeof(myMod->tau), INT32);
if (!n) {
return -1;
}
ts += n;
LOG(level, ("tau received. %d bytes. tau: %d\n", n, myMod->tau));
n = receiveData(file_des, myMod->eV, sizeof(myMod->eV), INT32);
if (!n) {
return -1;
}
ts += n;
LOG(level, ("eV received. %d bytes. eV: %d\n", n, myMod->eV[0]));
// dacs
if (nDacs != (myMod->ndac)) {
LOG(logERROR, ("received wrong number of dacs. "
"Expected %d, got %d\n",
nDacs, myMod->ndac));
return 0;
}
n = receiveData(file_des, myMod->dacs, sizeof(int) * (myMod->ndac), INT32);
if (!n) {
return -1;
}
ts += n;
LOG(level, ("dacs received. %d bytes.\n", n));
// channels
#if defined(EIGERD) || defined(MYTHEN3D)
if (((myMod->nchan) != 0) && // no trimbits
(nChans != (myMod->nchan))) { // with trimbits
LOG(logERROR, ("received wrong number of channels. "
"Expected %d, got %d\n",
nChans, (myMod->nchan)));
return 0;
}
n = receiveData(file_des, myMod->chanregs, sizeof(int) * (myMod->nchan),
INT32);
LOG(level, ("chanregs received. %d bytes.\n", n));
if (!n && myMod->nchan != 0) {
return -1;
}
ts += n;
#endif
LOG(level, ("received module of size %d register %x\n", ts, myMod->reg));
return ts;
}
void Server_LockedError() {
ret = FAIL;
char buf[INET_ADDRSTRLEN] = "";
getIpAddressinString(buf, dummyClientIP);
sprintf(mess, "Detector locked by %s\n", buf);
LOG(logWARNING, (mess));
}
int Server_VerifyLock() {
if (differentClients && lockStatus)
Server_LockedError();
return ret;
}
int Server_SendResult(int fileDes, intType itype, void *retval,
int retvalSize) {
// send success of operation
int ret1 = ret;
sendData(fileDes, &ret1, sizeof(ret1), INT32);
if (ret == FAIL) {
// send error message
if (strlen(mess))
sendData(fileDes, mess, MAX_STR_LENGTH, OTHER);
// debugging feature. should not happen.
else
LOG(logERROR, ("No error message provided for this failure in %s "
"server. Will mess up TCP.\n",
(isControlServer ? "control" : "stop")));
}
// send return value
sendData(fileDes, retval, retvalSize, itype);
return ret;
}
void getMacAddressinString(char *cmac, int size, uint64_t mac) {
memset(cmac, 0, size);
sprintf(
cmac, "%02x:%02x:%02x:%02x:%02x:%02x",
(unsigned int)((mac >> 40) & 0xFF), (unsigned int)((mac >> 32) & 0xFF),
(unsigned int)((mac >> 24) & 0xFF), (unsigned int)((mac >> 16) & 0xFF),
(unsigned int)((mac >> 8) & 0xFF), (unsigned int)((mac >> 0) & 0xFF));
}
void getIpAddressinString(char *cip, uint32_t ip) {
memset(cip, 0, INET_ADDRSTRLEN);
#if defined(EIGERD) && !defined(VIRTUAL)
inet_ntop(AF_INET, &ip, cip, INET_ADDRSTRLEN);
#else
sprintf(cip, "%d.%d.%d.%d", (ip >> 24) & 0xff, (ip >> 16) & 0xff,
(ip >> 8) & 0xff, (ip)&0xff);
#endif
}
void getIpAddressFromString(char *cip, uint32_t *ip) {
char buf[INET_ADDRSTRLEN] = "";
memset(buf, 0, INET_ADDRSTRLEN);
char *byte = strtok(cip, ".");
while (byte != NULL) {
sprintf(cip, "%02x", atoi(byte));
strcat(buf, cip);
byte = strtok(NULL, ".");
}
sscanf(buf, "%x", ip);
}