#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <signal.h>
#include <sys/shm.h>
#include <assert.h>
#include "opt.h"
#include "dioctl.h"
#include "dioname.h"
#include "netdio.h"

extern int modelId;
int client_modelid=-1;
extern uint8 DioValue[256];

#ifdef CLIENT_ONLY
void generic_SetDioDir(int dionum,int asOutput) {
}

void generic_SetDio(int dionum,int asHigh) {
}

int generic_GetDioDir(int dionum) {  // 1 = is output
  return 0;
}

int generic_GetDio(int dionum) {    // 1 = reading high
  return 0;
}

void generic_CommitDio(int n) {
}

void generic_DioInit() {
  int i;

  SetDioDir = generic_SetDioDir;
  SetDio = generic_SetDio;
  GetDioDir = generic_GetDioDir;
  GetDio = generic_GetDio;
  CommitDio = generic_CommitDio;
}

void DioInit() {
  generic_DioInit();
}
#else
void ts4200_DioInit();
void ts4500_DioInit();
void ts75xx_DioInit();

int dio_generic[200];

void DioInit() {
  int boardid = ts_boardid();
  char buf[128];

  sprintf(buf,"/etc/dioctl/ts%X.dioctl.config",boardid);
  fprintf(stderr,"board id=%X, file=%s\n",boardid,buf);
  DIOConfigFileProcess(&DIOMapNamePin,buf);
	
  modelId = boardid;
  if (boardid == 0x4200) {
    ts4200_DioInit();
  } else if (boardid == 0x4500) {
    ts4500_DioInit();
  } else if (boardid == 0x7500 || boardid == 0x7550 || boardid == 0x7552 || boardid == 0x7553) {
    ts4500_DioInit();
  } else {
    fprintf(stderr,"boardid=%X\n",boardid);
    fprintf(stderr,"This binary only supports the following boards:\n");
    fprintf(stderr,"TS-4200, TS-4500, TS-7550, TS-7552, TS-7553\n");
    exit(3);
  }
}
#endif

// TO CONSIDER:
// map groups and DIOs into the same address space. for example,
// let DIOs 240-255 represent a whole group.  then we can uniformly
// operate on both groups and individual dios. the only problem
// with this is the expectation of how much data gets returned!
// OLD FUNCTIONS:

int opt_int(char *arg,int *target,int opt) {
  if (!arg) {
    *target = 4500;
  } else {
    *target = atoi(arg);
  }
  return 1;
}

char *parse_dec_octets(char *buf,int *n) {
  char *ret,*s;
  int i,len = strlen(buf),count=0;
  *n = 0;
  for (i=0;i<len;i++) {
    if (buf[i] == ':') {
      count++;
    }
  }
  ret = malloc(2+count);
  while (buf) {
    s = strchr(buf,':');
    if (s) {
      *s++ = 0;
    }
//    ret[n[0]] = strtoul(buf,0,10);
    ret[n[0]] = getDioNumFromNameOrNumber(buf);
    n[0]++;
    buf = s;
  }
  return ret;
}

/*
any time client changes, we need to call:
i = netBoardModelGet(client);
then we need to set up our DIO names somehow...

so this really means we can't call opt_cli, we need a wrapper for it!
all this wrapper needs to do is keep track of the model id of the server we are currently talking to

if we are NOT the server, we still need some initialization,
    specifically, of the data structure side of things.
    if (!opt_server) {
    }
*/
int opt_client = -1,diomapUpToDate=0;
FILE *client;

int getDioNumFromNameOrNumber(char *nameOrNumber) {
	int j = atoi(nameOrNumber);
	
	if (j != 0 || !strcmp(nameOrNumber,"0")) return j;
	if (!diomapUpToDate) {
		if (!netDIONamesList(client,&DIOMapNamePin)) {
			fprintf(stderr,"error getting dio map\n");
			exit(1);
		}
		diomapUpToDate = 1;
	}
        {
	      Map val,*got;
	      val.key = nameOrNumber;
	      got=MapFindBinary(DIOMapNamePin,val,MapCompareKey);
	      if (got) {
		      j = got->val;
	      } else {
		      j = -1;
	      }
        }
	return (j < 0) ? 0 : j;
}

/*

opt_cli2: mark current dio map as dirty
opt_dio_seq: whenever we call getDioNumFromNameOrNumber (perhaps move this function to dioctl.c) if we do not have a number and our current dio map is dirty, call dioctl_GetDioMap on the current server before continuing.
*/
int opt_cli2(char *arg,int *target,int opt) {
  int flag = 1;

  if (!opt_cli(arg,target,opt)) return 0;
  diomapUpToDate = 0;
  setsockopt(opt_client,IPPROTO_TCP,TCP_NODELAY,(char *)&flag,sizeof(int));
  client = fdopen(opt_client,"a+");
  if (!client) {
	fprintf(stderr,"fdopen:%m");
	exit(1);
  }
  client_modelid = netBoardModelGet(client);
  if (client_modelid < 0) {
	  fprintf(stderr,"error talking to server to establish model id\n");
	  return 0;
  }
  return 1;
}

int opt_dioseq(char *arg,unsigned *target,int opt) {
  int i,j;
  char *buf;
  struct diocaps *caps;
  void printDIOvalue(int index,int value) {
    printf("diodirG%d=%d\n",index,(value&2)?1:0);
    printf("diovalG%d=%d\n",index,(value&1)?1:0);
  }
  void printDIOvalue1(int index,int value) {
    printf("diovalG%d=%d\n",index,(value&1)?1:0);
  }

  if (opt_client < 0) {
    fprintf(stderr,"must specify port first!\n");
    return 0;
  }
  switch (opt) {
  case 'g':
    caps = netDIOCapabilitiesGet(client);
    if (!caps) {
      printf("server=0\n");
    } else {
      printf("server=1\n");
      printf("numdios=%d\n",caps->numdios);
      for (i=0;i<caps->numdios;i++) {
	printf("dioCanInput%d=%d\n",i,(caps->caps[i] & 1) != 0);
	printf("dioCanDriveHigh%d=%d\n",i,(caps->caps[i] & 2) == 2);
	printf("dioCanDriveLow%d=%d\n",i,(caps->caps[i] & 4) == 4);
      }
      free(caps);
    }
    break;
  case 'r':
    j = getDioNumFromNameOrNumber(arg);
    if (j >= 1000) {
      netDIOGroupGet(client,j-1000,printDIOvalue);
    } else {
      i = netDIOGet(client,j);
      if (i < 0) {
	printf("server=0\n");
      } else {
	printf("server=1\n");
	printf("diodir%d=%d\n",j,(i & 2)?1:0);
	printf("dioval%d=%d\n",j,(i & 1)?1:0);
      }
    }
    break;
  case '1':
    j = getDioNumFromNameOrNumber(arg);
    if (j >= 1000) {
      netDIOGroupSetAs(client,j-1000,1,1);
    } else {
      netDIOSet(client,j,1,1);
    }
    break;
  case '0':
    j = getDioNumFromNameOrNumber(arg);
    if (j >= 1000) {
      netDIOGroupSetAs(client,j-1000,1,0);
    } else {
      netDIOSet(client,j,1,0);
    }
    break;
  case 'i':
    j = getDioNumFromNameOrNumber(arg);
    if (j >= 1000) {
      netDIOGroupSetAs(client,j-1000,0,0);
    } else {
      netDIOSet(client,j,0,0);
    }
    break;
  case 'G': {
    int *dios;
    buf = parse_dec_octets(arg,&j);
    dios = malloc(sizeof(int) * j);
    for (i=0;i<j-1;i++) {
      dios[i] = buf[i+1];
    }
    netDIOGroupDefine(client,buf[0],j-1,dios);
    break;
  }
  case 'w': {
    int *vals;
    buf = parse_dec_octets(arg,&j);
    vals = malloc(sizeof(int) * j);
    for (i=0;i<j-1;i++) {
	vals[i] = buf[i+1];
    }
    netDIOGroupWaitOld(client,buf[0],j-1,vals,printDIOvalue1);
    break;
  }
  case 'W': {
    char *pos = strstr(arg,":");
    if (!pos) {
	fprintf(stderr,"invalid format for --Wait option\n");
    } else {
	*pos = 0; pos++;
	i = atoi(arg);
	j = atoi(pos);
	netDIOWait(client,i,j);
    }
    break;
  }
  case 'd': {
    int diomap[200];
	  
//    if (!arch_dio) arch_dio = diomap;
/*
    getDioNumFromNameOrNumber("dummy"); // force dio map up to date
    if (!netDIOConnectorList(client,diomap)) {
	printf("error getting connector map\n");
	exit(1);
    }
    printf("DIO number,DIO name,connector name\n");
*/
    printf("<<unimplemented>>\n");
//    DumpDioInfo();
    break;
  }
  case 'm':
    printf("modelid=%X\n",client_modelid);
    break;
  case 'l':
    j=netDIONameLookup(client,arg);
    if (j != -1 && j != 0x7FFFFFFF) printf("dionum=%d\n",j);
    break;
  case 'L': {
    char *pos = strstr(arg,":");
    if (!pos) {
      fprintf(stderr,"Lookup reqires <strmatch>:<value> format\n");
      break;
    }
    *pos = 0; pos++;
    j = atoi(pos);
    pos=netDIOLookup(client,arg,j);
    if (pos) {
      printf("dioname=%s\n",pos);
      free(pos);
    }
    break;
  }
  case 'D': {
    char *pos = strstr(arg,":");
    if (!pos) {
	fprintf(stderr,"invalid format for --Define option\n");
    } else {
      *pos = 0; pos++;
      j = atoi(pos);
      netDIONameAssign(client,j,arg);
    }
    break;
  }
  case 'U':
    netDIONameRemove(client,arg);
    break;
  }
  return 1;
}

int getBaseBoardId(int handle) {
  int dioAdrs0,dioAdrs1,dioAdrs2,dioInBit,extraBit;
  int adrs0,adrs1,adrs2,extra;
  int i,value=0,tmp;

  dioAdrs0 = dio_lookupCached(handle,"ts.socket.ADRS0");
  dioAdrs1 = dio_lookupCached(handle,"ts.socket.ADRS1");
  dioAdrs2 = dio_lookupCached(handle,"ts.socket.ADRS2");
  dioInBit = dio_lookupCached(handle,"ts.socket.IN");
  extraBit = dio_lookupCached(handle,"ts.socket.INLOOP");

  // save current values
  // imperfect: we save driven outputs by what they are reading back, not
  // what we are actually driving them to
  adrs0 = dio_getpinstate(handle,dioAdrs0) ? dio_getpin(handle,dioAdrs0) : DIO_HIGHZ;
  adrs1 = dio_getpinstate(handle,dioAdrs1) ? dio_getpin(handle,dioAdrs1) : DIO_HIGHZ;
  adrs2 = dio_getpinstate(handle,dioAdrs2) ? dio_getpin(handle,dioAdrs2) : DIO_HIGHZ;
  extra = dio_getpinstate(handle,extraBit) ? dio_getpin(handle,extraBit) : DIO_HIGHZ;

  dio_setpin(handle,dioInBit,DIO_HIGHZ);
  dio_setpin(handle,extraBit,DIO_HIGHZ);
  for (i=7;i>=0;i--) {
    dio_setpin(handle,dioAdrs0,i&1?0:1);
    dio_setpin(handle,dioAdrs1,i&2?0:1);
    dio_setpin(handle,dioAdrs2,i&4?1:0);
    /*
    tmp = dio_getpin(handle,dioAdrs0);
    if (tmp != (i&1?0:1)) printf("i=%d, adrs0 failure\n",i);
    tmp = dio_getpin(handle,dioAdrs1);
    if (tmp != (i&2?0:1)) printf("i=%d, adrs1 failure\n",i);
    tmp = dio_getpin(handle,dioAdrs2);
    if (tmp != (i&4?1:0)) printf("i=%d, adrs2 failure\n",i);
    */
    usleep(50000);
    value <<= 1;
    value |= dio_getpin(handle,dioInBit);
  }  // restore current values

  dio_setpin(handle,dioAdrs0,adrs0);
  dio_setpin(handle,dioAdrs1,adrs1);
  dio_setpin(handle,dioAdrs2,adrs2);
  dio_setpin(handle,extraBit,extra);
  return value;
}

int opt_config(char *arg,char **target,int opt) {
  char *fn = malloc(strlen(arg) + 32);
  sprintf(fn,"%s.dioctl.config",arg);
  DIOConfigFileProcess(&DIOMapNamePin,fn);
  free(fn);
  return 1;
}

 /*
 * This function records a PID so that ts7500ctl --loadfpga will send
 * a SIGHUP to the PID after FPGA reconfiguration.
 *
 * Predefined slots:
 *  0 - sdctl NBD service
 *  1 - nand NBD service
 *  2 - SPI flash NBD service
 *  3 - xuartctl --server service
 *  4 - canctl --server service
 *  5 - dmxctl --server service
 *  6 - spictl --server service
 *  7 - dioctl --server service
 *  8 - reserved
 *  >= 9 is invalid
 *
 * Before calling, application should setup or ignore the SIGHUP signal.
 * e.g. signal(SIGHUP, SIG_IGN);
 */
record_daemon_pid(int slot) {
  key_t shmkey;
  int shmid;
  unsigned int *sbus_shm;

  shmkey = 0x75000000;
  shmid = shmget(shmkey, 0x1000, IPC_CREAT);
  assert(shmid != -1);
  sbus_shm = shmat(shmid, NULL, 0);
  sbus_shm += (slot * 32);
  sbus_shm[0] = getpid();

  shmdt(sbus_shm);
  return 0;
}

int gotHUP = 0;

void do_hup() {
  gotHUP = 1;
}

extern int BusCyclesLog;

int main(int argc,char *argv[]) {
  int h,i,j,modelDIO[200];
  int opt_server = 0, opt_doseq, opt_test=0,opt_pollrate=10, opt_arch = 0;

  struct option2 opts[] = {
    { 0, (opt_func)opt_bool  ,&opt_arch    ,"<a>rch", "              display what arches this binary supports" },
    { 2, (opt_func)opt_int   ,&opt_server  ,"<s>erver", "<port>      Daemonize and run as server listening on port" },
    { 1, (opt_func)opt_int   ,&opt_pollrate,"p<o>ll", "rate          milliseconds between DIO polls (0 = never poll)" },
    { 1, (opt_func)opt_config,&opt_doseq   ,"<f>ile"  ,"board        read the config definitions for the specified board" },
    { 2, (opt_func)opt_cli2  ,&opt_client  ,"<p>ort", "<host><:port> Talk to dioctl server" },
    { 0, (opt_func)opt_dioseq,&opt_doseq   ,"<g>etcaps", "           Get DIO capabilities" },
    { 0, (opt_func)opt_dioseq,&opt_doseq   ,"<m>odel", "             Get model id of board" },
    { 1, (opt_func)opt_dioseq,&opt_doseq   ,"<l>ookup", "name        Get logical DIO number from DIO name" },
    { 1, (opt_func)opt_dioseq,&opt_doseq   ,"<L>ookup", "name:value  Get full DIO name from partial match and value" },
    { 1, (opt_func)opt_dioseq,&opt_doseq   ,"<D>efine", "name:DIOnum Associate new name with logical DIO number" },
    { 1, (opt_func)opt_dioseq,&opt_doseq   ,"<U>ndef", "name         De-Associate name with logical DIO number" },
    { 1, (opt_func)opt_dioseq,&opt_doseq   ,"<r>ead", "DIOnum        Read the state of the specified DIO" },
    { 1, (opt_func)opt_dioseq,&opt_doseq   ,"<1>", "DIOnum           set the specified DIO to output and drive high" },
    { 1, (opt_func)opt_dioseq,&opt_doseq   ,"<0>", "DIOnum           set the specified DIO to output and drive low" },
    { 1, (opt_func)opt_dioseq,&opt_doseq   ,"<i>nput", "DIOnum       set the specified DIO to an input" },
    { 1, (opt_func)opt_dioseq,&opt_doseq   ,"<G>roup", "num:val1...  set the specified DIO Group number to the list of DIOs" },
    { 1, (opt_func)opt_dioseq,&opt_doseq   ,"<w>ait", "num:val1...   wait for any DIO in the specified group number to be the given value" },
    { 1, (opt_func)opt_dioseq,&opt_doseq   ,"<W>ait", "num:val       wait for the specified DIO number to read as the given value" },
    { 0, (opt_func)opt_bool  ,&opt_test    ,"<t>est", "              test macro-controller with base board" },
    { 1, (opt_func)opt_int   ,&BusCyclesLog,"<B>us", "debuglevel     log bus cycle accesses to stderr" },
    { 0, (opt_func)opt_dioseq,&opt_doseq   ,"<d>ump", "              dump a table of the current server's DIO mappings" },
    { 0,0,0,"Technologic Systems DIO controller manipulation.\n\nGeneral options:\n",
      "To specify a DIO group where a DIO number is expected, add 1000 to the group number.\nOtherwise, DIOnum can be specified by an absolute DIO number, a DIO name, or\nthe connector name.\n"
    }
  };
  
  opt_cli_defaultport = 4500;
  process_options(argc,argv,opts);
  if (opt_arch) {
    printf("supported=0x4200\n");
    printf("supported=0x7550\n");
    printf("supported=0x7552\n");
    printf("supported=0x7553\n");
  }
  if (opt_test) {
    if (opt_client < 0) {
      fprintf(stderr,"Must specify port to run test on\n");
      return 1;
    }
    if (!client) {
      client = fdopen(opt_client,"a+");
      if (!client) {
	fprintf(stderr,"fdopen:%m");
	exit(1);
      }
    }
    i = netBoardModelGet(client);
    printf("modelid = %X\n",i);
    if (i != 0x4500 && i != 0x4200) {
	printf("I do not know how to test this board.\n");
	return 1;
    }
    h = dio_fdopen(opt_client);
    j = getBaseBoardId(h);
    switch (j) {
    case 0xF0:  j=0x9490; break;
    case 1:     j=0x8395; break;
    case 3:     j=0x8510; break; // IIRC
    case 0x00:
    case 0xFF:  j=0x8200; break;
    default:    
      printf("unknown baseboard code %X\n",j);
      return 1;
    }
    printf("baseboardid=%X\n",j);
    // forcing baseboardid=0x9490
    {
      char harness[32],*str,*name,fn[128];
      int maxconn,wires,*test,i,i2,n,dionum,conn,pin,val,passed=0,failed=0,grp;

      sprintf(harness,"%X",j);
      sprintf(fn,"/etc/dioctl/ts%s.dioctl.config",harness);
      dio_configfile(h,fn);
      str = malloc(60+strlen(harness));
      sprintf(str,"attrib.%s.Wire.MaxConnections",harness);
      maxconn = dio_lookupCached(h,str);
      sprintf(str,"attrib.%s.Wire.Count",harness);
      wires  = dio_lookupCached(h,str);
      test = malloc(sizeof(unsigned) * wires * maxconn);

      if (wires == 0x7FFFFFFF || maxconn == 0x7FFFFFFF) {
	fprintf(stderr,"config file error\n");
	return 1;
      }
      for (i=0;i<wires;i++) {
	for (j=0;j<maxconn;j++) {
	  sprintf(str,"attrib.%s.Wire.Connector.%d.%d",harness,i,j);
	  conn = dio_lookupCached(h,str);
	  if (conn == 0x7FFFFFFF) {
	    dionum = -1;
	  } else {
	    //fprintf(stderr,"%s->%d\n",str,conn);
	    sprintf(str,"attrib.%s.Wire.Pin.%d.%d",harness,i,j);
	    pin = dio_lookupCached(h,str);
	    //fprintf(stderr,"%s->%d\n",str,pin);
	    name = netDIOLookup(client,"attrib.Connector.Name.",conn);
	    //fprintf(stderr,"connector %d->%s\n",conn,name);
	    sprintf(str,"%s%d",name+22,pin);
	    dionum = dio_lookupCached(h,str);
	    if (dionum == 0x7FFFFFFF) dionum = -1;
	    //fprintf(stderr,"%s->%d\n",str,dionum);
	    //fprintf(stderr,"%s:",str);
	  }
	  test[j+i*maxconn] = dionum;
	  //if (failed < 30) {
	  //fprintf(stderr,"test[%d][%d]=%d (offset=%d)\n",j,i,dionum,j+i*maxconn);
	  //failed++;
	  //}
	}
      }

      failed = 0;
      // get current state of all logical DIO pins
      // set all logical DIO pins to input-only
      // note: we don't lock anything yet...
      // so for completeness, we should do this again on each group
      for (i=0;i<wires*maxconn;i++) {
	if (test[i] != -1) {
	  dio_setpin(h,test[i],DIO_HIGHZ);
	}
      }
#define LOCKIT
      // now run the tests
      for (j=0;j<wires;j++) {
	// first, lock the pins connected to the wire
#ifdef LOCKIT
	n = 0;
	grp = dio_groupinit(h);
	//fprintf(stderr,"wire %d, group %d=",j,grp);
	for (i2=0;i2<maxconn;i2++) {
	  if (test[i2+j*maxconn] != -1) {
	    //fprintf(stderr,"[%d %d] %d ",i2,j,test[i2+j*maxconn]);
	    dio_groupaddpin(h,grp,test[i2+j*maxconn]);
	    n++;
	  }
	}
	//fprintf(stderr,"\n");
#endif
	if (n == 0) {
#ifdef LOCKIT
	  dio_groupfree(h,grp);
#endif
	  continue;
	}
#ifdef LOCKIT
	//fprintf(stderr,"locking group %d\n",grp);
	dio_grouplock(h,grp);
#endif
	dio_groupisync(h,grp);
	// second, test the pins connected to the wire
	for (i=0;i<maxconn;i++) {
	  dionum = test[i+j*maxconn];
	  if (dionum == -1) {
	    continue;
	  }
	  // set DIO on wire i to output low
	  dio_setpin(h,dionum,0);
	  dio_grouposync(h,grp);
	  usleep(50000);
	  dio_groupisync(h,grp);
	  // check that other wires are low
	  for (i2=0;i2<maxconn;i2++) {
	    if (test[i2+j*maxconn] >= 0) {
	      val = dio_getpin(h,test[i2+j*maxconn]);
	      if (val != 0) {
		if (failed < 25) {
		  //printf("DIO %d failed low on DIO %d low (i=%d, i2=%d, j=%d, offset1=%d, offset2=%d)\n",
		  //	   test[i2+j*maxconn],dionum,i,i2,j,i2+j*maxconn,i+j*maxconn);
		  printf("DIO %d failed low on DIO %d low\n",
		  	   test[i2+j*maxconn],dionum);
		}
		failed++;
	      } else {
		//printf("DIO %d PASSED low on DIO %d low (i=%d, i2=%d, j=%d, offset1=%d, offset2=%d)\n",
		//test[i2+j*maxconn],dionum,i,i2,j,i2+j*maxconn,i+j*maxconn);
		passed++;
	      }
	    }
	  }
	  // set DIO on wire i to output high
	  dio_setpin(h,dionum,1);
	  dio_grouposync(h,grp);
	  usleep(50000);
	  dio_groupisync(h,grp);
	  // check that other wires are high
	  for (i2=0;i2<maxconn;i2++) {
	    if (test[i2+j*maxconn] >= 0) {
	      val = dio_getpin(h,test[i2+j*maxconn]);
	      if (val != 1) {
		if (failed < 25) {
		  printf("DIO %d failed high on DIO %d high (i=%d, i2=%d, j=%d, offset1=%d, offset2=%d)\n",
			 test[i2+j*maxconn],dionum,i,i2,j,i2+j*maxconn,i+j*maxconn);
		  //printf("DIO %d failed high on DIO %d high\n",
		  //test[i2+j*maxconn],dionum);
		}
		failed++;
	      } else {
		//printf("DIO %d PASSED high on DIO %d high (i=%d, i2=%d, j=%d, offset1=%d, offset2=%d)\n",
		//test[i2+j*maxconn],dionum,i,i2,j,i2+j*maxconn,i+j*maxconn);
		passed++;
	      }
	    }
	  }
	  // set DIO on wire i to input
	  dio_setpin(h,dionum,DIO_HIGHZ);
	  dio_grouposync(h,grp);
	  usleep(50000);
	}
	// third, unlock the pins connected to the wire
#ifdef LOCKIT
	//fprintf(stderr,"UNlocking group %d\n",grp);
	dio_groupunlock(h,grp);
	dio_groupfree(h,grp);
#endif
      }
      printf("%d passed, %d failed\n",passed,failed);
      // a more sophisticated test would make sure no other DIOs were
      // affected by a different wire than the one they were on.
    }
  }
  if (opt_server) {
    DioInit();
    for (i=0;i<256;i++) {
      DioValue[i] = 0xFF;
    }
    lock_init(256); // one write lock for each possible DIO
    init_watch(256);

    
    struct sigaction sa;

    sa.sa_handler = do_hup;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGHUP, &sa, NULL);
    signal(SIGPIPE,SIG_IGN);
  
    daemon(1,0);
    record_daemon_pid(7);
    run_dioctl_server(opt_server,opt_pollrate);
  }
  return 0;
}

/*
  Author: Michael Schmidt (michael@embeddedARM.com)
 */
