// CCU box control program, MSU, 7-25-2000 version // The prorgam general description and revision history are at the end of the program. // The only configuration required is: // 1) giving the CCU an identity. // 2) set the maximum PAD number. // 3) set the RomLT value. // 4) enable the correct serial communications code segment (232/485) // The configs are located in the next few highlited lines: // 11-19-2000 Termination character added at the end of each command. // 5-29-2002 Increase read buffer size, if near overflow, flush read buffer. #nodebug #use vdriver.lib //vdriver.lib for timing #use aascz0.lib //AASC driver for channel 0 // for e-shop multichannel box #use aascz1.lib // dean 8-8-2000 #use eziolp31.lib // ********************************************************************** // The following two lines contain the CCU identity; change accordingly: char ccu_id[] = "CCU22:"; // this is the identifier that must precede commands to this particular CCU char ccu_num[] = "22"; // This is used in formatting responses FROM the CCU; should be TWO-DIGIT number // ********************* // The following line defines the highest PAD number: unsigned char RomPM = 48; // the default PADMAX (set to 8 for the prototype box; 24 or 48 for a real CCU) //********************** // The following line defines the threshold ADC value for determining PAD-PLUGGED-IN / NOT-PLUGGED-IN int RomLT = 200; // the default lower threshold, in ADC counts, goes here. // ********************* // the above value for RomLT was found for the 8-channel CCU prototype. I expect the real CCUs // to have a different value. In fact, each CCU might be a little different. To find the appropriate // value, ask the CCU for a full report, and look at the ADC current values for PADs that are plugged // in and not plugged in. RomLT should be the average of these two values. (Of course, this requires // TWO program downloads, but it does the job). // ********************************************************************** int RomRV = 25; // this is the default volts value for the HV voltage ramp (should be OK) unsigned char PADMAX; // initialized from the RomPM constant char cmd[3]; char param1[3]; char param2[4]; char param3[4]; char *id_loc; int cmd_loc; int i; int st; // PAD communication short delay count int lt; // PAD communication long time count int ct; // time count between RS485 transmit and off_485() int LowerThreshold; // this is the 12 bit count from the ADC; initialized from RomLT int Pad_Current[50]; int p1,p2,p3; unsigned char HV_Incr; // this is the maximum change in HV byte param per loop iteration. int Ramp_Volts; unsigned char Noisy; unsigned char PWR; // the flag for power-bit status unsigned char Pad; unsigned char Next_Pad; unsigned char Status[50]; unsigned char Needs_Upload[50]; // zero for OK; one => needs upload unsigned char New_State; unsigned int Update_Log[50]; int HVFromCMD; int HV_Val[50]; // this is the value of the HV setting from the command packet float THR_Val[50]; // this is the value of the Threshold from the command packet float THFromCMD; // this is the Threshold from the command packet unsigned char Watching_Pad[50]; unsigned int Phy_Addr; unsigned char ADC_Select_Bits; unsigned char Addr_Bits_List[25]; unsigned char HV_Set[50]; unsigned char THR_Set[50]; unsigned char HV_Cur[50]; unsigned char THR_Cur[50]; unsigned char Bits; int pktlen; unsigned long tmMark; char PKTTERM = '\r'; char rBuf[1024]; char wBuf[1024]; // [these were 128]... now 1024 char pkt[1024]; struct _Channel *chan; unsigned int buffree; unsigned int minfree = 80; // 80 char from overflow; char rBuf2[1024]; char wBuf2[1024]; // [these were 128]... now 1024 char pkt2[1024]; struct _Channel *chan2; void Exif_Cmd(void); // command processor void Init_Params(void); // initialization void Uploa(void); // This sends the bits the the PADs void Wt(int kkk); // Simply wastes time int Nint(float f); // Nearest Integer Function //********************************MAIN*************************************** nodebug main() { _GLOBAL_INIT(); eioBrdInit(0); lp31ADCInit(); VdInit(); // The following segment is for RS232 communications: outport(0x4084,1); //flip the RS 232 driver anc CTS switches to set outport(0x4083,1); //up both 232 for operation on an LP3100 outport(0x4082,1); chan = aascOpen(DEV_Z0, 0, ASCI_PARAM_8N1+ASCI_PARAM_1200*8, NULL); aascSetReadBuf(chan,rBuf,sizeof(rBuf)); aascSetWriteBuf(chan,wBuf,sizeof(wBuf)); aascTxSwitch(chan,1); aascRxSwitch(chan,1); //End of the RS 232 code segment // The following segment is for RS485 communications: chan2 = aascOpen(DEV_Z1,0,ASCI_PARAM_8N1+ASCI_PARAM_1200*8,NULL); aascSetReadBuf(chan2,rBuf2,sizeof(rBuf2)); //assign read and aascSetWriteBuf(chan2,wBuf2,sizeof(wBuf2)); //write buffers aascTxSwitch(chan2,1); //enable both transmit and aascRxSwitch(chan2,1); //receive off_485(); //make sure you are off the network... // Init_Params(); //********************Here is the main loop beginning******************** do { // First we'll look in the RS232 receive buffer: buffree = aascReadBufFree(chan); if (buffree <= minfree) { aascFlushRdBuf(chan); // flush buffer if minfree characters before overflow; aascPrintf(chan,"\r\nRS232 free buffer LE %d characters, so flushed.\r\n",buffree); } pktlen = aascScanTerm(chan, PKTTERM); if (pktlen) { aascReadBlk(chan,pkt,pktlen,1); // flag value??? memcpy(pkt+pktlen-1,"\0",1); id_loc = strstr(pkt,ccu_id); if( id_loc != NULL ) // IF VALID HEADER { cmd_loc = id_loc - pkt + 6; memcpy( cmd, pkt + cmd_loc, 2 ); memcpy(cmd+2,"\0",1); // reinstall string terminator!!!!!!!! Exif_Cmd(); } } // And next we'll look in the RS485 receive buffer: buffree = aascReadBufFree(chan2); if (buffree <= minfree) { aascFlushRdBuf(chan2); // flush buffer if minfree characters before overflow; if (Noisy) { on_485(); aascPrintf(chan2,"RS485 free buffer LE %d characters, so flushed.\r\n",buffree); Wt(ct); off_485(); } } pktlen = aascScanTerm(chan2, PKTTERM); if (pktlen) { aascReadBlk(chan2,pkt,pktlen,1); // flag value??? memcpy(pkt+pktlen-1,"\0",1); id_loc = strstr(pkt,ccu_id); if( id_loc != NULL ) // IF VALID HEADER { cmd_loc = id_loc - pkt + 6; memcpy( cmd, pkt + cmd_loc, 2 ); memcpy(cmd+2,"\0",1); // reinstall string terminator!!!!!!!! Exif_Cmd(); } } tmMark = MS_TIMER; if (PWR) // no PWR => we can skip the rest of the loop { // begin if (PWR) // Pick the next PAD number and ADC bits... done early to give max settling time for ADC Next_Pad = Pad; // make a copy of the number, to play with Next_Pad++; // bump the number... if (Next_Pad > PADMAX) {Next_Pad = 1;} // recycle at the limit if (Next_Pad < 25) {Phy_Addr=0x8081; ADC_Select_Bits=Next_Pad-1;} // write to /DS1 else {Phy_Addr=0x8101; ADC_Select_Bits=Next_Pad-25;} // write to /DS2 // the very next line is where we can place any additional delay for the ADC settling: // Now read the proper ADC channel if (Pad < 25) Pad_Current[Pad] = eioBrdAI(16); // board #1 -> AIN1 else Pad_Current[Pad] = eioBrdAI(17); // board #2 -> AIN2 // Now set the analog multiplexer to the next PAD current sense line outport(Phy_Addr,ADC_Select_Bits); // select next channel as early as possible // now adjust the current reading to make sense: Pad_Current[Pad] = 4095 - Pad_Current[Pad]; if (Watching_Pad[Pad]) // this allows us to ignore flaky ADC channels if needed... { // then decide about the current New_State = 0; // assume not plugged in if (Pad_Current[Pad] > LowerThreshold) New_State = 1; // current => set state to plugged in if (New_State != Status[Pad]) { // then state has changed if (!New_State) // unplug handler { Status[Pad]=0; aascPrintf(chan,"CCU%s-PAD%d set to unplugged\r\n",ccu_num,Pad); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-PAD%d set to unplugged\r\n",ccu_num,Pad); Wt(ct); off_485(); } } if (New_State) // plugin handler { Status[Pad]=1; HV_Cur[Pad] = 0; // zeroing triggers a rampup to HV_Set Needs_Upload[Pad] = 50; // start the countdown to upload aascPrintf(chan,"CCU%s-PAD%d set to Plugged_In\r\n",ccu_num,Pad); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-PAD%d set to Plugged_In\r\n",ccu_num,Pad); Wt(ct); off_485(); } } } // end of change of state } // end of the decision about current // now adjust the upload countdown: if (Needs_Upload[Pad] > 1) Needs_Upload[Pad] = Needs_Upload[Pad] - 1; // decrement at each pass of the loop // ALL PAD communication passes through this gateway: if ((HV_Cur[Pad] != HV_Set[Pad]) || (THR_Cur[Pad] != THR_Set[Pad]) || (Needs_Upload[Pad] == 1)) { // begin the update/ramp... adjust and send THR_Cur[Pad] = THR_Set[Pad]; // no ramp for the THReshold; just set it. if ((HV_Cur[Pad]+HV_Incr) < HV_Set[Pad]) // is change greater then HV_Incr? HV_Cur[Pad] = HV_Cur[Pad] + HV_Incr; // increase by HV_Incr else if (HV_Cur[Pad] < HV_Set[Pad]) // otherwise, increase by the remainder HV_Cur[Pad] = HV_Set[Pad]; if (HV_Cur[Pad] > HV_Set[Pad]) // no rampdown HV_Cur[Pad] = HV_Set[Pad]; Uploa(); // this sends bits corresponding to the recently adjusted _Cur values Needs_Upload[Pad] = 0; // upload accomplished, clear the request flag // now, if this is the LAST upload, we'll bump the update record: if ((HV_Cur[Pad] == HV_Set[Pad]) && (THR_Cur[Pad] == THR_Set[Pad])) { Update_Log[Pad]++; aascPrintf(chan,"CCU%s-Done uploading to PAD#%d, update log incremented.\r\n",ccu_num,Pad); aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-Done uploading to PAD#%d, update log incremented.\r\n",ccu_num,Pad); aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } } } // end of the update/ramp // and now start using the next pad#, which we computed earlier: Pad = Next_Pad; } // end if (PWR) } while (1); // ************bottom of endless main loop ****************** } // *************************** end of MAIN ****************************** void Uploa(void) //********************************** { unsigned char i; i= Pad; if (i < 25) Phy_Addr=0x8001; // writing to /DS0 else {Phy_Addr=0x8181;i=i-24;} // writing to /DS3 Bits=Addr_Bits_List[i]; //if (Noisy) aascPrintf(chan,"CCU%s-Sending Bits:PAD:%d HV:%d THR:%d\r\n",ccu_num,Pad,HV_Cur[Pad],THR_Cur[Pad]); outport(Phy_Addr,Bits); //set B9=0 Wt(lt); outport(Phy_Addr,Bits | 1); //CLK goes high Wt(st); outport(Phy_Addr,Bits); //set B8=0 Wt(st); outport(Phy_Addr,Bits | 1); //CLK goes high Wt(st); outport(Phy_Addr,Bits | ((THR_Cur[Pad] >> 6) & 2)); //set B7=MSB(THR) Wt(st); outport(Phy_Addr,Bits | ((THR_Cur[Pad] >> 6) & 2) | 1); //CLK goes high Wt(st); outport(Phy_Addr,Bits | ((THR_Cur[Pad] >> 5) & 2)); //set B6 Wt(st); outport(Phy_Addr,Bits | ((THR_Cur[Pad] >> 5) & 2) | 1); //CLK goes high Wt(st); outport(Phy_Addr,Bits | ((THR_Cur[Pad] >> 4) & 2)); //set B5 Wt(st); outport(Phy_Addr,Bits | ((THR_Cur[Pad] >> 4) & 2) | 1); //CLK goes high Wt(st); outport(Phy_Addr,Bits | ((THR_Cur[Pad] >> 3) & 2)); //set B4 Wt(st); outport(Phy_Addr,Bits | ((THR_Cur[Pad] >> 3) & 2) | 1); //CLK goes high Wt(st); outport(Phy_Addr,Bits | ((THR_Cur[Pad] >> 2) & 2)); //set B3 Wt(st); outport(Phy_Addr,Bits | ((THR_Cur[Pad] >> 2) & 2) | 1); //CLK goes high Wt(st); outport(Phy_Addr,Bits | ((THR_Cur[Pad] >> 1) & 2)); //set B2 Wt(st); outport(Phy_Addr,Bits | ((THR_Cur[Pad] >> 1) & 2) | 1); //CLK goes high Wt(st); outport(Phy_Addr,Bits | (THR_Cur[Pad] & 2)); //set B1 Wt(st); outport(Phy_Addr,Bits | (THR_Cur[Pad] & 2) | 1); //CLK goes high Wt(st); outport(Phy_Addr,Bits | ((THR_Cur[Pad] << 1) & 2)); //set B0=LSB(THR) Wt(st); outport(Phy_Addr,Bits | ((THR_Cur[Pad] << 1) & 2) | 1); //CLK goes high Wt(lt); outport(Phy_Addr,0); //This releases /CS Wt(lt); outport(Phy_Addr,Bits); //set B9=0 Wt(lt); outport(Phy_Addr,Bits | 1); //CLK goes high Wt(st); outport(Phy_Addr,Bits | 2); //set B8=1 Wt(st); outport(Phy_Addr,Bits | 3); //CLK goes high Wt(st); outport(Phy_Addr,Bits | ((HV_Cur[Pad] >> 6) & 2)); //set B7=MSB(HV) Wt(st); outport(Phy_Addr,Bits | ((HV_Cur[Pad] >> 6) & 2) | 1); //CLK goes high Wt(st); outport(Phy_Addr,Bits | ((HV_Cur[Pad] >> 5) & 2)); //set B6 Wt(st); outport(Phy_Addr,Bits | ((HV_Cur[Pad] >> 5) & 2) | 1); //CLK goes high Wt(st); outport(Phy_Addr,Bits | ((HV_Cur[Pad] >> 4) & 2)); //set B5 Wt(st); outport(Phy_Addr,Bits | ((HV_Cur[Pad] >> 4) & 2) | 1); //CLK goes high Wt(st); outport(Phy_Addr,Bits | ((HV_Cur[Pad] >> 3) & 2)); //set B4 Wt(st); outport(Phy_Addr,Bits | ((HV_Cur[Pad] >> 3) & 2) | 1); //CLK goes high Wt(st); outport(Phy_Addr,Bits | ((HV_Cur[Pad] >> 2) & 2)); //set B3 Wt(st); outport(Phy_Addr,Bits | ((HV_Cur[Pad] >> 2) & 2) | 1); //CLK goes high Wt(st); outport(Phy_Addr,Bits | ((HV_Cur[Pad] >> 1) & 2)); //set B2 Wt(st); outport(Phy_Addr,Bits | ((HV_Cur[Pad] >> 1) & 2) | 1); //CLK goes high Wt(st); outport(Phy_Addr,Bits | (HV_Cur[Pad] & 2)); //set B1 Wt(st); outport(Phy_Addr,Bits | (HV_Cur[Pad] & 2) | 1); //CLK goes high Wt(st); outport(Phy_Addr,Bits | ((HV_Cur[Pad] << 1) & 2)); //set B0=LSB(HV) Wt(st); outport(Phy_Addr,Bits | ((HV_Cur[Pad] << 1) & 2) | 1); //CLK goes high Wt(lt); outport(Phy_Addr,0); //This releases /CS Wt(lt); } void Init_Params(void) //********************************* { Pad=1; outport (0x04060,1); // set the power control bit high PWR=1; // default to PAD power relay ON st=1; // timing for PAD communication short delay lt=10; // timing for PAD communication long delay ct=1000; // timing between RS485 transmit and off_485() Noisy=0; // default to QUIET mode... as if this is the final version Ramp_Volts = RomRV; // initialize the volts version of the ramp to the default HV_Incr = Nint(255 * (Ramp_Volts / 1000.0)); // find the BYTE value for the HV ramping increment PADMAX = RomPM; // initialize PADMAX to the default LowerThreshold = RomLT; // initialize the lower threshold value for (i=1;i<17;i++) Addr_Bits_List[i]=4*i+28; for (i=17;i<25;i++) Addr_Bits_List[i]=4*i+60; for (i=1;i<50;i++) { HV_Val[i]=0; // This is kept for user feedback THR_Val[i]=3.5; // Full threshold Needs_Upload[i]=1; // All PADs need upload upon startup... Watching_Pad[i]=1; // default all to watched Status[i]=0; // assume that all are unplugged. Update_Log[i]=0; // clear the update log HV_Set[i]=0; // default to no-HV THR_Set[i]=255; // default to full-scale threshold HV_Cur[i]=0; // zero these to start THR_Cur[i]=0; // zero these to start Pad_Current[i]=0; // just in case someone peeks before the values are ready } } //end of the void Init_Params(void) void Exif_Cmd(void) //************************************* // this is the command processor { if (strstr(cmd,"He") || strstr(cmd,"he")) { aascPrintf(chan,"CCU control program version 11-20-2000\r\n"); aascPrintf(chan,"contact: C. Bromberg or Dean Shooltz (MSU)\r\n"); aascPrintf(chan,"CCUnn:Sbnn,xxx,xxx Update PAD nn to HV,THR (BYTE values)\r\n"); aascPrintf(chan,"CCUnn:Svnn,xxx,xxx Update PAD nn to HV,THR (Volts, mVs)\r\n"); aascPrintf(chan,"example: CCU17:Sv06,789,2.1\r\n"); aascPrintf(chan,"example: CCU17:Sb06,202,194\r\n"); aascPrintf(chan,"CCUnn:Stnn,xxx Update PAD nn to THR (millivolt values)\r\n"); aascPrintf(chan,"CCUnn:Shnn,xxx Update PAD nn to HV (Volt values)\r\n"); aascPrintf(chan,"*Note*: use PAD number 99 to send params to ALL PADs\r\n"); aascPrintf(chan,"CCUnn:Srxxx Set the HV ramping increment(001V - 999V)\r\n"); aascPrintf(chan,"CCUnn:Rt Report loop timing\r\n"); aascPrintf(chan,"CCUnn:Rb Send brief, somewhat formatted report\r\n"); aascPrintf(chan,"CCUnn:Rf Send full report\r\n"); aascPrintf(chan,"CCUnn:Cu Clear update log (and dates?)\r\n"); aascPrintf(chan,"CCUnn:Spxx Set PADMAX, the highest pad #(1 - 48)\r\n"); aascPrintf(chan,"CCUnn:Slxxxx Set the lower threshold ADC value\r\n"); aascPrintf(chan,"CCUnn:Swnn Set channel nn to watched(def: ALL Watched)\r\n"); aascPrintf(chan,"CCUnn:Sunn Set channel nn to unwatched (to ignore flakes)\r\n"); aascPrintf(chan,"CCUnn:Upnn Immediately update PAD nn with local values\r\n"); aascPrintf(chan,"CCUnn:Ua Update ALL pads with local values NOW\r\n"); aascPrintf(chan,"CCUnn:Mn enter Noisy mode (for Debugging)\r\n"); aascPrintf(chan,"CCUnn:Mq enter Quiet mode (network-like)\r\n"); aascPrintf(chan,"CCUnn:Pu Turn on the PAD power supplies, force uploads(def: ON)\r\n"); aascPrintf(chan,"CCUnn:Pd Turn off the PAD power supplies\r\n"); aascPrintf(chan,"CCUnn:He Send this help file\r\n"); aascPrintf(chan,"OK\r\n"); } if (strstr(cmd,"Rf")) { on_485(); aascPrintf(chan,"CCU control program version 7-7-2000\r\n"); aascPrintf(chan,"bromberg@pa.msu.edu / shooltz@pa.msu.edu\r\n"); if (PWR) aascPrintf(chan,"PAD power is ON.\r\n"); else aascPrintf(chan,"Pad power is OFF.\r\n"); aascPrintf(chan,"PADMAX = %d\r\n",PADMAX); aascPrintf(chan,"PAD current Threshold = %d\r\n",LowerThreshold); aascPrintf(chan,"HV ramp increment=%d volts, %d as BYTE\r\n",Ramp_Volts,HV_Incr); aascPrintf(chan,"CCU\tPAD\tStatus\tWatch\tHV_Val\tTH_Val\tUpdates\tCurrent\r\n"); for (i=1;i<=PADMAX;i++) { aascPrintf(chan,"%s\t%d\t%d\t%d",ccu_num,i,Status[i],Watching_Pad[i]); aascPrintf(chan,"\t%d\t%3.1f\t%d\t%d\r\n",HV_Val[i],THR_Val[i],Update_Log[i],Pad_Current[i]); } aascPrintf(chan,"OK\r\n"); aascPrintf(chan2,"CCU control program version 7-7-2000\r\n"); aascPrintf(chan2,"bromberg@pa.msu.edu / shooltz@pa.msu.edu\r\n"); if (PWR) aascPrintf(chan2,"PAD power is ON.\r\n"); else aascPrintf(chan2,"Pad power is OFF.\r\n"); aascPrintf(chan2,"PADMAX = %d\r\n",PADMAX); aascPrintf(chan2,"PAD current Threshold = %d\r\n",LowerThreshold); aascPrintf(chan2,"HV ramp increment=%d volts, %d as BYTE\r\n",Ramp_Volts,HV_Incr); aascPrintf(chan2,"CCU\tPAD\tStatus\tWatch\tHV_Val\tTH_Val\tUpdates\tCurrent\r\n"); for (i=1;i<=PADMAX;i++) { aascPrintf(chan2,"%s\t%d\t%d\t%d",ccu_num,i,Status[i],Watching_Pad[i]); aascPrintf(chan2,"\t%d\t%3.1f\t%d\t%d\r\n",HV_Val[i],THR_Val[i],Update_Log[i],Pad_Current[i]); } aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } if (strstr(cmd,"Rb")) { on_485(); for (i=1;i<=PADMAX;i++) { aascPrintf(chan,"%s\t%d\t%d\t%d",ccu_num,i,Status[i],Watching_Pad[i]); aascPrintf(chan,"\t%d\t%3.1f\t%d\t%d\r\n",HV_Val[i],THR_Val[i],Update_Log[i],Pad_Current[i]); aascPrintf(chan2,"%s\t%d\t%d\t%d",ccu_num,i,Status[i],Watching_Pad[i]); aascPrintf(chan2,"\t%d\t%3.1f\t%d\t%d\r\n",HV_Val[i],THR_Val[i],Update_Log[i],Pad_Current[i]); } aascPrintf(chan,"OK\r\n"); aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } if (strstr(cmd,"Rm")) { on_485(); for (i=1;i<=PADMAX;i++) { // aascPrintf(chan,"%s\t%d\t%d\t%d",ccu_num,i,Status[i],Watching_Pad[i]); aascPrintf(chan,"\t%d\t%3.1f\t%d\t%d\r\n",HV_Val[i],THR_Val[i],Update_Log[i],Pad_Current[i]); // aascPrintf(chan2,"%s\t%d\t%d\t%d",ccu_num,i,Status[i],Watching_Pad[i]); aascPrintf(chan2,"\t%d\t%3.1f\t%d\t%d\r\n",HV_Val[i],THR_Val[i],Update_Log[i],Pad_Current[i]); } aascPrintf(chan,"OK\r\n"); aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } if (strstr(cmd,"Cu")) { for (i=1;i<50;i++) Update_Log[i]=0; // clear the update log aascPrintf(chan,"CCU%s-The Update Log has been cleared\r\n",ccu_num); aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-The Update Log has been cleared\r\n",ccu_num); aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } } if (strstr(cmd,"Sw")) // Set Watched { memcpy(param1,pkt+cmd_loc+2,2); memcpy(param1+2,"\0",1); //Important: NULL at the end! p1=atoi(param1); if ((p1>0)&&(p1<=PADMAX)) { Watching_Pad[p1]=1; // update to watched HV_Cur[p1]=0; // trigger HV rampup Needs_Upload[p1]=1; // induce an upload (I think this is a good idea...) aascPrintf(chan,"CCU%s-PAD#%d set to watched status\r\n",ccu_num,p1); aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-PAD#%d set to watched status\r\n",ccu_num,p1); aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } } else { aascPrintf(chan,"CCU%s-Bad PAD number!\r\n",ccu_num); aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-Bad PAD number!\r\n",ccu_num); aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } } } if (strstr(cmd,"Si")) // Set Ignored { memcpy(param1,pkt+cmd_loc+2,2); memcpy(param1+2,"\0",1); //Important: NULL at the end! p1=atoi(param1); if ((p1>0)&&(p1<=PADMAX)) { Watching_Pad[p1]=0; HV_Cur[p1]=0; // trigger rampup of HV Needs_Upload[p1]=1; // induce an upload aascPrintf(chan,"CCU%s-PAD#%d set to ignored status\r\n",ccu_num,p1); aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-PAD#%d set to ignored status\r\n",ccu_num,p1); aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } } else { aascPrintf(chan,"CCU%s-Bad PAD number!\r\n",ccu_num); aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-Bad PAD number!\r\n",ccu_num); aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } } } if (strstr(cmd,"Pu")) { aascPrintf(chan,"CCU%s-PAD power goes on.\r\n",ccu_num); aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-PAD power goes on.\r\n",ccu_num); aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } outport (0x04060,1); // set the power control bit high PWR = 1; // set the flag to on for (i=1;i<=PADMAX;i++) { Needs_Upload[i]=255; //trigger upload after countdown HV_Cur[i]=0; //force rampup of HV } } if (strstr(cmd,"Sr")) // set the HV ramping increment { memcpy(param1,pkt+cmd_loc+2,3); memcpy(param1+3,"\0",1); //Important: NULL at the end! Ramp_Volts=atoi(param1); //integer, from 0 to 999 //dean if ((Ramp_Volts > 0) && (Ramp_Volts <=999)) { p1 = Nint(255 * (Ramp_Volts / 1000.0)); if (p1 <= 0) p1=1; // a zero ramp is disallowed if (p1 > 255) p1=255; HV_Incr=p1; aascPrintf(chan,"CCU%s-HV ramp incr. set to %d volts, %d as byte\r\n",ccu_num,Ramp_Volts,HV_Incr); aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-HV ramp incr. set to %d volts, %d as byte\r\n",ccu_num,Ramp_Volts,HV_Incr); aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } } else { aascPrintf(chan,"CCU%s-bad params!\r\n",ccu_num); aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-bad params!\r\n",ccu_num); aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } } } if (strstr(cmd,"Sb")) // Set _Cur with BYTE values { memcpy(param1,pkt+cmd_loc+2,2); memcpy(param2,pkt+cmd_loc+5,3); memcpy(param3,pkt+cmd_loc+9,3); memcpy(param1+2,"\0",1); //Important: NULL at the end! memcpy(param2+3,"\0",1); //Important: NULL at the end! memcpy(param3+3,"\0",1); //Important: NULL at the end! p1=atoi(param1); p2=atoi(param2); p3=atoi(param3); // don't enforce limits on these... just skip if the values are out of range: if((p1>0)&&(p1<=PADMAX)&&(p2>=0)&&(p2<=255)&&(p3>=0)&&(p3<=255)) { HV_Set[p1]=p2; HV_Val[p1]=Nint(p2 / 255.0 * 1000.0); //approximate THR_Val[p1]=(3.3 * p3 / 255.0) + 0.2; // approximate THR_Set[p1]=p3; Needs_Upload[p1]=1; // force an upload, even for redundant parameters aascPrintf(chan,"CCU%s-HV byte=%d, THR byte=%d\r\n",ccu_num,HV_Set[p1],THR_Set[p1]); aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-HV byte=%d, THR byte=%d\r\n",ccu_num,HV_Set[p1],THR_Set[p1]); aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } } else if (p1 != 99) { aascPrintf(chan,"CCU%s-Bad params!\r\n",ccu_num); aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-Bad params!\r\n",ccu_num); aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } } // Now, if the pad number is the Magic Number, and all else good, set EVERYBODY... if( (p1 == 99) && (p2>=0) && (p2<=255) && (p3>=0) && (p3<=255) ) { for (i=1;i<=PADMAX;i++) { Needs_Upload[i]=1; //trigger an upload HV_Set[i]=p2; THR_Val[i]=(3.3 * p3 / 255.0) + 0.2; // approximate HV_Val[i]=Nint(p2 / 255.0 * 1000.0); //approximate THR_Set[i]=p3; } aascPrintf(chan,"CCU%s-All PADs set to HV byte=%d, THR byte=%d\r\n",ccu_num,p2,p3); aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-All PADs set to HV byte=%d, THR byte=%d\r\n",ccu_num,p2,p3); aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } } } if (strstr(cmd,"Sv")) // Set _Cur with Voltage values { memcpy(param1,pkt+cmd_loc+2,2); memcpy(param2,pkt+cmd_loc+5,3); memcpy(param3,pkt+cmd_loc+9,3); memcpy(param1+2,"\0",1); //Important: NULL at the end! memcpy(param2+3,"\0",1); //Important: NULL at the end! memcpy(param3+3,"\0",1); //Important: NULL at the end! p1=atoi(param1); // this is the PAD # HVFromCMD=atoi(param2); //integer from 1 to 999 THFromCMD=atof(param3); //floating point value n.n if (HVFromCMD < 0) HVFromCMD = 0; if (HVFromCMD > 999) HVFromCMD = 999; if (THFromCMD < 0.2) THFromCMD = 0.2; if (THFromCMD > 3.5) THFromCMD = 3.5; //if (Noisy) aascPrintf(chan,"CCU%s-from command line, HVFromCMD=%d\r\n",ccu_num,HVFromCMD); //if (Noisy) aascPrintf(chan,"CCU%s-from command line, THFromCMD=%3.1f\r\n",ccu_num,THFromCMD); // now convert the values to BYTE values: p2 = Nint(255 * (HVFromCMD / 1000.0)); p3 = Nint(255 * (THFromCMD - 0.2) / 3.3); //if (Noisy) aascPrintf(chan,"CCU%s-HV as nearest bytesize integer=%d\r\n",ccu_num,p2); //if (Noisy) aascPrintf(chan,"CCU%s-TH as nearest bytesize integer=%d\r\n",ccu_num,p3); // now, per Carl's suggestion, make out-of-range values into limit values: if (p2 < 0) p2=0; if (p2 > 255) p2=255; if (p3 < 0) p3=0; if (p3 > 255) p3=255; if((p1>0)&&(p1<=PADMAX)) { // then we're ready... HV_Set[p1]=p2; HV_Val[p1]=HVFromCMD; THR_Set[p1]=p3; THR_Val[p1]=THFromCMD; Needs_Upload[p1]=1; // forces an upload, even in the case of redundant parameters aascPrintf(chan,"CCU%s-HV as sent byte=%d\r\n",ccu_num,p2); // aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-HV as sent byte=%d\r\n",ccu_num,p2); // aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } aascPrintf(chan,"CCU%s-TH as sent byte=%d\r\n",ccu_num,p3); // aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-TH as sent byte=%d\r\n",ccu_num,p3); // aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } } else if (p1 != 99) { aascPrintf(chan,"CCU%s-Bad params!\r\n",ccu_num); aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-Bad params!\r\n",ccu_num); aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } } // Now, if the pad number is the Magic Number, set EVERYBODY... if (p1 == 99) { for (i=1;i<=PADMAX;i++) { Needs_Upload[i]=1; //trigger an upload HV_Set[i]=p2; HV_Val[i]=HVFromCMD; THR_Set[i]=p3; THR_Val[i]=THFromCMD; } aascPrintf(chan,"CCU%s-All PADs set to HV byte=%d, THR byte=%d\r\n",ccu_num,p2,p3); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-All PADs set to HV byte=%d, THR byte=%d\r\n",ccu_num,p2,p3); Wt(ct); off_485(); } } } if (strstr(cmd,"Sh")) // Set _Cur with Voltage values { memcpy(param1,pkt+cmd_loc+2,2); memcpy(param2,pkt+cmd_loc+5,3); memcpy(param1+2,"\0",1); //Important: NULL at the end! memcpy(param2+3,"\0",1); //Important: NULL at the end! p1=atoi(param1); // this is the PAD # HVFromCMD=atoi(param2); //integer from 1 to 999 if (HVFromCMD < 0) HVFromCMD = 0; if (HVFromCMD > 999) HVFromCMD = 999; //if (Noisy) aascPrintf(chan,"CCU%s-from command line, HVFromCMD=%d\r\n",ccu_num,HVFromCMD); // now convert the values to BYTE values: p2 = Nint(255 * (HVFromCMD / 1000.0)); //if (Noisy) aascPrintf(chan,"CCU%s-HV as nearest bytesize integer=%d\r\n",ccu_num,p2); // now, per Carl's suggestion, make out-of-range values into limit values: if (p2 < 0) p2=0; if (p2 > 255) p2=255; if((p1>0)&&(p1<=PADMAX)) { // then we're ready... HV_Set[p1]=p2; HV_Val[p1]=HVFromCMD; Needs_Upload[p1]=1; // forces an upload, even in the case of redundant parameters aascPrintf(chan,"CCU%s-HV as sent byte=%d\r\n",ccu_num,p2); // aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-HV as sent byte=%d\r\n",ccu_num,p2); // aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } } else if (p1 != 99) { aascPrintf(chan,"CCU%s-Bad params!\r\n",ccu_num); aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-Bad params!\r\n",ccu_num); aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } } // If the pad number is the Magic Number, set EVERYBODY... if (p1 == 99) { for (i=1;i<=PADMAX;i++) { Needs_Upload[i]=1; //trigger an upload HV_Set[i]=p2; HV_Val[i]=HVFromCMD; } aascPrintf(chan,"CCU%s-All PADs set to HV byte=%d\r\n",ccu_num,p2); aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-All PADs set to HV byte=%d\r\n",ccu_num,p2); aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } } } if (strstr(cmd,"St")) // Set Threshold_Cur with Voltage values { memcpy(param1,pkt+cmd_loc+2,2); memcpy(param3,pkt+cmd_loc+5,3); memcpy(param1+2,"\0",1); //Important: NULL at the end! memcpy(param3+3,"\0",1); //Important: NULL at the end! p1=atoi(param1); // this is the PAD # THFromCMD=atof(param3); //floating point value n.n if (THFromCMD < 0.2) THFromCMD = 0.2; if (THFromCMD > 3.5) THFromCMD = 3.5; //if (Noisy) aascPrintf(chan,"CCU%s-from command line, THFromCMD=%3.1f\r\n",ccu_num,THFromCMD); // now convert the values to BYTE values: p3 = Nint(255 * (THFromCMD - 0.2) / 3.3); if (Noisy) aascPrintf(chan,"CCU%s-TH as nearest bytesize integer=%d\r\n",ccu_num,p3); // now, per Carl's suggestion, make out-of-range values into limit values: if (p3 < 0) p3=0; if (p3 > 255) p3=255; if((p1>0)&&(p1<=PADMAX)) { // then we're ready... THR_Set[p1]=p3; THR_Val[p1]=THFromCMD; Needs_Upload[p1]=1; // forces an upload, even in the case of redundant parameters aascPrintf(chan,"CCU%s-TH as sent byte=%d\r\n",ccu_num,p3); // aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-TH as sent byte=%d\r\n",ccu_num,p3); // aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } } else if (p1 != 99) { aascPrintf(chan,"CCU%s-Bad params!\r\n",ccu_num); aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-Bad params!\r\n",ccu_num); aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } } // Now, if the pad number is the Magic Number, set EVERYBODY... if (p1 == 99) { for (i=1;i<=PADMAX;i++) { Needs_Upload[i]=1; //trigger an upload THR_Set[i]=p3; THR_Val[i]=THFromCMD; } aascPrintf(chan,"CCU%s-All PADs set to THR byte=%d\r\n",ccu_num,p3); aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-Bad params!\r\n",ccu_num); aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } } } if (strstr(cmd,"Up")) // upload to a specific PAD { memcpy(param1,pkt+cmd_loc+2,2); memcpy(param1+2,"\0",1); //Important: NULL at the end! p1 = atoi(param1); if ((p1>0)&&(p1<=PADMAX)) { Needs_Upload[p1]=1; // force upload HV_Cur[p1]=0; // clearing the HV triggers rampup aascPrintf(chan,"CCU%s-Uploading to PAD#%d now...\r\n",ccu_num,p1); aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-Uploading to PAD#%d now...\r\n",ccu_num,p1); aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } } else { aascPrintf(chan,"CCU%s-Bad PAD#!\r\n",ccu_num); aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-Bad PAD#!\r\n",ccu_num); aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } } } if (strstr(cmd,"Ua")) // Upload to all PADs { aascPrintf(chan,"CCU%s-Uploading to all PADs now...\r\n",ccu_num); aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-Uploading to all PADs now...\r\n",ccu_num); aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } for (i=1;i<=PADMAX;i++) { Needs_Upload[i]=1; //trigger upload HV_Cur[i]=0; //force rampup of HV } } if (strstr(cmd,"Mn")) { Noisy=1; aascPrintf(chan,"CCU%s-now in Noisy mode\r\n",ccu_num); aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-now in Noisy mode\r\n",ccu_num); aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } } if (strstr(cmd,"Mq")) { Noisy=0; aascPrintf(chan,"CCU%s-Entering RS485 quiet mode.\r\n",ccu_num); aascPrintf(chan,"OK\r\n"); } if (strstr(cmd,"Pd")) { aascPrintf(chan,"CCU%s-PAD power is now shut off...\r\n",ccu_num); aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-PAD power is now shut off...\r\n",ccu_num); aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } outport (0x04060,0); // set the power control bit low; PWR = 0; // set the flag to 'off' for (i=1;i<=PADMAX;i++) { Pad_Current[i]=0; // default to 0 when is power off; } } if (strstr(cmd,"Sl")) // set the threshold value for PAD current decision { memcpy(param1,pkt+cmd_loc+2,4); memcpy(param1+4,"\0",1); //Important: NULL at the end! p1=atoi(param1); if((p1>=0)&&(p1<=4095)) { LowerThreshold = p1; aascPrintf(chan,"CCU%s-the lower threshold has been set to %d\r\n",ccu_num,LowerThreshold); aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-the lower threshold has been set to %d\r\n",ccu_num,LowerThreshold); aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } } else { aascPrintf(chan,"CCU%s-bad params!\r\n",ccu_num); aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-bad params!\r\n",ccu_num); aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } } } if (strstr(cmd,"Tt")) // test the Wt() delay function { memcpy(param1,pkt+cmd_loc+2,4); memcpy(param1+4,"\0",1); //Important: NULL at the end! p1=atoi(param1); if((p1>=0)&&(p1<=9999)) { ct=p1; aascPrintf(chan,"CCU%s-test of the Wt(%d)\r\n",ccu_num,ct); tmMark = MS_TIMER; Wt(ct); aascPrintf(chan,"CCU%s-mS=%d\r\n",ccu_num,MS_TIMER-tmMark); aascPrintf(chan,"OK\r\n"); } } if (strstr(cmd,"Sp")) { memcpy(param1,pkt+cmd_loc+2,2); memcpy(param1+2,"\0",1); //Important: NULL at the end! p1=atoi(param1); if((p1>0)&&(p1<=48)) { PADMAX = p1; aascPrintf(chan,"CCU%s-PADMAX is now%d\r\n",ccu_num,PADMAX); aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-PADMAX is now%d\r\n",ccu_num,PADMAX); aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } } else { aascPrintf(chan,"CCU%s-bad params!\r\n",ccu_num); aascPrintf(chan,"OK\r\n"); if (Noisy) { on_485(); aascPrintf(chan2,"CCU%s-bad params!\r\n",ccu_num); aascPrintf(chan2,"OK\r\n"); Wt(ct); off_485(); } } } if (strstr(cmd,"Rt")) { aascPrintf(chan,"CCU%s-mS since bottom of command chain=%d\r\n",ccu_num,MS_TIMER-tmMark); aascPrintf(chan,"OK\r\n"); } } // end of the command processor void Wt(int kkk) // function to absorb time { for (i=1;i<=kkk;i++){} } int Nint(float f) { // function body. Z-World didn't include a nearest-integer function! if ( (ceil(f)-f) <= (f-floor(f)) ) return ceil(f); else return floor(f); }