/*-------------------------------------------------------------------------
			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 */
}
