1607 lines
42 KiB
C
1607 lines
42 KiB
C
/*-------------------------------------------------------------------------
|
|
S I N Q H M
|
|
|
|
Implementation file for the SINQ histogram memory utility functions.
|
|
|
|
David Maden, Mark Koennecke, April 1997
|
|
|
|
Updated for TOF support: Mark Koennecke, December 1998
|
|
|
|
Added Project for AMOR: Mark Koennecke, August 2001
|
|
|
|
Copyright:
|
|
|
|
Labor fuer Neutronenstreuung
|
|
Paul Scherrer Institut
|
|
CH-5423 Villigen-PSI
|
|
|
|
|
|
The authors hereby grant permission to use, copy, modify, distribute,
|
|
and license this software and its documentation for any purpose, provided
|
|
that existing copyright notices are retained in all copies and that this
|
|
notice is included verbatim in any distributions. No written agreement,
|
|
license, or royalty fee is required for any of the authorized uses.
|
|
Modifications to this software may be copyrighted by their authors
|
|
and need not follow the licensing terms described here, provided that
|
|
the new terms are clearly indicated on the first page of each file where
|
|
they apply.
|
|
|
|
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
|
|
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
|
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
|
|
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
|
|
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
|
|
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
|
|
MODIFICATIONS.
|
|
----------------------------------------------------------------------------*/
|
|
#include <errno.h>
|
|
#include <netdb.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <ctype.h>
|
|
#include <math.h>
|
|
#include <sys/socket.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <assert.h>
|
|
|
|
#ifdef FORTIFY
|
|
#include "fortify.h"
|
|
#endif
|
|
|
|
#include "sinqhm.h"
|
|
#include "sinqhm.i"
|
|
|
|
/* missing in some network stuff?? */
|
|
|
|
#ifndef MSG_WAITALL
|
|
#define MSG_WAITALL 0
|
|
#endif
|
|
|
|
/* this may be a cludge for a missing prototype on Digital Unix */
|
|
extern int close(int fp);
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
static int SendDAQCommand(pSINQHM self, int iCommand, int *iDaq)
|
|
{
|
|
struct req_buff_struct Req_buff;
|
|
struct rply_buff_struct Rply_buff;
|
|
int status, iRet;
|
|
|
|
assert(self);
|
|
assert(self->iClientSocket);
|
|
|
|
memset(&Req_buff, 0, sizeof(struct req_buff_struct));
|
|
memset(&Rply_buff, 0, sizeof(struct rply_buff_struct));
|
|
|
|
/* prepare a message */
|
|
Req_buff.bigend = htonl(0x12345678);
|
|
Req_buff.cmnd = htonl(SQHM_DAQ);
|
|
Req_buff.u.daq.sub_cmnd = htonl(iCommand);
|
|
|
|
/* send the message */
|
|
status =
|
|
send(self->iClientSocket, (char *) &Req_buff, sizeof(Req_buff), 0);
|
|
if (status == -1) {
|
|
return SEND_ERROR;
|
|
}
|
|
if (status != sizeof(Req_buff)) {
|
|
return SEND_ERROR;
|
|
}
|
|
|
|
/* get a response */
|
|
status = recv(self->iClientSocket, (char *) &Rply_buff,
|
|
sizeof(Rply_buff), MSG_WAITALL);
|
|
|
|
/* check various error conditions */
|
|
if (status == -1) {
|
|
return RECEIVE_ERROR;
|
|
}
|
|
if (status != sizeof(Rply_buff)) {
|
|
return INSUFFICIENT_DATA;
|
|
}
|
|
if (ntohl(Rply_buff.bigend) != 0x12345678) {
|
|
return BYTE_ORDER_CHAOS;
|
|
}
|
|
if ((iRet = ntohl(Rply_buff.status)) != KER__SUCCESS) {
|
|
return SOFTWARE_ERROR;
|
|
}
|
|
|
|
*iDaq = ntohs(Rply_buff.u.daq.daq_now);
|
|
|
|
/* success */
|
|
return 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
static int SendDAQStatus(pSINQHM self, struct rply_buff_struct *pReply)
|
|
{
|
|
struct req_buff_struct Req_buff;
|
|
int status, iRet;
|
|
|
|
assert(self);
|
|
|
|
if (!self->iClientSocket) {
|
|
return 0;
|
|
}
|
|
|
|
/* prepare a message */
|
|
Req_buff.bigend = htonl(0x12345678);
|
|
Req_buff.cmnd = htonl(SQHM_STATUS);
|
|
|
|
/* send the message */
|
|
status =
|
|
send(self->iClientSocket, (char *) &Req_buff, sizeof(Req_buff), 0);
|
|
if (status == -1) {
|
|
return SEND_ERROR;
|
|
}
|
|
if (status != sizeof(Req_buff)) {
|
|
return SEND_ERROR;
|
|
}
|
|
|
|
/* get a response */
|
|
status = recv(self->iClientSocket, (char *) pReply,
|
|
sizeof(struct rply_buff_struct), MSG_WAITALL);
|
|
|
|
/* check various error conditions */
|
|
if (status == -1) {
|
|
return RECEIVE_ERROR;
|
|
}
|
|
if (status != sizeof(struct rply_buff_struct)) {
|
|
return INSUFFICIENT_DATA;
|
|
}
|
|
if (ntohl(pReply->bigend) != 0x12345678) {
|
|
return BYTE_ORDER_CHAOS;
|
|
}
|
|
if ((iRet = ntohl(pReply->status)) != KER__SUCCESS) {
|
|
return SOFTWARE_ERROR;
|
|
}
|
|
|
|
/* success */
|
|
return 1;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
pSINQHM CreateSINQHM(char *pHMComputer, int iMasterPort)
|
|
{
|
|
pSINQHM pNew = NULL;
|
|
|
|
/* new memory */
|
|
pNew = (pSINQHM) malloc(sizeof(SINQHM));
|
|
if (!pNew) {
|
|
return NULL;
|
|
}
|
|
memset(pNew, 0, sizeof(SINQHM));
|
|
|
|
pNew->pHMComputer = strdup(pHMComputer);
|
|
pNew->iMasterPort = iMasterPort;
|
|
|
|
return pNew;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
pSINQHM CopySINQHM(pSINQHM self)
|
|
{
|
|
pSINQHM pNew = NULL;
|
|
|
|
assert(self);
|
|
|
|
pNew = CreateSINQHM(self->pHMComputer, self->iMasterPort);
|
|
if (!pNew) {
|
|
return NULL;
|
|
}
|
|
pNew->iBinWidth = self->iBinWidth;
|
|
pNew->iPacket = self->iPacket;
|
|
pNew->iRank = self->iRank;
|
|
pNew->iLength = self->iLength;
|
|
return pNew;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
void SINQHMSetPar(pSINQHM self, int iRank, int iLength, int iBin)
|
|
{
|
|
assert(self);
|
|
|
|
self->iRank = iRank;
|
|
self->iLength = iLength;
|
|
self->iBinWidth = iBin;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
void DeleteSINQHM(pSINQHM self)
|
|
{
|
|
int i;
|
|
|
|
assert(self);
|
|
|
|
if (self->pHMComputer) {
|
|
free(self->pHMComputer);
|
|
}
|
|
|
|
for (i = 0; i < self->iBanks; i++) {
|
|
if (self->pBank[i].iEdges) {
|
|
free(self->pBank[i].iEdges);
|
|
}
|
|
}
|
|
|
|
/* make sure a possible clients connection gets murdered */
|
|
if (self->iClientSocket) {
|
|
SINQHMCloseDAQ(self);
|
|
}
|
|
free(self);
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
int SINQHMConfigure(pSINQHM self, int iMode, int iRank, int iLength,
|
|
int iBinWidth, int iLowBin, int iCompress)
|
|
{
|
|
int status, iRet;
|
|
struct req_buff_struct Req_buff;
|
|
struct rply_buff_struct Rply_buff;
|
|
|
|
assert(self);
|
|
|
|
/* branch specially for TOF flight mode */
|
|
if ((iMode >= SQHM__TOF) && (iMode < SQHM__HM_PSD)) {
|
|
self->iBinWidth = iBinWidth;
|
|
return SINQHMTimeBin(self, iMode);
|
|
}
|
|
|
|
/* fill in the request data structure */
|
|
Req_buff.bigend = htonl(0x12345678);
|
|
Req_buff.cmnd = htonl(SQHM_CONFIG);
|
|
Req_buff.u.cnfg.mode = htonl(iMode);
|
|
Req_buff.u.cnfg.u.hm_dig.n_hists = htonl(iRank);
|
|
printf("%d\n", ntohl(Req_buff.u.cnfg.u.hm_dig.n_hists));
|
|
Req_buff.u.cnfg.u.hm_dig.lo_bin = htonl(iLowBin);
|
|
Req_buff.u.cnfg.u.hm_dig.num_bins = htonl(iLength);
|
|
Req_buff.u.cnfg.u.hm_dig.bytes_per_bin = htonl(iBinWidth);
|
|
Req_buff.u.cnfg.u.hm_dig.compress = htonl(iCompress);
|
|
|
|
/* try, get a connection to master server */
|
|
status = OpenMasterConnection(self);
|
|
if (status < 0) {
|
|
return status;
|
|
}
|
|
|
|
/* send request */
|
|
status =
|
|
send(self->iMasterSocket, (char *) &Req_buff, sizeof(Req_buff), 0);
|
|
if (status == -1) {
|
|
return SEND_ERROR;
|
|
}
|
|
|
|
/* get a reply */
|
|
iRet = GetMasterReply(self, &Rply_buff, sizeof(Rply_buff));
|
|
if (iRet < 0) {
|
|
/* try close the socket */
|
|
close(self->iMasterSocket);
|
|
self->iMasterSocket = 0;
|
|
return iRet;
|
|
} else {
|
|
/* configure successful, keep the data */
|
|
self->iBinWidth = iBinWidth;
|
|
self->iLength = iLength;
|
|
self->iRank = iRank;
|
|
|
|
/* close the socket */
|
|
status = close(self->iMasterSocket);
|
|
self->iMasterSocket = 0;
|
|
if ((status != 0) && (errno != ECONNRESET)) {
|
|
return CLOSE_ERROR;
|
|
}
|
|
}
|
|
return 1; /* success, finally */
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
int SINQHMConfigurePSD(pSINQHM self, int iMode,
|
|
int xSize, int xOff, int xFac,
|
|
int ySize, int yOff, int yFac,
|
|
int iBinWidth, float *iEdges, int iEdgeLength)
|
|
{
|
|
int status, iRet;
|
|
struct req_buff_struct Req_buff;
|
|
struct rply_buff_struct Rply_buff;
|
|
int iLength, i, iDelay;
|
|
unsigned int iExtra;
|
|
char *pBuffer = NULL, *pPtr;
|
|
struct tof_edge_arr tea;
|
|
int iTeaLength;
|
|
struct tof_bank toba;
|
|
|
|
assert(self);
|
|
|
|
/* set up detector bank information. This code supports only
|
|
one detector bank as of now. Which is appropriate for the
|
|
detector at hand.
|
|
*/
|
|
self->iBinWidth = iBinWidth;
|
|
SINQHMDefineBank(self, 0, 0, xSize * ySize, iEdges, iEdgeLength);
|
|
|
|
/* figure out how long we are going to be */
|
|
iLength = 36 + self->iBanks * sizeof(struct tof_bank);
|
|
for (i = 0; i < self->iBanks; i++) {
|
|
iLength += 8 + self->pBank[i].iEdgeLength * sizeof(SQint32);
|
|
}
|
|
if (iLength < 64)
|
|
iLength = 64;
|
|
/* allocate send buffer */
|
|
pBuffer = (char *) malloc(iLength * sizeof(char));
|
|
if (!pBuffer) {
|
|
return HIST_BAD_ALLOC;
|
|
}
|
|
memset(pBuffer, 0, iLength);
|
|
|
|
/* do the message header */
|
|
iExtra = iLength - sizeof(Req_buff);
|
|
if (iExtra < 0)
|
|
iExtra = 0;
|
|
iDelay = self->pBank[0].iEdges[0];
|
|
Req_buff.bigend = htonl(0x12345678);
|
|
Req_buff.cmnd = htonl(SQHM_CONFIG);
|
|
Req_buff.u.cnfg.mode = htonl(iMode);
|
|
Req_buff.u.cnfg.u.psd.n_extra_bytes = htonl(iExtra);
|
|
Req_buff.u.cnfg.u.psd.n_edges = htons(1);
|
|
Req_buff.u.cnfg.u.psd.n_banks = htons(1);
|
|
Req_buff.u.cnfg.u.psd.xOffset = htons(xOff);
|
|
Req_buff.u.cnfg.u.psd.yOffset = htons(yOff);
|
|
Req_buff.u.cnfg.u.psd.xFactor = htons(xFac);
|
|
Req_buff.u.cnfg.u.psd.yFactor = htons(yFac);
|
|
Req_buff.u.cnfg.u.psd.xSize = htons(xSize);
|
|
Req_buff.u.cnfg.u.psd.ySize = htons(ySize);
|
|
Req_buff.u.cnfg.u.psd.preset_delay = htonl((int) iEdges[0]);
|
|
memcpy(pBuffer, &Req_buff, 36);
|
|
pPtr = pBuffer + 36;
|
|
|
|
/* do the edge thingies */
|
|
for (i = 0; i < self->iBanks; i++) {
|
|
tea.n_bins = htonl(self->pBank[i].iEdgeLength - 1);
|
|
if (self->pBank[i].iEdgeLength == 2) {
|
|
tea.flag = htonl(0);
|
|
} else {
|
|
tea.flag = htonl(1);
|
|
}
|
|
tea.edges = self->pBank[i].iEdges;
|
|
memcpy(pPtr, &tea, 8);
|
|
pPtr += 8;
|
|
iTeaLength = self->pBank[i].iEdgeLength * 4;
|
|
memcpy(pPtr, self->pBank[i].iEdges, iTeaLength);
|
|
pPtr += iTeaLength;
|
|
}
|
|
|
|
/* do the swiss bank structures */
|
|
for (i = 0; i < self->iBanks; i++) {
|
|
toba.first = htons(self->pBank[i].iStart);
|
|
toba.n_cntrs = htons(self->pBank[i].iEnd);
|
|
toba.edge_indx = htons(i);
|
|
toba.bytes_per_bin = htons(self->iBinWidth);
|
|
memcpy(pPtr, &toba, sizeof(struct tof_bank));
|
|
pPtr += sizeof(struct tof_bank);
|
|
}
|
|
|
|
/* all packed up neat and nicely, send it */
|
|
/* try, get a connection to master server */
|
|
status = OpenMasterConnection(self);
|
|
if (status < 0) {
|
|
if (pBuffer)
|
|
free(pBuffer);
|
|
return status;
|
|
}
|
|
|
|
/* send request */
|
|
status = send(self->iMasterSocket, pBuffer, iLength, 0);
|
|
if (pBuffer) {
|
|
free(pBuffer);
|
|
}
|
|
if (status == -1) {
|
|
return SEND_ERROR;
|
|
}
|
|
|
|
/* get a reply */
|
|
iRet = GetMasterReply(self, &Rply_buff, sizeof(Rply_buff));
|
|
if (iRet < 0) {
|
|
/* try close the socket */
|
|
close(self->iMasterSocket);
|
|
self->iMasterSocket = 0;
|
|
return iRet;
|
|
} else {
|
|
/* close the socket */
|
|
status = close(self->iMasterSocket);
|
|
self->iMasterSocket = 0;
|
|
if ((status != 0) && (errno != ECONNRESET)) {
|
|
return CLOSE_ERROR;
|
|
}
|
|
}
|
|
return 1; /* success, finally */
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
int SINQHMDeconfigure(pSINQHM self, int iHarsh)
|
|
{
|
|
int status, iRet;
|
|
struct req_buff_struct Req_buff;
|
|
struct rply_buff_struct Rply_buff;
|
|
|
|
assert(self);
|
|
if ((iHarsh != 0) && (iHarsh != 1)) {
|
|
return INVALID_HARSH;
|
|
}
|
|
memset(&Req_buff, 0, sizeof(struct req_buff_struct));
|
|
memset(&Rply_buff, 0, sizeof(struct rply_buff_struct));
|
|
|
|
/* fill in the request data structure */
|
|
Req_buff.bigend = htonl(0x12345678);
|
|
Req_buff.cmnd = htonl(SQHM_DECONFIG);
|
|
Req_buff.u.decnfg.sub_code = htonl(iHarsh);
|
|
|
|
/* try, get a connection to master server */
|
|
status = OpenMasterConnection(self);
|
|
if (status < 0) {
|
|
return status;
|
|
}
|
|
|
|
/* send request */
|
|
status =
|
|
send(self->iMasterSocket, (char *) &Req_buff, sizeof(Req_buff), 0);
|
|
if (status == -1) {
|
|
return SEND_ERROR;
|
|
}
|
|
|
|
/* get a reply */
|
|
iRet = GetMasterReply(self, &Rply_buff, sizeof(Rply_buff));
|
|
if (iRet < 0) {
|
|
close(self->iMasterSocket);
|
|
self->iMasterSocket = 0;
|
|
return iRet;
|
|
} else {
|
|
status = close(self->iMasterSocket);
|
|
self->iMasterSocket = 0;
|
|
if ((status != 0) && (errno != ECONNRESET)) {
|
|
return CLOSE_ERROR;
|
|
}
|
|
}
|
|
return 1; /* success, finally */
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
int SINQHMGetStatus(pSINQHM self, int *iMode, int *iDaq,
|
|
int *iRank, int *iBinWidth,
|
|
int *iLength, int *iClients)
|
|
{
|
|
int status, iRet;
|
|
short sDaq, sFill;
|
|
struct req_buff_struct Req_buff;
|
|
struct rply_buff_struct Rply_buff;
|
|
|
|
assert(self);
|
|
|
|
|
|
status = 0;
|
|
if (self->iClientSocket) {
|
|
status = SendDAQStatus(self, &Rply_buff);
|
|
} else {
|
|
/* fill in the request data structure */
|
|
Req_buff.bigend = htonl(0x12345678);
|
|
Req_buff.cmnd = htonl(SQHM_STATUS);
|
|
|
|
/* try, get a connection to master server */
|
|
status = OpenMasterConnection(self);
|
|
if (status < 0) {
|
|
return status;
|
|
}
|
|
|
|
/* send request */
|
|
status =
|
|
send(self->iMasterSocket, (char *) &Req_buff, sizeof(Req_buff), 0);
|
|
if (status == -1) {
|
|
return SEND_ERROR;
|
|
}
|
|
|
|
/* get a reply */
|
|
iRet = GetMasterReply(self, &Rply_buff, sizeof(Rply_buff));
|
|
if (iRet < 0) {
|
|
close(self->iMasterSocket);
|
|
self->iMasterSocket = 0;
|
|
return iRet;
|
|
} else {
|
|
status = 1;
|
|
/* close the socket and go */
|
|
iRet = close(self->iMasterSocket);
|
|
self->iMasterSocket = 0;
|
|
if ((iRet != 0) && (errno != ECONNRESET)) {
|
|
return CLOSE_ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (status) {
|
|
/* transfer results */
|
|
*iMode = ntohl(Rply_buff.u.status.cfg_state);
|
|
if ((sDaq = ntohs(Rply_buff.u.status.daq_now)) == 0) { /* DAQ active */
|
|
*iDaq = 1;
|
|
} else {
|
|
sFill = ntohs(Rply_buff.u.status.filler_mask);
|
|
if (sFill & sDaq) {
|
|
/* filler is not running */
|
|
*iDaq = 0;
|
|
} else {
|
|
/* inhibited by some mean client */
|
|
*iDaq = 2;
|
|
}
|
|
}
|
|
*iRank = ntohs(Rply_buff.u.status.n_hists);
|
|
*iLength = ntohl(Rply_buff.u.status.num_bins);
|
|
*iBinWidth = Rply_buff.u.status.bytes_per_bin;
|
|
*iClients = Rply_buff.u.status.act_srvrs;
|
|
}
|
|
return 1; /* success, finally */
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
int SINQHMDebug(pSINQHM self, int iLevel)
|
|
{
|
|
int status, iRet;
|
|
struct req_buff_struct Req_buff;
|
|
struct rply_buff_struct Rply_buff;
|
|
|
|
assert(self);
|
|
|
|
/* fill in the request data structure */
|
|
Req_buff.bigend = htonl(0x12345678);
|
|
Req_buff.cmnd = htonl(SQHM_DBG);
|
|
Req_buff.u.dbg.mask = htonl(iLevel);
|
|
|
|
/* try, get a connection to master server */
|
|
status = OpenMasterConnection(self);
|
|
if (status < 0) {
|
|
return status;
|
|
}
|
|
|
|
/* send request */
|
|
status =
|
|
send(self->iMasterSocket, (char *) &Req_buff, sizeof(Req_buff), 0);
|
|
if (status == -1) {
|
|
return SEND_ERROR;
|
|
}
|
|
|
|
/* get a reply */
|
|
iRet = GetMasterReply(self, &Rply_buff, sizeof(Rply_buff));
|
|
if (iRet < 0) {
|
|
close(self->iMasterSocket);
|
|
self->iMasterSocket = 0;
|
|
return iRet;
|
|
} else {
|
|
status = close(self->iMasterSocket);
|
|
self->iMasterSocket = 0;
|
|
if ((status != 0) && (errno != ECONNRESET)) {
|
|
return CLOSE_ERROR;
|
|
}
|
|
}
|
|
return 1; /* success, finally */
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
int SINQHMKill(pSINQHM self)
|
|
{
|
|
int status, iRet;
|
|
struct req_buff_struct Req_buff;
|
|
struct rply_buff_struct Rply_buff;
|
|
|
|
assert(self);
|
|
|
|
/* fill in the request data structure */
|
|
Req_buff.bigend = htonl(0x12345678);
|
|
Req_buff.cmnd = htonl(SQHM_EXIT);
|
|
|
|
/* try, get a connection to master server */
|
|
status = OpenMasterConnection(self);
|
|
if (status < 0) {
|
|
return status;
|
|
}
|
|
|
|
/* send request */
|
|
status =
|
|
send(self->iMasterSocket, (char *) &Req_buff, sizeof(Req_buff), 0);
|
|
if (status == -1) {
|
|
return SEND_ERROR;
|
|
}
|
|
|
|
/* get a reply */
|
|
iRet = GetMasterReply(self, &Rply_buff, sizeof(Rply_buff));
|
|
if (iRet < 0) {
|
|
close(self->iMasterSocket);
|
|
self->iMasterSocket = 0;
|
|
return iRet;
|
|
} else {
|
|
status = close(self->iMasterSocket);
|
|
self->iMasterSocket = 0;
|
|
if ((status != 0) && (errno != ECONNRESET)) {
|
|
return CLOSE_ERROR;
|
|
}
|
|
}
|
|
return 1; /* success, finally */
|
|
}
|
|
|
|
/*====================== DAQ functions ==================================*/
|
|
int SINQHMOpenDAQ(pSINQHM self)
|
|
{
|
|
int status, iRet, iPacket;
|
|
struct sockaddr_in lcl_sockname;
|
|
struct sockaddr_in rmt_sockname;
|
|
struct hostent *rmt_hostent;
|
|
struct in_addr *rmt_inet_addr_pntr;
|
|
struct req_buff_struct Req_buff;
|
|
struct rply_buff_struct Rply_buff;
|
|
|
|
assert(self);
|
|
|
|
memset(&Req_buff, 0, sizeof(struct req_buff_struct));
|
|
memset(&Rply_buff, 0, sizeof(struct rply_buff_struct));
|
|
|
|
/* fill in the request data structure */
|
|
Req_buff.bigend = htonl(0x12345678);
|
|
Req_buff.cmnd = htonl(SQHM_CNCT);
|
|
Req_buff.u.cnct.max_pkt = htonl(8192);
|
|
Req_buff.u.cnct.strt_mode = htonl(0);
|
|
|
|
|
|
/* try, get a connection to master server */
|
|
status = OpenMasterConnection(self);
|
|
if (status < 0) {
|
|
return status;
|
|
}
|
|
|
|
/* send request */
|
|
status =
|
|
send(self->iMasterSocket, (char *) &Req_buff, sizeof(Req_buff), 0);
|
|
if (status == -1) {
|
|
return SEND_ERROR;
|
|
}
|
|
|
|
/* get a reply */
|
|
iRet = GetMasterReply(self, &Rply_buff, sizeof(Rply_buff));
|
|
status = close(self->iMasterSocket);
|
|
self->iMasterSocket = 0;
|
|
if (iRet < 0) {
|
|
return iRet;
|
|
}
|
|
if (status != 0) {
|
|
return CLOSE_ERROR;
|
|
}
|
|
|
|
/* read the port and packet size to use */
|
|
self->iClientPort = ntohl(Rply_buff.u.cnct.port);
|
|
iPacket = ntohl(Rply_buff.u.cnct.pkt_size);
|
|
self->iPacket = iPacket;
|
|
|
|
/* now we are ready to open the connection to our very own histogram
|
|
memory slave server
|
|
*/
|
|
|
|
/* first a socket */
|
|
self->iClientSocket = socket(AF_INET, SOCK_STREAM, 0);
|
|
if (self->iClientSocket == -1) {
|
|
return SOCKET_ERROR;
|
|
}
|
|
|
|
/* now try a bind */
|
|
lcl_sockname.sin_family = AF_INET;
|
|
lcl_sockname.sin_port = htons(0);
|
|
lcl_sockname.sin_addr.s_addr = 0;
|
|
status = bind(self->iClientSocket, (struct sockaddr *) &lcl_sockname,
|
|
sizeof(lcl_sockname));
|
|
if (status == -1) {
|
|
self->iClientSocket = 0;
|
|
return BIND_ERROR;
|
|
}
|
|
|
|
/* get hostname (again). This is double work (has happened in
|
|
OpenMasterConnection before) but I decided for this in order to
|
|
avoid carrying that extra adress pointer needed for connect around.
|
|
*/
|
|
rmt_hostent = gethostbyname(self->pHMComputer);
|
|
if (rmt_hostent == NULL) {
|
|
/* this should never happen, as we got it recently in
|
|
OpenMasterConnection
|
|
*/
|
|
return HMCOMPUTER_NOT_FOUND;
|
|
}
|
|
rmt_inet_addr_pntr = (struct in_addr *) rmt_hostent->h_addr_list[0];
|
|
|
|
/* and connect */
|
|
rmt_sockname.sin_family = AF_INET;
|
|
rmt_sockname.sin_port = htons(self->iClientPort);
|
|
rmt_sockname.sin_addr.s_addr = rmt_inet_addr_pntr->s_addr;
|
|
status = connect(self->iClientSocket, (struct sockaddr *) &rmt_sockname,
|
|
sizeof(rmt_sockname));
|
|
if (status == -1) {
|
|
self->iClientSocket = 0;
|
|
return CONNECT_ERROR;
|
|
}
|
|
|
|
/* done! Surprise! Everything worked! */
|
|
return 1;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
int SINQHMCloseDAQ(pSINQHM self)
|
|
{
|
|
struct req_buff_struct Req_buff;
|
|
int status, iRet;
|
|
|
|
assert(self);
|
|
if (self->iClientSocket <= 0) {
|
|
/* already colsed */
|
|
return 1;
|
|
}
|
|
|
|
iRet = 1;
|
|
memset(&Req_buff, 0, sizeof(struct req_buff_struct));
|
|
|
|
|
|
/* send close message, this helps the master to clean up */
|
|
Req_buff.bigend = htonl(0x12345678);
|
|
Req_buff.cmnd = htonl(SQHM_CLOSE);
|
|
status =
|
|
send(self->iClientSocket, (char *) &Req_buff, sizeof(Req_buff), 0);
|
|
if (status == -1) {
|
|
iRet = SEND_ERROR;
|
|
}
|
|
if (status != sizeof(Req_buff)) {
|
|
iRet = SEND_ERROR;
|
|
}
|
|
status = close(self->iClientSocket);
|
|
if (status != 0) {
|
|
iRet = CLOSE_ERROR;
|
|
}
|
|
self->iClientSocket = 0;
|
|
self->iClientPort = 0;
|
|
return iRet;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
int SINQHMStartDAQ(pSINQHM self)
|
|
{
|
|
int status, iDaq;
|
|
|
|
assert(self);
|
|
|
|
status = SendDAQCommand(self, DAQ__GO, &iDaq);
|
|
if (status < 0) { /* error */
|
|
return status;
|
|
}
|
|
if (iDaq != 0) {
|
|
return DAQ_INHIBIT;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
int SINQHMStopDAQ(pSINQHM self)
|
|
{
|
|
int status, iDaq;
|
|
|
|
assert(self);
|
|
|
|
status = SendDAQCommand(self, DAQ__STOP, &iDaq);
|
|
if (status < 0) { /* error */
|
|
return status;
|
|
}
|
|
if (iDaq == 0) {
|
|
return DAQ_NOTSTOPPED;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
int SINQHMContinueDAQ(pSINQHM self)
|
|
{
|
|
int status, iDaq;
|
|
|
|
assert(self);
|
|
|
|
status = SendDAQCommand(self, DAQ__CLR, &iDaq);
|
|
if (status < 0) { /* error */
|
|
return status;
|
|
}
|
|
if (iDaq != 0) {
|
|
return DAQ_INHIBIT;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
int SINQHMInhibitDAQ(pSINQHM self)
|
|
{
|
|
int status, iDaq;
|
|
|
|
assert(self);
|
|
|
|
status = SendDAQCommand(self, DAQ__INH, &iDaq);
|
|
if (status < 0) { /* error */
|
|
return status;
|
|
}
|
|
if (iDaq == 0) {
|
|
return DAQ_NOTSTOPPED;
|
|
}
|
|
return 1;
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
int SINQHMWrite(pSINQHM self, int iNum, int iStart, int iEnd, void *pData)
|
|
{
|
|
long lBytes2Go, lBins, i;
|
|
int status, iRet;
|
|
struct req_buff_struct Req_buff;
|
|
struct rply_buff_struct Rply_buff;
|
|
SQint16 *p16;
|
|
SQint32 *p32;
|
|
char *pPtr;
|
|
|
|
assert(self);
|
|
|
|
/* calculate number of bins */
|
|
lBins = iEnd;
|
|
|
|
/* take care of byte order first */
|
|
if (0x12345678 != ntohl(0x12345678)) {
|
|
/* Swap bytes, if necessary */
|
|
switch (self->iBinWidth) {
|
|
case 1:
|
|
break;
|
|
case 2:
|
|
p16 = (SQint16 *) pData;
|
|
for (i = 0; i < lBins; i++) {
|
|
p16[i] = htons(p16[i]);
|
|
}
|
|
break;
|
|
case 4:
|
|
p32 = (SQint32 *) pData;
|
|
for (i = 0; i < lBins; i++) {
|
|
p32[i] = htonl(p32[i]);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* initialize the Request data */
|
|
Req_buff.bigend = htonl(0x12345678);
|
|
Req_buff.cmnd = htonl(SQHM_WRITE);
|
|
Req_buff.u.write.n_bins = htonl(lBins);
|
|
Req_buff.u.write.first_bin = htonl(iStart);
|
|
Req_buff.u.write.bytes_per_bin = htonl(self->iBinWidth);
|
|
Req_buff.u.write.hist_no = htonl(iNum);
|
|
|
|
/* send the message */
|
|
status =
|
|
send(self->iClientSocket, (char *) &Req_buff, sizeof(Req_buff), 0);
|
|
if (status == -1) {
|
|
return SEND_ERROR;
|
|
}
|
|
if (status != sizeof(Req_buff)) {
|
|
return SEND_ERROR;
|
|
}
|
|
|
|
/* send data */
|
|
lBytes2Go = lBins * self->iBinWidth;
|
|
pPtr = (char *) pData;
|
|
while (lBytes2Go > 0) {
|
|
i = (lBytes2Go > self->iPacket) ? self->iPacket : lBytes2Go;
|
|
status = send(self->iClientSocket, (char *) pPtr, i, 0);
|
|
if (status <= 0) {
|
|
return SEND_ERROR;
|
|
}
|
|
lBytes2Go -= status;
|
|
pPtr += status;
|
|
}
|
|
|
|
/* get status */
|
|
status = recv(self->iClientSocket, (char *) &Rply_buff,
|
|
sizeof(Rply_buff), MSG_WAITALL);
|
|
|
|
/* check various error conditions */
|
|
if (status == -1) {
|
|
return RECEIVE_ERROR;
|
|
}
|
|
if (status != sizeof(Rply_buff)) {
|
|
return INSUFFICIENT_DATA;
|
|
}
|
|
if (ntohl(Rply_buff.bigend) != 0x12345678) {
|
|
return BYTE_ORDER_CHAOS;
|
|
}
|
|
if ((iRet = ntohl(Rply_buff.status)) == KER__BAD_VALUE) {
|
|
return HIST_BAD_VALUE;
|
|
}
|
|
if (iRet != KER__SUCCESS) {
|
|
return HIST_BAD_CODE;
|
|
}
|
|
/* success */
|
|
return 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
int SINQHMRead(pSINQHM self, int iNum, int iStart, int iEnd,
|
|
void *pData, int iDataLen)
|
|
{
|
|
long lBins2Get, lSpace, iNoBins, i;
|
|
int status, iRet;
|
|
struct req_buff_struct Req_buff;
|
|
struct rply_buff_struct Rply_buff;
|
|
SQint16 *p16;
|
|
SQint32 *p32;
|
|
char *pPtr;
|
|
char pBuffer[8192];
|
|
|
|
assert(self);
|
|
|
|
/* initialize the Request data */
|
|
Req_buff.bigend = htonl(0x12345678);
|
|
Req_buff.cmnd = htonl(SQHM_READ);
|
|
Req_buff.u.read.n_bins = htonl(iEnd - iStart);
|
|
Req_buff.u.read.first_bin = htonl(iStart);
|
|
Req_buff.u.read.hist_no = htonl(iNum);
|
|
|
|
/* send the message */
|
|
status = send(self->iClientSocket, (char *) &Req_buff,
|
|
sizeof(Req_buff), 0);
|
|
if (status == -1) {
|
|
return SEND_ERROR;
|
|
}
|
|
if (status != sizeof(Req_buff)) {
|
|
return SEND_ERROR;
|
|
}
|
|
|
|
/* wait for an answer */
|
|
status = recv(self->iClientSocket, (char *) &Rply_buff,
|
|
sizeof(Rply_buff), MSG_WAITALL);
|
|
|
|
/* check various error conditions */
|
|
if (status == -1) {
|
|
return RECEIVE_ERROR;
|
|
}
|
|
if (status != sizeof(Rply_buff)) {
|
|
return INSUFFICIENT_DATA;
|
|
}
|
|
if (ntohl(Rply_buff.bigend) != 0x12345678) {
|
|
return BYTE_ORDER_CHAOS;
|
|
}
|
|
iRet = ntohl(Rply_buff.status);
|
|
if (iRet != KER__SUCCESS) {
|
|
return HIST_BAD_CODE;
|
|
}
|
|
|
|
/* calculate the size of things to come */
|
|
lBins2Get =
|
|
ntohl(Rply_buff.u.read.n_bins) *
|
|
ntohl(Rply_buff.u.read.bytes_per_bin);
|
|
|
|
/* read data */
|
|
pPtr = (char *) pData;
|
|
lSpace = iDataLen;
|
|
iNoBins = ntohl(Rply_buff.u.read.n_bins);
|
|
while (lBins2Get > 0) {
|
|
if (lBins2Get > self->iPacket) {
|
|
i = self->iPacket;
|
|
} else {
|
|
i = lBins2Get;
|
|
}
|
|
status = recv(self->iClientSocket, pBuffer, i, 0);
|
|
if (status == -1) {
|
|
return SEND_ERROR;
|
|
}
|
|
lBins2Get -= status;
|
|
if ((lSpace - status) > 0) {
|
|
memcpy(pPtr, pBuffer, status);
|
|
lSpace -= status;
|
|
pPtr += status;
|
|
} else {
|
|
if (lSpace > 0) {
|
|
memcpy(pPtr, pBuffer, lSpace);
|
|
lSpace = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* swap bytes if necessary */
|
|
if ((self->iBinWidth > 0) && (Rply_buff.bigend != 0x12345678)) {
|
|
switch (self->iBinWidth) { /* Byte swapping is necessary */
|
|
case 2:
|
|
/* Not sure how to do this - this might be wrong! */
|
|
p16 = (SQint16 *) pData;
|
|
for (i = 0; i < iNoBins; i++) {
|
|
p16[i] = ntohs(p16[i]);
|
|
}
|
|
break;
|
|
case 4:
|
|
p32 = (SQint32 *) pData;
|
|
for (i = 0; i < iNoBins; i++) {
|
|
p32[i] = ntohl(p32[i]);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
/* done */
|
|
return 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
int SINQHMProject(pSINQHM self, int code, int xStart, int nx,
|
|
int yStart, int ny, void *pData, int iDataLen)
|
|
{
|
|
long lBins2Get, lSpace, iNoBins, i;
|
|
int status, iRet;
|
|
struct req_buff_struct Req_buff;
|
|
struct rply_buff_struct Rply_buff;
|
|
SQint16 *p16;
|
|
SQint32 *p32;
|
|
char *pPtr;
|
|
char pBuffer[8192];
|
|
|
|
assert(self);
|
|
|
|
/* initialize the Request data */
|
|
Req_buff.bigend = htonl(0x12345678);
|
|
Req_buff.cmnd = htonl(SQHM_PROJECT);
|
|
Req_buff.u.project.sub_code = htonl(code);
|
|
|
|
Req_buff.u.project.x_lo = htonl(xStart);
|
|
Req_buff.u.project.nx = htonl(nx);
|
|
Req_buff.u.project.y_lo = htonl(yStart);
|
|
Req_buff.u.project.ny = htonl(ny);
|
|
Req_buff.u.project.nhist = htonl(1);
|
|
|
|
/* send the message */
|
|
status = send(self->iClientSocket, (char *) &Req_buff,
|
|
sizeof(Req_buff), 0);
|
|
if (status == -1) {
|
|
return SEND_ERROR;
|
|
}
|
|
if (status != sizeof(Req_buff)) {
|
|
return SEND_ERROR;
|
|
}
|
|
|
|
/* wait for an answer */
|
|
status = recv(self->iClientSocket, (char *) &Rply_buff,
|
|
sizeof(Rply_buff), MSG_WAITALL);
|
|
|
|
/* check various error conditions */
|
|
if (status == -1) {
|
|
return RECEIVE_ERROR;
|
|
}
|
|
if (status != sizeof(Rply_buff)) {
|
|
return INSUFFICIENT_DATA;
|
|
}
|
|
if (ntohl(Rply_buff.bigend) != 0x12345678) {
|
|
return BYTE_ORDER_CHAOS;
|
|
}
|
|
iRet = ntohl(Rply_buff.status);
|
|
if (iRet != KER__SUCCESS) {
|
|
return HIST_BAD_CODE;
|
|
}
|
|
|
|
/* calculate the size of things to come */
|
|
lBins2Get = ntohl(Rply_buff.u.project.n_bins) *
|
|
ntohl(Rply_buff.u.project.bytes_per_bin);
|
|
|
|
/* read data */
|
|
pPtr = (char *) pData;
|
|
lSpace = iDataLen;
|
|
iNoBins = ntohl(Rply_buff.u.project.n_bins);
|
|
while (lBins2Get > 0) {
|
|
if (lBins2Get > self->iPacket) {
|
|
i = self->iPacket;
|
|
} else {
|
|
i = lBins2Get;
|
|
}
|
|
status = recv(self->iClientSocket, pBuffer, i, 0);
|
|
if (status == -1) {
|
|
return SEND_ERROR;
|
|
}
|
|
lBins2Get -= status;
|
|
if ((lSpace - status) > 0) {
|
|
memcpy(pPtr, pBuffer, status);
|
|
lSpace -= status;
|
|
pPtr += status;
|
|
} else {
|
|
if (lSpace > 0) {
|
|
memcpy(pPtr, pBuffer, lSpace);
|
|
lSpace = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* swap bytes if necessary */
|
|
iNoBins = iDataLen / self->iBinWidth;
|
|
if ((self->iBinWidth > 0) && (Rply_buff.bigend != 0x12345678)) {
|
|
switch (self->iBinWidth) { /* Byte swapping is necessary */
|
|
case 2:
|
|
/* Not sure how to do this - this might be wrong! */
|
|
p16 = (SQint16 *) pData;
|
|
for (i = 0; i < iNoBins; i++) {
|
|
p16[i] = ntohs(p16[i]);
|
|
}
|
|
break;
|
|
case 4:
|
|
p32 = (SQint32 *) pData;
|
|
for (i = 0; i < iNoBins; i++) {
|
|
p32[i] = ntohl(p32[i]);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
/* done */
|
|
return 1;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------
|
|
This is the old version, using a master socjet, delete if the other version
|
|
with client socket works alright.
|
|
*/
|
|
int SINQHMZero2(pSINQHM self, int iNumber, int iStart, int iEnd)
|
|
{
|
|
int status, iRet;
|
|
struct req_buff_struct Req_buff;
|
|
struct rply_buff_struct Rply_buff;
|
|
|
|
assert(self);
|
|
|
|
/* fill in the request data structure */
|
|
Req_buff.bigend = htonl(0x12345678);
|
|
Req_buff.cmnd = htonl(SQHM_ZERO);
|
|
Req_buff.u.zero.hist_no = htonl(iNumber);
|
|
Req_buff.u.zero.first_bin = htonl(iStart);
|
|
Req_buff.u.zero.n_bins = htonl(iEnd);
|
|
|
|
/* try, get a connection to master server */
|
|
status = OpenMasterConnection(self);
|
|
if (status < 0) {
|
|
return status;
|
|
}
|
|
|
|
/* send request */
|
|
status =
|
|
send(self->iMasterSocket, (char *) &Req_buff, sizeof(Req_buff), 0);
|
|
if (status == -1) {
|
|
return SEND_ERROR;
|
|
}
|
|
|
|
/* get a reply */
|
|
iRet = GetMasterReply(self, &Rply_buff, sizeof(Rply_buff));
|
|
if (iRet < 0) {
|
|
close(self->iMasterSocket);
|
|
self->iMasterSocket = 0;
|
|
return iRet;
|
|
} else {
|
|
status = close(self->iMasterSocket);
|
|
self->iMasterSocket = 0;
|
|
if ((status != 0) && (errno != ECONNRESET)) {
|
|
return CLOSE_ERROR;
|
|
}
|
|
}
|
|
return 1; /* success, finally */
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
int SINQHMZero(pSINQHM self, int iNumber, int iStart, int iEnd)
|
|
{
|
|
int status, iRet;
|
|
struct req_buff_struct Req_buff;
|
|
struct rply_buff_struct Rply_buff;
|
|
|
|
assert(self);
|
|
|
|
/* fill in the request data structure */
|
|
Req_buff.bigend = htonl(0x12345678);
|
|
Req_buff.cmnd = htonl(SQHM_ZERO);
|
|
Req_buff.u.zero.hist_no = htonl(iNumber);
|
|
Req_buff.u.zero.first_bin = htonl(iStart);
|
|
Req_buff.u.zero.n_bins = htonl(iEnd);
|
|
|
|
/* send request */
|
|
status =
|
|
send(self->iClientSocket, (char *) &Req_buff, sizeof(Req_buff), 0);
|
|
if (status == -1) {
|
|
return SEND_ERROR;
|
|
}
|
|
if (status != sizeof(Req_buff)) {
|
|
return SEND_ERROR;
|
|
}
|
|
|
|
/* get a reply */
|
|
iRet = recv(self->iClientSocket, (char *) &Rply_buff, sizeof(Rply_buff),
|
|
MSG_WAITALL);
|
|
if (iRet < 0) {
|
|
return RECEIVE_ERROR;
|
|
}
|
|
if (iRet != sizeof(Rply_buff)) {
|
|
return INSUFFICIENT_DATA;
|
|
}
|
|
if (ntohl(Rply_buff.bigend) != 0x12345678) {
|
|
return BYTE_ORDER_CHAOS;
|
|
}
|
|
iRet = ntohl(Rply_buff.status);
|
|
if (iRet != KER__SUCCESS) {
|
|
return HIST_BAD_CODE;
|
|
}
|
|
return 1; /* success, finally */
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
static int OpenMasterConnection(pSINQHM self)
|
|
{
|
|
struct hostent *rmt_hostent;
|
|
struct sockaddr_in lcl_sockname;
|
|
int rmt_sockname_len;
|
|
struct sockaddr_in rmt_sockname;
|
|
struct in_addr *rmt_inet_addr_pntr;
|
|
int status;
|
|
|
|
|
|
/* get hostname */
|
|
rmt_hostent = gethostbyname(self->pHMComputer);
|
|
if (rmt_hostent == NULL) {
|
|
return HMCOMPUTER_NOT_FOUND;
|
|
}
|
|
rmt_inet_addr_pntr = (struct in_addr *) rmt_hostent->h_addr_list[0];
|
|
|
|
|
|
/* try, open socket */
|
|
self->iMasterSocket = socket(AF_INET, SOCK_STREAM, 0);
|
|
if (self->iMasterSocket == -1) {
|
|
return SOCKET_ERROR;
|
|
}
|
|
|
|
/* bind it */
|
|
lcl_sockname.sin_family = AF_INET;
|
|
lcl_sockname.sin_port = htons(0);
|
|
lcl_sockname.sin_addr.s_addr = 0;
|
|
status = bind(self->iMasterSocket, (struct sockaddr *) &lcl_sockname,
|
|
sizeof(lcl_sockname));
|
|
if (status == -1) {
|
|
return BIND_ERROR;
|
|
}
|
|
|
|
/* try to connect */
|
|
rmt_sockname_len = sizeof(rmt_sockname);
|
|
rmt_sockname.sin_family = AF_INET;
|
|
rmt_sockname.sin_port = htons(self->iMasterPort);
|
|
rmt_sockname.sin_addr.s_addr = rmt_inet_addr_pntr->s_addr;
|
|
status = connect(self->iMasterSocket, (struct sockaddr *) &rmt_sockname,
|
|
sizeof(rmt_sockname));
|
|
if (status == -1) {
|
|
return CONNECT_ERROR;
|
|
}
|
|
|
|
/* Success */
|
|
return 1;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
static int GetMasterReply(pSINQHM self, struct rply_buff_struct *reply,
|
|
int iBufLen)
|
|
{
|
|
|
|
int status;
|
|
|
|
assert(self->iMasterSocket);
|
|
|
|
/* get reply structure */
|
|
status = recv(self->iMasterSocket, (char *) reply, iBufLen, MSG_WAITALL);
|
|
if (status == -1) {
|
|
return RECEIVE_ERROR;
|
|
} else if (status != iBufLen) {
|
|
return INSUFFICIENT_DATA;
|
|
}
|
|
|
|
/* check endedness */
|
|
if (ntohl(reply->bigend) != 0x12345678) {
|
|
return BYTE_ORDER_CHAOS;
|
|
}
|
|
|
|
/* check histogram memory status codes */
|
|
status = ntohl(reply->status);
|
|
if (status == KER__SUCCESS) {
|
|
return 1;
|
|
} else if (status == KER__BAD_CREATE) {
|
|
return HIST_BAD_CREATE;
|
|
} else if (status == KER__BAD_STATE) {
|
|
return HIST_BAD_STATE;
|
|
} else if (status == KER__BAD_VALUE) {
|
|
return HIST_BAD_VALUE;
|
|
} else if (status == KER__BAD_RECV) {
|
|
return HIST_BAD_RECV;
|
|
} else if (status == KER__BAD_ALLOC) {
|
|
return HIST_BAD_ALLOC;
|
|
} else {
|
|
return HIST_BAD_CODE;
|
|
}
|
|
/* not reached, usually */
|
|
return HIST_BAD_CODE;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
int SINQHMError2Text(int iErr, char *pBuffer, int iBufLen)
|
|
{
|
|
/* the trivial case */
|
|
if (iErr > 0) {
|
|
strncpy(pBuffer, "No error ocurred", iBufLen);
|
|
return 0;
|
|
}
|
|
|
|
switch (iErr) {
|
|
case HMCOMPUTER_NOT_FOUND:
|
|
strncpy(pBuffer,
|
|
"No name server entry for histogram memory computer", iBufLen);
|
|
break;
|
|
case SOCKET_ERROR:
|
|
strncpy(pBuffer,
|
|
"Insufficient system resources for socket creation", iBufLen);
|
|
break;
|
|
case BIND_ERROR:
|
|
strncpy(pBuffer, "Cannot bind", iBufLen);
|
|
break;
|
|
case CONNECT_ERROR:
|
|
strncpy(pBuffer,
|
|
"Cannot connect, probably port number wrong", iBufLen);
|
|
break;
|
|
case RECEIVE_ERROR:
|
|
strncpy(pBuffer, "Error receiving data", iBufLen);
|
|
break;
|
|
case INSUFFICIENT_DATA:
|
|
strncpy(pBuffer,
|
|
"Not enough bytes received from host, network trouble",
|
|
iBufLen);
|
|
break;
|
|
case BYTE_ORDER_CHAOS:
|
|
strncpy(pBuffer, "Reply not in network byte order", iBufLen);
|
|
break;
|
|
case HIST_BAD_CREATE:
|
|
strncpy(pBuffer,
|
|
"Master histogram server failed to spawn child", iBufLen);
|
|
break;
|
|
case HIST_BAD_VALUE:
|
|
strncpy(pBuffer, "Invalid parameter detected", iBufLen);
|
|
break;
|
|
case HIST_BAD_STATE:
|
|
strncpy(pBuffer, "Histogram memory NOT configured", iBufLen);
|
|
break;
|
|
case HIST_BAD_RECV:
|
|
strncpy(pBuffer, "Histogram server failed to read command", iBufLen);
|
|
break;
|
|
case HIST_BAD_ALLOC:
|
|
strncpy(pBuffer, "Histogram memory out of memory!", iBufLen);
|
|
break;
|
|
case HIST_BAD_CODE:
|
|
strncpy(pBuffer,
|
|
"Unknown or corrupted status code sent from master server",
|
|
iBufLen);
|
|
break;
|
|
case SEND_ERROR:
|
|
strncpy(pBuffer, "Error sending data", iBufLen);
|
|
break;
|
|
case CLOSE_ERROR:
|
|
strncpy(pBuffer, "Error closing connection", iBufLen);
|
|
break;
|
|
case INVALID_HARSH:
|
|
strncpy(pBuffer, "Invalid parameter for harshness", iBufLen);
|
|
break;
|
|
case SOFTWARE_ERROR:
|
|
strncpy(pBuffer,
|
|
"Internal error or software error at histogram memory computer, consult a hacker",
|
|
iBufLen);
|
|
break;
|
|
case DAQ_INHIBIT:
|
|
strncpy(pBuffer, "Data aquisition inhibited by some client", iBufLen);
|
|
break;
|
|
case DAQ_NOTSTOPPED:
|
|
strncpy(pBuffer,
|
|
"Data aquisition not stopped, suggests SW or network problem",
|
|
iBufLen);
|
|
break;
|
|
|
|
default:
|
|
strncpy(pBuffer, "Unknown error code", iBufLen);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
SINQHM needs an additional top bin defining the upper edge of the
|
|
histogram. So, for a 512 bin array, 513 bins are needed. The additional
|
|
bin is created in the code below. This explains the strange arithmetic with
|
|
EdgeLength and the code at the end of the for loop
|
|
*/
|
|
int SINQHMDefineBank(pSINQHM self, int iBankNumber, int iStart, int iEnd,
|
|
float *iEdges, int iEdgeLength)
|
|
{
|
|
pSBank pWork = NULL;
|
|
int i, iDelay, iDiff;
|
|
|
|
assert(self);
|
|
assert(iBankNumber >= 0);
|
|
assert(iBankNumber < MAXBANK);
|
|
assert(iEdgeLength >= 1);
|
|
assert(iStart >= 0);
|
|
assert(iEnd >= iStart);
|
|
|
|
if (iBankNumber >= self->iBanks) {
|
|
self->iBanks = iBankNumber + 1;
|
|
}
|
|
pWork = &(self->pBank[iBankNumber]);
|
|
if (pWork->iEdges != NULL) {
|
|
free(pWork->iEdges);
|
|
pWork->iEdges = NULL;
|
|
}
|
|
iDelay = (int) iEdges[0];
|
|
pWork->iStart = iStart;
|
|
pWork->iEnd = iEnd;
|
|
pWork->iEdgeLength = iEdgeLength;
|
|
if (iEdgeLength == 2) { /*
|
|
fixed binwidth: two values required: start stop in
|
|
edge[0], edge[1]
|
|
*/
|
|
pWork->iFlag = 0;
|
|
pWork->iDelay = iDelay;
|
|
pWork->iEdges = (unsigned int *) malloc(2 * sizeof(unsigned int));
|
|
if (!pWork->iEdges) {
|
|
return HIST_BAD_ALLOC;
|
|
}
|
|
pWork->iEdges[0] = htonl((unsigned int) iEdges[0]);
|
|
pWork->iEdges[1] = htonl((unsigned int) (iEdges[1] - iDelay));
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
normal case: create the bin boundaries
|
|
*/
|
|
pWork->iFlag = 1;
|
|
pWork->iEdgeLength++;
|
|
iEdgeLength++;
|
|
pWork->iEdges = (unsigned int *) malloc(iEdgeLength *
|
|
sizeof(unsigned int));
|
|
if (!pWork->iEdges) {
|
|
return HIST_BAD_ALLOC;
|
|
}
|
|
pWork->iDelay = iDelay;
|
|
for (i = 0; i < iEdgeLength - 1; i++) {
|
|
pWork->iEdges[i] = htonl((unsigned int) (iEdges[i] - iDelay));
|
|
}
|
|
iDiff = iEdges[1] - iEdges[0];
|
|
pWork->iEdges[iEdgeLength - 1] = htonl(iEdges[iEdgeLength - 2]
|
|
+ iDiff - iDelay);
|
|
return 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
struct tof {
|
|
uint n_extra_bytes;
|
|
usint n_edges;
|
|
usint n_banks;
|
|
uint preset_delay;
|
|
struct tof_edge_arr edge_0;
|
|
struct tof_bank bank_0;
|
|
};
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
int SINQHMTimeBin(pSINQHM self, int iMode)
|
|
{
|
|
int status, iRet;
|
|
struct req_buff_struct Req_buff;
|
|
struct rply_buff_struct Rply_buff;
|
|
int iLength, i, iDelay;
|
|
unsigned int iExtra;
|
|
char *pBuffer = NULL, *pPtr;
|
|
struct tof_edge_arr tea;
|
|
int iTeaLength;
|
|
struct tof_bank toba;
|
|
struct tof tofi;
|
|
|
|
assert(self);
|
|
|
|
memset(&Req_buff, 0, sizeof(struct req_buff_struct));
|
|
memset(&Rply_buff, 0, sizeof(struct rply_buff_struct));
|
|
|
|
/* figure out how long we are going to be */
|
|
iLength = 24 + self->iBanks * sizeof(struct tof_bank);
|
|
for (i = 0; i < self->iBanks; i++) {
|
|
iLength += 8 + self->pBank[i].iEdgeLength * sizeof(SQint32);
|
|
}
|
|
if (iLength < 64)
|
|
iLength = 64;
|
|
/* allocate send buffer */
|
|
pBuffer = (char *) malloc(iLength * sizeof(char));
|
|
if (!pBuffer) {
|
|
return HIST_BAD_ALLOC;
|
|
}
|
|
memset(pBuffer, 0, iLength);
|
|
|
|
/* do the message header */
|
|
iExtra = iLength - 64;
|
|
if (iExtra < 0)
|
|
iExtra = 0;
|
|
iDelay = self->pBank[0].iEdges[0];
|
|
Req_buff.bigend = htonl(0x12345678);
|
|
Req_buff.cmnd = htonl(SQHM_CONFIG);
|
|
Req_buff.u.cnfg.mode = htonl(iMode);
|
|
memcpy(pBuffer, &Req_buff, 12);
|
|
pPtr = pBuffer + 12;
|
|
|
|
tofi.n_extra_bytes = htonl(iExtra);
|
|
tofi.n_edges = htons(self->iBanks);
|
|
tofi.n_banks = htons(self->iBanks);
|
|
tofi.preset_delay = htonl(self->pBank[0].iDelay);
|
|
memcpy(pPtr, &tofi, 12);
|
|
pPtr += 12;
|
|
|
|
/* do the edge thingies */
|
|
for (i = 0; i < self->iBanks; i++) {
|
|
tea.n_bins = htonl(self->pBank[i].iEdgeLength - 1);
|
|
if (self->pBank[i].iEdgeLength == 2) {
|
|
tea.flag = htonl(0);
|
|
} else {
|
|
tea.flag = htonl(1);
|
|
}
|
|
tea.edges = self->pBank[i].iEdges;
|
|
memcpy(pPtr, &tea, 8);
|
|
pPtr += 8;
|
|
iTeaLength = self->pBank[i].iEdgeLength * 4;
|
|
memcpy(pPtr, self->pBank[i].iEdges, iTeaLength);
|
|
pPtr += iTeaLength;
|
|
}
|
|
|
|
/* do the swiss bank structures */
|
|
for (i = 0; i < self->iBanks; i++) {
|
|
toba.first = htons(self->pBank[i].iStart);
|
|
toba.n_cntrs = htons(self->pBank[i].iEnd);
|
|
toba.edge_indx = htons(i);
|
|
toba.bytes_per_bin = htons(self->iBinWidth);
|
|
memcpy(pPtr, &toba, sizeof(struct tof_bank));
|
|
pPtr += sizeof(struct tof_bank);
|
|
}
|
|
|
|
/* all packed up neat and nicely, send it */
|
|
/* try, get a connection to master server */
|
|
status = OpenMasterConnection(self);
|
|
if (status < 0) {
|
|
if (pBuffer)
|
|
free(pBuffer);
|
|
return status;
|
|
}
|
|
|
|
/* send request */
|
|
status = send(self->iMasterSocket, pBuffer, iLength, 0);
|
|
if (pBuffer) {
|
|
free(pBuffer);
|
|
}
|
|
if (status == -1) {
|
|
return SEND_ERROR;
|
|
}
|
|
|
|
/* get a reply */
|
|
iRet = GetMasterReply(self, &Rply_buff, sizeof(Rply_buff));
|
|
if (iRet < 0) {
|
|
/* try close the socket */
|
|
close(self->iMasterSocket);
|
|
self->iMasterSocket = 0;
|
|
return iRet;
|
|
} else {
|
|
/* close the socket */
|
|
status = close(self->iMasterSocket);
|
|
self->iMasterSocket = 0;
|
|
if ((status != 0) && (errno != ECONNRESET)) {
|
|
return CLOSE_ERROR;
|
|
}
|
|
}
|
|
return 1; /* success, finally */
|
|
}
|