/*************************************************************************************** * * Title: inmemDecode.c version: 1.0 * * inmemDecode decodes specified links inside ROD input memories & places the * results in either a binary or text file. The defined inputs are shown in the * summary help file (see doHelp routine). * * later: * -d: decode the hit data. * -pixel: Pixel data format * -sct: SCT data format * -skip (h(eader), t(railer) or ht: skip past the header(s) & remove * trailer(s) & trailing zeros. * * If there is no input, the program searches for a text file named * inmemDecode_dft, and if it finds it will use the inputs within it (they * must be all on one line). * * Author: Douglas Ferguson **************************************************************************************/ #include #include typedef unsigned int UINT32; #define FALSE 0 #define TRUE 1 #define TXT_LINE_LEN 60 #define ARG_MAX 20 #define ARG_LEN 300 struct ProgramCtrl { FILE *inFile, *outFile; int fileSize, nBits, latency; int fileCount; char cntStr[12]; char *inBuff; char outFileName[300], inFileName[300]; char timeBits, timeStr[51]; UINT32 linkfield[2]; char binOutput, timeStamp, useFileCounter, parseActiveLinks, skipWhiteSpace, skipHeader, skipTrailer, bufferReady, decode, pixel, sct, skipLatency, reversedByte, twinOutput, txtOutput, unused[1]; }; int parseArguments(int argc, char *argv[], struct ProgramCtrl *pc); int processLink(char link, struct ProgramCtrl *pc, int *errorCode); void doHelp(void); int parse(char *line, char *word, int wLenMax); void leftShift(char *line, int nShift); int getFileSize(FILE *file, int *size); /************************************************************************************** * Main * **************************************************************************************/ int main(int argc, char *argv[]){ char link; int bit, prevBit, thisBit; int status, linkError; FILE *cntFile; char string[300], nConverts; int cnt; struct ProgramCtrl pc; time_t currentTime; struct tm *timeStruct; /* Parse the command-line arguments (or use default file), and fill the program-control structure */ if (!parseArguments(argc, argv, (struct ProgramCtrl *) &pc)) { printf("inmemDecode: bad arguments, exiting.\n"); printf("--- PRESS ANY KEY ---"); getchar(); exit(1); } /* If the counting flag is set, attempt to open the count file. If it is not there, create it and intialize to zero; otherwise read it and over-write with the incremented value. If file problems are encountered, a count of 0 is used. If the time-stamp flag is set, create the time string. */ if (pc.useFileCounter) { cntFile= fopen("inmemDecode_cnt.txt", "r"); if (cntFile == NULL) { cntFile= fopen("inmemDecode_cnt.txt", "w"); if (cntFile != NULL) { fputs("0\n", cntFile); fclose(cntFile); //Create initial count (0). } cntFile= fopen("inmemDecode_cnt.txt", "r"); } if (cntFile != NULL) { fgets(string, 299, cntFile); fclose(cntFile); nConverts= sscanf(string, "%d", &cnt); //Get the current count. if (nConverts == 1) { pc.fileCount= cnt; sprintf(string, "%d\n", ++cnt); //Increment the count. cntFile= fopen("inmemDecode_cnt.txt", "w"); if (cntFile != NULL) { fputs(string, cntFile); fclose(cntFile); //Store updated count. } } } else { pc.fileCount= 0; } sprintf(pc.cntStr, "_n%03d", pc.fileCount); //Now create the counter string. } //End of count-file access & manipulation else {strcpy(pc.cntStr, ""); } //Empty counter string if (pc.timeStamp) { time(¤tTime); timeStruct= localtime(¤tTime); strcpy(string, ""); strcpy(pc.timeStr, "_ts"); if (pc.timeBits & 8) { sprintf(string, "%02d", timeStruct->tm_mday); strcat(pc.timeStr, string); } if (pc.timeBits & 16) { sprintf(string, "%02d", timeStruct->tm_mon +1); strcat(pc.timeStr, string); } if (pc.timeBits & 32) { sprintf(string, "%02d", timeStruct->tm_year -100); strcat(pc.timeStr, string); } if (pc.timeBits & (8+16+32)) strcat(pc.timeStr, "-"); if (pc.timeBits & 4) { sprintf(string, "%02d", timeStruct->tm_hour +1); strcat(pc.timeStr, string); } if (pc.timeBits & 2) { sprintf(string, "%02d", timeStruct->tm_min); strcat(pc.timeStr, string); } if (pc.timeBits & 1) { sprintf(string, "%02d", timeStruct->tm_sec); strcat(pc.timeStr, string); } } else {strcpy(pc.timeStr, ""); } //Empty time-stamp string. /* If the activeLinks flag is set, find any links which have a fluctuating signal and add them to the link-processing bitfield. For any link, the bit (i.e. crossing) offset is 6*bit, link-byte offset is link/8 and the link-bit offset within the chosen byte is link%8 which is gotten here by link & 7. */ if (pc.parseActiveLinks) { for (link=0; link<48; ++link) { for (bit= 1; bit < pc.nBits; ++bit) { prevBit= (pc.inBuff[6*(bit-1) +(link/8)] & (1<<(link&7)) ); thisBit= (pc.inBuff[6*(bit) +(link/8)] & (1<<(link&7)) ); if (thisBit != prevBit) { if (link < 32) pc.linkfield[0] |= 1<<(link); else pc.linkfield[1] |= 1<<(link-32); continue; //Skip searching the bits & go on to next link. } } } } /* Now process the links. For each processed link, either a text or binary file will be produced which contains the bits. Depending on the setting of the different flags, any leading/trailing zeros & the header or trailer may be skipped. If decoding is enabled, a link log file is produced listing the link contents & compatability with expaectations. */ for (link=0; link<48; ++link) { if (link < 32) {if (!(pc.linkfield[0] & (1<<(link )))) continue; } else {if (!(pc.linkfield[1] & (1<<(link-32)))) continue; } status= processLink(link, (struct ProgramCtrl *) &pc, &linkError); } return 0; } /************************************************************************************** * parseArguments: If no command line arguments (argc= 1 => executable name is * * argv[0]), parse them from the default input file, if it exists. * * Also use an input file if only one argument which is a text file. Otherwise * * parse them from the input command line. * **************************************************************************************/ int parseArguments(int argc, char *argv[], struct ProgramCtrl *pc) { int arg, i, j, status= TRUE; char command[ARG_MAX][ARG_LEN], cmd[ARG_LEN], string[300]; char parsingArguments, parseLine, multiArg; char recognized, nConverts, convertSuccess; int lat, link, firstLink, lastLink; memset((void *) pc, 0, sizeof(struct ProgramCtrl)); /* If a single argument on the command line is a text file, use that instead of the default input file. Otherwise, read the arguments from the command line. */ if (argc == 2) { strcpy(string, argv[1]); for (i=0; iinFile= fopen (string, "r")) != NULL) ) { while (fgets(string, 299, pc->inFile) != NULL) { parseLine= TRUE; while ((argc < ARG_MAX)&&(parseLine)) { parseLine= parse(string, command[argc], (ARG_LEN-1)); if (strlen(command[argc]) != 0) ++argc; } } fclose(pc->inFile); if (argc >= ARG_MAX) parsingArguments= TRUE; else parsingArguments= FALSE; } else { //Read the arguments from the command line prompt. if (argc >= ARG_MAX) parsingArguments= TRUE; else { parsingArguments= FALSE; for (arg=1; arg < argc; ++arg) strncpy(command[arg], argv[arg], (ARG_LEN-1)); } } //Check to see that the # of arguments is in the valid range: if (argc == 1) { printf("inmemDecode: no input.\n"); return FALSE; } else if (parsingArguments) { printf("inmemDecode: too many inputs (> %d).\n", (ARG_MAX)); return FALSE; } arg= 1; parsingArguments= TRUE; multiArg= FALSE; while(parsingArguments) { if (arg == argc) { //End of input reached if (!multiArg) { parsingArguments= FALSE; break; } else { printf("Incomplete argument found at the end of input.\n"); return FALSE; } } /* If not currently parsing a new command line argument (or multi-argument set), look for the defined keywords. */ if (!multiArg) { strcpy(cmd,""); if (strstr(command[arg], "-help")) { doHelp(); printf("--- PRESS ANY KEY ---"); getchar(); exit(1); } else if (strstr(command[arg], "-binr")) { //Must be before -bin check. pc->binOutput= TRUE; pc->reversedByte= TRUE; } else if (strstr(command[arg], "-bin")) {pc->binOutput= TRUE; } else if (strstr(command[arg], "-txt")) {pc->twinOutput= TRUE; } //Before -t else if (strstr(command[arg], "-rws")) {pc->skipWhiteSpace= TRUE; } else if (strstr(command[arg], "-c")) {pc->useFileCounter= TRUE; } else if ( (strstr(command[arg], "-f")) ||(strstr(command[arg], "-lat")) ||(strstr(command[arg], "-t")) ||(strstr(command[arg], "-link")) ) { strcpy(cmd, command[arg]); multiArg= TRUE; if (strstr(command[arg], "-t")) {pc->timeStamp= TRUE; } } else { printf("unrecognized input: %s\n", command[arg]); } } /* Otherwise (parsing a multi-argument set), retrieve & process the next argument. */ else { if (strstr(cmd, "-f")) { strcpy(pc->inFileName,command[arg]); pc->inFile= fopen (pc->inFileName, "rb"); if (pc->inFile == NULL) { printf("Input file %s does not exist!\n", pc->inFileName); status= FALSE; } else if (getFileSize(pc->inFile, &pc->fileSize) == FALSE) { printf("Trouble reading input file!\n"); status= FALSE; } else { for (i=0; iinFileName); ++i) if (isupper(pc->inFileName[i])) pc->inFileName[i]= tolower(pc->inFileName[i]); pc->nBits= pc->fileSize/6; pc->inBuff= calloc(pc->fileSize, 1); fread(pc->inBuff, sizeof(char), pc->fileSize, pc->inFile); fclose(pc->inFile); pc->bufferReady= TRUE; } multiArg= FALSE; } else if (strstr(cmd, "-t")) { if ((strchr(command[arg], 's'))||(strchr(command[arg], 'S'))) pc->timeBits|= 1; if ((strchr(command[arg], 'h'))||(strchr(command[arg], 'H'))) pc->timeBits|= 4; if ((strchr(command[arg], 'd'))||(strchr(command[arg], 'D'))) pc->timeBits|= 8; if ((strchr(command[arg], 'y'))||(strchr(command[arg], 'Y'))) pc->timeBits|= 32; if (strchr(command[arg], 'm')) pc->timeBits|= 2; if (strchr(command[arg], 'M')) pc->timeBits|= 16; multiArg= FALSE; } else if (strstr(cmd, "-lat")) { nConverts= sscanf(command[arg], "%d", &lat); if ( (nConverts == 1) && (lat >= 0)) { pc->latency= lat; pc->skipLatency= TRUE; } multiArg= FALSE; } else if (strstr(cmd, "-link")) { recognized= FALSE; convertSuccess= FALSE; if (strstr(command[arg], "nz")) { //search for active links. recognized= TRUE; pc->parseActiveLinks= TRUE; } else if (strchr(command[arg], '-')) { // e.g. 10-15 if (strstr(command[arg], "0x")) { nConverts= sscanf(command[arg], "0x%x-%x", &firstLink, &lastLink); //Convert from ROD base-12 format to decimal: if (nConverts == 2) { firstLink= 12*(firstLink/16) +(firstLink & 0xf); lastLink= 12*(lastLink/16) +(lastLink & 0xf); } } else { nConverts= sscanf(command[arg], "%d-%d", &firstLink, &lastLink); } if ( (nConverts == 2) &&((firstLink >= 0)&&(firstLink < 47)) &&((lastLink >= 1)&&(lastLink < 48)) &&(firstLink < lastLink ) ) convertSuccess= TRUE; } else { //Single link. if (strstr(command[arg], "0x")) { nConverts= sscanf(command[arg], "0x%x", &link); //Convert from ROD base-12 format to decimal: if (nConverts == 1) link= 12*(link/16) +(link & 0xf); } else { nConverts= sscanf(command[arg], "%d", &link); } if ( (nConverts == 1) && ((link >= 0)&&(link < 48)) ) { convertSuccess= TRUE; firstLink= lastLink= link; } } if (convertSuccess) { recognized= TRUE; for (link= firstLink; link<= lastLink; ++link) { if (link < 32) pc->linkfield[0] |= 1<<(link); else pc->linkfield[1] |= 1<<(link-32); } } //If not continuing on with a new link argument, exit this sub-loop: if (command[arg][strlen(command[arg])-1] != ',') multiArg= FALSE; if (!recognized) { printf("unrecognized input: %s\n", command[arg]); } } //-link command } //multi-argument input. ++arg; //increment to next argument. } if (!pc->bufferReady) { //A file must be read in among the arguments. printf("Bad input file.\n"); status= FALSE; } if ((pc->skipLatency) && (pc->latency > pc->nBits)) { printf("Too much latency.\n"); status= FALSE; } else if ((pc->skipLatency) && ((pc->skipWhiteSpace)||(pc->skipHeader))) { printf("Latency cannot be used with skipping arguments.\n"); status= FALSE; } if ((!pc->binOutput) || (pc->twinOutput)) {pc->txtOutput= TRUE; } return status; } #ifdef COMMENTED for (arg=0; arginFileName, pc->outFileName); printf(" linkfield: 0x%04x %08x\n", pc->linkfield[1], pc->linkfield[0]); printf(" binOutput: %d, timeStamp: %d, fileCounter:%d, parseActive: %d \n", pc->binOutput, pc->timeStamp, pc->useFileCounter, pc->parseActiveLinks); printf(" skip ws: %d, skip header: %d, skip trailer:%d, buffer ready: %d \n", pc->skipWhiteSpace, pc->skipHeader, pc->skipTrailer, pc->bufferReady); printf(" decode: %d, pixel: %d, sct:%d, unused: %d \n", pc->decode, pc->pixel, pc->sct, pc->unused); printf("--- wait before continuing ---"); getchar(); #endif /************************************************************************************** * processLink: Processes an input link. If latency is set, will skip past the 1st * * latency bits. If skipping (skip white-space, header and/or trailer) * * is set, will skip the relevant bits. If text files are desired (default), will * * create a text file with 0 & 1 indicating the bits; otherwise will create a * * binary file with the bits packed. If decoding is desired, will attempt to * * decode the hits within the link and, if desired, test them for compatability * * with one of the possible mask stages. A log file will then be produced with * * either the raw hits or a compatability summary with the mask stage. Normally * * the routine returns true, but it can fail if there are problems creating * * either the buffers or output file; in this case it will return an error. * * Additionally, a link may fail a decoding test or threshold, in which case the * * routine will return a non-zero error code through its arguments. * **************************************************************************************/ int processLink(char link, struct ProgramCtrl *pc, int *errorCode) { int status= TRUE, i, bit, firstBit, lastBit, nBytes, nWords; char *buffer, *packedBuffer, byte, bitTest, bitOffset, bitVal, byteOffset; char string[TXT_LINE_LEN+2]; static char first= TRUE; //Setup: *errorCode= 0; byteOffset= link/8; bitTest= 1<<(link&7); bitOffset= (link&7); if (first) { first= FALSE; buffer= calloc(pc->nBits, sizeof(char)); packedBuffer= calloc(pc->nBits/8, sizeof(char)); } else { memset(buffer, 0, pc->nBits); memset(packedBuffer, 0, pc->nBits/8); } if ((buffer == NULL) || (packedBuffer == NULL)) return FALSE; //Get link file name: memset(pc->outFileName, 0, 300); strncpy(pc->outFileName, pc->inFileName, strlen(pc->inFileName)-4); if (strstr(pc->inFileName, "inmemb")) { sprintf(string,"_0x%02x", (4 +(link/12))*16 +link%12); } else { sprintf(string,"_0x%02x", (link/12)*16 +link%12); } strcat(pc->outFileName, string); strcat(pc->outFileName, pc->cntStr); strcat(pc->outFileName, pc->timeStr); firstBit= 0; lastBit= pc->nBits -1; if (pc->skipLatency) { firstBit= pc->latency; } else { if (pc->skipWhiteSpace) { while( (pc->inBuff[6*firstBit +byteOffset] & bitTest) == 0) ++firstBit; while( (pc->inBuff[6*lastBit +byteOffset] & bitTest) == 0) --lastBit; } } for (i= 0, bit= firstBit; bit <= lastBit; ++bit, ++i) { buffer[i]= (pc->inBuff[6*bit +byteOffset] & bitTest)>>bitOffset; } if (pc->binOutput) { /* Pack the bits so that they appear 1/bit of the binary file. The bits are reversed so that when viewed in a hex viewer, the output is parsed naturally (ie. bit 0 => word 0, bit 31, bit 1 => word 0, bit 30, etc. If a -binr flag was given, the inmem-bit to word bit mapping is given by: bit 0=> byte 0, bit 7, bit 1=> byte 0, bit 6, ... bit 8=> byte 1 bit 7, etc. (e.g. for Witched) */ for (i= 0, bit= firstBit; bit <= lastBit; ++bit, ++i) { if (pc->reversedByte) { //The i>>3 divides by 8 (8 bits per byte) packedBuffer[(i>>3)]|= (buffer[i])<<(7-(i&7)); } else { //The complicated looking offset to the buffer takes the output for //inmem bits 0-7 and places them (reversed) in the 7 MSB of the word, etc. packedBuffer[4*(i>>5) +(3- ((i>>3)&3))]|= (buffer[i])<<(7-(i&7)); } } strcat(pc->outFileName, ".bin"); pc->outFile= fopen(pc->outFileName, "wb"); /* open binary file for writing */ if (pc->reversedByte) { nBytes= (lastBit -firstBit +1)/8; if ((lastBit -firstBit +1)%8 != 0) ++nBytes; fwrite(packedBuffer, sizeof(char), nBytes, pc->outFile); } else { nWords= (lastBit -firstBit +1)/32; if ((lastBit -firstBit +1)%32 != 0) ++nWords; fwrite(packedBuffer, sizeof(int), nWords, pc->outFile); } fclose(pc->outFile); } /* Write the bits into the text file. Unless the option (dpsf add) is specified, they are written as TXT_LINE_LEN bits per line. */ if (pc->txtOutput) { strcpy(string,""); strcat(pc->outFileName, ".txt"); pc->outFile= fopen(pc->outFileName, "w"); /* open file for writing */ for (i= 0, bit= firstBit; bit <= lastBit; ++bit, ++i) { if (buffer[i]) strcat(string, "1"); else strcat(string, "0"); if (strlen(string) == (TXT_LINE_LEN)) { //If line is done, place in file. strcat(string, "\n"); fputs(string, pc->outFile); strcpy(string, ""); } } if (strlen(string) > 0) { //Place any remaining lines in file. strcat(string, "\n"); fputs(string, pc->outFile); } fclose(pc->outFile); } return status; } /************************************************************************************** * doHelp: Print out some text summarizing the options. * **************************************************************************************/ void doHelp(void) { printf("Valid arguments:\n"); printf(" -f : Input file to parse. \n"); printf(" -help: Print this summary. \n"); printf("\n"); printf(" -bin: Produce binary file(s) as output (default is text file(s)).\n"); printf(" -binr: Like -bin except the binary output is suited for reversed \n"); printf(" byte-order viewers like Witched (least significant byte \n"); printf(" is seen 1st on the left). \n"); printf(" -txt: If input in combination with binary, gives text output too.\n"); printf("\n"); printf(" -rws: Skip blank (white) space to header, and remove trailing \n"); printf(" zeros. If no bit-variation within a link is detected, it \n"); printf(" is considered to be filled with zeros. \n"); printf(" -lat : Skip past the 1st bits (1 bit = 25 ns). \n"); printf("\n"); printf(" -c: Use a file with counter inside to mark output files.\n"); printf(" -t : Use a time-stamp to mark output files with any \n"); printf(" combination of the 6 possible times. \n"); printf("\n"); printf(" -link : Process all non-zero links ( = nz), process \n"); printf(" the indicated input link ( = n), or range of \n"); printf(" input links ( = first-last). Links can be input in \n"); printf(" either decimal (no prefix) or the ROD \"base-12\" formatter \n"); printf(" style (prefix= 0x). This command can be input multiple times, \n"); printf(" with the arguments spaced by commas: -link 1, 0x15, 0x20-25...\n"); printf("\n"); /* printf(" -decode : Decode the link into header, hits & trailer; will \n"); printf(" tolerate up to mistakes in the header(s) and \n"); printf(" trailer(s) before giving up. \n"); printf(" -pixel : Used in conjunction with decode; indicates that the \n"); printf(" data is pixel data. The data field gives the \n"); printf(" expected number of time-slices within an event. \n"); printf(" -sct: Used in conjunction with decode; indicates that the \n"); printf(" data is SCT data. \n"); printf(" -anal: Used in conjunction with decode. This flag will \n"); printf(" cause the program to attampt to analyze the hits, \n"); printf(" measuring conformity with one of the mask stages. \n"); printf("\n"); */ printf(" The program can be run without any command-line input options \n"); prinff(" by either using the default input file (inmemDecode_dft.txt), \n"); prinff(" or by running the program with a single argument giving the \n"); prinff(" input file's name; if done the latter way the input file must \n"); prinff(" be a text file. \n"); printf("\n"); } /************************************************************************************** * parse: Retrieve next word, ignoring white space. Each time the word is removed * * from the line. When done, return 0, otherwise return 1. * **************************************************************************************/ int parse(char *line, char *word, int wLenMax) { int i= 0, j= 0, wlen; /* Skip past white-space before the next word (if any). If the line's end is reached, return FALSE (i.e. done) */ word[0]= 0; while ( (line[i] == ' ' )||(line[i] == '\t') ||(line[i] == '\n')||(line[i] == '\r') ) ++i; if (i == strlen(line)) return FALSE; /* Now parse the word */ j= i; //j=> start of word. while ( (line[i]) &&(line[i]!= ' ' )&&(line[i]!= '\t') &&(line[i]!= '\n')&&(line[i]!= '\r') ) ++i; wlen= ((i-j) <= wLenMax)? (i-j):wLenMax; strncpy(word, &line[j], wlen); word[wlen]=0; /* Check to see if there are any more words in the line: */ while ( (line[i] == ' ' )||(line[i] == '\t') ||(line[i] == '\n')||(line[i] == '\r') ) ++i; if (i == strlen(line)) return FALSE; else { /* Remove word and any white-space surrounding it from the line: */ leftShift(line,i); return TRUE; } } /************************************************************************************** * leftShift: Remove specified # of characters from beginning of the line. * **************************************************************************************/ void leftShift(char *line, int nShift) { int j= 0; if (nShift > strlen(line)) nShift= strlen(line); for (j= nShift; j <= strlen(line); ++j) line[j-nShift]= line[j]; } /************************************************************************************** * getFileSize: retrieve the file size of the requested file, in bytes. * **************************************************************************************/ int getFileSize(FILE *file, int *size) { int status, xsize; *size= 0; status= fseek(file, 0, SEEK_END); if (!status) { xsize= ftell(file); if (xsize >= 0) *size= xsize; else status= xsize; //ftell returns -1 if unsuccessful. } rewind(file); if (status) return FALSE; else return TRUE; }