// MODULE mblk10s mblk10s.cpp Vers 0.65 Jan 23 2011 // DOS compile (Bourland c++): dapcc mblk10s // // mblk10s ramps to within xx% of pk, then switches to slower RATE2 for final // approach of peak. The "s" suffix stands for "shared memory" vers. // This prog. does not directly use shared mem, but mterml_sh2.cpp does. // mblk10 (iP0,iP1,cp2i,cp2o,bout,itime,nlchannels ) // - value in pipe 'iP0 and ip1' are a/d inputs // - cp2i, cp2o are comm pipes to the PCside program // - bout is binary pipe to PCside (*.dap module sends it to $BINOUT) // - itime is sample rate in microSec. // - nlchannels no. of a/d channels // //Long int names generally start with "il" or "nl" prefix characters. // // Module name mblk10 must be distinct from the DAPL command name // assigned below. // Copyright (C) 2010 F.A. Conle // This file is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the license, or (at // your option) any later version. // This file is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTA- // BILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public // License for more details. // You should have received a copy of the GNU General PUblic License along // with this program; if not, write to the Free Software Foundation, Inc., // 59 Temple Place -Suite 330, Boston, MA 02111-1307, USA. Try also their // #define COMMAND "MBLK10" #define ENTRY MBLK10_entry #include "DTDMOD.H" #include "DTD.H" // #include #include #define MAX_STORE 1000 //max history blocks stored // blocks are in form: #BLOCK= pk1 pk2 nramps // Run data is stored in form: // pk1 pk2 nramps rpk1 rpk2 // where rpk1 and rpk2 are the actual reversal points // needed to achieve pk1 and pk2. // Program auto ramps towards a peak until reaches XX% of ramp // (like threshold in flex10) then switches to peak approach mode. // The variable "nramps" can be equal to 1, creating a single ramp // from pk1 to pk2 // // It is up to user to ensure no gaps between BLOCKS. #define BUF_SIZE 1024 //size of bout (or $BINOUT) pipe buffer int __stdcall ENTRY (PIB **plib); extern "C" __declspec(dllexport) int __stdcall ModuleInstall(void *hModule) { return (CommandInstall(hModule, COMMAND, ENTRY, NULL)) ; } // - - - - - command implementation section - - - - - - - - - - int __stdcall ENTRY (PIB **plib) { // Storage for parameters void **argv; int argc; PIPE * iP0; // AD0 PIPE * iP1; // AD1 PIPE * bout; // Hopefully the $BINOUT pipe ? PIPE * cp2i; // Cp2In comm pipe for reading text + histories etc from PCside. PIPE * cp2o; // Cp2Out comm pipe for send text to PCside VAR * itime; // a/d sample rate in microSec. Set by *.dap VAR * nlchannels; PBUF * outbuf; // buffer for bout pipe short int *ibinstore; //binary volts out storage long int ilbincount, ilbinstoremax; //counters for binout buffer. long int nlbuff; //buffer no. transmitted in buffer // Storage for processing GENERIC_SCALAR pipe_value; // Used here to get voltage int from iP0 // the GenericScalar type can be a number of different types. //GENERIC_SCALAR iv_0; //voltage ints for $Binout to user(future) //GENERIC_SCALAR iv_1; //GENERIC_SCALAR str_cp2in; // use to read Cp2In pipe value //GENERIC_SCALAR str_cp2out; // use to write Cp2Out pipe value short int i; // temp variable short int ivout; // 16bit number for d/a output voltage long int ilvout; // same as ivout for doing range checks short int ivstepsize; //voltage increment/decrement size short int idac; // d/a number: is 0 or 1 for DAP840 short int ivad0, ivad1; // integer voltage read from a/d pipes iP0, iP1 short int ithreshValue; // threshold trigger voltage short int ithresh; // used in ithstore[ithresh] short int ivTarget; short int ivnewTarget; // voltage for next reversal short int istVolts; long int ilvolts; // used to read voltages from history long int il_vDelta; // used to compute diff between two short int voltages long int il_diff; // used to compute diff between two short int voltages short int ivoldTarget; short int ioldCommand; short int ivfeedbackMin, ivfeedbackMax; //drag these along a ramp voltage long int ilpart; //used to split 8byte word into 2 4byte words long int il_inThresh[130]; //storage for 128 initial thresholds long int il_maxBlocks; // Limit of no. of history repeats long int nlvout; // total number of the voltage output values in ivstore[] long int il_daRate1; long int il_daRate2; float scale1; // multiplier to convert volts to 16bit int float scale2; // multiplier to convert 16bit int to Volts float f_threshold; // used to read threshold volts from *.env file short int ideltaThreshold; //integer value of above. long int il, jl, ij ; // general counters long int ilblock; // counts the number of reps of the history long int ilsubBlock; // counts each Block line in history long int il_rampCount; //counts no. of ramps in each sub-block long int il_rateCounter; //counts down to 0 between each d/a out long int ilsample; long int nldeplete; //counts a/d samples between a/d saves for $binout long int il_adConvRate; // = 1000000 / *itime; long int il_SampPerSecPerChan; //= il_adConvRate / nchan; long int il_userSampPerSecPerChan; // = il_SampPerSecPerChan / nldeplete; long int il_Sum0, il_Sum1, il_nsum, il_naverage; // used to compute avg. long int il_peakptr, il_newpeakptr; // ptr to peak or target in history long int il_err; long int iln; // used to read long ints. short int nchan; // no. of a/d chan short int inum; // a counter for how many in a pipe short int iendblock; //Signal that end of block occurred at last threshold change short int ipause; //Signal PAUSE= 1, RUN =0 : turns d/a volt incrementer off/on char testTitle[50], threshTitle[50], histTitle[50]; // title stringpointers // double pointer below is needed for crappy Borland compiler char sentence[132]; // string used to read a line from cp2in pipe char * sentencePtr = &(sentence[0]); char sentence2[132]; // string used to read a line from cp2in pipe char * sentencePtr2 = &(sentence2[0]); char cfield1[50], cfield2[50]; // strings used to decode sentence char * cfield1Ptr = &(cfield1[0]); char * cfield2Ptr = &(cfield2[0]); float peakError; //window of tolerance in volts short int ipeakError, ipeakWindow; // window of tolerance in integer float cmdError; //Max allowed over-program voltage short int icmdError; long int ilvoltsOverPeak; // ivTarget +- icmdError // One cannot define large arrays here. Must be done runtime. search for "ralloc" // For example: // short int ipk1[MAX_STORE]; won't work if MAX_STORE is big. // One should however define the pointers to those arrays here: short int *ipk1; // 1st peak in sub-block short int *ipk2; // 2nd peak in sub-block long int *nramps; // No. of ramps between ipk1 and ipk2 short int *irpk1; // 1st observed peak in sub-block short int *irpk2; // 2nd observed peak in sub-block long int ilpk1, ilpk2; // used during input of history voltages // Access parameters argv = param_process (plib, &argc, 7, 7, T_PIPE_W, T_PIPE_W, T_PIPE_B, T_PIPE_B, T_PIPE_W, T_VAR_L, T_VAR_L ); iP0 = (PIPE *) argv[1]; iP1 = (PIPE *) argv[2]; cp2i = (PIPE *) argv[3]; cp2o = (PIPE *) argv[4]; bout = (PIPE *) argv[5]; //pipe ptr to *.dap for $BINOUT itime = (VAR *) argv[6]; //ptr to a/d sample rate in microSecs, a long int nlchannels = (VAR *) argv[7]; //pointer to a long int // ivoutPipe0 = (PIPE *) argv[6]; // ivoutPipe1 = (PIPE *) argv[7]; printf ("#mblk10s: starts with printf...\r"); // cannot send to cp2o yet. (not open) // Perform initializations pipe_open (cp2i, P_READ); //comm pipe Cp2In from PCside printf ("#mblk10: opened pipe cp2i \r"); pipe_open (cp2o, P_WRITE); //comm pipe Cp2Out to PCside printf ("#mblk10: opened pipe cp2o\r"); printf ("#mblk10: STARTED Params set. \r" ); // fprintf (cp2o, "#mblk10: STARTED Params set. \r\n" ); fprintf (cp2o, "#mblk10: DAP A/D SampleRate= %d uS \r\n", *itime ); //Initilize some stuff nchan = (short int)(*nlchannels); //No of channels of A/D //Note that nchan is used to compute the boundary of the buffer points //It is also used by other programs on PC side and must be placed into //shared memory area 1. fprintf (cp2o, "#mblk10: DAP no. of A/D channels= %d \r\n", nchan ); scale1 = 3276.7 ; // = (32767 / 10) to convert 10v to 16bit int scale2 = 1.0 / scale1; // Note: in a high speed test avoid floating pt inside control loop // // Debug: print out all pointers addresses to check if set // If %p does not work below, try %8lx // Badly set ptrs will contain lots of 0s fprintf (cp2o, "#cp2o: All pointers in mblk10:\r\n"); fprintf (cp2o, "#cp2o: iP0 %p iP1= %p cp2i= %p cp2o= %p \r\n", iP0,iP1,cp2i,cp2o ); fprintf (cp2o, "#cp2o: cfield1Ptr= %p cfield2ptr= %p\r\n", cfield1Ptr, cfield2Ptr); fprintf (cp2o, "#cp2o: bout= %p outbuf= %p ibinstore= %p\r\n", bout,outbuf,ibinstore); task_switch(); //pause, should also flush fprintf buffers //printf("#mblk10: returned from task_switch()\r"); // allocate the memory for the storage arrays: ipk1 = (short int *) ralloc(MAX_STORE*sizeof(short int)); ipk2 = (short int *) ralloc(MAX_STORE*sizeof(short int)); nramps = (long int *) ralloc(MAX_STORE*sizeof(long int)); irpk1 = (short int *) ralloc(MAX_STORE*sizeof(short int)); irpk2 = (short int *) ralloc(MAX_STORE*sizeof(short int)); ibinstore = (short int *) ralloc(BUF_SIZE*sizeof(short int)); ilbinstoremax = (long int) (( (short int)((BUF_SIZE - 7)/nchan) ) * nchan +6 ); //when this number is filled there is no more room for a complete set of a/d //pts in the Buffer storage. //Expecting a "#RESET= i j k" at Cp2In pipe. Check now. while (1) //read stuff from pipe until we get a #RESET= { while ( pipe_num(cp2i) <= 0 ) task_switch(); //wait for input to pipe fgets (sentence, 100, cp2i); fprintf (cp2o, "#mblk10: got sentence: %s\r\n", sentence); //printf ("mblk10: got sentence: %s\r\n", sentence); cfield1Ptr = strtok(sentence, " "); //get first field // strtok is a weird function. For details of strtok() see: // http://www.cplusplus.com/reference/clibrary/cstring/strtok/ // note that strcmp(s1,s2) = 0 when s1=s2 if ( strcmp(cfield1Ptr,"#RESET=\0" ) ==0) { //yes, then get the 2nd field printf("#mblk10: Got: #RESET= \r"); fprintf(cp2o, "#mblk10: Got: #RESET= \r\n"); cfield2Ptr = strtok(NULL," "); if (cfield2Ptr == NULL ) //then no 2nd field was found {fprintf(cp2o, "#mblk10: Error: No 2nd field after #RESET= \r\n"); goto STOP; } else // 2nd field was found { if( strcmp(cfield2Ptr, "1\0" ) == 0 ) { //yes, a "1" means reset wanted //printf("#mblk10: Got 1, doing a volt zero.\r"); idac = 0; ivout = 0; dac_out (idac, ivout); fprintf (cp2o, "#got#RESET= 1\r\n"); break; } if( strcmp(cfield2Ptr, "0\0" ) == 0 ) { //yes, a "0" means reset not wanted //printf("#mblk10: Got 0, no voltage zero set.\r"); fprintf (cp2o, "#got#RESET= 0\r\n"); break; } } // if the 2nd field was something else, do not do a reset printf("#mblk10: 2nd field on #RESET= line not 1 or 0. Error.\r\n"); goto STOP; } // if it was not a #RESET= print it out and keep looking fprintf (cp2o, "#mblk10: While expecting #RESET=: got: %s\r\n", sentence); } il_daRate1= 0; //Set these to 0 and then check to see if changed after while() il_daRate2= 0; ipeakError= -1; icmdError= -1; ideltaThreshold=0; il_maxBlocks=0; nldeplete=-1; ivstepsize=0; while (1) { //Next lines should be the mblk10.env file data ------------------------------------- while ( pipe_num(cp2i) <= 0 ) task_switch(); //wait for input to pipe fgets (sentence, 100, cp2i); fprintf(cp2o, "#Mb: Got: %s\r\n", sentence); cfield1Ptr = strtok (sentence, " "); //fetch a line // Note that strcmp(s1,s2) = 0 when s1=s2 if (strcmp ( cfield1Ptr, "#TITLE=\0") == 0) { fprintf(cp2o, "#Mb: Got #TITLE= \r\n"); cfield2Ptr = strtok (NULL, " "); if (cfield2Ptr == NULL ) //then no 2nd field was found //if( strcmp (cfield2Ptr, NULL) == 0) { strcpy (testTitle, "none\0"); } else { strcpy (testTitle, cfield2Ptr); } fprintf(cp2o, "#Mb: Set: #TITLE= %s\r\n", testTitle); continue; } if (strcmp (cfield1Ptr, "#PKERROR=\0") == 0) { //read and save the allowable Peak error in volts and convert to 16 bit word. // Error is diff between target and actual voltage at peak or valley cfield2Ptr = strtok (NULL, " "); if (cfield2Ptr == NULL ) //then no 2nd field was found { fprintf (cp2o, "#Mb: Error: no 2nd field after #PKERROR=\r\n"); goto STOP; } sscanf (cfield2Ptr, "%f", &peakError ); ipeakError = (short)(peakError * scale1); //convert to 16bits fprintf (cp2o, "#mblk10: Peak error in *.env file = %f=%d \r\n",peakError, ipeakError); ipeakWindow = ipeakError; fprintf (cp2o, "#mblk10: Will also be used to determine peak or valley.\r\n"); if (ipeakError <= 0) { fprintf (cp2o, "#mblk10: Error: PKERROR is -ve number=%f %d\r\n",peakError,ipeakError); goto STOP; } continue; } if (strcmp (cfield1Ptr, "#CMDERROR=\0") == 0) { //read and save the allowable OverProgram error in volts and convert to 16 bit word. // Error is diff between target and actual voltage cfield2Ptr = strtok (NULL, " "); if (cfield2Ptr == NULL ) //then no 2nd field was found { fprintf (cp2o, "#Mb: Error: no 2nd field after #CMDERROR=\r\n"); goto STOP; } sscanf (cfield2Ptr, "%f", &cmdError ); icmdError = (short)(cmdError * scale1); //convert to 16bits fprintf (cp2o, "#mblk10: CMD(max over-prog.) error in *.env file = %f=%d \r\n", cmdError, icmdError); if (icmdError <= 0) { fprintf (cp2o, "#mblk10: Error: CMDERROR is -ve number=%f %d\r\n",cmdError,icmdError); goto STOP; } continue; } if (strcmp (cfield1Ptr, "#RATE1=\0") == 0) { // read the no. of tics(a/d reads) between d/a voltage steps cfield2Ptr = strtok (NULL, " "); if (cfield2Ptr == NULL ) //then no 2nd field was found { fprintf (cp2o, "#Mb: Error: no 2nd field after #RATE1=\r\n"); goto STOP; } sscanf (cfield2Ptr, "%d", &il_daRate1 ); continue; } if (strcmp (cfield1Ptr, "#RATE2=\0") == 0) { // read the no. of tics(a/d reads) between d/a voltage steps cfield2Ptr = strtok (NULL, " "); if (cfield2Ptr == NULL ) //then no 2nd field was found { fprintf (cp2o, "#Mb: Error: no 2nd field after #RATE2=\r\n"); goto STOP; } sscanf (cfield2Ptr, "%d", &il_daRate2 ); fprintf (cp2o, "#Mb: Set: #Ramp RATE2= %d, End of ramp RATE2= %d\r\n", il_daRate1, il_daRate2); continue; } if (strcmp (cfield1Ptr, "#THRESHOLD=\0") == 0) { // read the voltage that is to be subtracted from peak to // determine the switch point to lower strain rate. cfield2Ptr = strtok (NULL, " "); if (cfield2Ptr == NULL ) //then no 2nd field was found { fprintf (cp2o, "#Mb: Error: no 2nd field after #THRESHOLD=\r\n"); goto STOP; } sscanf (cfield2Ptr, "%f", &f_threshold ); ideltaThreshold = (short) ( f_threshold * scale1 ); fprintf (cp2o, "#Mb: Set: #THRESHOLD= %f volts = %d int\r\n", f_threshold, ideltaThreshold ); continue; } if (strcmp (cfield1Ptr, "#MAXREPEATS=\0") == 0) { // read the history repeat counter max cfield2Ptr = strtok (NULL, " "); if (cfield2Ptr == NULL ) //then no 2nd field was found { fprintf (cp2o, "#Mb: Error: no 2nd field after #MAXREPEATS=\r\n"); goto STOP; } sscanf (cfield2Ptr, "%d", &il_maxBlocks ); fprintf (cp2o, "#Mb: Set: #MAXREPEATS= %d\r\n", il_maxBlocks ); continue; } if (strcmp (cfield1Ptr, "#DEPLETE=\0") == 0) { // read the no of a/d samples ignored between saves cfield2Ptr = strtok (NULL, " "); if (cfield2Ptr == NULL ) //then no 2nd field was found { fprintf (cp2o, "#Mb: Error: no 2nd field after #DEPLETE=\r\n"); goto STOP; } sscanf (cfield2Ptr, "%d", &nldeplete ); fprintf (cp2o, "#Mb: Set: #DEPLETE= %d \r\n", nldeplete); continue; } if (strcmp (cfield1Ptr, "#STEPSIZE=\0") == 0) { // read the voltage increment/decrement cfield2Ptr = strtok (NULL, " "); if (cfield2Ptr == NULL ) //then no 2nd field was found { fprintf (cp2o, "#Mb: Error: no 2nd field after #STEPSIZE=\r\n"); goto STOP; } sscanf (cfield2Ptr, "%i", &ivstepsize ); fprintf (cp2o, "#Mb: Set: #STEPSIZE= %d \r\n", ivstepsize); continue; } if (strcmp (cfield1Ptr, "#END=\0") == 0) { // end of *.env file lines fprintf (cp2o, "#Mb: found #END= in *.env file.\r\n" ); break; } // ignore any comment lines in *.env file } // end of mblk10.env read while() //Check to see if important items were actually read if(icmdError == -1 ) { fprintf (cp2o, "#Mb: Error: #CMDERROR= not found in mblk10.env file"); goto STOP; } if(ipeakError == -1 ) { fprintf (cp2o, "#Mb: Error: #PKERROR= not found in mblk10.env file"); goto STOP; } if(il_daRate1 == 0 ) { fprintf (cp2o, "#Mb: Error: #RATE1= not found in mblk10.env file"); goto STOP; } if(il_daRate2 == 0 ) { fprintf (cp2o, "#Mb: Error: #RATE2= not found in mblk10.env file"); goto STOP; } if(ideltaThreshold == 0 ) { fprintf (cp2o, "#Mb: Error: #THRESHOLD= not found in mblk10.env file"); goto STOP; } if(il_maxBlocks == 0 ) { fprintf (cp2o, "#Mb: Error: #MAXREPEATS= not found in mblk10.env file"); goto STOP; } if(nldeplete == -1 ) { fprintf (cp2o, "#Mb: Error: #DEPLETE= not found in mblk10.env file"); goto STOP; } if(ivstepsize == 0 ) { fprintf (cp2o, "#Mb: Error: #STEPSIZE= not found in mblk10.env file"); goto STOP; } // Read in the history file ----------------------------------------------------- // blocks are in form: #BLOCK= pk1 pk2 nramps // Run data is stored in form: // ipk1 ipk2 nramps irpk1 irpk2 fprintf(cp2o, "#Mb : Waiting for history file...\r\n"); while(1) { //Read the mblk10.his file data lines. find the #HISTORY= line while ( pipe_num(cp2i) <= 0 ) task_switch(); //wait for input to pipe fgets (sentence, 100, cp2i); fprintf(cp2o, "#Mb #HISTORY=wait: got: %s\r\n", sentence); cfield1Ptr = strtok (sentence, " "); //fetch a line // Note that strcmp(s1,s2) = 0 when s1=s2 if (strcmp ( cfield1Ptr, "#HISTORY=\0") == 0) { fprintf(cp2o, "#Mb found #HISTORY= \r\n"); cfield2Ptr = strtok (NULL, " \r\n,"); fprintf(cp2o, "#Mb: cfield2Ptr= %s \r\n", cfield2Ptr ); if (cfield2Ptr == NULL ) //then no 2nd field was found { strcpy (histTitle, "none\0"); } else { strcpy (histTitle, cfield2Ptr); } break; }// if not its a comment line. keep reading lines } fprintf (cp2o, "#Mb: Set #HISTORY= %s\r\n", histTitle); // Read the data lines. 1 value per line, all integers il=0; //counter while (1) { //read and save the volt value (floating pt) while ( pipe_num(cp2i) <= 0 ) task_switch(); //wait for input to pipe fgets (sentence, 100, cp2i); sentencePtr2 = sentencePtr; //make a copy, strtok probably clobbers sentence fprintf(cp2o, "#Mb histDataWait: got: %s\r\n", sentence); cfield1Ptr = strtok (sentence, " \r\n,"); if ( strcmp (cfield1Ptr, "#END=\0") == 0) { fprintf (cp2o, "#Mb: *.his file found #END= after %d data lines\r\n", il); break; } //if its not #END= then it must be data. il=il+1; if( il > MAX_STORE) { fprintf (cp2o, "#Mb: Error: too many history pts. = %d\r\n", il); fprintf (cp2o, "#Mb: recompile mblk10.cpp with bigger MAX_STORE.\r\n"); goto STOP; } //This sscanf line does not work in Borland compiler //sscanf (sentence2, "%d%d%d", &ilpk1, &ilpk2, &nramps[il]); //from flex10b.cpp code sscanf (cfield1Ptr, "%d", &ilpk1 ); // get 1st peak // Note that strcmp(s1,s2) = 0 when s1=s2 cfield2Ptr = strtok (NULL, " "); if (cfield2Ptr == NULL ) //then no 2nd field was found { fprintf (cp2o, "#Mb: Error: no 2nd field in dataline %d \r\n", il); goto STOP; } sscanf (cfield2Ptr, "%d", &ilpk2 ); //get 2nd peak cfield2Ptr = strtok (NULL, " "); if (cfield2Ptr == NULL ) //then no 2nd field was found { fprintf (cp2o, "#Mb: Error: no 3rd field in dataline %d \r\n", il); goto STOP; } sscanf (cfield2Ptr, "%d", &nramps[il] ); //get no. of ramps if( ilpk1 > 32767) { fprintf (cp2o, "#Error: Blk. %d in hist Pk1=%d is > 32767\r\n", il,ilpk1); goto STOP; } if( ilpk1 < -32767) { fprintf (cp2o, "#Error: Blk. %d in hist Pk1=%d is < -32767\r\n", il,ilpk1); goto STOP; } //Seems ok, save it as a short int ipk1[il] = ilpk1; if( ilpk2 > 32767) { fprintf (cp2o, "#Error: Blk. %d in hist Pk2=%d is > 32767\r\n", il,ilpk2); goto STOP; } if( ilpk2 < -32767) { fprintf (cp2o, "#Error: Blk. %d in hist Pk2=%d is < -32767\r\n", il,ilpk2); goto STOP; } //Seems ok, save it as a short int ipk2[il] = ilpk2; fprintf (cp2o, "#Mb: Set ipk1=%d ipk2=%d nramps=%d\r\n", ipk1[il], ipk2[il], nramps[il]); } // end of while() for data lines nlvout=il; //save the total no of history points or sub-blocks // Lets compute some of the timing stuff here // *itime is the no of uSec between a/d conversions, thus: il_adConvRate= 1000000 / (*itime); il_SampPerSecPerChan= il_adConvRate / nchan; // Meanwhile the depletion rate nldeplete will only // keep ever nldeplete a/d value from each channel. Thus in a pipe // setup the user will get: il_userSampPerSecPerChan = il_SampPerSecPerChan / nldeplete; // This is regardless of No. of Chans. It is A/D rate // and each channel takes its turn with the a/d converter. // Thus decrement icount after each sample from AD0 // fprintf (cp2o, "#Mblk10: DAP has set TIME to %d uSec \r\n", *itime ); fprintf (cp2o, "# Thus each of the %d A/D Chans is sampled %d*%d uSecs.\r\n", nchan,nchan,*itime); fprintf (cp2o, "#SampleRate= %d Samples/Sec/Chan.\r\n",il_SampPerSecPerChan ); fprintf (cp2o, "# If you wish to change this rate, change TIME in the *.dap module\r\n"); fprintf (cp2o, "#\n# Data Depletion:\r\n"); fprintf (cp2o, "# In the high speed processes the a/d samples are coming in too fast\r\n"); fprintf (cp2o, "# to all be transmitted to PC. Thus we must deplete some of data\r\n"); fprintf (cp2o, "#Deplete= %d points between transmitted points\r\n", nldeplete ); fprintf (cp2o, "#DepletedSampleRate= %d samples/sec/chan \r\n", il_userSampPerSecPerChan ); // Tell PC side mterml_sh.cpp that mblk10 is ready to start. // PCside will then tell *.dap module to start A/Ds /// write "#READY= \R" to Cp2Out pipe fprintf (cp2o, "#READY= 1 \r\n"); // PCside comterm.cpp will intercept the #READY and send a START A to *.dap // *.dap module will soon start A/Ds. Check for #ADON= from PCside. pipe_open (iP0, P_READ); //pipe from A/D 0 pipe_open (iP1, P_READ); //pipe from A/D 1 pipe_open (bout, P_WRITE); //open the $BINOUT pipe pipe_purge (bout); //clear pipe of leftovers outbuf = pbuf_open (bout, BUF_SIZE); //set size of pipe buffer ibinstore = (short int *) pbuf_get_data_ptr(outbuf); //link the data storage to pipe storage fprintf (cp2o, "#Mb: opened pipes iP0 and iP1 and bout\r\n"); fprintf(cp2o, "#Mb: waiting for #ADON= ....\r\n"); while (1) { while ( pipe_num(cp2i) <= 0 ) task_switch(); //wait for input to pipe fgets (sentence, 100, cp2i); fprintf(cp2o, "#Mb #ADONwait: got: %s\r\n", sentence); cfield1Ptr = strtok (sentence, " "); if ( strcmp (cfield1Ptr, "#ADON=\0") == 0) { fprintf (cp2o, "#Mb: got #ADON= \r\n"); //send out the stuff to populate shared memory iln = (long int)nchan; fprintf(cp2o,"#ForSM= #NCHAN= %li \r\n",iln); fprintf(cp2o,"#ForSM= #STATUS= 1 \r\n"); fprintf(cp2o,"#ForSM= #PKERROR= %i \r\n",ipeakError); fprintf(cp2o,"#ForSM= #CMDERROR= %i \r\n",icmdError); fprintf(cp2o,"#ForSM= #RATE1= %li \r\n",il_daRate1); fprintf(cp2o,"#ForSM= #RATE2= %li \r\n",il_daRate2); fprintf(cp2o,"#ForSM= #THRESHOLD= %i \r\n",ideltaThreshold); fprintf(cp2o,"#ForSM= #DEPLETE= %li \r\n",nldeplete); fprintf(cp2o,"#ForSM= #STEPSIZE= %i \r\n",ivstepsize); fprintf(cp2o,"#ForSM= #MAXREPEATS= %li \r\n",il_maxBlocks); break; } } fprintf(cp2o, "#Mblk10 TEST BEGINS....\r\n"); // Begin continuous processing. // At typical sample rates of "TIME 50" we are getting too many samples // out to do anything with. Thus we deplete before stuffing the // a/d voltages into the $BINOUT pipe. Only when ilsample = nldeplete // we will save or transfer the a/d values of all channels. // At begin of test do this stuff: ilsample=0; //Prep the binary buffer storage ibinstore[0] = 32767; //place 2 markers in buffer ibinstore[1] = -32767; // // since this is the 1st history block, we can just put 0 in next two words ibinstore[2] = 0; //1st half of block no. ibinstore[3] = 1; //2nd half of block no. nlbuff=1; ibinstore[4] = 0; //1st half of buff no. ibinstore[5] = 1; //2nd half of buff no. // leave ibinstore[6] empty for later write of ilbincout ilbincount=6; iendblock = 0; // signal for end of block of peaks when =1 //At this point A/Ds are running. Get a value set pipe_value_get(iP0,&pipe_value); ivad0=pipe_value._i16; ilbincount = ilbincount+1; //save the first ad value ibinstore[ilbincount] = ivad0; ilsample= ilsample+1; istVolts= ivad0; ivoldTarget= ivad0; ivfeedbackMax = ivad0; ivfeedbackMin = ivad0; pipe_value_get(iP1,&pipe_value); ivad1=pipe_value._i16; ilbincount = ilbincount+1; //save the first ad value ibinstore[ilbincount] = ivad1; //START RUNNING // istVolts = present voltage from AD0 // ivout = present output on DA0 // ivTarget = next target voltage // ivoldTarget = previous target voltage // ivDelta or il_diff = diff between target and istVolts (a +ve number) // Target peak or valley is set. Present voltage is set. Start Ramp // Check for null ramp (or same peak or valley as last one) // This would happen if first peak is zero and d/a was reset to zero. //START: ilblock = 1; //a counter for the block we are in ilsubBlock = 0; il_peakptr = 0; while(1) // over all loop that selects a sub-block & counts blocks or HISREPEATS -------------- { ilsubBlock=ilsubBlock+1; //ilsubBlock selects the sub-block or line in history file. if ( ilsubBlock == (nlvout +1) ) { // All sub blocks have been completed, go back to begin & start next block fprintf(cp2o, "#Mb: HistRep %d done.\r\n", ilblock); if(ilblock == il_maxBlocks) { fprintf(cp2o, "#Mb: Max Hist. Reps.= %d reached as per *.env file.\r\n", ilblock); goto CLOSE; } ilblock = ilblock+1; fprintf(cp2o,"#ForSM= #HISREPEATS= %li \r\n",ilblock); ilsubBlock = 1; il_peakptr = 0; } fprintf(cp2o,"#ForSM= #BLOCKNO= %li \r\n",ilsubBlock); il_rampCount = 0; while(1) //-------------------------ramp selector loop ----------------------------------- { // This is the ramp counter. i.e. the no. of ramps between ipk1 and ipk2 il_rampCount = il_rampCount + 1; //fprintf(cp2o,"#ForSM= #RAMPNO= %li \r\n",il_rampCount); //not implemented yet. if( il_rampCount == (nramps[ilsubBlock]+1) ) break; //this sub-block is done il_peakptr = il_peakptr+1; //points to target peak in ivstore[] Equals either 1 or 2 if(il_peakptr ==3 ) il_peakptr = 1; if(il_peakptr == 1) { ivTarget = ipk1[ilsubBlock]; } if(il_peakptr == 2) { ivTarget = ipk2[ilsubBlock]; } il_diff = ( (long)ivTarget - (long)istVolts ); if (il_diff < 0) { il_diff = -il_diff ; //Get abs value of diff ithreshValue = istVolts - (il_diff - ideltaThreshold ) ; } else { ithreshValue = istVolts + (il_diff - ideltaThreshold ) ; } //fprintf(cp2o, "#Mb Ramp: istV= %d ithV= %d ivTarg= %d ipeakW= %d \r\n", // istVolts, ithreshValue, ivTarget, ipeakWindow ); // il_diff has comes out of above if as +ve number if (il_diff <= ipeakWindow) { //we are already there. since its 1st peak do not adjust threshold fprintf(cp2o, "#Mb: Ramp: istV within ivtarg +-ipeakW. get next pk\r\n"); // we dont need to change ivoldTarget. We are still at last point or peak continue; // go to next ramp } // Ok, targ is significantly diff from present peak, thus check direction. // We must use the ivoldTarget as base for computing thresholds etc. if (ivTarget < ivoldTarget ) goto CRAMP; TRAMP: //------------------------ Ramp in the tensile (+ve voltage) direction // In either tensile or compressive ramps there are two "zones" or modes: // 1. check when threshold is reached // ( if yes: then switch to slower rate an approach the peak) // 2. check when peak is reached, // ( if yes: check for Pause etc, then go back to next ramp) // ithreshValue needs to have been set previous to this. il_rateCounter = il_daRate1; //ivout =istVolts; //doing this causes slight jump (cals not same) ilvout=(long)ivout; //keep a long int version for out of range checks dac_out (idac, ivout); //put out 1st voltage of ramp // During a block this actually duplicates what happens at thresh. // but after a PAUSE or on 1st Ramp, it is the only one. //fprintf (cp2o, "#Mb:T.pk= %d ivout= %d ivoldTar= %d ithr= %d ivTar= %d\r\n", // il_peakptr, ivout, ivoldTarget, ithreshValue, ivTarget); ilvoltsOverPeak = ( (long)ivTarget + (long)icmdError ); //compute max D/A value allowed ivfeedbackMax = istVolts; // update d/a & check a/d to see if threshold is reached-------------- Find Threshold--------- while (1) { pipe_value_get (iP0, &pipe_value); ivad0 = pipe_value._i16; //feedback istVolts = ivad0; ilsample = ilsample + 1; //count for depletion il_rateCounter = il_rateCounter -1; //decrement coutner for next d/a out if (il_rateCounter == 0 ) { //time to increment and put out a new voltage if(ipause != 1 ) //if we are in PAUSE do not increment the d/a out voltage { ilvout = ilvout +ivstepsize; if (ilvout <= -32767 || ilvout >= 32767) { fprintf (cp2o, "#Mb:T:Error: D/A volts out of range = %d\r\n",ilvout); goto STOP; } if (ilvout >= ( ilvoltsOverPeak ) )// Check limit of over program { fprintf (cp2o, "#Mb:T:Error: D/A volts exceed overProg Pk = %d\r\n",ilvout); fprintf (cp2o, "#Mb:T: Target= %d, OvProg= %d\r\n",ivTarget,ilvoltsOverPeak); goto STOP; } ivout = (short)ilvout; } //skip to here in PAUSE mode dac_out (idac, ivout); il_rateCounter = il_daRate1; //This is hopefully a good place to check for any commands from mterm // such as cmds sent through shared memory area 1 if( pipe_num(cp2i) > 0 ) //is something in pipe? // Note: this check is only made once each A/D loop. (clock tick) { fgets (sentence, 100, cp2i); //fprintf(cp2o, "#Mb: Got: %s\r\n", sentence); cfield1Ptr = strtok (sentence, " "); //fetch a string // Note that strcmp(s1,s2) = 0 when s1=s2 if (strcmp ( cfield1Ptr, "#PAUSE=\0") == 0) { fprintf(cp2o, "#Mb: Got #PAUSE= \r\n"); fprintf(cp2o, "#ForSM= #STATUS= 0\r\n"); //send status change to sh mem. ipause=1; //set the pause flag to skip d/a ops. // Note.: in a pause the program must keep running in order to // empty the a/d pipes. The only difference is that // no d/a ops occur and one could skip peak detect etc. goto TENDPCHECK; //do this to eliminate other "if" evaluations. //Probably the user will PAUSE before any other cmd. // but not necessarily. } if (strcmp ( cfield1Ptr, "#STOP=\0") == 0) { fprintf(cp2o, "#Mb: Got #STOP= \r\n"); fprintf(cp2o, "#ForSM= #STATUS= 999\r\n"); //send status change to sh mem. ipause=1; //this is a "stop right now" type of comand goto CLOSE; } if (strcmp ( cfield1Ptr, "#CONTINUE=\0") == 0) { fprintf(cp2o, "#Mb: Got #CONTINUE= \r\n"); fprintf(cp2o, "#ForSM= #STATUS= 1\r\n"); //send run status to sh mem. ipause=0; //set the pause flag to skip d/a ops. goto TENDPCHECK; } if (strcmp (cfield1Ptr, "#ILPKERROR=\0") == 0) { //read and save the allowable Peak error in int. cfield2Ptr = strtok (NULL, " "); if (cfield2Ptr == NULL ) //then no 2nd field was found { fprintf (cp2o, "#Mb: Error: no 2nd field after #ILPKERROR=\r\n"); goto TENDPCHECK; } sscanf (cfield2Ptr, "%li", &iln ); ipeakError = (short)(iln); //convert to 16bits fprintf (cp2o, "#ForSM= #PKERROR= %d \r\n",ipeakError); ipeakWindow = ipeakError; goto TENDPCHECK; } if (strcmp (cfield1Ptr, "#ILCMDERROR=\0") == 0) { cfield2Ptr = strtok (NULL, " "); if (cfield2Ptr == NULL ) //then no 2nd field was found { fprintf (cp2o, "#Mb: Error: no 2nd field after #ILCMDERROR=\r\n"); goto TENDPCHECK; } sscanf (cfield2Ptr, "%li", &iln ); icmdError = (short)(iln); //convert to 16bits fprintf (cp2o, "#ForSM= #CMDERROR= %d \r\n",icmdError); goto TENDPCHECK; } if (strcmp (cfield1Ptr, "#ILRATE1=\0") == 0) { cfield2Ptr = strtok (NULL, " "); if (cfield2Ptr == NULL ) //then no 2nd field was found { fprintf (cp2o, "#Mb: Error: no 2nd field after #ILRATE1=\r\n"); goto TENDPCHECK; } sscanf (cfield2Ptr, "%li", &il_daRate1 ); fprintf (cp2o, "#ForSM= #RATE1= %li \r\n",il_daRate1); goto TENDPCHECK; } if (strcmp (cfield1Ptr, "#ILRATE2=\0") == 0) { cfield2Ptr = strtok (NULL, " "); if (cfield2Ptr == NULL ) //then no 2nd field was found { fprintf (cp2o, "#Mb: Error: no 2nd field after #ILRATE2=\r\n"); goto TENDPCHECK; } sscanf (cfield2Ptr, "%li", &il_daRate2 ); fprintf (cp2o, "#ForSM= #RATE2= %li \r\n",il_daRate2); goto TENDPCHECK; } if (strcmp (cfield1Ptr, "#ILTHRESHOLD=\0") == 0) { cfield2Ptr = strtok (NULL, " "); if (cfield2Ptr == NULL ) //then no 2nd field was found { fprintf (cp2o, "#Mb: Error: no 2nd field after #ILTHRESHOLD=\r\n"); goto TENDPCHECK; } sscanf (cfield2Ptr, "%li", &iln ); ideltaThreshold = (short)(iln); //convert to 16bits fprintf (cp2o, "#ForSM= #THRESHOLD= %d \r\n",ideltaThreshold); goto TENDPCHECK; } if (strcmp (cfield1Ptr, "#ILDEPLETE=\0") == 0) { cfield2Ptr = strtok (NULL, " "); if (cfield2Ptr == NULL ) //then no 2nd field was found { fprintf (cp2o, "#Mb: Error: no 2nd field after #ILDEPLETE=\r\n"); goto TENDPCHECK; } sscanf (cfield2Ptr, "%li", &nldeplete ); fprintf (cp2o, "#ForSM= #DEPLETE= %d \r\n",nldeplete); goto TENDPCHECK; } if (strcmp (cfield1Ptr, "#ILSTEPSIZE=\0") == 0) { cfield2Ptr = strtok (NULL, " "); if (cfield2Ptr == NULL ) //then no 2nd field was found { fprintf (cp2o, "#Mb: Error: no 2nd field after #ILSTEPSIZE=\r\n"); goto TENDPCHECK; } sscanf (cfield2Ptr, "%li", &iln ); ivstepsize = (short)( iln ); fprintf (cp2o, "#ForSM= #STEPSIZE= %d \r\n",ivstepsize); goto TENDPCHECK; } if (strcmp (cfield1Ptr, "#ILMAXREPEATS=\0") == 0) { cfield2Ptr = strtok (NULL, " "); if (cfield2Ptr == NULL ) //then no 2nd field was found { fprintf (cp2o, "#Mb: Error: no 2nd field after #ILMAXREPEATS=\r\n"); goto TENDPCHECK; } sscanf (cfield2Ptr, "%li", &il_maxBlocks ); fprintf (cp2o, "#ForSM= #MAXREPEATS= %d \r\n",il_maxBlocks); goto TENDPCHECK; } //if we get to here something odd was in pipe. fprintf(cp2o,"#Mb: Junk in pipe cp2o: %s \r\n",sentence); } //end of cp2i pipe check TENDPCHECK: } //end of d/a output if() pipe_value_get (iP1, &pipe_value); ivad1 = pipe_value._i16; // 2nd a/d channel. if (ilsample == nldeplete) { //fprintf(cp2o, "#Mb: ivout= %d istV= %d \r\n", ivout, istVolts); ilbincount = ilbincount+1; ibinstore[ilbincount] = ivad0; ilbincount = ilbincount+1; ibinstore[ilbincount] = ivad1; if (ilbincount >= ilbinstoremax) //is buffer full? { //buffer is full send to bout i=(short)ilbincount; ibinstore[6]=i; //send the counter too pbuf_put_set_cnt(outbuf, BUF_SIZE); // Prep the next buffer header nlbuff = nlbuff +1; //increment the buffer count ibinstore[0] = 32767; //place a marker in buffer ibinstore[1] = -32767; //place a marker in buffer ilpart = ilblock & 0xFFFF0000; //mask off the bottom 16 bits ibinstore[2] = (short) (ilpart >> 16) ; // shift result to bottom half of 16bit word ilpart = ilblock & 0x0000FFFF; //mask off the top 16 bits ibinstore[3] = (short) ilpart ; // shift result to bottom half of 16bit word ilpart = nlbuff & 0xFFFF0000; //mask off the bottom 16 bits ibinstore[4] = (short) (ilpart >> 16) ; // shift result to bottom half of 16bit word ilpart = nlbuff & 0x0000FFFF; //mask off the top 16 bits ibinstore[5] = (short) ilpart ; // shift result to bottom half of 16bit word ilbincount=6; // leave ibinstore[6] empty for later write of ilbincount //NOTE!: if you alter the number of preliminary non-data pts you // will need to alter ilbinstoremax somewhere above. } // Non-buffered pipe method: //pipe_value._i16 = ivad0; //pipe_value_put (bout, &pipe_value ); //pipe_value._i16 = ivad1 //pipe_value_put (bout, &pipe_value ); ilsample =0; } //Update the comand voltage // ivfeedbackMax is dragged along with istVolts as we go up if (istVolts > ivfeedbackMax ) ivfeedbackMax = istVolts; // There is a possibility that we might reach target in this region (before // reaching the threshold) but we will ignore this for now // If we reach the threshold, break out of while loop if (istVolts >= ithreshValue) { // Yes threshold has been reached. //fprintf (cp2o, "#Mb: got thres. = %d \r\n", ithreshValue); break; //break out of threshold detect while() } } //end of threshold detect while(1) // Now check a/d to see when target is reached. -------Find Peak---------- // As each a/d value comes in also update the d/a // The final target is approached with a il_daRate2 strain rate // It is also possible to run out of numbering system; e.g peak is +10V. Check for this il_rateCounter = il_daRate2; while (1) { pipe_value_get (iP0, &pipe_value); ivad0 = pipe_value._i16; //feedback istVolts = ivad0; ilsample = ilsample + 1; //count for depletion il_rateCounter = il_rateCounter -1; //decrement counter for next d/a out if (il_rateCounter == 0 ) { //time to increment and put out a new voltage if(ipause !=1) //if we are in a PAUSE do not increment d/a out volts { ilvout = ilvout +ivstepsize; if (ilvout <= -32767 || ilvout >= 32767) { fprintf (cp2o, "#Mb:T:Error: D/A volts out of range = %d\r\n",ilvout); fprintf(cp2o, "# Blk= %d, SubBlk= %d \r\n", ilblock, ilsubBlock ); fprintf(cp2o, "# Possible cause: SetPt off, Span too small ?\r\n"); goto STOP; } if (ilvout >= ( ilvoltsOverPeak ) )// Check limit of over program { fprintf (cp2o, "#Mb:T:Error: D/A volts exceed overProg Pk = %d\r\n",ilvout); fprintf (cp2o, "#Mb:T: Target= %d OvProg= %d\r\n",ivTarget,ilvoltsOverPeak); goto STOP; } ivout = (short)ilvout; } //skip to here when in PAUSE //fprintf(cp2o, "#Mbp: %d %d %d\r\n", ivout, istVolts, ivTarget); dac_out (idac, ivout); il_rateCounter = il_daRate2; } pipe_value_get (iP1, &pipe_value); ivad1 = pipe_value._i16; // 2nd a/d channel. if (ilsample == nldeplete) { ilbincount = ilbincount+1; ibinstore[ilbincount] = ivad0; ilbincount=ilbincount+1; ibinstore[ilbincount] = ivad1; if (ilbincount == (ilbinstoremax) ) //subtraction depends on no of a/d Chans. { //buffer is full send to bout i=(short)ilbincount; ibinstore[6]=i; pbuf_put_set_cnt(outbuf, BUF_SIZE); //prep the next buffer header ibinstore[0] = 32767; //place a marker in buffer ibinstore[1] = -32767; //place a marker in buffer ilpart = ilblock & 0xFFFF0000; //mask off the bottom 16 bits ibinstore[2] = (short) (ilpart >> 16) ; // shift result to bottom half of 16bit word ilpart = ilblock & 0x0000FFFF; //mask off the top 16 bits ibinstore[3] = (short) ilpart ; // shift result to bottom half of 16bit word nlbuff = nlbuff +1; ilpart = nlbuff & 0xFFFF0000; ibinstore[4] = (short) (ilpart >> 16) ; ilpart = nlbuff & 0x0000FFFF; ibinstore[5] = (short) ilpart ; // Leave location [6] empty for now ilbincount=6; } //pipe_value._i16 = ivad0 //pipe_value_put (bout, &pipe_value ); //pipe_value._i16 = ivad1 //pipe_value_put (bout, &pipe_value ); ilsample =0; } // ivfeedbackMax is still dragged along with istVolts as we go up if (istVolts > ivfeedbackMax ) { ivfeedbackMax = istVolts; } if (istVolts > (ivTarget - ipeakWindow ) ) // check if within window { // yes, time to reverse ramp. Exit the peak detect while() //fprintf(cp2o, "#Mb: got pk = %d, ivout= %d\r\n", ivfeedbackMax, ivout); //ivoldTarget = ivTarget; break; } } //end of peak detect while loop goto ENDRAMP; //-------------------COMPRESSION RAMP in -ve Voltage direction --------------- CRAMP: // Code is basically a mirror of TRAMP code. // ithreshValue needs to have been set previously. //Compute the initial d/a volt out //m: ivout =(short) ( ( (long)ivoldTarget + (long)ivTarget )/2 ); il_rateCounter = il_daRate1; //ivout = istVolts; //doing this causes slight jump due to diffs in calib. ilvout = (long)ivout; ilvoltsOverPeak = ( (long)ivTarget - (long)icmdError ); dac_out (idac, ivout); //put out 1st voltage of ramp //fprintf (cp2o, "#Mb:C.pk=%d ivout=%d ivoldTarg=%d ivth=%d ivTarg=%d\r\n", // il_peakptr, ivout, ivoldTarget, ithreshValue, ivTarget); //ivfeedbackMin = istVolts; // Update d/a & check a/d to see when threshold is reached------ Find Threshold-------- while (1) { pipe_value_get (iP0, &pipe_value); ivad0 = pipe_value._i16; //feedback istVolts = ivad0; ilsample = ilsample + 1; //count for depletion il_rateCounter = il_rateCounter -1; //decrement couner for next d/a out if (il_rateCounter == 0 ) { //time to increment and put out a new voltage if(ipause != 1) //if we are in a PAUSE skip d/a volt increment { ilvout = ilvout - ivstepsize; if (ilvout <= -32767 || ilvout >= 32767) { fprintf (cp2o, "#Mb:C:Error: D/A volts out of range = %d\r\n",ilvout); fprintf(cp2o, "# Blk= %d, SubBlk= %d \r\n", ilblock, ilsubBlock ); fprintf(cp2o, "# Possible cause: SetPt off, Span too small ?\r\n"); goto STOP; } if (ilvout <= ( ilvoltsOverPeak ) )// Check limit of over program { fprintf (cp2o, "#Mb:C:Error: D/A volts exceed overProg Pk = %d\r\n",ilvout); fprintf (cp2o, "#Mb:C:Target= %d, OvProg= %d\r\n",ivTarget,ilvoltsOverPeak); goto STOP; } ivout = (short)ilvout; } //skip to here during a PAUSE dac_out (idac, ivout); il_rateCounter = il_daRate1; //This is hopefully a good place to check for any commands from mterm // such as cmds sent through shared memory area 1 if( pipe_num(cp2i) > 0 ) //is something in pipe? // Note: this check is only made once each A/D loop. (clock tick) { fgets (sentence, 100, cp2i); //fprintf(cp2o, "#Mb: Got: %s\r\n", sentence); cfield1Ptr = strtok (sentence, " "); //fetch a string // Note that strcmp(s1,s2) = 0 when s1=s2 if (strcmp ( cfield1Ptr, "#PAUSE=\0") == 0) { fprintf(cp2o, "#Mb: Got #PAUSE= \r\n"); fprintf(cp2o, "#ForSM= #STATUS= 0\r\n"); //send status change to sh mem. ipause=1; //set the pause flag to skip d/a ops. // Note.: in a pause the program must keep running in order to // empty the a/d pipes. The only difference is that // no d/a ops occur and one could skip peak detect etc. goto CENDPCHECK; //do this to eliminate other "if" evaluations. //Probably the user will PAUSE before any other cmd. // but not necessarily. } if (strcmp ( cfield1Ptr, "#STOP=\0") == 0) { fprintf(cp2o, "#Mb: Got #STOP= \r\n"); fprintf(cp2o, "#ForSM= #STATUS= 999\r\n"); //send status change to sh mem. ipause=1; //this is a "stop right now" type of comand goto CLOSE; } if (strcmp ( cfield1Ptr, "#CONTINUE=\0") == 0) { fprintf(cp2o, "#Mb: Got #CONTINUE= \r\n"); fprintf(cp2o, "#ForSM= #STATUS= 1\r\n"); //send run status to sh mem. ipause=0; //set the pause flag to skip d/a ops. goto CENDPCHECK; } if (strcmp (cfield1Ptr, "#ForSM= #PKERROR=\0") == 0) { //read and save the allowable Peak error in int. cfield2Ptr = strtok (NULL, " "); if (cfield2Ptr == NULL ) //then no 2nd field was found { fprintf (cp2o, "#Mb: Error: no 2nd field after #ILPKERROR=\r\n"); goto CENDPCHECK; } sscanf (cfield2Ptr, "%li", &iln ); ipeakError = (short)(iln); //convert to 16bits fprintf (cp2o, "#ForSM= #PKERROR= %d \r\n",ipeakError); ipeakWindow = ipeakError; goto CENDPCHECK; } if (strcmp (cfield1Ptr, "#ILCMDERROR=\0") == 0) { cfield2Ptr = strtok (NULL, " "); if (cfield2Ptr == NULL ) //then no 2nd field was found { fprintf (cp2o, "#Mb: Error: no 2nd field after #ILCMDERROR=\r\n"); goto CENDPCHECK; } sscanf (cfield2Ptr, "%li", &iln ); icmdError = (short)(iln); //convert to 16bits fprintf (cp2o, "#ForSM= #CMDERROR= %d \r\n",icmdError); goto CENDPCHECK; } if (strcmp (cfield1Ptr, "#ILRATE1=\0") == 0) { cfield2Ptr = strtok (NULL, " "); if (cfield2Ptr == NULL ) //then no 2nd field was found { fprintf (cp2o, "#Mb: Error: no 2nd field after #ILRATE1=\r\n"); goto CENDPCHECK; } sscanf (cfield2Ptr, "%li", &il_daRate1 ); fprintf (cp2o, "#ForSM= #RATE1= %li \r\n",il_daRate1); goto CENDPCHECK; } if (strcmp (cfield1Ptr, "#ILRATE2=\0") == 0) { cfield2Ptr = strtok (NULL, " "); if (cfield2Ptr == NULL ) //then no 2nd field was found { fprintf (cp2o, "#Mb: Error: no 2nd field after #ILRATE2=\r\n"); goto CENDPCHECK; } sscanf (cfield2Ptr, "%li", &il_daRate2 ); fprintf (cp2o, "#ForSM= #RATE2= %li \r\n",il_daRate2); goto CENDPCHECK; } if (strcmp (cfield1Ptr, "#ILTHRESHOLD=\0") == 0) { cfield2Ptr = strtok (NULL, " "); if (cfield2Ptr == NULL ) //then no 2nd field was found { fprintf (cp2o, "#Mb: Error: no 2nd field after #ILTHRESHOLD=\r\n"); goto CENDPCHECK; } sscanf (cfield2Ptr, "%li", &iln ); ideltaThreshold = (short)(iln); //convert to 16bits fprintf (cp2o, "#ForSM= #THRESHOLD= %d \r\n",ideltaThreshold); goto CENDPCHECK; } if (strcmp (cfield1Ptr, "#ILDEPLETE=\0") == 0) { cfield2Ptr = strtok (NULL, " "); if (cfield2Ptr == NULL ) //then no 2nd field was found { fprintf (cp2o, "#Mb: Error: no 2nd field after #ILDEPLETE=\r\n"); goto CENDPCHECK; } sscanf (cfield2Ptr, "%li", &nldeplete ); fprintf (cp2o, "#ForSM= #DEPLETE= %d \r\n",nldeplete); goto CENDPCHECK; } if (strcmp (cfield1Ptr, "#ILSTEPSIZE=\0") == 0) { cfield2Ptr = strtok (NULL, " "); if (cfield2Ptr == NULL ) //then no 2nd field was found { fprintf (cp2o, "#Mb: Error: no 2nd field after #ILSTEPSIZE=\r\n"); goto CENDPCHECK; } sscanf (cfield2Ptr, "%li", &iln); //cannot be read as a short int ? ivstepsize = (short)( iln ); fprintf (cp2o, "#ForSM= #STEPSIZE= %d \r\n",ivstepsize); goto CENDPCHECK; } if (strcmp (cfield1Ptr, "#ILMAXREPEATS=\0") == 0) { cfield2Ptr = strtok (NULL, " "); if (cfield2Ptr == NULL ) //then no 2nd field was found { fprintf (cp2o, "#Mb: Error: no 2nd field after #ILMAXREPEATS=\r\n"); goto CENDPCHECK; } sscanf (cfield2Ptr, "%li", &il_maxBlocks ); fprintf (cp2o, "#ForSM= #MAXREPEATS= %d \r\n",il_maxBlocks); goto CENDPCHECK; } //if we get to here something odd was in pipe. fprintf(cp2o,"#Mb: Junk in pipe cp2o: %s \r\n",sentence); } //end of cp2i pipe check CENDPCHECK: } //end of d/a output if() pipe_value_get (iP1, &pipe_value); ivad1 = pipe_value._i16; // 2nd a/d channel. if (ilsample == nldeplete) { //fprintf(cp2o, "#Mb: ivout=%d istV=%d \r\n", ivout, istVolts); ilbincount = ilbincount+1; ibinstore[ilbincount] = ivad0; ilbincount = ilbincount+1; ibinstore[ilbincount] = ivad1; if (ilbincount >= (ilbinstoremax) ) //subtraction depends on no of ad chans { //buffer is full send to bout i=(short)ilbincount; ibinstore[6]=i; pbuf_put_set_cnt(outbuf, BUF_SIZE); // Prep the next buffer header ibinstore[0] = 32767; //place a marker in buffer ibinstore[1] = -32767; //place a marker in buffer ilpart = ilblock & 0xFFFF0000; //mask off the bottom 16 bits ibinstore[2] = (short) (ilpart >> 16) ; // shift result to bottom half of 16bit word ilpart = ilblock & 0x0000FFFF; //mask off the top 16 bits ibinstore[3] = (short) ilpart ; // shift result to bottom half of 16bit word nlbuff = nlbuff +1; ilpart = nlbuff & 0xFFFF0000; // save buffer no. ibinstore[4] = (short) (ilpart >> 16) ; ilpart = nlbuff & 0x0000FFFF; ibinstore[5] = (short) ilpart ; // Leave [6] empty for now ilbincount=6; } // non-buffered output version: //pipe_value._i16 = ivad0 //pipe_value_put (bout, &pipe_value ); //pipe_value._i16 = ivad1 //pipe_value_put (bout, &pipe_value ); ilsample =0; } //ivout = (short)( ((long)ivTarget + (long)istVolts)/2 ); //dac_out (idac, ivout); //put out voltage //fprintf(cp2o, "#Mb: ivout=%d istV=%d \r\n", ivout, istVolts); // ivfeedbackMin is dragged along with istVolts as we go down if (istVolts < ivfeedbackMin ) ivfeedbackMin = istVolts; // There is a possibility that we might reach target in this region (before // reaching the threshold) but we will ignore this for now // If we reach the threshold, break out of while loop if (istVolts <= ithreshValue) { // Yes threshold has been reached. Prepare for upward ramp command //fprintf(cp2o, "#Mb: got Cthr= %d \r\n", ithreshValue); break; // break out of threshold detect while(1) } } //end of threshold detect while(1) // Now check a/d to see when old target is reached. -------Find Peak-------------- // As each a/d value comes in also update the d/a // The final target is approached with a il_daRate2 strain rate // It is also possible to run out of numbering system; e.g peak is -10V. Check for this il_rateCounter=il_daRate2; while (1) { pipe_value_get (iP0, &pipe_value); ivad0 = pipe_value._i16; //feedback istVolts = ivad0; ilsample = ilsample + 1; //count for depletion il_rateCounter = il_rateCounter -1; //decrement counter for next d/a out if (il_rateCounter == 0 ) { //time to increment and put out a new voltage if(ipause != 1) //if we are in a PAUSE do not decrement d/a out volts { ilvout = ilvout - ivstepsize; if (ilvout <= -32767 || ilvout >= 32767) { fprintf (cp2o, "#Mb:C:Error: D/A volts out of range = %d\r\n",ilvout); fprintf(cp2o, "# Blk= %d, SubBlk= %d \r\n", ilblock, ilsubBlock ); fprintf(cp2o, "# Possible cause: SetPt off, Span too small ?\r\n"); goto STOP; } if (ilvout <= ( ilvoltsOverPeak ) )// Check limit of over program { fprintf (cp2o, "#Mb:C:Error: D/A volts exceed overProg Pk = %d\r\n",ilvout); fprintf (cp2o, "#Mb:C:Target= %d, OvProg= %d\r\n",ivTarget,ilvoltsOverPeak); goto STOP; } ivout = (short)ilvout; } //skip to here when in PAUSE //fprintf(cp2o, "#Mbp: %d %d %d\r\n", ivout, istVolts, ivTarget); dac_out (idac, ivout); il_rateCounter = il_daRate2; } pipe_value_get (iP1, &pipe_value); ivad1 = pipe_value._i16; // 2nd a/d channel. if (ilsample == nldeplete) { ilbincount = ilbincount+1; ibinstore[ilbincount] = ivad0; ilbincount = ilbincount+1; ibinstore[ilbincount] = ivad1; if (ilbincount >= (ilbinstoremax) )//subtraction depends on no of a/d chans { //buffer is full send to bout i=(short)ilbincount; ibinstore[6]=i; pbuf_put_set_cnt(outbuf, BUF_SIZE); //prep the next buffer header ibinstore[0] = 32767; //place a marker in buffer ibinstore[1] = -32767; //place a marker in buffer ilpart = ilblock & 0xFFFF0000; //mask off the bottom 16 bits ibinstore[2] = (short) (ilpart >> 16) ; // shift result to bottom half of 16bit word ilpart = ilblock & 0x0000FFFF; //mask off the top 16 bits ibinstore[3] = (short) ilpart ; // shift result to bottom half of 16bit word nlbuff = nlbuff +1; ilpart = nlbuff & 0xFFFF0000; // save buffer no. ibinstore[4] = (short) (ilpart >> 16) ; ilpart = nlbuff & 0x0000FFFF; ibinstore[5] = (short) ilpart ; // Leave [6] empty for now ilbincount=6; } //pipe_value._i16 = ivad0 //pipe_value_put (bout, &pipe_value ); //pipe_value._i16 = ivad1 //pipe_value_put (bout, &pipe_value ); ilsample =0; } // ivfeedbackMin is still dragged along with istVolts as we go down if (istVolts < ivfeedbackMin ) { ivfeedbackMin = istVolts; } if (istVolts < (ivTarget + ipeakWindow ) ) // check if above window { // yes, a reversal has been detected // Compare the detected peak to target. ivfeedbackMin is the Observed Peak // Change the threshold for this point by the error amount // But do not change if we were comming off a PAUSE //fprintf(cp2o, "#Mb: got Cpk= %d, ivout= %d\r\n", ivfeedbackMin, ivout); //ivoldTarget = ivTarget; break; // exit loop for PAUSE etc check } } //end of Comp. peak detect while loop ENDRAMP: } //End of Ramp while() // In debug mode put out the peaks and thresholds for plotting if (iendblock == 1) { //fprintf (cp2o, "#Mb: i Pk1 Pk2 n rPk1 rPk2:\r\n"); //il =1; //while (1) //{ fprintf (cp2o, "%d %d %d %d \r\n", il,ipk1[il], ipk2[il],nramp[il], //irpk1[il], irpk2[il] ); //il = il+1; //if (il > nlvout) break; //} iendblock = 0; //turn off the end of block signal } if (ilblock > il_maxBlocks ) //block repeater { // we have reached max required blocks. Let user know and go to CLOSE fprintf (cp2o, "#Mb: max blocks= %d reached\r\n", il_maxBlocks ); goto CLOSE; } } //End of SubBlock while() (also counts Blocks) //----Close files & pipes and STOP-------------------------------------------- CLOSE: //it is not clear if there is a pipe_close() command // Seems there is not one. Probably the *.dap module does it // when it receives a STOP command fprintf (cp2o, "#CLOSE:Debug: %s,%s, %f, %d,%d, %d,%d, %p\r\n", cfield1Ptr, cfield2Ptr, scale2, ipeakWindow, ioldCommand, ivnewTarget, ivad1, bout); STOP: // Send a signal to PCside : comterm.cpp to shut down stuff. fprintf(cp2o, "#STOP= 0 0 0\r\n"); // Exit mblk10 return 0; } // closing brace for int __stdcall ENTRY (PIB **plib) near begining