/* Call me Mark5A. I read command lines from either a serial port * (COM1 alias /dev/tty0 or /dev/ttyS0) or a socket (as described * below) and send them to Parse5A() (which see). I send the * return from Parse5A() to the port from which the command came. * I loop and try to read and send more commands until ^C. * I also check periodically for new requests for socket connections. * Revised: 2005 June 07, JAB */ #include "Parse5A.h" #include "setrot.h" /* For setrot() to get ROT broadcasts */ #include /* For signal() to catch ^C */ #include /* For ftime() */ #include /* For tcgetattr(), etc. */ #define DEVI "/dev/ttyS0" /* Or /dev/tty0 */ #define MAXPORTS 9 /* Maximum number of open ports */ #define DIR "/var/dir/Mark5A" /* For sdir */ #define KOUNT 100000000L /* Debug print timing every KOUNT bytes */ XLR_ERROR_CODE error = 0; /* Return from error request, etc. */ char messg[XLR_ERROR_LENGTH]; /* Error message as a string */ int dirf; /* File descriptor for DIR */ extern int errno; /* To check after accept() */ void signalint(int k); /* To catch signal SIGINT (below) */ void signalpipe(int k); /* To catch signal SIGPIPE (below) */ double dend(unsigned long * ind); /* Change endian of a (fake) double */ unsigned long lend(unsigned long inl); /* Change endian of a long */ int getrot(); /* Process ROT broadcast */ SSHANDLE dev; /* xlrDevice */ UINT indx = 1; /* Index; use this card */ S_DIR dir; /* Directory */ S_DRIVEINFO dinfo[16]; /* Drive information */ S_DRIVESTATS dstats[XLR_MAXBINS]; /* Drive stats */ S_DEVINFO devinfo; /* Device information */ S_READDESC readdesc; /* Read description (readDesc) */ S_XLRSWREV swrev; /* Software and firmware versions, etc. */ S_BANKSTATUS bkstat; /* Bank status */ S_DEVSTATUS devstatus; /* Device status, devStatus */ int drive = 0; /* SS drive number, 0 ... 15 */ UINT bank = 0; /* Which bank? */ /* The following four parameters can be changed by net_protocol */ unsigned int socbuf = SOCBUF; /* Size of buffer to send to socket, bytes */ int nbuf = 8; /* Number of socbuf-size blocks in rbuf[] FIFO */ unsigned int sndbufs = 0; /* Socket send buffer size, bytes */ unsigned int rcvbufs = 0; /* Socket receive buffer size, bytes */ unsigned long rbuff[4 * BUFFL]; /* Read buffer */ unsigned long long * rbuf = NULL; /* From calloc() for FIFO buffers */ /* (Do not confuse rbuff[] and rbuf[]) */ sem_t semtoX; /* Semaphore for toX() */ pthread_t threadtoX = 0xffffffff; /* For toX() */ /* (pthread_t is an unsigned long) */ sem_t semXto; /* Semaphore for Xto() */ pthread_t threadXto = 0xffffffff; /* For Xto() */ struct outB outb = { /* Output board parameters, defaults */ "st", /* mode[] */ 8.0, /* freq */ FALSE, /* active */ FALSE, /* synced */ 15, /* trka */ 16, /* trkb */ 32, /* tmode */ 0, /* numrs */ FALSE, /* throt */ "mark4" /* formt[] */ }; struct inB inb = { /* Input board parameters, defaults */ "st", /* mode[] */ 32, /* ntracks */ FALSE /* notclock */ }; /* The following three are used for disk2net, etc. */ unsigned long long startbyte = 0L; unsigned long long endbyte = 0L; unsigned long long nowbyte = 0L; unsigned long long orpntr = 0L; /* Old value of record pointer */ unsigned long task_id; /* Which task ID now? */ struct timeval tvROT; /* Time at which ROT is valid */ double rot = 0.0; /* ROT at time tvROT */ double rot_rate = 32.0e6; /* To be 32.0e6 * speed_up */ unsigned long baseRange; /* From XLRGetBaseRange() */ unsigned long * windowAddr; /* From XLRGetWindowAddr() */ char udir[sizeof(struct SDir) + sizeof(struct Vsn)]; struct SDir * sdir = (struct SDir *) udir; /* Pointer to scan directory */ struct Vsn * pvsn = (struct Vsn *) (udir+sizeof(struct SDir)); /* Pointer to VSN structure */ struct LDir ldir; /* Last scans and files */ struct DTim dattime; /* Info for data_check */ int ports[MAXPORTS]; /* Allow up to MAXPORTS ports */ FILE * fports[MAXPORTS]; /* Each of ports[] open also as a stream */ int icount = 0; /* In2net overflow-poll counter */ int rcount = 0, pcount = 0; /* Play-poll and record-poll counters */ volatile int datah = 0; /* Status of ports[0], data socket, if any */ /* datah = 0 No data socket (m5data) open, no special transfer in progress * 1 Receive-data socket open (for net2disk or net2out) * 2 Receive-data socket open and connected (or udp) * 3 Send-data socket open and connected * 4 And sending data, disk2net case (cf., nowbyte) * 5 And sending data, in2net case * 6 Disc2file active (also cf., nowbyte) * 7 File2disk active */ unsigned int mss = 1472; /* MTU minus headers for udp socket, default */ unsigned int udpbs; /* UDP buffer size, bytes */ char * smod[] = { "tcp", "tcp", "tcp" }; /* For net_protocol */ /* (That's command and query, receive data, send data) */ char * me; /* My name */ /* Following three can be changed from the command line */ int msglev = 1; /* Default debug message level */ int forml = TRUE; /* Default formal parsing */ int maxports = MAXPORTS; /* Default maximum number of ports in use */ int found = 0; /* 0 = not found, 1 = Mark-5A board, 2 = Mark-5B */ int main(int argc, char * argv[]) { /* Mark5A */ static char * sepr = " =:;\t\n\r"; /* Token separators */ static int serial = SERIAL; /* Use RS-232 serial? */ char linei[1024]; /* Input command */ char lineo[1024]; /* Output response */ char * ptl1; /* Start parse in linei[] */ char * ptl2; /* End parse in linei[] */ char * ptr; /* For answer from Parse5A() */ char * ptc; /* Scratch */ int sock; /* Original command and query socket */ int sock2; /* Temporary socket */ int nports = 0; /* Number of ports in use */ int devi = -1; /* DEVI open? */ struct sockaddr_in socadd; /* For accept() socket info */ unsigned char * uc = (unsigned char *) &socadd.sin_addr.s_addr; socklen_t kk; /* For accept() */ fd_set readfds; /* For select() */ fd_set writefds; /* For select() */ fd_set errorfds; /* For select() */ struct timeval timeout; /* For select(), etc. */ int nfdmax = 0; /* Maximum file descripter in use */ int proom = FALSE; /* No-room message printed? */ struct termios ts; /* For tcgetattr(), etc. */ int i, ii, j, jend, k, len, more; unsigned long long opinct = 0L; /* Old value of play increment */ unsigned long long pinct = 0L; /* Current play increment */ unsigned long plapnt[2]; /* Convert to/from long long */ unsigned long long * pplapnt = (unsigned long long *) plapnt; unsigned long long nowoff; struct timeb time1, time2; /* From ftime() */ double dt; /* Duration of transfer (etc.), seconds */ /* *** Initialize *** */ me = (me = strrchr(argv[0], '/')) == NULL ? argv[0] : me+1; /* My name */ /* Parse command-line options, if any */ k = 0; while (k >= 0) { switch (k = getopt(argc, argv, "hHm:M:f:F:s:S:d:D:")) { /* That's help, msglev, formal parsing, * maximum number of active sockets, disk FIFO */ case 'h' : /* Help? */ case 'H' : (void) fprintf(stderr, "%s USAGE: \n" " %s -m -f -s -d \n" " where is the debug msglev (range -1 to 3, default 1), \n" " sets formal parsing (0 for FALSE, 1 TRUE, default TRUE), \n" " sets the maximum number of sockets" " (range 1 to 7, default 7), \n" " sets disk-FIFO-only mode" " (0 for FALSE, 1 TRUE, default FALSE), \n" " and -h shows this help message \n", me, me); return(0); /* End here for this case */ break; /* (Not used) */ case 'm' : /* msglev */ case 'M' : /* msglev = -1 Vast quantities of debuggery prints * msglev = 0 Some debuggery prints * msglev = 1 Default and normal operation; warnings and errors print * msglev = 2 Only errors and operational messages print * msglev = 3 Nothing prints except fatal errors when program dies * (default 1 above) */ msglev = atoi(optarg); /* (No check) */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DEBUG: msglev set to %d \n", me, msglev); break; case 'f' : /* forml? */ case 'F' : /* Formal parsing, TRUE or FALSE (default above) * (Use 0 to get informal parsing of input lines) */ forml = atoi(optarg); /* (No check) */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DEBUG: forml set to %d \n", me, forml); break; case 's' : /* maxports */ case 'S' : /* Maximum number of active sockets; range 1 to MAXPORTS - 2 */ if ((i = atoi(optarg)) > 0 && i < MAXPORTS - 1) /* OK? */ maxports = i + 2; /* Yes, two are already used up */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DEBUG: maxports set to %d, maximum control ports %d \n", me, maxports, i); break; case 'd' : /* dfifo? */ case 'D' : /* Special disk-FIFO-only mode with limited other functions * (default above) */ ldir.dfifo = atoi(optarg); /* (No check) */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DEBUG: dfifo set to %d \n", me, ldir.dfifo); break; case '?' : /* Error: character not in list */ if (msglev < 2) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s WARNING: Unknown option on command line \n", me); break; case ':' : /* Error: missing numerical parameter */ if (msglev < 2) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s WARNING: Missing number on command line \n", me); break; default : /* Probably -1, end of parameters */ break; } /* End of switch on k */ } /* End of while k */ /* *** More initialize *** */ ldir.f2dlstn = -1; ldir.n2dlstn = -1; ldir.dsmask = 0x7; /* Default all three bits to TRUE */ /* ** Initialize and check XLR ** */ if (XLRDeviceFind() <= 0) { /* StreamStor cards? */ /* (Returns number of cards found) */ (void) fprintf(stderr, "%s ERROR: \007 XLRDeviceFind() returned none \n", me); /* Error */ return(-1); /* Error */ } /* XLR errors? */ (void) errors(); /* We try to go on */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DEBUG: XLRDeviceFind() OK \n", me); if (XLRCardReset(indx) != XLR_SUCCESS) { /* Reset, OK? */ (void) fprintf(stderr, "%s ERROR: \007 XLRCardReset() returned error \n", me); /* Nope */ (void) errors(); return(-2); /* Error */ } /* XLR errors? */ (void) errors(); /* We try to go on */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, "%s DEBUG: XLRCardReset() OK \n", me); /* Yes */ (void) sleep(2); /* Wait a bit for XLRCardReset() to finish */ /* Special disk-FIFO-only mode? */ if (ldir.dfifo) { /* Disk FIFO? */ if (XLRSetAppID(indx, SS_APP_1) != XLR_SUCCESS) { /* Yes. OK? */ (void) fprintf(stderr, "%s ERROR: \007 XLRSetAppID() returned error \n", me); /* Nope */ (void) errors(); return(-2); /* Error */ } /* XLRSetAppID() seems to generate spurious error 7, Invalid command */ if ((error = XLRGetLastError()) == 3 || error == 7) { /* Other error? */ error = 0; /* Nope, OK */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, "%s DEBUG: XLRSetAppID() OK \n", me); } else { /* Real error */ if (msglev < 2) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s ERROR: XLRSetAppID() generated error \n", me); (void) errors(); /* Error, but we try to go on */ } if (msglev < 2) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s WARNING: Only disk-FIFO mode will be functional \n", me); } /* End of if dfifo disk FIFO */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DEBUG: Trying to XLROpen() ... \n", me); if (XLROpen(indx, &dev) != XLR_SUCCESS) { /* Open, OK? */ (void) fprintf(stderr, "%s ERROR: \007 XLROpen() returned error \n", me); /* Nope */ (void) errors(); XLRClose(dev); /* See manual notes on XLROpen() */ (void) XLRCardReset(indx); return(-3); /* Error */ } if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DEBUG: XLROpen() OK \n", me); /* XLR errors? */ (void) errors(); /* We try to go on */ ldir.mounted = TRUE; /* Disks are now mounted */ signal(SIGINT, signalint); /* Catch interrupt signal */ signal(SIGPIPE, signalpipe); /* Catch broken-pipe signal */ /* XLRSetMode modes abstract from xlrapi.h: * SS_MODE_PCI Record from PCI, play to PCI (old default) * SS_MODE_EXT Record from INB, play to OUTB * SS_MODE_READ_EXT Pass from INB to PCI (no disks) * SS_MODE_WRITE_EXT Pass from PCI to OUTB (no disks) * SS_MODE_PCI_FORK Record from PCI and also pass to OUTB * SS_MODE_EXT_FORK Record from INB and also pass to PCI * SS_MODE_EXT_TO_PCI_FIFO Fifo data through disk from external to PCI (But see ldir.dfifo and XLRSetAppID() above) * SS_MODE_EXT_FORK_TOP Data forked from front port to disk and top port * SS_MODE_EXT_FORK_FRT Data forked from top port to disk and front port * SS_MODE_EXT_PASS_TOP Pass through from front port to top (no disk) * SS_MODE_EXT_PASS_FRT Pass through from top port to front port (no disk) * These modes affect XLRRecord(), XLRAppend(), and XLRPlay() * and XLRRead() */ if (ldir.dfifo) { /* Special disk-FIFO-only mode? */ /* Yes, first try to disable bank mode */ /* ?? This doesn't really seem to work ?? */ if (XLRSetBankMode(dev, SS_BANKMODE_DISABLED) != XLR_SUCCESS) { /* OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s ERROR: XLRSetBankMode() returned error \n", me); (void) errors(); XLRClose(dev); /* See manual notes on XLROpen() */ (void) XLRCardReset(indx); return(-4); /* Error */ } (void) errors(); /* Else OK */ ldir.bmode = FALSE; ldir.abmode = FALSE; /* Change to FIFO mode */ if (XLRSetMode(dev, SS_MODE_EXT_TO_PCI_FIFO) != XLR_SUCCESS) { /* OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s ERROR: \007 XLRSetMode() returned error \n", me); (void) errors(); XLRClose(dev); /* See manual notes on XLROpen() */ (void) XLRCardReset(indx); return(-4); /* Error */ } } else { /* Not special disk FIFO, set default mode */ if (XLRSetMode(dev, SS_MODE_PCI) != XLR_SUCCESS) { /* OK? */ (void) fprintf(stderr, "%s ERROR: \007 XLRSetMode() returned error \n", me); /* Nope */ (void) errors(); XLRClose(dev); /* See manual notes on XLROpen() */ (void) XLRCardReset(indx); return(-4); /* Error */ } } /* Set default FPDP mode */ if (XLRSetFPDPMode(dev, SS_FPDP_RECVMASTER, SS_OPT_FPDPNRASSERT) != XLR_SUCCESS) { /* (Or SS_OPT_FPDPALL) OK? */ (void) fprintf(stderr, "%s ERROR: \007 XLRSetFPDPMode() returned error \n", me); /* Nope */ (void) errors(); XLRClose(dev); /* See manual notes on XLROpen() */ (void) XLRCardReset(indx); return(-5); /* Error */ } if (XLRGetDeviceInfo(dev, &devinfo) != XLR_SUCCESS) { /* Device info, OK? */ (void) fprintf(stderr, /* Nope */ "%s ERROR: \007 XLRGetDeviceInfo() returned error \n", me); (void) errors(); XLRClose(dev); /* See manual notes on XLROpen() */ (void) XLRCardReset(indx); return(-6); /* Error */ } if (msglev < 1) /* OK, debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DEBUG: BoardType %s, SerialNum %d, NumDrives %d, \n " " NumBuses %d, TotalCapacity %d * 4096 bytes \n " " MaxBandwidth %d PciBus %#x PciSlot %#x \n", me, devinfo.BoardType, devinfo.SerialNum, devinfo.NumDrives, devinfo.NumBuses, devinfo.TotalCapacity, devinfo.MaxBandwidth, devinfo.PciBus, devinfo.PciSlot); /* XLR errors? */ (void) errors(); /* We try to go on */ if (XLRGetDeviceStatus(dev, &devstatus) != XLR_SUCCESS) { /* Device Stats, OK? */ (void) fprintf(stderr, /* Nope */ "%s ERROR: \007 XLRGetDeviceStatus() returned error \n", me); (void) errors(); XLRClose(dev); /* See manual notes on XLROpen() */ (void) XLRCardReset(indx); return(-7); /* Error */ } if (msglev < 1) { /* OK, debuggery? */ (void) fprintf(stderr, "%s DEBUG: ", me); /* Yes */ if (! devstatus.SystemReady) (void) fprintf(stderr, " NOT"); (void) fprintf(stderr, " SystemReady,"); if (! devstatus.BootmonReady) (void) fprintf(stderr, " NOT"); (void) fprintf(stderr, " BootmonReady,"); if (! devstatus.Recording) (void) fprintf(stderr, " NOT"); (void) fprintf(stderr, " Recording \n "); if (! devstatus.Playing) (void) fprintf(stderr, " NOT"); (void) fprintf(stderr, " Playing,"); // if (! devstatus.VRActive[0]) // (void) fprintf(stderr, " NOT"); // (void) fprintf(stderr, " VRActive[0],"); // if (! devstatus.VRActive[1]) // (void) fprintf(stderr, " NOT"); // (void) fprintf(stderr, " VRActive[1],"); if (! devstatus.FifoActive) (void) fprintf(stderr, " NOT"); (void) fprintf(stderr, " FifoActive,"); if (! devstatus.DriveFail) (void) fprintf(stderr, " NOT DriveFail \n "); else /* DriveFail--presumably an error */ (void) fprintf(stderr, " DriveFailNumber %d \n ", devstatus.DriveFailNumber); if (! devstatus.SysError) (void) fprintf(stderr, " NOT SysError,"); else /* SysError--presumably an error */ (void) fprintf(stderr, " SysErrorCode %d", devstatus.SysErrorCode); if (! devstatus.CtlrError) (void) fprintf(stderr, " NOT"); (void) fprintf(stderr, " CtlrError,"); if (! devstatus.FifoFull) (void) fprintf(stderr, " NOT"); (void) fprintf(stderr, " FifoFull,"); if (! devstatus.Overflow[0]) (void) fprintf(stderr, " NOT"); (void) fprintf(stderr, " Overflow[0],"); if (! devstatus.Overflow[1]) (void) fprintf(stderr, " NOT"); (void) fprintf(stderr, " Overflow[1] \n"); } /* End of if debuggery */ /* XLR errors? */ (void) errors(); /* We try to go on */ if (XLRGetVersion(dev, &swrev) != XLR_SUCCESS) { /* SW Version, OK? */ (void) fprintf(stderr, /* Nope */ "%s ERROR: \007 XLRGetVersion() returned error \n", me); (void) errors(); XLRClose(dev); /* See manual notes on XLROpen() */ (void) XLRCardReset(indx); return(-8); /* Error */ } if (msglev < 1) /* OK, debuggery? */ (void) fprintf(stderr, "%s DEBUG: " /* Yes */ " ApiVersion %s, ApiDateCode %s, FirmwareVersion %s, \n " " FirmDateCode %s, MonitorVersion %s, XbarVersion %s, \n " " AtaVersion %s, UAtaVersion %s, DriverVersion %s \n", me, swrev.ApiVersion, swrev.ApiDateCode, swrev.FirmwareVersion, swrev.FirmDateCode, swrev.MonitorVersion, swrev.XbarVersion, swrev.AtaVersion, swrev.UAtaVersion, swrev.DriverVersion); /* XLR errors? */ (void) errors(); /* We try to go on */ windowAddr = XLRGetWindowAddr(dev); /* Data-write address */ (void) errors(); baseRange = XLRGetBaseRange(dev); /* Data-write size */ (void) errors(); if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DEBUG: BaseRange %ld \n", me, baseRange); /* ** In disk-FIFO-only mode, we skip the disk-related stuff ** */ if (! ldir.dfifo) { /* Special disk-FIFO-only mode? */ /* No, normal mode (not disk FIFO) */ /* ** Open or create file DIR for sdir (directory) ** */ if ((dirf = open(DIR, O_RDWR | O_CREAT)) < 0) { /* OK? */ (void) fprintf(stderr, "%s ERROR: \007 Can't open() file ", me); /* No */ perror(DIR); /* Error */ XLRClose(dev); /* See manual notes on XLROpen() */ (void) XLRCardReset(indx); return(-9); /* Error */ } /* ** Check banks and disks, verify disk mounting, get disk info ** * (CheckBanks() executes checkDisks() and readdir() if necessary; * here necessary because ldir.bmode initializes to FALSE) */ if (CheckBanks() < 0) { /* OK? */ XLRClose(dev); /* Nope. See manual notes on XLROpen() */ (void) XLRCardReset(indx); return(-10); /* Error */ } /* ** Check: Was this disk pack recorded off the end (bank_switch=on) * as signified by having a scanName with an appended '+' * in the scan after the last (i.e., numbered off the end)? ** */ sdir->scanName[sdir->nscans][MAXLENGTH - 1] = '\0'; /* Don't run off the end */ if (strchr(sdir->scanName[sdir->nscans], '+') != NULL) { /* Got '+'? */ if (msglev < 1) /* Yes, debuggery? */ (void) fprintf(stderr, "%s DEBUG: Found + scan %d %s \n", /* Yes */ me, sdir->nscans + 1, sdir->scanName[sdir->nscans]); sdir->recpnt = XLRGetLength(dev); /* Update record offset, bytes */ (void) errors(); sdir->length[sdir->nscans] = sdir->recpnt - sdir->start[sdir->nscans]; /* Correct length back a few bytes from TotalCapacity */ sdir->nscans++; /* Bump nscans to include the added + scan */ sdir->scanName[sdir->nscans][0] = '\0'; /* Clear the new next scan */ (void) writedir(); /* Save copy of modified sdir on SS disks */ } sdir->n = 0; /* Reset pointer to first scan (if any) */ /* Reset stuff in ldir */ ldir.filenam[0] = '\0'; /* Reset Set_scan() defaults */ /* (May be changed below) */ ldir.scann = 0; /* Reset last scan found in Set_scan() */ ldir.reclstn = -1; /* Last scan recorded by Record() */ ldir.f2dlstn = -1; /* Last scan created by File2disc() */ ldir.n2dlstn = -1; /* Last scan created by Net2disc() */ /* Resets from sdir-> */ if (sdir->nscans > 0) { /* Any scans? */ startbyte = sdir->plapnt = sdir->start[sdir->n]; /* Yes, start of scan */ endbyte = sdir->start[sdir->n] + sdir->length[sdir->n]; /* End */ /* We also set the (default) filename to the scan label */ (void) strncpy(ldir.filenam, sdir->scanName[sdir->n], MAXNAME); /* But we delete experiment name, source name, and station code * as separated by spaces (' '), if any. This is for legacy only */ if ((ptc = strchr(ldir.filenam, ' ')) != NULL) /* Find ' ', if any */ ptc[0] = '\0'; /* Yes, end filenam here */ /* We append ".mk5" unless there is already a filename suffix */ if (strchr(ldir.filenam, '.') == NULL) /* Already got '.'? */ (void) strncat(ldir.filenam, ".mk5", /* No, add suffix */ MAXNAME - 1 - strlen(ldir.filenam)); if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DEBUG: Set filenam to \"%s\" \n", me, ldir.filenam); } else { /* No scans */ startbyte = sdir->plapnt = sdir->start[sdir->n] = 0; /* Start of scan */ endbyte = sdir->length[sdir->n] = 0; /* End */ } sdir->recpnt = XLRGetLength(dev); /* Update record offset, bytes */ } /* End of if not disk FIFO */ else { /* Special disk-FIFO-only mode */ sdir->n = sdir->nscans = 0; /* No scans */ startbyte = sdir->plapnt = sdir->start[sdir->n] = 0; /* Start of scan */ endbyte = sdir->length[sdir->n] = 0; /* End */ } (void) errors(); /* ** Set defaults to I/O board ** */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DEBUG: Setting defaults to outBoard() and inBoard() \n", me); (void) outBoard(SET); (void) inBoard(SET); /* ** Create a socket to be m5drive ** */ if ((sock = mksock("m5drive", NULL, 0)) < 0) { /* Errors? */ (void) fprintf(stderr, /* Yes */ "%s ERROR: \007 mksock() returned %d ", me, sock); perror("error"); XLRClose(dev); /* See manual notes on XLROpen() */ (void) XLRCardReset(indx); return(-17); /* Fatal error */ } /* * Initialize all ports[] to not in use * */ for (i = 0; i < MAXPORTS; i++) /* Each of ports[] */ ports[i] = -1; /* * Set rbuf from calloc(). (This is changeable by Net_protocol(), * * * * which is why its from calloc()) (Do not confuse rbuf with rbuff) */ if ((rbuf = (unsigned long long *) calloc(nbuf, socbuf)) == NULL) { /* OK? */ (void) fprintf(stderr, /* Nope */ "%s ERROR: \007 calloc(%u, %u) returned ", me, nbuf, socbuf); perror("error"); XLRClose(dev); /* See manual notes on XLROpen() */ (void) XLRCardReset(indx); return(-18); /* Fatal error */ } /* ** End of initialization ** */ ///* ** Check to see whether anyone has done erase or recording while // * we weren't watching ** */ //if (msglev < 2 && sdir->recpnt != XLRGetLength(dev)) /* Changed? */ // (void) fprintf(stderr, /* Yes */ // "%s WARNING: \007 Record length %Ld and directory are no longer " // "valid! \n Suggest reset = erase \n", me, sdir->recpnt); ///* XLR errors (from XLRGetLength())? */ //(void) errors(); /* We try to go on */ if (msglev < 2) /* Debuggery? */ (void) fprintf(stderr, "%s Ready. End with EndM5, please \n", me); /* *** Main working loop *** */ while (TRUE) { /* Loop forever */ /* ** Setup for select() ** */ nfdmax = 0; FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&errorfds); for (i = 0; i < MAXPORTS; i++) { /* Each of ports[] */ if (ports[i] < 0) /* Active? */ continue; /* Nope */ FD_SET(ports[i], &errorfds); /* Check all for errors */ if (i > 0 || datah == 7) /* Read? */ /* Yes, read from socket(s) or from file */ FD_SET(ports[i], &readfds); if (i == 0 && (datah == 6 || datah == 7)) /* Write? */ /* Yes, write to socket or file */ /* (The cases datah = 2, 4, and 5 are handled by threads * toX() and Xto()) */ FD_SET(ports[0], &writefds); if (ports[i] > nfdmax) nfdmax = ports[i]; } /* End of for i each of ports[] */ /* ** Wait for data to be available to be read or timeout ** */ timeout.tv_sec = 1; /* That's 1 second */ timeout.tv_usec = 0; if ((k = select(nfdmax+1, &readfds, &writefds, &errorfds, &timeout)) < 0) { /* Errors? */ (void) fprintf(stderr, "%s ERROR: \007 select() returned %d ", me, k); perror("error"); XLRClose(dev); /* See manual notes on XLROpen() */ (void) XLRCardReset(indx); return(-20); /* Error */ } if (msglev < 0 && nfdmax > 0) /* Debuggery? */ (void) fprintf(stderr, "%s DEBUG from select(): k %d \n", me, k); /* Now k is the number of bits set in the bit masks */ /* ** Did we get something? ** */ if (k != 0) { /* OK? (timeout gives 0) */ /* ** Here we have something waiting on at least one of ports[] ** */ if (msglev < 0) /* Debuggery? */ (void) fprintf(stderr, "%s DEBUG from select(): k = %d \n", me, k); for (i = 0; i < MAXPORTS; i++) { /* Each of ports[] */ if (ports[i] < 0) /* Any such socket? */ continue; /* Nope, try another */ /* * Check: socket errors? * */ if (FD_ISSET(ports[i], &errorfds)) { /* Error on ports[i]? */ if (msglev < 2) { /* Debuggery? */ (void) fprintf(stderr, "%s ERROR: ports[%d] %d ", /* Yes */ me, i, ports[i]); perror("error"); } (void) sprintf(messg, "FD_ISSET() error ports[%d] %d", i, ports[i]); error = 1009; continue; /* Error, but we try to go on to next i */ } /* * Port 0 is a special case: It is the data socket, and * we might be waiting for either read or write data * */ if (i == 0) { /* Special case data socket? */ if (FD_ISSET(ports[0], &readfds)) { /* Yes, read? */ if (msglev < 0) /* Yes, debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DEBUG: Port %d active to read \n", me, ports[0]); /* If datah == 2, then we read data from this socket, * or if datah == 7, then we read data from this file, * first to a buffer, then transfer from the buffer to SS. * Otherwise we discard the read data */ /* (Most of net2disk (datah = 2) and net2out (also datah = 2) * is done in threads toX() and Xto()) */ if (datah == 7) { /* File2disk? */ len = fread((void *) rbuff, 1, /* Yes, read from file */ MIN(sizeof(rbuff), endbyte - nowbyte), fports[0]); if (len > 0) { /* Read OK? */ if (len % 8 != 0) { /* Yes, SS needs len integer * 8, OK? */ if (msglev < 1) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s WARNING: fread() on ports[0] %d, " "len %d, %% 8 %d \n", me, ports[0], len, len % 8); len &= 0xfffffff8; /* Bad, but alternatives are worse */ } if (XLRWriteData(dev, (void *) rbuff, len) != XLR_SUCCESS) /* Transfer to SS, OK? */ (void) fprintf(stderr, /* Nope */ "%s WARNING: XLRWriteData() returned error \n", me); /* (We try to go on) */ (void) errors(); nowbyte += len; /* Count this XLRWriteData() */ } /* End of if read OK */ else { /* len <= 0, other-end disconnect or end-of-file? */ if (len < 0) { /* Yes, errors? */ if (msglev < 2) { /* Yes, debuggery? */ (void) fprintf(stderr, "%s ERROR: fread() " "on ports[0] %d returned %d ", me, ports[0], len); perror("error"); } (void) sprintf(messg, "recv() or fread() error on ports[0] %d", ports[0]); error = 1015; /* Error, but we try to go on */ } if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DEBUG: fread() on ports[0] %d " "returned %d; closing \n", me, ports[0], len); if (ports[0] >= 0) /* OK to close? */ (void) close(ports[0]); /* Yes */ ports[0] = -1; /* No longer in use */ /* End; Turn recording off * (This is required before data can be used) */ if (XLRStop(dev) != XLR_SUCCESS) { /* Stop, OK? */ if (msglev < 2) /* Nope, debuggery? */ (void) fprintf(stderr, /* Yes */ "%s WARNING: XLRStop() returned error \n", me); } /* We try to go on */ (void) errors(); if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, "%s DEBUG: XLRStop() \n", me); if (XLRGetDirectory(dev, &dir) != XLR_SUCCESS) /* OK? */ if (msglev < 2) /* Nope, debuggery? */ (void) fprintf(stderr, /* Yes */ "%s WARNING: XLRGetDirectory() returned error \n", me); /* We try to go on */ (void) errors(); if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DEBUG: XLRGetDirectory() \n", me); sdir->length[sdir->nscans] = dir.AppendLength; sdir->recpnt = dir.Length; if (++sdir->nscans >= MAXSCANS) { /* Bump for next scan, OK? */ if (msglev < 2) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s WARNING: Directory overflow \n", me); sdir->nscans = 0; /* Not OK. Reset (!) */ sdir->n = 0; } sdir->start[sdir->nscans] = 0L; /* Clear this next entry */ sdir->length[sdir->nscans] = 0L; sdir->scanName[sdir->nscans][0] = '\0'; sdir->n = MAX(0, sdir->nscans - 1); /* Set the scan pointer to the just-recorded scan */ startbyte = sdir->plapnt = sdir->start[sdir->n]; /* Set play pointer to start of the just-recorded scan */ endbyte = startbyte + dir.AppendLength; (void) writedir(); /* Save copy of current sdir on SS disks */ /* Configure SS back to default mode */ if (XLRSetMode(dev, SS_MODE_PCI) != XLR_SUCCESS) if (msglev < 2) /* Nope, degubbery? */ (void) fprintf(stderr, /* Yes */ "%s WARNING: XLRSetMode() returned error \n", me); (void) errors(); datah = 0; /* Data socket closed */ ldir.f2ddoing = 0; /* File2disk done */ } /* End of else disconnect or end-of-file */ } /* End of if file2disk */ } /* End of if read */ if (datah > 3 && datah < 7 && FD_ISSET(ports[0], &writefds)) { /* Write? */ if (msglev < 0) /* Yes. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DEBUG: Data port %d active to write \n", me, ports[0]); /* Here datah = 4, 5, or 6. For datah = 6, we read from SS into * rbuff[], then send rbuff[] to the file. Most of datah = 4 * and 5 is handled in separate threads toX() and Xto() */ if (msglev < 1 && datah != 5 && nowbyte == startbyte) /* Debuggery and start of transfer? */ (void) ftime(&time1); /* Yes, what time is it? */ /* (We'll use these times below) */ if (datah == 6) { /* Disk2file? */ *pplapnt = nowbyte; /* Yes */ plapnt[0] &= 0xfffffff8; /* Now 8-byte aligned */ readdesc.XferLength = MIN(sizeof(rbuff), endbyte - nowbyte); readdesc.XferLength &= 0xfffffff8; /* Now 8-byte aligned */ if (XLRReadData(dev, rbuff, plapnt[1], plapnt[0], readdesc.XferLength) != XLR_SUCCESS) { /* Read into rbuff, OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s ERROR: XLRReadData() returned error \n", me); (void) errors(); /* Error, but what to do? Maybe just end the transfer */ datah = 0; /* End */ if (ports[0] >= 0) /* OK to close? */ (void) close(ports[0]); /* Yes */ if (msglev < 2) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s WARNING: Closed ports[0] = %d \n", me, ports[0]); ports[0] = -1; /* No longer in use */ if (XLRStop(dev) != XLR_SUCCESS) /* Stop, OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s WARNING: XLRStop() returned error \n", me); /* We try to go on */ (void) errors(); continue; /* To next i */ } /* End of if read OK */ } /* End of if disk2file */ else if (datah == 5) { /* In2net? */ /* (Most of in2net is now done in threads toX() and Xto()) */ if (msglev < 1 && ++icount > 99) { /* Check for overflow? */ if (XLRGetDeviceStatus(dev, &devstatus) != XLR_SUCCESS) { /* Yes, get device status, OK? */ (void) fprintf(stderr, "%s ERROR: " /* Nope */ " XLRGetDeviceStatus() returned error \n", me); /* Error, but we try to go on */ (void) errors(); } else if (devstatus.FifoFull) { /* Fifo overflow? */ (void) fprintf(stderr, /* Yes */ "%s ERROR: Fifo overflow \n", me); (void) strcpy(messg, "FIFO overflow"); error = 1016; } icount = 0; /* For next time */ } /* End of if check for in2net overflow */ if (msglev < 0 && nowbyte == 0) { /* Debuggery? */ /* (First bufferfull only) */ readdesc.BufferAddr = rbuff; /* Yes */ (void) PatScan(&readdesc); } } /* End of else if datah == 5, in2net */ if (datah == 6) { /* Disc2file? */ if (msglev < 0) { /* Yes, special Mark5B debuggery for RJC? */ /* Yes, look for a bad deed in this bufferfull */ jend = readdesc.XferLength / 4; /* To words */ nowoff = (nowbyte - startbyte) / 4L; /* To words */ for (j = 0; j < jend; j++) { /* Each word in rbuff[j] */ if (msglev < 0 && rbuff[j] == SYNC) /* Mark5B SYNC? */ (void) fprintf(stderr, /* Yes */ "%s DEBUG: SYNC at %Lu \n", me, nowoff + j); if (rbuff[j] == rbuff[(j + 1) % jend]) /* Duplicate? */ (void) fprintf(stderr, /* Yes */ "%s DEBUG: Duplicate at %Lu \n", me, nowoff + j); } /* End of for j in rbuff[j] */ } /* End of if Mark5B debuggery */ // nowbyte += fwrite((void *) rbuff, 1, // readdesc.XferLength, fports[0]); nowoff = readdesc.XferLength * fwrite((void *) rbuff, readdesc.XferLength, 1, fports[0]); if (nowoff == readdesc.XferLength) /* fwrite() OK? */ nowbyte += nowoff; /* Yes */ else if (msglev < 2) { /* Not OK, debuggery? */ (void) fprintf(stderr, /* Yes */ "%s ERROR: fwrite() returned ", me); perror("error"); /* Error, but we try to go on */ } } /* End of if Disc2file */ if (datah != 5 && nowbyte + 8 > endbyte) { /* Done? */ if (msglev < 1) /* Yes, debuggery? */ (void) ftime(&time2); /* Yes, now what time is it? */ /* (We'll use these times below) */ if (datah == 4) /* Disk2net done? */ datah = 3; /* Yes, end, but let output drain */ if (datah == 6) { /* Disc2file done? */ datah = 0; /* Yes, end */ if (ports[0] >= 0) { /* OK to close? */ (void) fclose(fports[0]); /* Yes, close the stream */ (void) close(ports[0]); /* Close the file */ } if (msglev < 0) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DEBUG: Closed ports[0] = %d \n", me, ports[i]); ports[0] = -1; /* No longer in use */ if (XLRStop(dev) != XLR_SUCCESS) /* Stop, OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s WARNING: XLRStop() returned error \n", me); /* We try to go on */ (void) errors(); } if (msglev < 1) { /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DEBUG: nowbyte >= endbyte; transfer done \n", me); dt = time2.time + time2.millitm/1000.0 - time1.time - time1.millitm/1000.0; (void) fprintf(stderr, "%s DEBUG: Transferred %Ld bytes " "in %.1f seconds at %.3e baud \n", me, endbyte - startbyte, dt, 8.0*(endbyte - startbyte)/dt); } /* End of if debuggery */ } /* End of if done */ } /* End of if write */ continue; } /* End of if port 0 special case */ if (i == 1) { /* Special case rotman socket? */ if (! FD_ISSET(ports[1], &readfds)) /* Yes, read ports[1]? */ continue; /* Nope, try another i */ (void) getrot(); /* Yes */ continue; } /* End of if port 1 special case */ /* * Check: Command or query waiting on this port? * */ if (! FD_ISSET(ports[i], &readfds)) /* Read ports[i]? */ continue; /* Nope, try another i */ if (msglev < 0) /* Debuggery? */ (void) fprintf(stderr, "%s DEBUG from FD_ISSET(read): i = %#x \n", me, i); /* * Read a command or query * */ if (fgets(linei, sizeof(linei), fports[i]) == NULL) { /* OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s WARNING: fgets() on ports[%d] = %d returned NULL \n", me, i, ports[i]); if (ports[i] >= 0) /* OK to close? */ (void) close(ports[i]); /* Yes, close this port */ if (msglev < 2) /* Debuggery? */ (void) fprintf(stderr, "%s WARNING: Closed ports[%d] = %d \n", me, i, ports[i]); ports[i] = -1; /* No longer in use */ proom = FALSE; continue; /* Try another i */ } // if (strlen(linei) < 4) { /* Command length OK? */ // if (msglev < 2) /* Nope. Debuggery? */ // (void) fprintf(stderr, /* Yes */ // "%s WARNING: Got short line[] from ports[%d] = %d \n", // me, i, ports[i]); // continue; /* Ignore short linei[], to next i */ } /* * Parse and do it (or them) * */ /* Here we allow for the possibility that more than one command, * separated by ';', can be on a line. We need to break linei[] * at ';' and send each part separately to Parse5A(). If you * put more than one command on a line, then there will be more * than one reply on the answer line. We also allow lines that * do not have the terminating ';' even though this is no fair * by the standard. */ more = TRUE; /* Initialize */ ptl1 = linei; /* Input line */ lineo[0] = '\0'; /* Output line */ while (more) { /* More commands in linei[]? */ if ((ptl2 = strchr(ptl1, ';')) == NULL) /* Yes, got ';'? */ more = FALSE; /* Nope, no more commands after this one */ else /* Yes ';' */ ptl2[0] = '\0'; /* End string here */ if (strspn(ptl1, sepr) < strlen(ptl1)) /* Command herein? */ ptr = Parse5A(ptl1); /* Yes, parse command, do it, get answer */ else /* Presume no command herein */ break; /* Out of while more (ignore rest of line) */ if (more) /* Possibly another command on this line? */ ptl1 = ptl2 + 1; /* Yes, start of string for next time */ /* * Check: Parse5A() OK? * */ if (ptr == NULL) { /* NULL pointer? */ if (msglev < 2) /* Yes. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s WARNING: Parse5A() returned NULL pointer \n", me); ptr = "!error! ;"; /* Return error */ } else if (ptr[0] == '\0') { /* Null string? */ if (msglev < 2) /* Yes. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s WARNING: Parse5A() returned a null string \n", me); ptr = "!error! ;"; /* Return error */ } else /* * Parse OK * */ if (msglev < 1) /* Debuggery */ (void) fprintf(stderr, /* Yes */ "%s DEBUG: Parse5A() returned \"%s\" \n", me, ptr); /* Append answer to lineo[] */ (void) strncat(lineo, ptr, sizeof(lineo)-strlen(lineo)); (void) strncat(lineo, " ", sizeof(lineo)-strlen(lineo)); } /* End of while more */ /* * Send the answer(s) back to where the command(s) came from * */ (void) strncat(lineo, "\n", sizeof(lineo)-strlen(lineo)); /* Add \n */ len = strlen(lineo); /* Length of answer line */ if (i == devi) { /* Serial port? */ if (write(ports[i], lineo, len) < len) { /* Yes, OK? */ if (msglev < 2) { /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s ERROR: \007 write() to ports[%d] = %d returned ", me, i, ports[i]); perror("error"); } (void) sprintf(messg, "write() to ports[%d] %d error", i, ports[i]); error = 1010; /* Error, but we try to go on */ } } else /* Not serial, so send to socket */ if (send(ports[i], lineo, len, 0) < len) { /* OK? */ if (msglev < 2) { /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s ERROR: \007 send() to ports[%d] = %d returned ", me, i, ports[i]); perror("error"); } (void) sprintf(messg, "send() to ports[%d] %d error", i, ports[i]); error = 1011; /* Error, but we try to go on */ } } /* End of for i each of ports[] */ } /* End of if k; did we get something? */ /* Device status is needed for polls and recording check below */ if (ldir.mounted && XLRGetDeviceStatus(dev, &devstatus) != XLR_SUCCESS) { /* Yes, get device status, OK? */ if (msglev < 2) /* Nope, debuggery? */ (void) fprintf(stderr, /* Yes */ "%s ERROR: \007 XLRGetDeviceStatus() returned error \n", me); (void) errors(); continue; /* Try again in a second or so */ } /* ** Poll for change in bank status; fix it if so ** */ if (ldir.mounted && ! devstatus.Playing && ! ldir.playing && ! devstatus.Recording && ! ldir.recording && ! ldir.dfifo && datah == 0 && (ii = CheckBanks()) < 0 && /* OK? */ msglev < 0) /* And debuggery? */ /* (CheckBanks() returns error if no bank is mounted) */ (void) fprintf(stderr, /* Yes */ "%s ERROR: CheckBanks() returned error %d \n", me, ii); /* Else bank status OK as is */ /* ** Periodically check recording, disk2net, or disk2file ** */ if (((datah == 0 && (devstatus.Recording || ldir.recording)) || /* Recording? */ (datah == 4 && ldir.d2ndoing == 2) || /* Or Disc2net() active? */ (datah == 6 && ldir.d2fdoing == 1)) && /* Or Disc2file() active? */ ++rcount > 9) { /* And rcount about every 10 seconds? */ if (datah == 0) { /* Yes, recording? */ sdir->recpnt = XLRGetLength(dev); /* Yes, record offset, bytes */ if ((error = XLRGetLastError()) == 3 && /* No errors? */ sdir->recpnt <= orpntr) { /* And record pointer incrementing? */ /* Nope, some problem, maybe no recording clock */ (void) errors(); if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s WARNING: Record pointer not incrementing \n", me); (void) strcpy(messg, "Record pointer not incrementing"); error = 1001; /* Probably an error */ } /* Now we also check for recording throttled */ (void) outBoard(GET); /* Update output-board parameters */ if (outb.throt) { /* Throttled? */ /* Yes, some problem, probable data loss */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s WARNING: Recording throttled (can't keep up) \n", me); (void) strcpy(messg, "Recording throttled (can't keep up)"); error = 1003; /* Probably an error */ } orpntr = sdir->recpnt; /* For next time */ } /* End of if recording */ else { /* Disc2net() or Disc2file() active */ if (nowbyte <= orpntr) { /* Yes, Nowbyte incrementing? */ /* Nope, some problem ... */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s WARNING: Current byte not incrementing \n", me); (void) strcpy(messg, "Current byte not incrementing"); error = 1017; /* Probably an error */ } orpntr = nowbyte; /* For next time */ } /* End of else Disc2net() or Disc2file() active */ rcount = 0; /* Reset for next time */ } /* End of if recording, Disc2net(), or Disc2file() ... */ /* ** Poll for playing halted (end of medium or end of scan) ** * * If we should be playing and aren't, we assume that we're halted * for end of medium from Play() or end of scan from ScanPlay() */ if (ldir.doOff && ! ldir.abmode && ! devstatus.Playing) { /* Should we be playing and aren't? */ (void) offPlay(); /* Yes, stop and clean up */ ldir.doOff = FALSE; /* Just once */ } /* ** Periodically check status of playing ** */ if ((ldir.playing || ldir.scanplaying) && ! ldir.delayed && devstatus.Playing && datah == 0 && ++pcount > 9) { /* Playing and pcount about every 10 seconds? */ pinct = XLRGetPlayLength(dev); /* Play increment */ /* (Note this is not a play pointer but instead * an increment since starting playing) */ if ((error = XLRGetLastError()) == 3 && /* Errors? */ pinct <= opinct) { /* Play increment incrementing? */ /* Nope, some problem */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s WARNING: Play pointer not incrementing \n", me); (void) strcpy(messg, "Play pointer not incrementing"); error = 1002; /* Probably an error */ } pcount = 0; opinct = pinct; /* For next time */ } else if (! devstatus.Playing && pcount > 0) { /* Not playing? */ pcount = 0; /* Yes, reset */ opinct = 0L; /* For next time */ } /* ** Try to open DEVI (RS-232 serial port) if it's not already ** */ if (serial && devi < 0) { /* Already open? */ /* * Nope, try to open DEVI serial port * */ /* Find an unused ports[] */ for (nports = 1; nports < MAXPORTS; nports++) /* Each of ports[] */ if (ports[nports] < 0) /* In use? */ break; /* Nope, use this one */ if (nports >= MAXPORTS) { /* OK? */ if (! proom) { /* Nope. Error message already printed? */ (void) fprintf(stderr, "%s WARNING: ports[] array full \n", me); /* Now it is */ proom = TRUE; /* Print this only once */ } continue; /* We can't accept any more socket connections */ } if ((ports[nports] = open(DEVI, O_RDWR | O_NDELAY)) < 0) { /* Errors? */ (void) fprintf(stderr, "%s ERROR: \007 open() on ", me); perror(DEVI); XLRClose(dev); /* See manual notes on XLROpen() */ (void) XLRCardReset(indx); return(-21); /* Error */ } /* This DEVI stuff is here in the forever loop so that we can * retry the open() and so forth if it fails the first time, * but these error returns defeat this. Fix it later. ?? */ /* * Set DEVI baud rate to 4800 * */ if ((k = tcgetattr(ports[nports], &ts)) < 0) { /* Errors? */ (void) fprintf(stderr, "%s ERROR: \007 tcgetattr() on ", me); perror(DEVI); XLRClose(dev); /* See manual notes on XLROpen() */ (void) XLRCardReset(indx); return(-22); /* Error */ } if ((k = cfsetospeed(&ts, B4800)) < 0) { /* Set output speed, OK? */ (void) fprintf(stderr, "%s ERROR: \007 cfsetospeed() on ", me); perror(DEVI); XLRClose(dev); /* See manual notes on XLROpen() */ (void) XLRCardReset(indx); return(-23); /* Error */ } if ((k = cfsetispeed(&ts, B4800)) < 0) { /* Set input speed, OK? */ (void) fprintf(stderr, "%s ERROR: \007 cfsetispeed() on ", me); perror(DEVI); XLRClose(dev); /* See manual notes on XLROpen() */ (void) XLRCardReset(indx); return(-24); /* Error */ } /* (We take all the other defaults) */ /* * Initialize DEVI * */ if ((k = tcsetattr(ports[nports], TCSAFLUSH, &ts)) < 0) { /* Errors? */ (void) fprintf(stderr, "%s ERROR: \007 tcsetattr() on ", me); perror(DEVI); XLRClose(dev); /* See manual notes on XLROpen() */ (void) XLRCardReset(indx); return(-25); /* Error */ } /* * Open DEVI also to read as a stream * */ if ((fports[nports] = fdopen(ports[nports], "r")) == NULL) { /* OK? */ (void) fprintf(stderr, /* Nope */ "%s ERROR: \007 fdopen() on ports[%d] = %d returned %d ", me, nports, ports[nports], k); perror("error"); (void) sprintf(messg, "fdopen() error ports[%d] %d", nports, ports[nports]); error = 1012; (void) close(ports[nports]); /* Error */ ports[nports] = -1; /* Not in use */ proom = FALSE; /* Error, but we try to go on */ } else { /* OK */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DEBUG: Opened RS-232 port %s \n", me, DEVI); devi = nports; /* Now got DEVI */ } } /* End of if serial and devi */ /* ** Accept connections on data socket? ** */ if (datah == 1 && ports[0] >= 0 && strcasecmp(smod[1], "tcp") == 0) { /* Accept tcp connection? */ kk = sizeof(struct sockaddr_in); /* Yes */ if ((sock2 = accept(ports[0], (struct sockaddr *) &socadd, &kk)) < 0) { /* Errors? */ if (errno != EAGAIN) { /* Maybe */ /* No new connection waiting? (This is not an error) */ /* Here we seem to have a real error */ if (msglev < 2) { /* Debuggery? */ (void) fprintf(stderr, "%s ERROR: \007 accept() returned %d ", me, ports[0]); perror("error"); } (void) sprintf(messg, "accept() error ports[%d] %d", 0, ports[0]); error = 1013; /* Error, but we try to go on */ } } else { /* (sock2 >= 0) */ /* Here we have an accept on the data socket */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DEBUG: Got accept() on ports[0] %d, sock2 %d \n", me, ports[0], sock2); (void) close(ports[0]); /* Accept no more connections */ ports[0] = sock2; /* Change descriptor to new connected socket */ /* In these cases, net2out or net2disk, we need to start up the * threads toX() and Xto() */ nowbyte = 0L; /* Just to avoid confusion */ if (pthread_create(&threadtoX, NULL, toX, NULL) != 0) { /* OK? */ if (msglev < 2) { /* Nope, debuggery? */ (void) fprintf(stderr, /* Yes */ "%s ERROR: pthread_create() on toX() returned ", me); perror("error"); /* Error */ } threadtoX = 0xffffffff; (void) strcpy(messg, "Can't pthread_create()"); error = 1020; /* Pthread error, but we try to go on */ } (void) pthread_detach(threadtoX); if (pthread_create(&threadXto, NULL, Xto, NULL) != 0) { /* OK? */ if (msglev < 2) { /* Nope, debuggery? */ (void) fprintf(stderr, /* Yes */ "%s ERROR: pthread_create() on Xto() returned ", me); perror("error"); /* Error */ } threadXto = 0xffffffff; (void) strcpy(messg, "Can't pthread_create()"); error = 1020; /* Pthread error, but we try to go on */ } (void) pthread_detach(threadXto); datah = 2; /* Now connected. This kicks off toX() and Xto() */ } /* End of else soc2 open */ } /* End of if accept tcp connections on data socket */ /* ** Accept connection requests on m5drive socket? ** */ /* Find an unused ports[] */ /* (We start from 2 because ports[0] and ports[1] are special cases) */ for (nports = 2; nports < maxports; nports++) /* Each of ports[] */ if (ports[nports] < 0) /* In use? */ break; /* Nope, use this one */ if (nports >= maxports) { /* OK? */ if (! proom) { /* Nope. Error message already printed? */ if (msglev < 2) /* No. Debuggery? */ (void) fprintf(stderr, "%s WARNING: ports[] array full \n", me); /* Now it is */ proom = TRUE; /* Print this only once */ } continue; /* We can't accept any more socket connections */ } kk = sizeof(struct sockaddr_in); if ((ports[nports] = accept(sock, (struct sockaddr *) &socadd, &kk)) < 0) { /* Errors? */ if (errno == EAGAIN) /* Maybe, no new connection waiting? */ /* Yes, this is not an error */ continue; /* To next while loop forever */ /* Else here we seem to have a real (fatal) error */ (void) fprintf(stderr, "%s ERROR: \007 accept() returned %d ", me, ports[nports]); perror("error"); XLRClose(dev); /* See manual notes on XLROpen() */ (void) XLRCardReset(indx); return(-26); /* Error */ } /* * Here we have a new socket connection in ports[nports] * */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DEBUG: Got accept() on ports[%d] = %d \n", me, nports, ports[nports]); /* ** Allow blocking on this new socket ** */ if ((k = fcntl(ports[nports], F_GETFL)) < 0) { /* Errors? */ if (msglev < 2) { /* Yes. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s ERROR: \007 fcntl() on ports[%d] = %d returned %d ", me, nports, ports[nports], k); perror("error"); } (void) sprintf(messg, "fcntl() error ports[%d] %d", nports, ports[nports]); error = 1014; (void) close(ports[nports]); ports[nports] = -1; /* Not in use */ proom = FALSE; continue; /* Error, but we try to go on */ } if ((k = fcntl(ports[nports], F_SETFL, k & ~ O_NONBLOCK)) < 0) { /* OK? */ if (msglev < 2) { /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s ERROR: \007 fcntl() on ports[%d] = %d returned %d ", me, nports, ports[nports], k); perror("error"); } (void) sprintf(messg, "fcntl() error ports[%d] %d", nports, ports[nports]); error = 1014; (void) close(ports[nports]); ports[nports] = -1; /* Not in use */ proom = FALSE; continue; /* Error, but we try to go on */ } if (msglev < 1) { /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DEBUG: New socket connection, ports[%d] = %d, accepted, \n", me, nports, ports[nports]); /* Presumably socadd now contains some interesting information */ (void) fprintf(stderr, " sin_family %d,", socadd.sin_family); (void) fprintf(stderr, " sin_port %d,", socadd.sin_port); (void) fprintf(stderr, " s_addr ["); for (i = 0; i < 4; i++) { if (i > 0) (void) fprintf(stderr, "."); (void) fprintf(stderr, "%u", uc[i]); } (void) fprintf(stderr, "] \n"); } /* End of if debuggery */ /* * Open this socket also to read as a stream * */ if ((fports[nports] = fdopen(ports[nports], "r")) == NULL) { /* OK? */ if (msglev < 2) { /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s ERROR: \007 fdopen() on ports[%d] = %d returned %d ", me, nports, ports[nports], k); perror("error"); } (void) sprintf(messg, "fdopen() error ports[%d] %d", nports, ports[nports]); error = 1012; (void) close(ports[nports]); /* Error */ ports[nports] = -1; /* Not in use */ proom = FALSE; continue; /* Error, but we try to go on */ } /* Else OK */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DEBUG: Port ports[%d] = %d open also as a stream \n", me, nports, ports[nports]); } /* End of while loop forever */ return(0); /* Not used */ } /* End of main = Mark5A */ int checkDisks() { /* Check disks and get disk info */ static char * masl[] = { "Master", "Slave" }; static char * nok[] = { "Faulty", "OK" }; static int range[] = { 75000, 150000, 300000, 600000, 1200000, 2400000, 4800000, -1 }; /* Defaults for dstats[].range */ /* The SS card has a 15-ns-period clock, so the end of the * first bin (75000) corresponds to 0.001125 second, and each * subsequent bin to twice the one before. Since this is the * time to transfer 65528 (2^16 - 8) bytes, the minimum speed * in the first bin is about 58.25e6 bytes/sec or about * 466e6 baud. Each subsequent bin corresponds to half the * speed of the one before. */ unsigned int kount = 0; /* Initialize count disks */ int slave = FALSE; /* Any slaves? */ int npair = FALSE; /* Any master without a slave? */ int gap = FALSE; /* Gaps in bus sequence? */ int last = -1; /* Last disk found */ unsigned int bus, obus, kbus, ms; int i, j; /* * We need device info first * */ if (XLRGetDeviceInfo(dev, &devinfo) != XLR_SUCCESS) { /* OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s checkDisks() ERROR: \007 XLRGetDeviceInfo() returned error \n", me); (void) errors(); return(-6); /* Error */ } (void) errors(); /* * And bank status * */ if (XLRGetBankStatus(dev, bank, &bkstat) != XLR_SUCCESS) { /* OK? */ /* Nope. (This error occurs if not in bank mode) */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s checkDisks() ERROR: XLRGetBankStatus() %d returned error \n", me, bank); (void) errors(); return(-7); /* Error */ } (void) errors(); /* * Assume disks OK unless FAULTED, ErrorCode, or other problems * */ if (bkstat.MediaStatus == MEDIASTATUS_FAULTED || /* Faulted? */ bkstat.ErrorCode > 0) { /* Or ErrorCode */ if (msglev < 1) { /* Yes. Debuggery? */ if (bkstat.MediaStatus == MEDIASTATUS_FAULTED) /* Faulted? */ (void) fprintf(stderr, /* Yes */ "%s checkDisks() DEBUG: bank %d MEDIASTATUS_FAULTED \n", me, bank); if (bkstat.ErrorCode > 0) /* ErrorCode? */ (void) fprintf(stderr, /* Yes */ "%s checkDisks() DEBUG: bank %d ErrorCode %u ErrorData %u \n", me, bank, bkstat.ErrorCode, bkstat.ErrorData); (void) fprintf(stderr, "%s checkDisks() DEBUG: trying SKIPCHECKDIR \n", me); } (void) errors(); (void) strcpy(messg, "Disks misconfigured or faulty"); error = 1008; /* Set option to skip checking disks */ if (XLRSetOption(dev, SS_OPT_SKIPCHECKDIR) != XLR_SUCCESS && /* OK? */ msglev < 2) /* Nope, debuggery? */ (void) fprintf(stderr, "%s checkDisks() ERROR: \007" /* Yes */ " XLRSetOption() SS_OPT_SKIPCHECKDIR returned error \n", me); /* We try to go on */ (void) errors(); /* End if faulted or ErrorCode */ } else { /* Not known to be faulty */ if (XLRClearOption(dev, SS_OPT_SKIPCHECKDIR) != XLR_SUCCESS && /* OK? */ msglev < 2) /* Nope, debuggery? */ (void) fprintf(stderr, /* Yes */ "%s checkDisks() ERROR: XLRClearOption() returned error \n", me); /* We try to go on */ (void) errors(); } /* * Verify disk mounting * * Rule: "If any drive cable has a slave drive, then all [in-use] cables * must have a slave drive. Connectors on the controller board should be * used in order without gaps starting from connector zero (0)." * (From the SS manual. "Drive cable," and "connector" mean bus.) * Here I'll try to check for this. */ for (j = 0; j < 16; j++) /* Each potential disk */ dinfo[j].Serial[0] = '\0'; /* Default: No such disk */ kbus = 0; /* Initialize count occupied buses */ obus = (unsigned int) -1; /* Initialize previously counted bus number */ for (j = 0; j < 16; j++) { /* Each potential disk again */ bus = j / 2; /* 0 to 7 */ ms = j % 2; /* Assume one master and one slave per bus */ /* (XLR_MASTER_DRIVE = 0, XLR_SLAVE_DRIVE = 1) */ if (XLRGetDriveInfo(dev, bus, ms, dinfo+j) != XLR_SUCCESS) { /* OK? */ (void) XLRGetLastError(); /* No, clear error */ dinfo[j].Serial[0] = '\0'; /* (For later check) */ continue; /* Assume no such disk, to next j */ } if (dinfo[j].Serial[0] == '\0') /* OK? */ continue; /* No, assume no such disk, to next j */ /* OK, here we have a disk */ kount++; /* Kount this disk */ if (bus != obus) { /* Already counted this bus as occupied? */ kbus++; /* Nope, count it */ obus = bus; /* This bus now counted */ } if (msglev < 1) { /* Debuggery? */ (void) fprintf(stderr, "%s checkDisks() DEBUG: Found disk in Bus %d %s, \n" /* Yes */ " Model %s, \n Serial %s, \n Revision %s, \n" " Capacity %d * 512 bytes \n", me, bus, masl[ms], dinfo[j].Model, dinfo[j].Serial, dinfo[j].Revision, dinfo[j].Capacity); if (dinfo[j].SMARTCapable) /* SMART? */ (void) fprintf(stderr, " SMARTState %s \n", nok[dinfo[j].SMARTState]); else /* Not SMART */ (void) fprintf(stderr, " NOT SMARTCapable \n"); } if (ms == XLR_SLAVE_DRIVE) { /* Slave? */ slave = TRUE; /* Yes, at least one slave disk */ if (last != j-1) { /* Master to match? */ if (msglev < 2) /* Nope, error. Debuggery? */ (void) fprintf(stderr, "%s checkDisks() WARNING: " /* Yes */ " Disks are misconfigured (see instructions) or faulty \n", me); /* Each slave must have a master */ (void) errors(); (void) strcpy(messg, "Disks are misconfigured or faulty"); error = 1008; /* Error, but we try to go on */ } } else /* Master */ if (last != j-1) /* Previous pair? */ npair = TRUE; /* Nope, previous master had no slave or skipped pair */ if (last != j-1 && last != j-2) /* Gap? */ gap = TRUE; /* Yes, error */ last = j; /* Last disk found and checked (for next time) */ /* More buses to check? */ if (kbus >= devinfo.NumBuses && ms == XLR_SLAVE_DRIVE) /* More? */ break; /* No, presumably done, out of for j */ } /* End of for j each potential disk */ (void) errors(); /* Now kount, the number of disks counted, should be NumDrives */ if (kount != devinfo.NumDrives && msglev < 2) /* OK? */ (void) fprintf(stderr, /* Nope */ "%s checkDisks() WARNING: NumDrives %d; counted %d disks \n", me, devinfo.NumDrives, kount); /* Nope, warning */ /* Now kbus, the number of buses counted, should be NumBuses */ if (kbus != devinfo.NumBuses && msglev < 2) /* OK? */ (void) fprintf(stderr, /* Nope */ "%s checkDisks() WARNING: NumBuses %d; counted %d buses \n", me, devinfo.NumBuses, kbus); /* Nope, warning */ /* Check for other problems */ if (gap || slave && (npair || last % 2 == 0)) { /* Disk mounting OK? */ if (msglev < 2) /* Nope, debuggery? */ (void) fprintf(stderr, /* Yes */ "%s checkDisks() ERROR: \007 Disks are incorrectly mounted \n" " or faulty; trying SKIPCHECKDIR \n", me); (void) errors(); (void) strcpy(messg, "Disks misconfigured or faulty"); error = 1008; /* Assume a faulty disk, try SKIPCHECKDIR */ if (XLRSetOption(dev, SS_OPT_SKIPCHECKDIR) != XLR_SUCCESS) { /* OK? */ if (msglev < 2) /* Nope, debuggery? */ (void) fprintf(stderr, /* Yes */ "%s checkDisks() ERROR: \007 XLRSetOption() returned error \n", me); (void) errors(); /* Error, but we try to go on */ } } /* End of if disk mounting not OK */ (void) errors(); if (msglev < 1) /* OK, debuggery? */ (void) fprintf(stderr, /* Yes */ "%s checkDisks() DEBUG: Found %d SS disk%s%s \n", me, kount, kount == 1 ? "" : "s", kount > 0 ? "; OK" : ""); if (XLRGetDirectory(dev, &dir) != XLR_SUCCESS) { /* OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s checkDisks() WARNING: XLRGetDirectory() returned error \n", me); (void) errors(); /* Error, but we try to go on */ } else /* Directory OK */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s checkDisks() DEBUG: SS directory Length %Ld, \n" " AppendLength %Ld, %s \n", me, dir.Length, dir.AppendLength, dir.Full ? "#Full#" : "NOT Full"); (void) errors(); if (XLRSetFillData(dev, FILL_PATTERN) != XLR_SUCCESS) { /* Set fill, OK? */ if (msglev < 2) /* Nope, debuggery? */ (void) fprintf(stderr, /* Nope */ "%s checkDisks() ERROR: \007 XLRSetFillData() returned error \n", me); (void) errors(); /* Error, but we try to go on */ } else /* Fill pattern OK */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s checkDisks() DEBUG: Set fill pattern OK \n", me); /* End of initialize and check XLR */ /* * Start collecting drive statistics and set default values * */ if (XLRSetOption(dev, SS_OPT_DRVSTATS) != XLR_SUCCESS) { /* Start collecting drive statistics, OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, "%s checkDisks() ERROR: \007 XLRSetOption() " "drive statistics returned error \n", me); (void) errors(); /* Error, but we try to go on */ } else /* Set drive stats OK */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s checkDisks() DEBUG: XLRSetOption() drive statistics OK \n", me); (void) errors(); for (i = 0; i < XLR_MAXBINS; i++) { /* Each dstats[] */ dstats[i].range = range[i]; /* Set range defaults */ dstats[i].count = 0; /* Clear counts */ } if (XLRSetDriveStats(dev, dstats) != XLR_SUCCESS) { /* Set these, OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s checkDisks() ERROR: \007 XLRSetDriveStats() returned error \n", me); (void) errors(); /* Error, but we try to go on */ } else /* Set drive stats OK */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s checkDisks() DEBUG: XLRSetDriveStats() OK \n", me); (void) errors(); /* End of drive statistics */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s checkDisks() DEBUG: Normal end \n", me); return(0); /* Normal end */ } /* End of checkDisks() */ int readdir() { /* Read user directory (if possible) */ /* Note that readdir() (usually) writes over *sdir. * And note that there are several different directories; * try to keep them straight. */ unsigned long plapnt[2] = { 0, 0 }; /* Convert to/from long long */ unsigned long long * pplapnt = (unsigned long long *) plapnt; int k; UINT len; /* Initialize */ (void) memset(udir, 0, sizeof(udir)); /* Clear udir[] */ /* First try to read the SS user directory. If this works, * then we don't need to try to read the in-line directory */ if (devstatus.Playing || devstatus.Recording) { /* OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, "%s readdir() ERROR: " /* Yes */ " Can't read directory when playing or recording \n", me); return(-2); /* Error, can't read directory */ } if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s readdir() DEBUG: Trying to read SS user directory \n", me); len = XLRGetUserDirLength(dev); (void) errors(); if (len != sizeof(udir) && len != sizeof(struct SDir)) { /* OK length? */ if (msglev < 1) /* Nope, debuggery */ (void) fprintf(stderr, "%s readdir() WARNING: " /* Yes */ " Can't read SS user directory, trying inline \n", me); } else if ((len == sizeof(udir) && /* OK length? */ XLRGetUserDir(dev, sizeof(udir), 0, (void *) udir) != XLR_SUCCESS) || /* Read OK? */ (len == sizeof(struct SDir) && /* OK length? */ XLRGetUserDir(dev, sizeof(struct SDir), 0, (void *) sdir) != XLR_SUCCESS)) { /* Read OK? */ if (msglev < 1) /* Nope, debuggery */ (void) fprintf(stderr, "%s readdir() WARNING: " /* Yes */ " XLRGetUserDir() returned error, trying inline \n", me); (void) errors(); } else { /* That seems OK, so we ignore inline directory, if any */ /* Sanity checks */ (void) errors(); if (sdir->nscans < 0 || sdir->nscans > MAXSCANS || sdir->n < 0 || sdir->n >= MAXSCANS) { /* OK? */ sdir->nscans = 0; /* Nope, maybe read data, not directory */ sdir->scanName[0][0] = '\0'; sdir->start[0] = 0L; sdir->length[0] = 0L; sdir->n = 0; sdir->recpnt = 0L; endbyte = startbyte = sdir->plapnt = 0L; if (msglev < 2) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s readdir() ERROR: Directory damaged and unusable \n", me); (void) lseek(dirf, 0, SEEK_SET); /* Rewind dirf */ if ((k = write(dirf, (void *) sdir, sizeof(struct SDir))) != sizeof(struct SDir)) { /* Write sdir to file DIR, OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s readdir() WARNING: write() returned %d on file ", me, k); perror(DIR); /* Error, but we try to go on */ } return(-3); /* Error, maybe read data, not directory */ } if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s readdir() DEBUG: XLRGetUserDir() OK \n", me); sdir->plapnt = 0L; /* Reset play pointer */ /* Copy directory to DIR */ (void) lseek(dirf, 0, SEEK_SET); /* Rewind dirf */ if ((k = write(dirf, (void *) sdir, sizeof(struct SDir))) != sizeof(struct SDir)) { /* Write sdir to file DIR, OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s readdir() WARNING: write() returned %d on file ", me, k); perror(DIR); /* Error, but we try to go on */ } if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s readdir() DEBUG: Directory read OK, nscans %d, recpnt %Ld \n", me, sdir->nscans, sdir->recpnt); return(0); /* Probably OK--normal end */ } /* Else try to read the SS in-line directory. * We need to check dir.Length and dir.AppendLength */ if (XLRGetDirectory(dev, &dir) != XLR_SUCCESS) { /* OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s readdir() WARNING: XLRGetDirectory() returned error \n", me); (void) errors(); /* Error, but we try to go on */ } (void) errors(); /* Check: AppendLength equal and recorded data longer than sdir? */ if (dir.AppendLength != sizeof(struct SDir) || dir.Length < sizeof(struct SDir)) { /* Directory OK? */ if (msglev > -1 || dir.Length < dir.AppendLength || /* Nope */ dir.AppendLength < sizeof(struct SDir)) { /* How desperate are we? */ sdir->nscans = 0; /* Assume no directory; clear it */ sdir->n = 0; sdir->recpnt = 0; sdir->plapnt = 0; (void) lseek(dirf, 0, SEEK_SET); /* Rewind dirf */ if ((k = write(dirf, (void *) sdir, sizeof(struct SDir))) != sizeof(struct SDir)) { /* Write sdir to file DIR, OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s readdir() WARNING: write() returned %d on file ", me, k); perror(DIR); /* Error, but we try to go on */ } if (msglev < 2) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s readdir() WARNING: No directory available \n", me); return(-4); /* Error, no directory */ } else /* We're desperate! */ (void) fprintf(stderr, "%s readdir() WARNING: Desperation reading directory \n", me); } /* End of if directory OK */ /* Set up to read directory from the end of the recorded data */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s readdir() DEBUG: Trying to read inline directory \n", me); *pplapnt = dir.Length - sizeof(struct SDir); plapnt[0] &= 0xfffffff8; /* Now 8-byte aligned */ readdesc.AddrHi = plapnt[1]; readdesc.AddrLo = plapnt[0]; readdesc.XferLength = sizeof(struct SDir); ; readdesc.BufferAddr = (unsigned long *) sdir; (void) XLRRead(dev, &readdesc); /* ?? First read usually fails ?? */ (void) errors(); if (XLRRead(dev, &readdesc) != XLR_SUCCESS) { /* Read into sdir, OK? */ sdir->nscans = 0; /* Nope, can't read directory */ sdir->n = 0; sdir->recpnt = 0L; endbyte = startbyte = sdir->plapnt = 0L; sdir->scanName[0][0] = '\0'; sdir->start[0] = 0L; sdir->length[0] = 0L; (void) lseek(dirf, 0, SEEK_SET); /* Rewind dirf */ if ((k = write(dirf, (void *) sdir, sizeof(struct SDir))) != sizeof(struct SDir)) { /* Write sdir to file DIR, OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s readdir() WARNING: write() returned %d on file ", me, k); perror(DIR); /* Error, but we try to go on */ } if (msglev < 2) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s readdir() ERROR: XLRRead() returned error \n", me); (void) errors(); if (msglev < 2) /* More debuggery? */ (void) fprintf(stderr, /* Yes */ "%s readdir() ERROR: Can't read directory \n", me); return(-5); /* Error, can't XLRRead() directory */ } /* Why is a stop necessary? */ if (XLRStop(dev) != XLR_SUCCESS) /* Stop, OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s readdir() WARNING: XLRStop() returned error \n", me); /* We try to go on */ (void) errors(); /* Sanity checks */ if (sdir->nscans < 0 || sdir->nscans >= MAXSCANS || sdir->n < 0 || sdir->n >= MAXSCANS) { /* OK? */ sdir->nscans = 0; /* Nope, presumably read data, not directory */ sdir->n = 0; sdir->recpnt = 0L; endbyte = startbyte = sdir->plapnt = 0L; sdir->scanName[0][0] = '\0'; sdir->start[0] = 0L; sdir->length[0] = 0L; if (msglev < 2) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s readdir() ERROR: Directory damaged and unusable \n", me); (void) lseek(dirf, 0, SEEK_SET); /* Rewind dirf */ if ((k = write(dirf, (void *) sdir, sizeof(struct SDir))) != sizeof(struct SDir)) { /* Write sdir to file DIR, OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s readdir() WARNING: write() returned %d on file ", me, k); perror(DIR); /* Error, but we try to go on */ } return(-6); /* Error, presumably read data, not directory */ } /* Else inline directory seems to be OK, copy DIR */ sdir->plapnt = 0L; /* Reset play pointer */ (void) lseek(dirf, 0, SEEK_SET); /* Rewind dirf */ if ((k = write(dirf, (void *) sdir, sizeof(struct SDir))) != sizeof(struct SDir)) { /* Write sdir to file DIR, OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s readdir() WARNING: write() returned %d on file ", me, k); perror(DIR); /* Error, but we try to go on */ } (void) errors(); if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s readdir() DEBUG: Directory read OK \n", me); return(0); /* Probably OK--normal end */ } /* End of readdir() */ int writedir() { /* Write current version of directory to SS disks */ int i, k; /* Write directory to file DIR first (so we'll have this copy even * if the write to SS disks fails because of end of medium) */ (void) lseek(dirf, 0, SEEK_SET); /* Rewind dirf */ if ((k = write(dirf, (void *) sdir, sizeof(struct SDir))) != sizeof(struct SDir)) { /* Write sdir to file DIR, OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s writedir() WARNING: write() returned %d on file ", me, k); perror(DIR); /* Error, but we try to go on */ } /* Write directory and Vsn to SS user directory next (so we'll have this * copy even if the write to SS disks fails because of end of medium) */ if (XLRGetLabel(dev, pvsn->vsn) != XLR_SUCCESS) { /* Get VSN, OK? */ if (msglev < 1) /* No. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s writedir() ERROR: XLRGetLabel() returned error \n", me); (void) errors(); /* We try to go on */ } for (i = 0; i < 8; i++) /* Fill out pvsn->Serial[] */ (void) strncpy(pvsn->dinfo[i].Serial, dinfo[i].Serial, XLR_MAX_DRIVESERIAL); if ((k = XLRSetUserDir(dev, (void *) udir, sizeof(udir))) != XLR_SUCCESS) { /* OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s writedir() WARNING: XLRSetUserDir() returned error \n", me); (void) errors(); /* Error, but we try to go on */ } else if (msglev < 1) /* Debuggery */ (void) fprintf(stderr, /* Yes */ "%s writedir() DEBUG: XLRSetUserDir() written \n", me); if (msglev < 1) { /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s writedir() DEBUG: Length %Ld \n", me, XLRGetLength(dev)); (void) errors(); } ///* Now try to write inline directory to SS disks */ //if (XLRAppend(dev) != XLR_SUCCESS) { /* Record, OK? */ // if (msglev < 2) /* Nope. Debuggery? */ // (void) fprintf(stderr, /* Yes */ // "%s writedir() WARNING: XLRAppend() returned error \n", me); // (void) errors(); // return(-1); /* Error */ } //if (XLRWriteData(dev, (void *) sdir, sizeof(struct SDir)) != XLR_SUCCESS) { // /* Write directory to SS disks, OK? */ // if (msglev < 2) /* Nope, debbuggery? */ // (void) fprintf(stderr, /* Yes */ // "%s writedir() WARNING: XLRWriteData() returned error \n", me); // (void) errors(); // return(-2); /* Error */ } //if (msglev < 1) /* Debuggery? */ // (void) fprintf(stderr, /* Yes */ // "%s writedir() DEBUG: Directory written OK \n", me); //if (XLRStop(dev) != XLR_SUCCESS) { /* Stop, OK? */ // if (msglev < 2) /* Nope. Debuggery? */ // (void) fprintf(stderr, /* Yes */ // "%s writedir() WARNING: XLRStop() returned error \n", me); // (void) errors(); // return(-3); /* Error */ } (void) errors(); orpntr = 0L; /* Reset old value of record pointer */ return(0); /* Normal end */ } /* End of writedir() */ int mksock(char * service, char * machine, int datahh) { /* Make a socket */ /* datahh = 0 Normal command & query socket, not data * 1 Receive-data socket * 2 Send-data socket */ /* (machine is used for datahh 2 only) */ int sock, i, k, type, tof, on; FILE * fsock; /* Socket also as a stream */ struct servent * set; /* From getservbyname() */ struct sockaddr_in socaddin; /* For bind() socket info */ struct hostent * hostinfo; /* From gethostbyname() */ unsigned char * uc; /* To debug print IP address */ unsigned int rcvbuf, rcvlowat, sndbuf, sndlowat; /* For getsockopt() */ /* (Don't confuse rcvbuf with rcvbufs or sndbuf with sndbufs) */ unsigned int mtu, lmss; /* MTU and local version of MSS */ socklen_t optlen; /* ** Create a socket ** */ if (strcasecmp(smod[datahh], "tcp") == 0) /* tcp? */ type = SOCK_STREAM; /* Yes */ else if (strcasecmp(smod[datahh], "udp") == 0) /* udp? */ type = SOCK_DGRAM; /* Yes */ else { /* Neither tcp nor udp is an error */ (void) fprintf(stderr, /* Yes */ "%s mksock() ERROR: Can't do type %s \n", me, smod[datahh]); return(-1); /* Error */ } if ((sock = socket(PF_INET, type, 0)) < 0) { /* Make socket, OK? */ (void) fprintf(stderr, /* Nope */ "%s mksock() ERROR: \007 socket() returned %d ", me, sock); perror("error"); return(-2); /* Error */ } /* If tcp, then we set keep-alive in case a firewall needs it */ if (type == SOCK_STREAM) { /* tcp? */ tof = TRUE; /* Yes */ if(setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &tof, sizeof(int)) < 0) { /* Set keep-alive, OK? */ if (msglev < 2) { /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s mksock() WARNING: setsockopt() SO_KEEPALIVE returned ", me); perror("error"); /* Error, but we try to go on */ } } } /* SO_SNDBUF sets or gets the maximum socket send buffer in bytes. * The default value is set by the wmem_default sysctl, and the * maximum allowed value is set by the wmem_max sysctl. * SO_RCVBUF sets or gets the maximum socket receive buffer in bytes. * The default value is set by the rmem_default sysctl, and the * maximum allowed value is set by the rmem_max sysctl. * SO_RCVLOWAT and SO_SNDLOWAT specify the minimum number of bytes * in the buffer until the socket layer will pass the data to the * protocol (SO_SNDLOWAT) or the user on receiving (SO_RCVLOWAT). * These two values are not changeable in Linux and their argument * size is always fixed to 1 byte. getsockopt is able to read them; * setsockopt will always return ENOPROTOOPT (protected option). */ if (datahh == 1 && rcvbufs > 0) { /* Change SO_RCVBUF? */ if(setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void *) &rcvbufs, sizeof(rcvbufs)) < 0) { /* Yes, socket receive-buffer size, OK? */ if (msglev < 2) { /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s mksock() WARNING: setsockopt() SO_RCVBUF %d returned ", me, rcvbufs); perror("error"); } /* Error, but we try to go on */ } else if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s mksock() DEBUG: setsockopt() SO_RCVBUF to %d \n", me, rcvbufs); } /* End of if change SO_RCVBUF */ if (datahh == 2 && sndbufs > 0) { /* Change SO_SNDBUF? */ if(setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void *) &sndbufs, sizeof(sndbufs)) < 0) { /* Yes, socket send-buffer size, OK? */ if (msglev < 2) { /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s mksock() WARNING: setsockopt() SO_SNDBUF %d returned ", me, sndbufs); perror("error"); } /* Error, but we try to go on */ } else if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s mksock() DEBUG: setsockopt() SO_SNDBUF to %d \n", me, sndbufs); } /* End of if change SO_SNDBUF */ if (msglev < 1) { /* Debuggery? */ optlen = sizeof(unsigned int); /* Yes */ (void) getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void *) &rcvbuf, &optlen); /* Socket receive-buffer size */ optlen = sizeof(unsigned int); (void) getsockopt(sock, SOL_SOCKET, SO_RCVLOWAT, (void *) &rcvlowat, &optlen); /* Socket receive-buffer low mark */ optlen = sizeof(unsigned int); (void) getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void *) &sndbuf, &optlen); /* Socket send-buffer size */ optlen = sizeof(unsigned int); (void) getsockopt(sock, SOL_SOCKET, SO_SNDLOWAT, (void *) &sndlowat, &optlen); /* Socket send-buffer low mark */ (void) fprintf(stderr, "%s mksock() DEBUG: sock %d, datahh %d, \n" " rcvbuf %u, rcvlowat %u, sndbuf %u, \n" " sndlowat %u, socbuf %u, nbuf %u \n", me, sock, datahh, rcvbuf, rcvlowat, sndbuf, sndlowat, socbuf, nbuf); } /* End of if debuggery */ /* ** Get service number for socket service ** */ if ((set = getservbyname(service, smod[datahh])) == NULL) { /* Errors? */ (void) fprintf(stderr, /* Yes */ "%s ERROR: \007 %s %s not found in /etc/services \n", me, service, smod[datahh]); (void) close(sock); return(-3); /* Error */ } socaddin.sin_port = set->s_port; /* Port service's number */ if (msglev < 1) /* Debuggery? */ /* Yes. For Intelendian, we need to swap bytes in set->s_port */ (void) fprintf(stderr, "%s mksock() DEBUG: %s %s port is %d \n", me, service, smod[datahh], ntohs(socaddin.sin_port)); socaddin.sin_family = PF_INET; /* To agree with socket() above */ socaddin.sin_addr.s_addr = INADDR_ANY; /* From any network address */ if (datahh < 2) { /* Receive connection(s) on this socket? */ /* ** Yes, prevent blocking on accept() ** */ if ((k = fcntl(sock, F_SETFL, O_NONBLOCK)) < 0) { /* Errors? */ (void) fprintf(stderr, /* Yes */ "%s mksock() ERROR: \007 fcntl() returned %d ", me, k); perror("error"); (void) close(sock); return(-4); /* Error */ } /* ** Allow reuse of the local socket address in bind() ** */ on = TRUE; if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on)) < 0) { /* OK? */ if (msglev < 2) { /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s mksock() WARNING: setsockopt() SO_REUSEADDR returned ", me); perror("error"); } /* Error, but we try to go on */ } /* ** Bind this socket to service ** */ if ((k = bind(sock, (struct sockaddr *) &socaddin, sizeof(struct sockaddr_in))) < 0) { /* OK? */ (void) fprintf(stderr, "%s ERROR: \007 bind() returned %d ", me, k); perror("error"); (void) close(sock); return(-5); /* Error */ } /* ** Listen for connections on tcp socket ** */ if (type == SOCK_STREAM && (k = listen(sock, 3)) < 0) { /* Errors? */ (void) fprintf(stderr, "%s ERROR: \007 listen() returned %d ", me, k); perror("error"); (void) close(sock); return(-6); /* Error */ } return(sock); /* Normal end for a receive socket */ } /* Following is for a connect and send-data socket */ /* * Find IP address of machine to connect to * */ if ((hostinfo = gethostbyname(machine)) == NULL) { /* Get IP, OK? */ (void) fprintf(stderr, /* Nope */ "%s mksock() ERROR: \007 gethostbyname() on %s returned NULL ", me, machine); herror("error"); /* Error */ switch (h_errno) { /* Which error? */ case HOST_NOT_FOUND : (void) fprintf(stderr, "%s mksock() ERROR: host %s not found \n", me, machine); break; case TRY_AGAIN : (void) fprintf(stderr, "%s mksock() ERROR: no response, try again later \n", me); break; case NO_RECOVERY : (void) fprintf(stderr, "%s mksock() ERROR: unknown error, not recoverable \n", me); break; case NO_ADDRESS : /* = NO_DATA */ (void) fprintf(stderr, "%s mksock() ERROR: No Internet address available \n", me); } /* End of switch */ (void) close(sock); return(-7); /* Error */ } /* End of if hostinfo NULL */ if (hostinfo->h_addr_list[0] == NULL) { /* First IP address OK? */ (void) fprintf(stderr, /* Nope */ "%s mksock() ERROR: \007 gethostbyname() on %s " "returned NULL IP address \n", me, machine); (void) close(sock); return(-8); /* Error */ } if (msglev < 1) { /* Debuggery? */ uc = (unsigned char *) hostinfo->h_addr_list[0]; /* Yes */ (void) fprintf(stderr, "%s mksock() DEBUG: IP address of %s is [", me, machine); for (i = 0; i < hostinfo->h_length; i++) { if (i > 0) (void) printf("."); (void) printf("%u", uc[i]); } (void) printf("] \n"); } socaddin.sin_addr.s_addr = *((unsigned long *) hostinfo->h_addr_list[0]); /* Use first address */ /* * Connect this socket to service on machine * */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s mksock() DEBUG: Trying to connect() \n", me); if (connect(sock, (const struct sockaddr *) &socaddin, sizeof(struct sockaddr_in)) < 0) { /* Connect, errors? */ (void) fprintf(stderr, /* Yes */ "%s mksock() ERROR: \007 connect() returned ", me); perror("error"); (void) close(sock); return(-9); /* Error */ } if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s mksock() DEBUG: Got a connect() on sock %d \n", me, sock); if(type == SOCK_DGRAM) { /* udp? */ /* Yes, so get MTU (see man ip) */ optlen = sizeof(unsigned int); if (getsockopt(sock, SOL_IP, IP_MTU, (void *) &mtu, &optlen) < 0) { /* Get MTU OK? */ (void) fprintf(stderr, /* No */ "%s mksock() ERROR: \007 getsockopt() returned ", me); perror("error"); (void) close(sock); return(-10); /* Error */ } /* Else OK udp * Each UDP datagram can be fragmented into frames whose size is given * by the maximum transmission unit (mtu) minus one or two headers. * The IP header, which is in every fragment, is 20 bytes (actually * sizeof(struct iphdr) from /usr/include/linux/ip.h), and the * UDP header, which is only in the first fragment, is 8 bytes * (actually sizeof(struct udphdr) from /usr/include/linux/udp.h). * So, if fragmentation, then the first fragment has MTU-28 data bytes, * and all subsequent fragments each have MTU-20 data bytes. */ mss = mtu - 28; /* MSS (in global, but probably not used elsewhere) */ lmss = mtu - 20; /* Local MSS for fragments */ /* mtu is typically 1500, mss 1472, and lmss 1480 bytes. * The following is empirical, but see "big datagram size" in man ip. * We adjust udpbs so that each fragment except the last is full. */ if (socbuf > 65536) /* Use socbuf? */ udpbs = 55000 / lmss * lmss - 8; /* No, presumably too big */ /* (This default typically udpbs = 54752 bytes in 37 fragments) */ else /* Use socbuf */ udpbs = (socbuf + 8) / lmss * lmss - 8; /* For full fragments */ /* We cannot assume mss and lmss are each an integer times 8 bytes, so: */ udpbs -= udpbs % 8; if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s mksock() DEBUG: MTU %d, mss %d, lmss %d, udpbs %d \n", me, mtu, mss, lmss, udpbs); } /* End of if udp */ /* * Open socket also as a stream * */ /* (?? This may not be needed ??) */ if ((fsock = fdopen(sock, "a")) == NULL) { /* OK? */ (void) fprintf(stderr, /* Nope */ "%s mksock() ERROR: \007 fdopen() on sock %d returned ", me, sock); perror("error"); (void) close(sock); /* Error */ return(-11); /* Error */ } if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s mksock() DEBUG: Socket %d open also as a stream \n", me, sock); /* OK, transfer to global array */ ports[0] = sock; fports[0] = fsock; return(sock); /* Normal end for case datahh = 2 */ } /* End of mksock() */ int CheckBanks() { /* Check bank status, correct if necessary */ /* (Note that CheckBanks() is called from within polling loop) */ UINT i; int k, obmode; char * ptc; /* Scratch */ /* Remember old value of bank mode */ obmode = ldir.bmode; /* Update device info */ if (XLRGetDeviceInfo(dev, &devinfo) != XLR_SUCCESS) { /* OK? */ if (msglev < 1) /* Nope. Debuggery? */ (void) fprintf(stderr, "%s CheckBanks() ERROR: \007 " /* Yes */ "XLRGetDeviceInfo() returned error \n", me); (void) errors(); /* We try to go on */ } (void) errors(); /* * Check status of both banks (assume only one can be Selected) * */ for (i = 0; i < 2; i++) { /* Each bank */ if (XLRGetBankStatus(dev, i, &bkstat) != XLR_SUCCESS) { /* OK? */ /* (This error occurs if not in bank mode) */ if (msglev < 1) /* Nope, debuggery? */ (void) fprintf(stderr, /* Yes */ "%s CheckBanks() ERROR: XLRGetBankStatus() %d returned error \n", me, i); (void) errors(); error = 3; /* Forget this error */ ldir.bmode = FALSE; sdir->nscans = 0; return(-1); /* Error and end of if not OK */ } if (bkstat.State == STATE_READY && bkstat.Selected) /* This bank? */ ldir.bmode = TRUE; /* Yes */ else /* Not this bank */ continue; /* Try another bank */ /* So bank i is Selected, but has this changed? */ if (i == bank && obmode) /* Bank OK? */ break; /* Yes, OK, ignore the other bank, out of for i */ /* ** Else newly bank mode or not the right bank ** * * We need to change everything over to the new bank */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s CheckBanks() DEBUG: bank %d, i %d, obmode %d \n", me, bank, i, obmode); bank = i; /* This bank is now active */ if (XLRGetDeviceStatus(dev, &devstatus) != XLR_SUCCESS) { /* Status OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s CheckBanks() ERROR: XLRGetDeviceStatus() returned error \n", me); (void) errors(); return(-2); /* Error */ } (void) errors(); if ((k = checkDisks()) < 0) { /* Check disks (also sets dinfo[]), OK? */ if (msglev < 2) /* Nope, debuggery? */ (void) fprintf(stderr, /* Yes */ "%s CheckBanks() ERROR: checkDisks() returned error %d \n", me, k); (void) errors(); (void) strcpy(messg, "Disks misconfigured or faulty"); error = 1008; /* checkDisks() returned error */ /* Formerly return(k) (Error); now we try to go on */ } /* End of if checkDisks() */ if (readdir() < 0) { /* Read a directory from the new disk(s), OK? */ if (msglev < 2) /* Nope, debuggery? */ (void) fprintf(stderr, "%s CheckBanks() WARNING: " /* Yes */ " readdir() reports directory flawed or missing \n", me); (void) strcpy(messg, "User directory flawed or missing"); error = 1018; /* We try to go on */ } (void) errors(); /* Disable automatic bank switching (because bank changed) */ if (XLRSetBankMode(dev, SS_BANKMODE_NORMAL) != XLR_SUCCESS) { /* OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s CheckBanks() ERROR: XLRSetBankMode() returned error \n", me); (void) errors(); (void) strcpy(messg, "Can't change auto-bank-switch mode"); error = 1019; /* We try to go on */ } /* End of if BankMode to normal not OK */ (void) errors(); /* Else OK, back to defaults: */ ldir.abmode = FALSE; /* Either way (?) */ drive = 0; /* Reset drive number for get_stats */ ldir.scanplaying = ldir.playing = FALSE; sdir->n = 0; /* Reset pointer to first scan (if any) */ /* Reset stuff in ldir */ ldir.filenam[0] = '\0'; /* Reset Set_scan() default */ /* (May be changed below) */ ldir.scann = 0; /* Reset last scan found in Set_scan() */ ldir.reclstn = -1; /* Last scan recorded by Record() */ ldir.f2dlstn = -1; /* Last scan created by File2disc() */ ldir.n2dlstn = -1; /* Last scan created by Net2disc() */ /* Resets from sdir-> */ if (sdir->nscans > 0) { /* Any scans? */ startbyte = sdir->plapnt = sdir->start[sdir->n]; /* Yes, start of scan */ endbyte = sdir->start[sdir->n] + sdir->length[sdir->n]; /* End */ /* We also set the (default) filename to the scan label */ (void) strncpy(ldir.filenam, sdir->scanName[sdir->n], MAXNAME); /* But we delete experiment name, source name, and station code * as separated by spaces (' '), if any. This is for legacy only */ if ((ptc = strchr(ldir.filenam, ' ')) != NULL) /* Find ' ', if any */ ptc[0] = '\0'; /* Yes, end filenam here */ /* We append ".mk5" unless there is already a filename suffix */ if (strchr(ldir.filenam, '.') == NULL) /* Already got '.'? */ (void) strncat(ldir.filenam, ".mk5", /* No, add suffix */ MAXNAME - 1 - strlen(ldir.filenam)); if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s CheckBanks() DEBUG: Set filenam to \"%s\" \n", me, ldir.filenam); } else { /* No scans */ startbyte = sdir->plapnt = sdir->start[sdir->n] = 0; /* Start of scan */ endbyte = sdir->length[sdir->n] = 0; /* End */ } sdir->recpnt = XLRGetLength(dev); /* Update record offset, bytes */ (void) errors(); orpntr = 0L; /* Reset old value of record pointer */ rcount = 0; /* And counter */ /* Check: Was this disk pack recorded off the end (bank_switch=on) * as signified by having a scanName with an appended '+' * in the scan after the last (i.e., numbered off the end)? */ k = strlen(sdir->scanName[sdir->nscans]); /* Number of chars in scanName[] */ if (k > 1 && strrchr(sdir->scanName[sdir->nscans], '+') == sdir->scanName[sdir->nscans] + k - 1) { /* Legal scanName[] with '+' at the end? */ if (msglev < 1) /* Yes, debuggery? */ (void) fprintf(stderr, /* Yes */ "%s CheckBanks() DEBUG: Found + ending scan %d %s \n", me, sdir->nscans + 1, sdir->scanName[sdir->nscans]); sdir->recpnt = XLRGetLength(dev); /* Update record offset, bytes */ (void) errors(); sdir->length[sdir->nscans] = sdir->recpnt - sdir->start[sdir->nscans]; /* Correct length back a few bytes from TotalCapacity */ sdir->nscans++; /* Bump nscans to include the added + scan */ sdir->scanName[sdir->nscans][0] = '\0'; /* Clear the new next scan */ sdir->n = 0; /* Initialize scan directory */ (void) writedir(); /* Save copy of modified sdir on SS disks */ (void) errors(); } /* End of if '+' at the end of scanName[] */ break; /* Ignore the other bank */ } /* End of for each bank */ if (i > 1) { /* Bank mode? */ ldir.bmode = FALSE; /* Apparently not */ sdir->nscans = 0; } (void) errors(); if (msglev < 0) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s CheckBanks() DEBUG: bmode %d, bank %u, nscans %d; Normal end \n", me, ldir.bmode, bank, sdir->nscans); return(0); /* Normal end */ } /* End of CheckBanks() */ int setrot() { /* Set up a socket to receive ROT broadcasts */ struct sockaddr_in sadd; /* For bind() */ int k; /* * If ports[1] is already open, then we do nothing * */ if (ports[1] >= 0) /* Open */ return(0); /* Yes */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s setrot() DEBUG: Opening socket for ROT broadcasts \n", me); /* * Create a socket * */ if ((ports[1] = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { /* Errors? */ (void) fprintf(stderr, /* Yes */ "%s ERROR: \007 socket() returned %d ", me, ports[1]); perror("error"); return(-1); /* Error */ } if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, "%s setrot() DEBUG: ports[1] is %d \n", /* Yes */ me, ports[1]); /* * Bind it to rotman's port * */ sadd.sin_family = PF_INET; sadd.sin_port = htons(7010); /* See RJC's rotman */ sadd.sin_addr.s_addr = INADDR_ANY; if ((k = bind(ports[1], (struct sockaddr *) &sadd, sizeof(struct sockaddr_in))) < 0) { /* OK? */ (void) fprintf(stderr, "%s ERROR: \007 bind() returned %d ", me, k); perror("error"); /* Nope */ return(-2); /* Error */ } if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, "%s setrot() DEBUG: bind() is OK \n", me); return(0); /* Normal end */ } /* End of setrot() */ int getrot() { /* Process ROT broadcast */ static unsigned long taskid = 0; /* Local copy of task_id */ struct timeval tv; /* For gettimeofday() */ struct tm * tmpo; /* From gmtime() */ char buf[sizeof(struct Set_Rot)+64]; struct Set_Rot * sr = (struct Set_Rot *) buf; int flags = 0; /* Or MSGWAITALL? */ int k, len; unsigned long ul; /* Scratch */ double dd; /* Scratch */ /* * First, what time is it? * */ if ((k = gettimeofday(&tv, NULL)) < 0) { /* Errors? */ (void) fprintf(stderr, /* Yes */ "%s getrot() ERROR: \007 gettimeofday() %d ", me, k); perror("error"); return(-1); /* Error */ } /* Else OK, we'll use this time below */ /* * Try to read a ROT-broadcast message * */ /* (We already know that some message is waiting on ports[1]) */ len = recv(ports[1], (void *) buf, sizeof(buf), flags); /* Get a message */ if (len != sizeof(struct Set_Rot)) /* This one? */ return(1); /* Nope, wrong message; try another */ /* Check: For this task_id? */ ul = lend(sr->su_array); /* Actually task_id */ if (ul != task_id) /* OK? */ return(2); /* Nope, this ROT broadcast does not apply to us */ /* Have we already received a valid ROT broadcast for this task_id? */ if (task_id == taskid) { /* Same task_id? */ /* Not OK; use only the first ROT broadcast for each task_id */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s getrot() DEBUG: Extra ROT broadcast ignored \n", me); return(3); /* Normal return for this case */ /* This return(3) code was added for Arpad and JIVE: They have multiple * ROT broadcasts for each task_id, and we ignore all but the first */ } /* End of if same task_id */ /* Else OK, get ROT rate */ rot_rate = dend(sr->rot_rate); /* ROT increment per systick in sysclks */ if (msglev < 2) { /* Debuggery? */ dd = rot_rate / 32.0e6; /* Should be speed_up (int) as a double */ if (fabs((int) dd - dd) > 0.00001) /* OK? */ (void) fprintf(stderr, /* Nope */ "%s getrot() WARNING: rot_rate is %.0f, should be 32e6 \n", me, rot_rate); /* We try to go on */ } /* Get and check ROT */ dd = dend(sr->rot); /* ROT, actually a double */ if (dd <= 0.0) { /* ROT OK? */ rot = 0.0; /* Nope. This may be the setup message */ tvROT.tv_sec = 0; tvROT.tv_usec = 0; if (msglev < 1) { /* Debuggery? */ tmpo = localtime(&tv.tv_sec); /* Yes, get EST or EDT */ (void) fprintf(stderr, "%s getrot() DEBUG: Received ROT %.0f at " "%4d%03d%02d:%02d:%02d %s \n", me, dd, 1900+tmpo->tm_year, 1+tmpo->tm_yday, tmpo->tm_hour, tmpo->tm_min, tmpo->tm_sec, tmpo->tm_zone); } /* (Note that we do not set taskid in this case) */ return(4); /* Normal end for this special case */ } /* Else OK; save this ROT and the associated tv time */ rot = dd; tvROT.tv_sec = tv.tv_sec; /* Time to which ROT applies */ // tvROT.tv_usec = tv.tv_usec + 624000; // tvROT.tv_usec = tv.tv_usec + 619100; // tvROT.tv_usec = tv.tv_usec + 458000; // tvROT.tv_usec = tv.tv_usec + 388427; // tvROT.tv_usec = tv.tv_usec + 980000; /* After ROTTOT offset in suman */ // tvROT.tv_usec = tv.tv_usec + 940000; // tvROT.tv_usec = tv.tv_usec + 955000; /* A correction about 17 msec was calculated from lots of examples of * processing with 64 tracks and 16-MHz sample rate (which averaged * to about -2209000 bytes); 2004 May 3 */ tvROT.tv_usec = tv.tv_usec + 972000; /* (The ROT in the message applies to the following one-second tick. * This is an empirically determined correction, which includes an * approximately 50-msec socket delay and probably also includes * some delays or offsets associated with the logging process) */ taskid = task_id; /* Remember this task_id as a local copy */ /* (This is used to ignore other ROT broadcasts with same task_id) */ if (msglev < 1) { /* Debuggery? */ tmpo = localtime(&tv.tv_sec); /* Yes, get EST or EDT */ (void) fprintf(stderr, "%s getrot() DEBUG: Received ROT %.0f at %4d%03d%02d:%02d:%02d %s \n", me, rot, 1900+tmpo->tm_year, 1+tmpo->tm_yday, tmpo->tm_hour, tmpo->tm_min, tmpo->tm_sec, tmpo->tm_zone); } /* End of if debuggery */ return(0); /* Normal end */ } /* End of getrot() */ /* ** Xto() and toX() are be separate threads, each with a semaphore, ** * ** that, together, process in2net, disk2net, net2out, and net2disk. ** */ void * Xto(void * null) { /* * Process input data transfers for in2net (i.e. read from input * board), disk2net (i.e., read from disk), net2out, and net2disk * (i.e., read from net). See also toX(). * */ extern volatile int datah; static int retrn = 0; /* Return code */ struct timespec wait; /* Wait time */ unsigned long plapnt[2]; /* Convert to/from long long */ unsigned long long * pplapnt = (unsigned long long *) plapnt; unsigned long long fill = ((long long) FILL_PATTERN << 32) + FILL_PATTERN; int index = 0; /* Initialize to first block in FIFO */ int indst = socbuf / 8; /* Step size per index, bytes */ int imax = socbuf / 8; /* socbuf bytes to long longs */ ssize_t lenn; /* Return from recv() */ unsigned long lenl; /* Return from XLRGetFIFOLength() */ struct timeb time1, time2; /* From ftime() */ double dt; /* Duration of timing, seconds */ long long ebytes = 0L; /* Count bytes */ unsigned long long nbyte; /* Local version of nowbyte */ int i, val, val2; int first = TRUE; /* ** Initialize our semaphore ** */ /* Initially no blocks filled */ if (sem_init(&semXto, 0, 0) < 0) { /* OK? */ if (msglev < 2) { /* Nope, error. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s Xto() ERROR: sem_init() returned ", me); perror("error"); retrn = -1; /* sem_init() error */ pthread_exit(&retrn); /* Error */ } } else if (msglev < 1) { /* Debuggery? */ (void) sem_getvalue(&semtoX, &val); /* Other semaphore */ (void) fprintf(stderr, /* Yes */ "%s Xto() DEBUG: Active, threadXto %#lx, semtoX val %d \n", me, threadXto, val); } (void) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); /* Allow cancellation (interrupt) during following nanosleeps */ /* * Wait for "on" * */ while (datah != 2 && datah != 4 && datah != 5) { if (msglev < 0) /* Yes. Debuggery? */ (void) fprintf(stderr, "w"); /* Yes */ pthread_testcancel(); wait.tv_sec = 0; /* Wait awhile */ wait.tv_nsec = 10000000; /* That's 0.01 seconds */ (void) nanosleep(&wait, NULL); /* Wait here */ } /* End of while wait for "on" */ (void) ftime(&time1); /* Initialize start time */ nbyte = nowbyte; /* Initialize local version of nowbyte */ ebytes = 0L; /* Initialize local bytes */ /* ** Loop until done ** */ while (datah > 0 && ports[0] >= 0) { /* Loop */ if (msglev < 1 && ebytes > KOUNT) { /* Debug log timing? */ (void) ftime(&time2); /* Yes, time now */ dt = time2.time + time2.millitm/1000.0 - (time1.time + time1.millitm/1000.0); /* Time since last time1 */ (void) fprintf(stderr, "%s Xto() DEBUG: " /* Yes */ " Transferred %Ld bytes in %.3f seconds at %.3e baud \n", me, ebytes, dt, 8.0*ebytes/dt); (void) ftime(&time1); /* Reinitialize start time */ ebytes = 0L; /* And end bytes */ } /* End of if debug log timing */ if (first && msglev < 1) /* First debuggery? */ (void) fprintf(stderr, "%s Xto() DEBUG: sem_wait() \n", me); /* Yes */ /* * Wait for other semaphore * */ (void) sem_wait(&semtoX); /* Wait for semtoX */ /* (No need for pthread_testcancel() here * because sem_wait() is a cancellation point) */ /* Here we know that the value of the "other" semaphore * (semtoX) was > 0, and this indicates that the next * FIFO block is available for us to write into. But first * initialize this FIFO block to all fill pattern */ for (i = 0; i < imax; i++) /* Each long long in rbuf[index] */ rbuf[index * indst + i] = fill; if (msglev < 0) /* Debuggery? */ (void) fprintf(stderr, "X"); /* Yes */ /* ** Disk2net? ** */ if (datah == 4) { /* OK? */ if (first && msglev < 1) /* Yes, first debuggery? */ (void) fprintf(stderr, /* Yes */ "%s Xto() DEBUG: Start disk2net, nowbyte %Ld \n", me, nowbyte); /* * Read from SS disk * */ *pplapnt = nowbyte; /* Starting at nowbyte */ plapnt[0] &= 0xfffffff8; /* Now 8-byte aligned */ if (strcasecmp(smod[2], "udp") == 0) /* Send udp? */ readdesc.XferLength = MIN(udpbs, endbyte - nowbyte); else /* Not udp, presumably tcp */ readdesc.XferLength = MIN(socbuf, endbyte - nowbyte); readdesc.XferLength &= 0xfffffff8; /* Now 8-byte aligned */ if (first && msglev < 1) /* First debuggery? */ (void) fprintf(stderr, /* Yes */ "%s Xto() DEBUG: Calling XLRReadData() \n", me); /* * Read into rbuf[index*indst], OK? * */ if (XLRReadData(dev, (unsigned long *) (rbuf + index * indst), plapnt[1], plapnt[0], readdesc.XferLength) != XLR_SUCCESS) { if (msglev < 2) /* Not OK. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s Xto() ERROR: XLRReadData() returned error \n", me); (void) errors(); /* Error, but what to do? Maybe just end the transfer */ datah = 3; retrn = -2; /* XLRReadData() error */ pthread_exit(&retrn); /* Error */ } /* Else OK */ if (first && msglev < 1) /* First debuggery? */ (void) fprintf(stderr, /* Yes */ "%s Xto() DEBUG: XLRReadData() OK, XferLength %lu \n", me, readdesc.XferLength); ebytes += readdesc.XferLength; /* Add to local bytes */ nbyte += readdesc.XferLength; /* Add to local nbyte */ /* (nowbyte is bumped in toX()) */ } /* End of if disk2net */ /* ** In2net? ** */ else if (datah == 5) { /* OK? */ if (first && msglev < 1) /* Yes, first debuggery? */ (void) fprintf(stderr, /* Yes */ "%s Xto() DEBUG: Start in2net, nowbyte %Ld \n", me, nowbyte); /* * Read from input board (through SS FIFO) * */ while ((lenl = XLRGetFIFOLength(dev)) < socbuf) { /* Got bytes? */ (void) errors(); /* Not yet enough */ pthread_testcancel(); /* (Otherwise this may become a spin loop */ wait.tv_sec = 0; /* Wait awhile */ wait.tv_nsec = 10000000; /* That's 0.01 seconds */ (void) nanosleep(&wait, NULL); /* Wait here */ } /* * Else OK * */ /* (Now lenl is the number of bytes waiting in the FIFO) */ readdesc.XferLength = MIN(socbuf, lenl); readdesc.XferLength &= 0xfffffff8; /* Now 8-byte aligned */ /* * Read from SS * */ if (first && msglev < 1) /* First debuggery? */ (void) fprintf(stderr, /* Yes */ "%s Xto() DEBUG: Calling XLRReadFifo(), lenl %lu \n", me, lenl); while (XLRReadFifo(dev, (unsigned long *) (rbuf + index * indst), readdesc.XferLength, FALSE) != XLR_SUCCESS) { /* Read to rbuf, OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s Xto() ERROR: XLRReadFifo() returned error \n", me); (void) errors(); /* Error, but what to do? Maybe just try again */ } /* Else OK */ if (first && msglev < 1) /* First debuggery? */ (void) fprintf(stderr, /* Yes */ "%s Xto() DEBUG: XLRReadFifo() OK, XferLength %lu \n", me, readdesc.XferLength); ebytes += readdesc.XferLength; /* Add to local bytes */ nbyte += readdesc.XferLength; /* Add to local nbyte */ /* (nowbyte is bumped in toX()) */ } /* End of else if in2net */ /* ** Net2out or net2disk (read from net)? ** */ else if (datah == 2) { /* OK? */ if (first && msglev < 1) /* Yes, first debuggery? */ (void) fprintf(stderr, /* Yes */ "%s Xto() DEBUG: Start net2out or net2disk, nowbyte %Ld \n", me, nowbyte); /* * If net2out, then check first for SS FIFO almost full * */ if (ldir.n2odoing > 0) /* Net2out? */ while (XLRGetFIFOLength(dev) > 500000000L) { /* Yes, OK to recv()? */ (void) errors(); /* Nope */ pthread_testcancel(); wait.tv_sec = 0; /* Wait awhile */ wait.tv_nsec = 100; /* That's 100 nanoseconds */ (void) nanosleep(&wait, NULL); /* Wait here */ } (void) errors(); /* * OK, then read from ports[0] * */ if (first && msglev < 1) /* First debuggery? */ (void) fprintf(stderr, /* Yes */ "%s Xto() DEBUG: Doing recv() \n", me); lenn = recv(ports[0], rbuf + index * indst, socbuf, MSG_WAITALL); /* * Various other checks * */ if ((unsigned) lenn < socbuf && msglev < 1) /* Short and debuggery? */ (void) fprintf(stderr, /* Yes */ "%s Xto() WARNING: recv() returned %d \n", me, lenn); if (lenn <= 0) { /* End of data or error? */ if (msglev < 1) /* Yes, debuggery? */ (void) fprintf(stderr, /* Yes */ "%s Xto() WARNING: End of data; closing socket \n", me); if (ports[0] >= 0) /* OK to close? */ (void) close(ports[0]); /* Yes */ ports[0] = -1; /* No longer in use */ datah = 0; /* Data socket closed */ ldir.n2odoing = 0; /* Net2out inactive */ /* (We don't set ldir.n2ddoing to 0 because lots of * clerical stuff needs to be done on net2disk = close) */ /* * The following is required before data can be used * */ /* Turn recording off */ if (XLRStop(dev) != XLR_SUCCESS) { /* Stop, OK? */ if (msglev < 2) /* Nope, debuggery? */ (void) fprintf(stderr, /* Yes */ "%s Xto() WARNING: XLRStop() returned error \n", me); (void) errors(); } /* We try to go on */ else if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, "%s Xto() DEBUG: XLRStop() OK \n", me); (void) errors(); /* Configure FPDP back to default */ if (XLRSetFPDPMode(dev, SS_FPDP_RECVMASTER, SS_OPT_FPDPNRASSERT) != XLR_SUCCESS) { /* OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s Xto() WARNING: XLRSetFPDPMode() returned error \n", me); (void) errors(); } /* We try to go on */ (void) errors(); /* Configure SS back to default */ if (XLRSetMode(dev, SS_MODE_PCI) != XLR_SUCCESS) { if (msglev < 2) /* Nope, degubbery? */ (void) fprintf(stderr, /* Yes */ "%s Xto() WARNING: XLRSetMode() returned error \n", me); (void) errors(); } /* We try to go on */ (void) errors(); /* End both threads */ (void) pthread_cancel(threadtoX); /* Other thread */ retrn = 0; /* Not known to be an error */ pthread_exit(&retrn); /* Probably normal end */ } /* End of if end of data or error */ /* Else OK, not end */ if (first && msglev < 1) /* First debuggery? */ (void) fprintf(stderr, /* Yes */ "%s Xto() DEBUG: recv() OK, lenn %d \n", me, lenn); ebytes += lenn; /* Add to local bytes */ nbyte += lenn; /* Add to local nbyte */ /* (nowbyte is bumped in toX()) */ } /* End of else if net2out or net2disk */ else if (datah == 3) { /* End of disk2net? (datah is reset by toX()) */ if (msglev < 1) /* Yes. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s Xto() DEBUG: Ending disk2net \n", me); ldir.d2ndoing = 1; /* Disk2net back to "connected" */ retrn = 1; /* Normal return for disk2net case, not an error */ pthread_exit(&retrn); /* Probably normal end */ } /* End of else if disk2net done */ /* Are we done with this transfer? */ else if (nbyte + 8 > endbyte) /* Done? */ continue; /* Yes, but we need to wait for toX() to finish */ else { /* Error: None of the above values of datah */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s Xto() WARNING: Wrong datah; ending \n", me); retrn = -4; /* Error: Wrong datah (or something) */ pthread_exit(&retrn); /* Error */ } /* Else OK, bump our index */ index = (index + 1) % nbuf; /* And bump our own semaphore to tell the other thread * that we're done with this index */ if (sem_post(&semXto) < 0) { /* OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s Xto() ERROR: sem_post() returned ", me); perror("error"); /* Error, but what to do? Maybe just end the transfer */ if (datah == 5) datah--; datah--; /* (That is datah 5 to 3, 4 to 3, and 2 to 1) */ retrn = -5; /* sem_post() error */ pthread_exit(&retrn); /* Error */ } /* Else OK */ if (first && msglev < 1) { /* First debuggery? */ (void) sem_getvalue(&semXto, &val); /* Yes, our semaphore */ (void) sem_getvalue(&semtoX, &val2); /* Other semaphore */ (void) fprintf(stderr, "%s Xto() DEBUG: sem_post OK, index %d, val %d, val2 %d \n", me, index, val, val2); first = FALSE; /* Just once */ } } /* End of while loop until done */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s Xto() DEBUG: Probably normal end \n", me); retrn = 0; /* Not known to be an error */ pthread_exit(&retrn); /* Probably normal end */ } /* End of Xto() */ void * toX(void * null) { /* * Process output data transfers for in2net and disk2net (i.e., * write to net), net2out (i.e., write to output board), and * net2disk (write to SS disk). See also Xto(). * */ extern volatile int datah; static int retrn = 0; /* Return code */ struct timespec wait; /* Wait time */ int index = 0; /* Initialize to first block in FIFO */ int indst = socbuf / 8; /* Step size per index, bytes */ ssize_t len; /* From send() */ struct timeb time1, time2; /* From ftime() */ double dt; /* Duration of timing, seconds */ long long ebytes = 0L; /* Count bytes */ int val, val2; int first = TRUE; /* ** Initialize our semaphore ** */ /* Initially nbuf blocks available for Xto() to write */ if (sem_init(&semtoX, 0, nbuf) < 0) { /* OK? */ if (msglev < 2) { /* Nope, error. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s toX() ERROR: sem_init() returned ", me); perror("error"); retrn = -1; /* sem_init() error */ pthread_exit(&retrn); /* Error */ } } else if (msglev < 1) { /* Debuggery? */ (void) sem_getvalue(&semXto, &val); /* Other semaphore */ (void) fprintf(stderr, /* Yes */ "%s toX() DEBUG: Active, threadtoX %#lx, semXto val %d \n", me, threadtoX, val); } (void) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); /* Allow cancellation (interrupt) during following nanosleeps */ /* * Wait for "on" * */ while (datah != 2 && datah != 4 && datah != 5) { if (msglev < 0) /* Yes. Debuggery? */ (void) fprintf(stderr, "w"); /* Yes */ pthread_testcancel(); wait.tv_sec = 0; /* Wait awhile */ wait.tv_nsec = 100000000; /* That's 0.1 second */ (void) nanosleep(&wait, NULL); /* Wait here */ pthread_testcancel(); } /* End of while wait for "on" */ (void) ftime(&time1); /* Initialize start time */ ebytes = 0L; /* Initialize local end bytes */ /* ** Loop until done ** */ while (datah > 0 && ports[0] >= 0) { /* Loop */ if (msglev < 1 && ebytes > KOUNT) { /* Debug log timing? */ (void) ftime(&time2); /* Yes, time now */ dt = time2.time + time2.millitm/1000.0 - (time1.time + time1.millitm/1000.0); /* Time since last time1 */ (void) fprintf(stderr, "%s toX() DEBUG: " /* Yes */ " Transferred %Ld bytes in %.2f seconds at %.3e baud \n", me, ebytes, dt, 8.0*ebytes/dt); (void) ftime(&time1); /* Reinitialize start time */ ebytes = 0L; /* And end bytes */ } /* End of if debug log timing */ if (first && msglev < 1) /* First debuggery? */ (void) fprintf(stderr, "%s toX() DEBUG: sem_wait() \n", me); /* Yes */ /* * Wait for the other semaphore * */ (void) sem_wait(&semXto); /* Wait for semXto */ /* (No need for pthread_testcancel() here * because sem_wait() is a cancellation point) */ /* Here we know that the value of the "other" semaphore * (semXto) was > 0, and this indicates that the next * FIFO block is available for us to read and process. */ if (msglev < 0) /* Debuggery? */ (void) fprintf(stderr, "T"); /* Yes */ /* * In2net or disk2net? * */ if (datah == 5 || datah == 4) { /* OK? */ if (first && msglev < 1) /* Yes, first debuggery? */ (void) fprintf(stderr, /* Yes */ "%s toX() DEBUG: Start in2net or disk2net, nowbyte %Ld \n", me, nowbyte); /* * OK, write to ports[0] * */ len = send(ports[0], rbuf + index * indst, socbuf, 0); if ((unsigned) len != socbuf) { /* OK? */ if (msglev < 2) { /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s toX() ERROR: Socket send() returned %d ", me, len); perror("error"); } (void) strcpy(messg, "Send() to socket failure"); error = 1004; /* Send to socket error */ /* Error, but what to do? Maybe just end the transfer */ if (datah == 5) datah--; datah--; /* (That's datah 5 to 3 and 4 to 3) */ retrn = -2; /* send() to ports[0] error */ pthread_exit(&retrn); /* Error */ } /* * Else OK * */ if (first && msglev < 1) /* First debuggery? */ (void) fprintf(stderr, /* Yes */ "%s toX() DEBUG: send() OK, len %d \n", me, len); nowbyte += len; /* Bump nowbyte */ ebytes += len; /* Bump local bytes */ } /* End of if in2net or disk2net */ /* * Net2out or net2disk? * */ else if (datah == 2) { /* OK? */ if (first && msglev < 1) /* Yes, first debuggery? */ (void) fprintf(stderr, /* Yes */ "%s toX() DEBUG: Start net2out or net2disk, nowbyte %Ld \n", me, nowbyte); /* Write to SS, OK? */ if (XLRWriteData(dev, rbuf + index * indst, socbuf) != XLR_SUCCESS) { if (msglev < 1) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s toX() WARNING: XLRWriteData() returned error \n", me); (void) errors(); datah--; /* (That's 2 to 1) */ retrn = -3; /* XLRWriteData() error */ pthread_exit(&retrn); /* Error */ } /* * Else OK * */ if (first && msglev < 1) /* First debuggery? */ (void) fprintf(stderr, /* Yes */ "%s toX() DEBUG: XLRWriteData() OK \n", me); nowbyte += socbuf; /* Bump nowbyte */ ebytes += socbuf; /* And local bytes */ } /* End of if net2out or net2disk */ else { /* Error: None of the above values of datah */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s toX() WARNING: Wrong datah; ending \n", me); retrn = -4; /* Error: Wrong datah (or something) */ pthread_exit(&retrn); /* Error */ } /* Else OK */ /* * Check: Are we done with disk2net? * */ if (datah == 4 && /* Disk2net? */ nowbyte + 8 > endbyte) { /* And done? */ if (msglev < 1) /* Yes. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s toX() DEBUG: Ending disk2net \n", me); datah = 3; /* Done with this disk2net "on" */ ldir.d2ndoing = 1; /* Disk2net back to "connected" */ retrn = 1; /* Normal return for disk2net case, not an error */ pthread_exit(&retrn); /* Probably normal end */ } /* End of if disk2net done */ /* Else OK, bump our index */ index = (index + 1) % nbuf; /* And bump our own semaphore to tell the other thread * that we're done with this index */ if (sem_post(&semtoX) < 0) { /* OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s toX() ERROR: sem_post() returned ", me); perror("error"); /* Error, but what to do? Maybe just end the transfer */ if (datah == 5) datah--; datah--; /* (That is datah 5 to 3, 4 to 3, and 2 to 1) */ retrn = -5; /* sem_post() error */ pthread_exit(&retrn); /* Error */ } /* Else OK */ if (first && msglev < 1) { /* First debuggery? */ (void) sem_getvalue(&semtoX, &val); /* Yes, our semaphore */ (void) sem_getvalue(&semXto, &val2); /* Other semaphore */ (void) fprintf(stderr, "%s toX() DEBUG: sem_post OK, index %d, val %d, val2 %d \n", me, index, val, val2); first = FALSE; /* Just once */ } } /* End of while loop until done */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s toX() DEBUG: Probably normal end \n", me); retrn = 0; /* Not known to be an error */ pthread_exit(&retrn); /* Probably normal end */ } /* End of toX() */ double dend(unsigned long * ind) { /* Fix endian of a double */ /* The input is an array of two longs that represent a double as * generated in a crate by rotman, thus in the wrong endian for * Intel. */ double outd; char * outa = (char *) &outd; char * pc; int i, j; pc = (char *) ind; /* Points to input */ for (i = 0; i < 8; i++) { /* Each char in the input */ j = 7-i; /* Corresponding char in the output */ outa[j] = pc[i]; } return(outd); } /* End of dend() */ unsigned long lend(unsigned long inl) { /* Fix endian of a long */ /* The input is a long to be endian reversed */ unsigned long outl; char * outa = (char *) &outl; char * pc; int i, j; pc = (char *) &inl; for (i = 0; i < 4; i++) { /* Each char in the input */ j = 3-i; /* Corresponding char in the output */ outa[j] = pc[i]; } return(outl); } /* End of lend() */ int errors() { /* XLR errors? Print XLR error code if so */ static XLR_ERROR_CODE lerror = 0; /* Last error printed */ if (msglev > 1) /* Should we be here? */ return(FALSE); /* Nope */ if (error == 0 || error == 3) { /* Pending errors? */ lerror = error; /* Nope, forget last error printed */ error = XLRGetLastError(); /* Get update */ } if (error == 3) { /* Error? */ lerror = error; /* Nope */ return(FALSE); /* Normal end for case no error */ } if (error == lerror) /* Error, but have we already printed it? */ return(TRUE); /* Yes, so don't repeat printing */ if (error < 1000) { /* XLR error? */ /* Yes, get XLR error message */ if (XLRGetErrorMessage(messg, error) != XLR_SUCCESS) /* OK? */ /* Nope (we already know that msglev < 2) */ (void) fprintf(stderr, "%s errors() ERROR: XLR error %ld, " "but XLRGetErrorMessage() failed \n", me, error); /* (Error in getting error message, but we try to go on) */ if (msglev < 1) { /* Debuggery? */ if (error != 7) /* Yes, Normal XLR error message? */ (void) fprintf(stderr, /* Yes */ "%s errors() ERROR: XLR error %lu %s \n", me, error, messg); else /* Demote XLR error 7 to warning */ (void) fprintf(stderr, /* Yes */ "%s errors() WARNING: XLR error %lu %s \n", me, error, messg); lerror = error; /* Remember that we printed this error */ } /* End of if debuggery */ } /* End of if XLR error */ else if (msglev < 1) { /* Print other (non-XLR) error message? */ (void) fprintf(stderr, /* Yes */ "%s errors() ERROR: %lu %s \n", me, error, messg); lerror = error; /* Remember that we printed this error */ } /* (But do not "use up" this error, i.e., do not set error to 0) */ return(TRUE); /* Normal end with error */ } /* End of errors() */ void signalint(int k) { /* To catch interrupt signal SIGINT */ /* (k is not used) */ extern SSHANDLE dev; /* xlrDevice */ extern char * me; /* My name */ extern int msglev; /* Debug message level */ if (msglev < 2) /* Debuggery? */ (void) fprintf(stderr, "%s INTERRUPT \n", me); /* Yes */ /* An XLRReset() here allows swapping disks after XLRClose() below */ if (XLRReset(dev) != XLR_SUCCESS) { /* OK? */ if (msglev < 2) /* No. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s WARNING: XLRReset() returned error \n", me); (void) errors(); } else if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, "%s DEBUG: XLRReset() OK \n", me); // XLRClose(dev); /* See manual notes on XLROpen() */ // if (msglev < 1) /* Debuggery? */ // (void) fprintf(stderr, "%s DEBUG: XLRClose() done \n", me); /* Yes */ if (msglev < 2) /* Debuggery? */ (void) printf("%s: The End \n", me); exit(0); /* Bye */ } /* End of signalint() */ void signalpipe(int k) { /* To catch broken-pipe signal SIGPIPE */ /* (k is not used) */ if (msglev < 2) /* Debuggery? */ (void) fprintf(stderr, "%s ERROR: SIGPIPE, broken pipe \n", me); /* Yes */ signal(SIGPIPE, signalpipe); /* Catch another broken-pipe signal */ (void) strcpy(messg, "Broken pipe"); error = 1005; return; } /* End of signalpipe() */