/* Alerts Control Script
123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456*/
/*===================================-======================================*/
/*                              ALERT ACTIONS                               */
/*-----------------------------------=--------------------------------------*/
/* AUTHORs:        Abdelouahab Abdesselam

   DESIGN ISSUEs:  This Script (file) changes the status of the Channel and the
                   status of the Crate, provides alert actions and writes
                   alert Values & Addresses to 'AlertHistory.txt' file in
                   the 'log' directory

   CONVENTIONS: - warning: not very important, some messages must be issued...etc.
   				- alarm: very important, some thing should be done...etc.
   	            - alert = warning or alarm
   	            
   MODIF_HISTORY:  28.10.2003 - first version
                   22.11.2003 - use one dpQueryConnectSingle(..) instead of two
                                dpConnect(..). This is because there was a
                                synchronisation problem when the 2 connected work
                                functions try to change the same datapoint element.
                                this happens, for example, when changing the channel Stat
                                after occuring of an alarm (warn and alrm).
                   03.12.03   - connection is to channel alarm datapoint and no 
                                longer to the crate one.
                   16.12.03   - add the code for counting the number of channels in alarm in 
                   				a crate. this is done in separate function crateCounter(...).
                   				this finction is conected to every channel Stat.
                   20.01.04   - channel and card have, now, only one Stat data point elemenet:
                                this means that there's no difference between LV and HV parameters.
                                they are treated on the same foot of equality...
                              - change fatal to alarm.
                   ?.02.04    - added two function: crateControllerAlerts and decodeChannelAndCardStat
/*--------------------------------------------------------------------------*/

main()
{
  string systemName = getSystemName();
  
  //dpSet(systemName+"Warn.Indx:_original.._value", 1);  /* System Warn_Thresold*/
  //dpSet(systemName+"Alrm.Indx:_original.._value", 1);  /* System alrm_Thresold*/
  dpConnect("startAndStopAlertsScript", FALSE, systemName+"Alert.Stat:_online.._value");
}

//this function simply connect and disconnect another function: warningAlarmActions
//and serve to start and stop the PVSS informative alert actions. (Remark: this does not  stop the script
// in the lib!!)
startAndStopAlertsScript(string alertStatPath, int alertStatValue)
 { 
 	int crate;
 	int hostMax, nodeMax, portMax, unitMax, crateMax;
 	string log_dir_path, cratePath;
 	
 	string systemName = getSystemName();
 	
 	//get the system configuration (find how many crate are used)
    dpGet(systemName+"Hmax.Numb:_original.._value"  , hostMax);
    dpGet(systemName+"Nmax.Numb:_original.._value"  , nodeMax);
    dpGet(systemName+"Pmax.Numb:_original.._value"  , portMax);
    dpGet(systemName+"Umax.Numb:_original.._value"  , unitMax);

    crateMax = hostMax * nodeMax * portMax * unitMax;

    if(alertStatValue)
   	  {
   	 	 //get log directory path (to put alarm history files there)
	     log_dir_path = getPath(LOG_REL_PATH);
         setAlertActions(log_dir_path+"AlertsHistory.txt", 10000, 1);
       	 Debug("\n  ALERT CONTROL SCRIPT STARTED...\n");
   	  }
    else
   	  {
   	 	 dpQueryDisconnect("warningAlarmActions", "chan_alertActions");
   	 	 dpQueryDisconnect("warningAlarmActions", "lvca_alertActions");
   	 	 
   	 	 dpQueryDisconnect("decodeChannelAndCardStat", "decodeChannelStat");
   	 	 dpQueryDisconnect("decodeChannelAndCardStat", "decodeLVcardStat");
   	 	 dpQueryDisconnect("decodeChannelAndCardStat", "decodeHVcardStat");
   	 	 
   	 	 dpQueryDisconnect("crateCounter", "crateCounterID");
	   	 dpDisconnect("closeAlertHistoryFile", systemName+"Alert.Indx:_original.._value");
	   	 for(crate=0; crate<crateMax; crate++)
	   	    {  
	   	       sprintf(cratePath, "Crate%02d", crate);
	   	       dpDisconnect("crateControllerAlerts", cratePath+".Controller.CCieEcod.Recv:_original.._value");
	   	    }
	   	 Debug("\n  ALERT CONTROL SCRIPT STOPPED...\n");
   	  }
 }

//this function do some initilisations and connect the alarm actions functions to channels and cards...etc.
setAlertActions(string alertsHistoryFileName, int alertsHistoryFileLenght, int hours)
 { 
   int success, crateState, LV_cardState, HV_cardState, channelState, alertRange;
   int icrate, ilvcard, ihvcard, ichannel, iparameter;
   int channelWarningCounter, channelAlarmCounter, channelWarningThreshold, channelAlarmThreshold;
   int LV_cardWarningCounter, LV_cardAlarmCounter, LV_cardWarningThreshold, LV_cardAlarmThreshold;
   int crateWarningCounter, crateAlarmCounter, crateWarningThreshold, crateAlarmThreshold;
   int systemWarningCounter, systemAlarmCounter, systemWarningThreshold, systemAlarmThreshold;
   int hostMax, nodeMax, portMax, unitMax, crateMax, lvcardMax, hvcardMax, channelMax;
   
   string cratePath, lvcardPath, hvcardPath, channelPath, query, alert_message;
   dyn_string channelParametersNames, LV_cardParametersNames;
   
   string systemName = getSystemName();
   
   //these are the channel parameters that contain alarm handling:
   channelParametersNames = makeDynString("LVch_Vcc", "LVps_Vcc", "LVretVcc", "LVch_Icc", "LVch_Vdd", 
  								          "LVps_Vdd", "LVretVdd", "LVch_Idd", "LVchVCSV", "LVchVCSI", 
  								          "LVchPINV", "LVchPINI", "MOch_Tm0", "MOch_Tm1", "HVchVolt", "HVchCurr");
    
   //these are the LV card parameters that contain alarm handling:
   LV_cardParametersNames = makeDynString("LVcaTemp", "LVcaPowr");
   
   // file for alarm History;
   addGlobal("alertHistoryFileName", STRING_VAR);
   addGlobal("alertFileName"       , STRING_VAR);
   // time between opening two alarm history files
   addGlobal("fileOpeningTime", TIME_VAR);
   //period at which one want to open a new file, file may opened each hour, each two hours ...etc.
   addGlobal("nHours", INT_VAR);
   //if it happens that one has to open several files within an hour an index is added to the file name
   addGlobal("secondary_files_index", INT_VAR);
   
   secondary_files_index = 0;
   nHours = hours;
   //innitialise warn and alrm thresholds (above these values the channel and crate state are changed)
   //1) for channels
   channelAlarmThreshold = 1;
   channelWarningThreshold = 1;
   //2) for LV Cards
   LV_cardWarningThreshold = 1;
   LV_cardAlarmThreshold = 1;
   //3) for crates
   crateWarningThreshold = 10;
   crateAlarmThreshold = 10;

   //file manipaulations
   alertFileName = alertsHistoryFileName;
   fileOpeningTime  = getCurrentTime();
   alertFileName = strrtrim(alertFileName, ".txt"); 
   alertHistoryFileName = formatTime(alertFileName+"_%Hh.txt", fileOpeningTime);
   
   addGlobal("alertHistoryFile", FILE_VAR);
   // counter for the number of line in the alerts history file
   addGlobal("number_of_lines", INT_VAR);
   addGlobal("fileLenght", INT_VAR);
   fileLenght = alertsHistoryFileLenght;
   number_of_lines = 0;
   // open Alerts history file for information
   alertHistoryFile = fopen(alertHistoryFileName, "w");  
   
   //print the column tiles line
   fprintf(alertHistoryFile, 
   "  COMMENTS           PVSS DATA POINT ELEMENT ADDRESSES      TIME AND DATE    CHAN W/A CNTR  LIMITS   DPE VALUES\n\n");
   
   //get the system configuration (find how many crate are used)
   dpGet(systemName+"Hmax.Numb:_original.._value"  , hostMax);
   dpGet(systemName+"Nmax.Numb:_original.._value"  , nodeMax);
   dpGet(systemName+"Pmax.Numb:_original.._value"  , portMax);
   dpGet(systemName+"Umax.Numb:_original.._value"  , unitMax);
   dpGet(systemName+"Cmax.Numb:_original.._value"  , channelMax);

   lvcardMax = 12; //to be replaced later (wait for info from Serguey!!)
   hvcardMax = 6; //same as before
   crateMax = hostMax * nodeMax * portMax * unitMax;
  
   //intialise the counters of the total number of alerts (warn and alrm) in the system
   systemWarningCounter = 0;
   systemAlarmCounter   = 0;
   
   // connect alerts actions to crates alert datapoints elements
   for(icrate=0; icrate<crateMax; icrate++)
    {
    	//intialise the counters of the number of alerts channels (warn and alrm) in each crate
        crateWarningCounter = 0;    
        crateAlarmCounter   = 0;
   		// form the crate path. take care of the two digit format!
		sprintf(cratePath, "Crate%02d", icrate);
         
     	// get crate state
     	dpGet(systemName+cratePath+".Stat:_online.._value", crateState);
        // check if the crate is in "off" state. if yes then escape!
       	//if((crateState & 0xC) != 0x0)//to be re-added later
     	  //{ 
            //loop on the channels in a crate
            for(ichannel=0; ichannel<channelMax; ichannel++)
               { 
                  //intialise channel alarm counters
                  channelWarningCounter = 0;
                  channelAlarmCounter = 0;
                  
                  //form channel path. take care of the two digit format!
                  sprintf(channelPath, "%s.Channel%02d", cratePath, ichannel);
                  //get the channel status
             	  dpGet(channelPath+".Stat:_online.._value", channelState); 
             	  // check if the channel is included. if not escape!
   				  if((channelState & 0xC) != 0x0)
   				    { 
                  	   //count how many  channel parameters are in alarm ( warn or alrm)
               	  	   for(iparameter=1; iparameter<=dynlen(channelParametersNames); iparameter++)
               	  	 	  {  
             		   		 //get parameter range of the alarm: alrm low, warn low, ok, warn high or alrm high
               		   		 dpGet(channelPath+"."+channelParametersNames[iparameter]
               		   		 								+".Recv:_alert_hdl.._act_range", alertRange);
               				 //increment the alert counters accordingly
               				 if(alertRange==2 || alertRange==4)//warn ranges
               					{
               					   channelWarningCounter = channelWarningCounter + 1;
               					}
               				 else if(alertRange==1 || alertRange==5)//alrm ranges
               					{
               					   channelWarningCounter = channelWarningCounter + 1; //because an alarm means also a warning!
               					   channelAlarmCounter = channelAlarmCounter + 1;
               					}
               	  	 	  }//end of for(iparameter=1; ...)
               	  	   //zero the two most right bits (status bits)
               	  	   channelState = channelState & 0xFFFFFC;
                  	   //change the channel status according the number of warn and alrm
                  	   if(channelAlarmCounter >= channelAlarmThreshold)
             	    	 { 
             		   		//set alarm
             		   		channelState = channelState | 0x1;
               	    	 }
                  	   else if(channelWarningCounter >= channelWarningThreshold)
             	    	 { 
             		   	 	//set warning
             		   		channelState = channelState | 0x2;
             	    	 }
                  	   dpSet(systemName+channelPath+".Stat:_original.._value", channelState);
                  	   
                  	   //initialise  the channel warning and alarm counters
                       dpSet(systemName+channelPath+".WarnMesg.Counter:_original.._value", channelWarningCounter);
                       dpSet(systemName+channelPath+".AlrmMesg.Counter:_original.._value", channelAlarmCounter);
                  
                       //set Thresholds: how many parameters must be in warn or in alarm to trigger a warn or alrm in a LV channel?
                       dpSet(systemName+channelPath+".WarnMesg.Threshold:_original.._value", channelWarningThreshold);
                       dpSet(systemName+channelPath+".AlrmMesg.Threshold:_original.._value", channelAlarmThreshold);
                       
                       //set the warn and alrm message to "" (i.e., empty message!)
           	           dpSet(systemName+channelPath+".WarnMesg.Message:_original.._value", "");
           	      	   dpSet(systemName+channelPath+".AlrmMesg.Message:_original.._value", ""); 
           	      	             				             				  
           	      	   //connect the action scripts
           	      	   query = "SELECT '_online.._value' FROM '{"+channelPath+
             		  	   				 ".WarnMesg.Message,"+channelPath+".AlrmMesg.Message}'";
				 	   dpQueryConnectSingle("warningAlarmActions", FALSE, "chan_alertActions", query);
				 	   
				 	   //connect the channel hardware Stats (LV and HV Stat) to the workfunction that treat these Stats
				 	   query = "SELECT '_online.._value' FROM '{"+channelPath+
             		  	   				 ".LVchStat.Recv,"+channelPath+".HVchStat.Recv}'";
				 	   dpQueryConnectSingle("decodeChannelAndCardStat", FALSE, "decodeChannelStat", query);
   				    }//end of if((channelState...)
               	  
   				  //count warning channels in the crate
   				  if(channelWarningCounter >= channelWarningThreshold)
   				    {
                       crateWarningCounter =  crateWarningCounter + 1; 
                    }  
                  //count alarm channels in the crate
   				  if(channelAlarmCounter >= channelAlarmThreshold)
   				    {
                       crateAlarmCounter =  crateAlarmCounter + 1; 
                       crateWarningCounter =  crateWarningCounter + 1; //because an alarm means also a warning!
                    }   
               }//end for(ichannel=0; ic...)
        
               //loop on the LV cards in a crate. the LV card is considered exactly as a channel!
               for(ilvcard=0; ilvcard<lvcardMax; ilvcard++)
                  {
				     //intialise card alert counters
                     LV_cardWarningCounter = 0;
                     LV_cardAlarmCounter = 0;
                     //form card path. take care of the two digit format!
                     sprintf(lvcardPath, "%s.LV_card%02d", cratePath, ilvcard);
                     //get the LV card status
             	     dpGet(lvcardPath+".Stat:_online.._value", LV_cardState); 

 				     // check if the LV card is included
   				     if((LV_cardState & 0xC)  != 0x0)
   				       { 
               	  	      //count how many LV card parameters are in alarm ( warn or alrm)
               	  	      for(iparameter=1; iparameter<=dynlen(LV_cardParametersNames); iparameter++)
               	  		     { 
             		   		    //get parameter range of the alarm: alrm low, warn low, ok, warn high or alrm high
               		   		    dpGet(lvcardPath+"."+LV_cardParametersNames[iparameter]+".Recv:_alert_hdl.._act_range", alertRange);
               				    //increment the LV alarm counters accordingly
               				    if(alertRange==2 || alertRange==4)//warn ranges
               				      {
               					     LV_cardWarningCounter = LV_cardWarningCounter + 1;
               				      }
               				    else if(alertRange==1 || alertRange==5)//alrm ranges
               				      {
               					     LV_cardWarningCounter = LV_cardWarningCounter + 1; //because an alarm means also a warning!
               					     LV_cardAlarmCounter   = LV_cardAlarmCounter + 1; 
               				      }
               	  		     }//end of for(iparameter=1; ...)
               	  	      //zero the two most right bits (status bits)
               	  	      LV_cardState = LV_cardState & 0xFFFFFC;
                  	      //change the LV card status according the number of warn and alarm and increment 
                  	      //crate alert counters. the LV card is considered exactly as a channel!
                  	      if(LV_cardAlarmCounter >= LV_cardAlarmThreshold)
             	    	    { 
             		   		   //set Alarm
             		   		   LV_cardState = LV_cardState | 0x1;
             		   		   //inrement crate warning and Alarm counter
             		   		   crateWarningCounter =  crateWarningCounter + 1;
             		   		   crateAlarmCounter =  crateAlarmCounter + 1; //because an alarm means also a warning!
               	    	    }
                  	      else if(LV_cardWarningCounter >= LV_cardWarningThreshold)
             	    	    { 
             		   	 	   //set warning
             		   		   LV_cardState = LV_cardState | 0x2;
             		   		   //inrement crate warning counter
             		   		   crateWarningCounter =  crateWarningCounter + 1;
             	    	    }
                  	      dpSet(systemName+lvcardPath+".Stat:_original.._value", LV_cardState);
         
                  	      //initialise  the LV card warning and alarm counters
                          dpSet(systemName+lvcardPath+".WarnMesg.Counter:_original.._value", LV_cardWarningCounter);
                          dpSet(systemName+lvcardPath+".AlrmMesg.Counter:_original.._value", LV_cardAlarmCounter);
                  
                          //set Thresholds: how many parameters must be in warn or in slarm to trigger a warn or alrm in a LV card?
                          dpSet(systemName+lvcardPath+".WarnMesg.Threshold:_original.._value", LV_cardWarningThreshold);
                          dpSet(systemName+lvcardPath+".AlrmMesg.Threshold:_original.._value", LV_cardAlarmThreshold);
                       
                          //set the warn and alrm message to "" (i.e., empty message!)
           	              dpSet(systemName+lvcardPath+".WarnMesg.Message:_original.._value", "");
           	      	      dpSet(systemName+lvcardPath+".AlrmMesg.Message:_original.._value", ""); 
           	      	                				             				  
           	      	      //connect the action scripts
           	      	      query = "SELECT '_online.._value' FROM '{"+lvcardPath+
             		  	   				    ".WarnMesg.Message,"+lvcardPath+".AlrmMesg.Message}'";             		  	 			    
				 	      dpQueryConnectSingle("warningAlarmActions", FALSE, "lvca_alertActions", query);
				 	      
				 	      //connect the LV card hardware Stat to the workfunction that treat these Stats
				 	      query = "SELECT '_online.._value' FROM '{"+lvcardPath+".LVcaStat.Recv}'";
				 	      dpQueryConnectSingle("decodeChannelAndCardStat", FALSE, "decodeLVcardStat", query);
   				       }//end of if((LV_cardState...)

                  }//end for(ilvcard=0; ic...)
 
               //loop on the HV cards in a crate. this is to decode the Hardware Stat
               for(ihvcard=0; ihvcard<hvcardMax; ihvcard++)
                  {
                     //form card path. take care of the two digit format!
                     sprintf(hvcardPath, "%s.HV_card%02d", cratePath, ihvcard);
                     //get the HV card status
             	     dpGet(hvcardPath+".Stat:_online.._value", HV_cardState); 

 				     // check if the HV card is included
   				     if((HV_cardState & 0xC)  != 0x0)
   				       { 				 	      
				 	      //connect the HV cards hardware Stat to the workfunction that treat these Stats
				 	      query = "SELECT '_online.._value' FROM '{"+hvcardPath+".HVcaStat.Recv}'";
				 	      dpQueryConnectSingle("decodeChannelAndCardStat", FALSE, "decodeHVcardStat", query);
   				       }

                  }//end for(ihvcard=0; ic...)
           				             				  
                //print the number of warn/alrm in each crate
                sprintf(alert_message, "Number of channels and LV_card in Warning in  Crate %2d  at Start: %5d",
                                                                                             icrate, crateWarningCounter);
                fprintf(alertHistoryFile, "                    %s \n", alert_message);
                //send the message to DAQ
                dpSet(cratePath+".Controller.AlertToDaq:_original.._value", alert_message);
                
                sprintf(alert_message, "Number of channels and LV_card in Alarm   in  Crate %2d  at Start: %5d",
                                                                                             icrate, crateAlarmCounter);
                fprintf(alertHistoryFile, "                    %s \n\n", alert_message);
                //send the message to DAQ
                dpSet(cratePath+".Controller.AlertToDaq:_original.._value", alert_message);

			   //count the number of the channel in alert in the system
               systemWarningCounter = systemWarningCounter + crateWarningCounter;
			   systemAlarmCounter   = systemAlarmCounter + crateAlarmCounter;
			   
			   //set the crate thresholds
 		 	   dpSet(cratePath+".WarnMesg.Threshold:_original.._value", crateWarningThreshold,
 		  	   cratePath+".AlrmMesg.Threshold:_original.._value", crateAlarmThreshold);
 		  	   
   			   //this is to deal with the crate status: first one has to count the number of channel in alert (warn or alrm) 
   			   //and then decide, depending on a threshold, if the crate should be in alert or not.
   			   //connect the crate counter function to the all channels stat dpe's
    		   query = "SELECT '_online.._value' FROM '{"+cratePath+
            						".Channel*.Stat,"+cratePath+".LV_card*.Stat}'";
			   dpQueryConnectAll("crateCounter", TRUE, "crateCounterID", query);
			   
			   //this connection is to process the alerts comming from the crate controller (ELMB)
			   dpConnect("crateControllerAlerts", FALSE, cratePath+".Controller.CCieEcod.Recv:_original.._value");
          //}//end of if((crateState & 0xC) > 0x0)//to be re-added later
     }//end of for(icrate=0; icrate < crateMax; icrate++)
    
   //print the total number of warn/alrm in the system
   sprintf(alert_message, "Number of channels and LV_card in Warning in the System at Start: %5d", systemWarningCounter);
   fprintf(alertHistoryFile, "                    %s \n", alert_message);
   //send the message to DAQ
   dpSet(cratePath+".Controller.AlertToDaq:_original.._value", alert_message);
   
   sprintf(alert_message, "Number of channels and LV_card in Alarm  in the System at Start: %5d", systemAlarmCounter);
   fprintf(alertHistoryFile, "                    %s \n\n", alert_message);
   //send the message to DAQ
   dpSet(cratePath+".Controller.AlertToDaq:_original.._value", alert_message);
   
   //close the alarm history file (for debuging)
   dpConnect("closeAlertHistoryFile",FALSE, systemName+"Alert.Indx:_original.._value");
 }
 
//this function implement the alarm actions.
warningAlarmActions(string identifier, dyn_dyn_anytype dpeNameAndValue)
 { 
 
 /*---------------------------------------------------------------------
 REMARK: in the following script, the names, often, refer to channels (e.g.
 	     channelStatus, channelWarningCounter...etc). but, in fact, this 
 	     script holds also for LV cards. this is true because the LV cards
 	     have, in our database, just the same structure as channels.
  ------------------------------------------------------------------------*/
  
   int    channelStatus, channelWarningCounter, channelWarningThreshold, channelAlarmCounter, channelAlarmThreshold;
   int    crateStatus, alertRange;
   int    increment, delta_time;
   float  alertLimit, alertValue;

   string cratePath, channelPath, parameterName;
   string alert_message, alert_type, came_went;
   dyn_string dpeSplit1, dpeSplit2, dpeSplit3;
  
   //****************************
   //this is to mesure this work function execution time
   //int seconds, milli_seconds;
   //float start_time, finish_time;
   
   
   //sscanf(formatTime("%S ", getCurrentTime(), "%04d"), "%d %d", seconds, milli_seconds);
   //start_time = seconds + milli_seconds/1000.0;
   //****************************
   
   //get the message isseued by the alert (warn or alrm)
   alert_message = dpeNameAndValue[2][2];
   //this return is needed because when connecting and disconnecting alert several time (see begining of this file)
   //the FALSE option in dpConnect functions (that means don't execute this funstion the first time) seems do not
   // work for a second, third, ...etc. connection (may be PVSS bug!) 
   if(alert_message == "") return;

   // find (construct) the channel path. remember
   // that the format of alert_message is (in case of warning came):
   // sprintf(alert_message, "WARNING CAME | %s | %s", dpeName, local_time) 
   dpeSplit1 = strsplit(alert_message, "|");
   // remove 1 blanc from the begining and the end of dpeSplit1[2],
   // otherwine dpGet complains!!
   dpeSplit1[2] = strltrim(dpeSplit1[2], " ");
   dpeSplit1[2] = strrtrim(dpeSplit1[2], " ");
   // remeber that the format of dpeName is:
   // sys:CrateXX.ChannelXX.Parameter
   dpeSplit2 = strsplit(dpeSplit1[2], ".");
   
   // construct the channel path:
   channelPath = dpeSplit2[1]+"."+dpeSplit2[2];

   // construct the crate path 
   cratePath = dpeSplit2[1];

   //get the crate status
   dpGet(cratePath+".Stat:_online.._value", crateStatus);
   // check that state is not off and crate is not disabled
   if(((crateStatus & 0xC) != 0x0) &&      // crate is included
     (( crateStatus & 0x3) != 0x3))        // Status is not Disabled
   	  {  
  		 // get the  channel status
   		 dpGet(channelPath+".Stat"+":_online.._value", channelStatus);

  		 // check that state is not off, channel is not disabled
  		 if(((channelStatus & 0xC) != 0x0) &&      // Channel is included
    	   ((channelStatus & 0x3) != 0x3))     // Status is not Disable
   	 	   {   
   	  		  // find if the alert is a warn or a alrm and if came or went (see the format above)
   	   		  dpeSplit3 = strsplit(dpeSplit1[1], " ");
   	  		  alert_type = dpeSplit3[1];
   	 		  came_went  = dpeSplit3[2];

   	 		  //warning actions
   	 		  if(alert_type == "WARNING")
   			    {
   		  		   // set the channel status; remember that the status is (at least) 8 bit
         		   // variable, it contains state and status in the 4 first bits
         		   // from the right; here we write to only the two first bits;
        	 	   // 00 means OK, 01 means Alarm, 10 means Warn and 11 means disabled
          		   if(came_went == "CAME") 
  	          		 { 
    	      		    increment = +1;
  	        	     }
          		   else
  	        	     { 
    	     		    increment = -1;
             	     }  
             	     
   		  		   //get the channel warning counter
   			       dpGet(channelPath+".WarnMesg.Counter:_online.._value", channelWarningCounter);
   			       //increment the channel warning counter
   			       channelWarningCounter = channelWarningCounter + increment;
   			
   			 	   //set the channel warning counter
   			       dpSet(channelPath+".WarnMesg.Counter:_original.._value", channelWarningCounter);
   			       
   			       //get the channel warning threshold
   			       dpGet(channelPath+".WarnMesg.Threshold:_online.._value", channelWarningThreshold);
	 
   			       // check that channel Status is not alarm
   			       if((channelStatus & 0x3) != 0x1)       
   			         {  
     		            if(channelWarningCounter >= channelWarningThreshold)
     		              {	
   			  	             //zero the most right two bits (status bits) 
     	     	        	 channelStatus = channelStatus & 0xFFFFFC;
   			  	             //set warning
     			      	     channelStatus = channelStatus  | 0x2;
     		              }
     		            else
     		              {
     			             //zero the most right two bits (status bits) 
     	     	        	 channelStatus = channelStatus & 0xFFFFFC;
     			             // remove warning (ok, then!!)
     			             channelStatus = channelStatus  | 0x0;
     		              }
     		            //set the (new) channel status
     		     	    dpSet(channelPath+".Stat:_original.._value", channelStatus);
   			         }//end of if((channelStatus & 0x3) != 0x1)
   			     
   			      // write to alert history file first,
   			      // get the actual value of the element that caused the warning
   			      dpGet(dpeSplit1[2]+".Recv:_online.._value", alertValue);
   			      //get parameter range of the alert: alrm low, warn low, ok, warn high or alrm high
               	  dpGet(dpeSplit1[2]+".Recv:_alert_hdl.._act_range", alertRange);

               	  //get the corresponding limit (to be printed in the alert history file)
               	  //Remark: because PVSS don't provide an easy way to get the limit that was crossed by an alert
               	  //(there is a bug and a request has been sent to the help), this is just a bricolage!! eg the limit 
               	  //given when the alert goes from low values to normal values is not correct (to be corrected when
               	  // a proper solution will be given by PVSS desk)
               	  if(alertRange >= 3) 
               	         dpGet(dpeSplit1[2]+".Recv:_alert_hdl.4._l_limit", alertLimit);
               	  else
               	         dpGet(dpeSplit1[2]+".Recv:_alert_hdl.2._u_limit", alertLimit);
   			  		               
   			  	  sprintf(alert_message, "PVSS %s |  %5d   | %8.2f  | %8.2f",
                                            alert_message, channelWarningCounter, alertLimit, alertValue);
   			      fprintf(alertHistoryFile, "%s\n", alert_message);
   			      //send the message to DAQ
   			      dpSet(cratePath+".Controller.AlertToDaq:_original.._value", alert_message);
   			      
   			      //increment the counter of lines in the history file and open a new if necessary
                  alertHistoryFileCounter();
   			    }//end of if(alert_type == "WARNING")
   	 		  else if(alert_type == "ALARM")
   		 	    {
   		 	       // set the channel status; remember that the status is (at least) 8 bit
   				   // variable, it contains state and status in the first 4 bits
   				   // from the right; here we write to only the two first bits;
   				   // 00 means OK, 01 means Alarm, 10 means Warn and 11 means disabled
   	 		       if(came_went == "CAME") 
   	 		         { 
     			        increment = +1;
				        //here are the actions taken when some of the parameters go to alert state
				        /*
        		        switch(parameterName)
     	 		          { 
     	 			         case "MOchTm0":
       				         case "MOchTm1":
          	   		 	        // send emergency message
               			        // dpSet() ...etc.
            		         break;
       		
       				         case "HVchVolt":
			   			        //set volt some secure value!
         	   		  	        //dpSet(dpeSplit1[2]+".Send:_original.._value", 80);
           			         break;
       		
       				         case "HVchCurr":
       					        //do some thing
         		
            		         break;
     	 		          }//end of switch(parameterName)
     	 		          */
   	 		         }//end of if(came_went == "CAME")
   	 		       else
   	  		  	     { 
     			        increment = -1;
   	    	  	     }      
   	    	  	     
   	 		       //get the channel alarm counter
   			       dpGet(channelPath+".AlrmMesg.Counter:_online.._value", channelAlarmCounter);
   			       //increment the channel alarm counter
   			       channelAlarmCounter = channelAlarmCounter + increment;
   			       
   			       //set the channel alarm counter
   			       dpSet(channelPath+".AlrmMesg.Counter:_original.._value", channelAlarmCounter);
   			
   			       //get the channel alarm threshold
   			       dpGet(channelPath+".AlrmMesg.Threshold:_online.._value", channelAlarmThreshold);	 

   			       //get the value of channel warning counter and threshold (neded when alarm goes (ie disappear))
   			       dpGet(channelPath+".WarnMesg.Counter:_online.._value", channelWarningCounter,
   		 					 channelPath+".WarnMesg.Threshold:_online.._value", channelWarningThreshold);
   			     	
     		       if(channelAlarmCounter >= channelAlarmThreshold)
     		         { 
   			  	        //zero the most right two bits (status bits) 
     	                channelStatus = channelStatus & 0xFFFFFC;
   			  	        //set alarm
     			        channelStatus = channelStatus  | 0x1;
     		         }
     		       else if(channelWarningCounter >= channelWarningThreshold)
     		         {
     			        //zero the most right two bits (status bits) 
     	                channelStatus = channelStatus & 0xFFFFFC;
     			        // remove alarm (warning, then!!) 
     			        channelStatus = channelStatus  | 0x2;
     		         }
     		       //set the (new) channel status
     		       dpSet(channelPath+".Stat:_original.._value", channelStatus);
   
   			      // write to alert history file first,
   			      // get the actual value of the element that caused the warning
   			      dpGet(dpeSplit1[2]+".Recv:_online.._value", alertValue);
   			      //get parameter range of the alert: alrm low, warn low, ok, warn high or alrm high
               	  dpGet(dpeSplit1[2]+".Recv:_alert_hdl.._act_range", alertRange);
               	  
               	  //get the corresponding limit
               	  //Remark: because PVSS don't provide an easy way to get the limit that was crossed by an alert
               	  //(there is a bug and a request has been sent to the help), this is just a bricolage!! eg the limit 
               	  //given when the alert goes from low values to normal values is not correct (to be corrected when
               	  // a proper solution will be given by PVSS desk)
               	  if(alertRange >= 3) 
               	         dpGet(dpeSplit1[2]+".Recv:_alert_hdl.5._l_limit", alertLimit);
               	  else
               	         dpGet(dpeSplit1[2]+".Recv:_alert_hdl.1._u_limit", alertLimit);

                  sprintf(alert_message, "PVSS %s |  %5d   | %8.2f  | %8.2f",
                                            alert_message, channelAlarmCounter, alertLimit, alertValue);
   			      fprintf(alertHistoryFile, "%s\n", alert_message);
   			      //send the message to DAQ
   			      dpSet(cratePath+".Controller.AlertToDaq:_original.._value", alert_message);

   			      //increment the counter of lines in the history file and open a new if necessary
                  alertHistoryFileCounter();
   		 	    }//end of else if(alert_type == "Alarm")
  		   }// end of  if(((channelStatus...)
     }//end of if(((CrateStatus...)
     
  //****************************
  //this is to mesure this work function execution time
  //sscanf(formatTime("%S ", getCurrentTime(), "%04d"), "%d %d", seconds, milli_seconds);
  //finish_time = seconds + milli_seconds/1000.0;
  //DebugN("============================== finish_time-start_time = ", finish_time-start_time);
  //****************************
 }

//decode the channels and cards hardware Stat
decodeChannelAndCardStat(string identifier, dyn_dyn_anytype dpeNameAndValue)
 { 
 
 /*---------------------------------------------------------------------
 REMARK: in the following script, the names, often, refer to channels (e.g.
 	     channelStat...etc). but, in fact, this 
 	     script holds also for LV cards. this is true because the LV cards
 	     have, in our database, just the same structure as channels.
  ------------------------------------------------------------------------*/
  
   int    channelHWStat;
   string cratePath, channelPath, alert_message, local_time_date;
   dyn_string pathSplit1;
  
   //get the alert_message isseued by the alert (warn or alrm)
   channelPath = dpeNameAndValue[2][1];
   channelHWStat = dpeNameAndValue[2][2];
     
   //get crate path, channel path and local date and time
   pathSplit1 = strsplit(channelPath, ".");
   cratePath = pathSplit1[1];
   channelPath = cratePath+"."+pathSplit1[2];
   local_time_date = formatTime("%H:%M:%S %d/%m/%Y", getCurrentTime());
   
   //find out if the stat's change concern a channel or a card
   if(substr(pathSplit1[2], 0, 7) == "Channel") //then the change is in channel Stat
   	 {
   	    //find out if the alert concerns an LV parameter or an HV parameter. first, consider LV case
   	    if(substr(pathSplit1[3], 0, 2) == "LV")
   	      {
   	 	     //check if bit five is 1 (0x10 is 00010000). if so, it means error in a LV parameter of a channel (trip,...etc.)
   	         if((channelHWStat&0x10) != 0)
   	           {
   	       	     if((channelHWStat&0x1) != 0) //the first bit is for Idd current trip (0x1 is 00000001)
   	       	       {
   	       	          alert_message = "ELMB Alert Mesg   | "+channelPath+"          | "+local_time_date+" | Idd Trip";   	     
   	       	          //write the alert message to DAQ
   	       	          dpSet(cratePath+".Controller.AlertToDaq:_original.._value", alert_message);
   	       	          //write the alert message to the history file
   	       	          fprintf(alertHistoryFile, "%s\n", alert_message);
   	       	          //increment the counter of lines in the history file and open a new if necessary
                      alertHistoryFileCounter();
   	       	       }
   	       	     if((channelHWStat&0x2) != 0)//the second bit is for Icc current trip (0x2 is 00000010)
   	       	   	   {
   	       	          alert_message = "ELMB Alert Mesg   | "+channelPath+"          | "+local_time_date+" | Icc Trip";   	     
   	       	          //write the alert message to DAQ
   	       	          dpSet(cratePath+".Controller.AlertToDaq:_original.._value", alert_message);
   	       	          //write the alert message to the history file
   	       	          fprintf(alertHistoryFile, "%s\n", alert_message);
   	       	          //increment the counter of lines in the history file and open a new if necessary
                      alertHistoryFileCounter();
   	       	       }
   	       	     if((channelHWStat&0x4) != 0)//the third bit is for module temperature trip (0x4 is 00000100)
   	       	       {
   	       	          alert_message = "ELMB Alert Mesg   | "+channelPath+"          | "+local_time_date+" | Module Temperature Trip";   	     
   	       	          //write the alert message to DAQ
   	       	          dpSet(cratePath+".Controller.AlertToDaq:_original.._value", alert_message);
   	       	          //write the alert message to the history file
   	       	          fprintf(alertHistoryFile, "%s\n", alert_message);
   	       	          //increment the counter of lines in the history file and open a new if necessary
                      alertHistoryFileCounter();
   	       	       }
   	       	     if((channelHWStat&0x8) != 0)//the fourth bit is for communication error (0x8 is 00001000)
   	       	       {
   	       	          alert_message = "ELMB Alert Mesg   | "+channelPath+"          | "+local_time_date+" | Communication Error";   	     
   	       	          //write the alert message to DAQ
   	       	          dpSet(cratePath+".Controller.AlertToDaq:_original.._value", alert_message);
   	       	          //write the alert message to the history file
   	       	          fprintf(alertHistoryFile, "%s\n", alert_message);
   	       	          //increment the counter of lines in the history file and open a new if necessary
                      alertHistoryFileCounter();
   	       	       }
   	       	     if((channelHWStat&0x20) != 0)//the fist bit is for channel break down (0x20 is 00100000)
   	       	       {
   	       	          alert_message = "ELMB Alert Mesg   | "+channelPath+"          | "+local_time_date+" | Channel Break Down";   	     
   	       	          //write the alert message to DAQ
   	       	          dpSet(cratePath+".Controller.AlertToDaq:_original.._value", alert_message);
   	       	          //write the alert message to the history file
   	       	          fprintf(alertHistoryFile, "%s\n", alert_message);
   	       	          //increment the counter of lines in the history file and open a new if necessary
                      alertHistoryFileCounter();
   	       	       }
   	           }
   	      }
   	    else if(substr(pathSplit1[3], 0, 2) == "HV") //then, consider the HV parameter case
   	      {
   	         //check if bit sixth is 1 (0x10 is 00100000). if so, it means error in an HV parameter of a channel (trip,...etc.)
   	         if((channelHWStat&0x20) != 0)
   	           {
   	       	     if((channelHWStat&0x40) != 0) //the seventh bit is for HV current trip (0x40 is 01000000)
   	       	       {
   	       	          alert_message = "ELMB Alert Mesg   | "+channelPath+"          | "+local_time_date+" | HV Current Trip";   	     
   	       	          //write the alert message to DAQ
   	       	          dpSet(cratePath+".Controller.AlertToDaq:_original.._value", alert_message);
   	       	          //write the alert message to the history file
   	       	          fprintf(alertHistoryFile, "%s\n", alert_message);
   	       	          //increment the counter of lines in the history file and open a new if necessary
                      alertHistoryFileCounter();
   	       	       }
   	       	     if((channelHWStat&0x80) != 0) //the eightch bit is for HV voltage trip (0x80 is 10000000)
   	       	       {
   	       	          alert_message = "ELMB Alert Mesg   | "+channelPath+"          | "+local_time_date+" | HV Voltage Trip";   	     
   	       	          //write the alert message to DAQ
   	       	          dpSet(cratePath+".Controller.AlertToDaq:_original.._value", alert_message);
   	       	          //write the alert message to the history file
   	       	          fprintf(alertHistoryFile, "%s\n", alert_message);
   	       	          //increment the counter of lines in the history file and open a new if necessary
                      alertHistoryFileCounter();
   	       	       }
   	       	   }
   	      }
   	 }
   else //the change is in card Stat
     {
     	//find out if the stat's change concern an LV card, ot HV card
     	if(substr(pathSplit1[2], 0, 2) == "LV") // the change is in LV_Card Stat
     	  {
     	     if((channelHWStat&0x1) != 0) //the first bit is for Hard Wired Interlock (0x1 is 00000001)
   	       	   {
   	       	      alert_message = "ELMB Alert Mesg   | "+channelPath+"          | "+local_time_date+" | Hard Wired Interlock";   	     
   	       	      //write the alert message to DAQ
   	       	      dpSet(cratePath+".Controller.AlertToDaq:_original.._value", alert_message);
   	       	      //write the alert message to the history file
   	       	      fprintf(alertHistoryFile, "%s\n", alert_message);
   	       	      //increment the counter of lines in the history file and open a new if necessary
                  alertHistoryFileCounter();
   	       	   }
     	  }
     	else //the change is in HV_Card Stat
     	  {
     	     //HV card errors are not implemeted yet
     	  }
     }
}


//this function counts the number of channel in alert in a crate and set its status accordingly..
crateCounter(string identifier, dyn_dyn_anytype statNameAndValue)
 { 
 	int index, channelStatus, LV_cardlStatus, crateStatus;
  	int crateWarningCounter, crateAlarmCounter;
  	int crateWarningThreshold, crateAlarmThreshold;
    string channelPath, cratePath;
	dyn_string channelPathSplit;
 
 	//initialise the counters to zero
	crateWarningCounter = 0; 
	crateAlarmCounter   = 0;
	
 	//get the crate path
 	//statNameAndValue[2][1] contains the first channel path: SCTmops1:CrateXX.Channel00.LV_Stat
 	channelPath = statNameAndValue[2][1];
 	channelPathSplit = strsplit(channelPath, ".");
 	cratePath = channelPathSplit[1];
 	
 	//get the crate status
 	dpGet(cratePath+".Stat:_online.._value", crateStatus);
 	
 	if((crateStatus & 0xC) != 0x0) // crate is included
 	  {
 		 //loop on the channels Stat to count the channels that are in 
 		 //alert (ie in warn or in alrm). index 2->59 (this corresponds to 48 channel!)
		 for(index=2; index<=59; index++)
       	    {
       	  	   //channel Stat: the loop index is on channel00 Stat
	   	 	   channelStatus = statNameAndValue[index][2];
	   	  
	   	  	   //increment the counters depending on the Stat value:
	   	  	   if((channelStatus&0x3)==1) //channel Stat is alarm
	   	    	 {
	   	  	   	    crateAlarmCounter = crateAlarmCounter + 1; //because an alarm means also a warning!
	   	  	   	    crateWarningCounter = crateWarningCounter + 1;
	   	  		 }
	   	  	   else if((channelStatus&0x3)==2) //channel Stat is warning
	   	    	 {
	   	  	   	    crateWarningCounter = crateWarningCounter + 1;
	   	  		 }
       	    }
       	    
       	 //loop on the LV cards Stat to count the cards in 
 		 //alarm (ie in alrm or in warn). index 98->109 (this corresponds to 12 LV cards!)
		 for(index=50; index<=dynlen(statNameAndValue); index++)
       	    {
       	  	   //get the LV Card Stat
	   	 	   LV_cardlStatus = statNameAndValue[index][2];
	   	  
	   	  	   //increment the counters depending on the Stat value:
	   	  	   if((LV_cardlStatus&0x3)==1) //LV card Stat is alarm
	   	    	 {
	   	  	   	    crateAlarmCounter = crateAlarmCounter + 1;
	   	  	   	    crateWarningCounter = crateWarningCounter + 1;
	   	  		 }
	   	  	   else if((LV_cardlStatus&0x3)==2) //LV card Stat is warning
	   	    	 {
	   	  	   	    crateWarningCounter = crateWarningCounter + 1;
	   	  		 }
       	    }
 	
		 //set the crate counters
 		 dpSet(cratePath+".WarnMesg.Counter:_original.._value", crateWarningCounter,
 		  	   cratePath+".AlrmMesg.Counter:_original.._value", crateAlarmCounter);
 	
 		 //set the crate Stat depending on the crate thresholds
 		 dpGet(cratePath+".WarnMesg.Threshold:_online.._value", crateWarningThreshold,
 		  	   cratePath+".AlrmMesg.Threshold:_online.._value", crateAlarmThreshold);
  		 //zero the most right two bits (status bits), this means also make the status ok!
   	     crateStatus = crateStatus & 0xFFFFFC;
   	     //change the crate status
 		 if(crateAlarmCounter >= crateAlarmThreshold)
 	  	   {
 	  	 	  //crate is in alarm
 	  	 	  crateStatus = crateStatus | 0x1;
 	  	   }
 		 else if(crateWarningCounter >= crateWarningThreshold)
 	  	   {
 	  	 	  //crate is warning
 	  	 	  crateStatus = crateStatus | 0x2;
 	  	   }
 		 dpSet(cratePath+".Stat:_original.._value", crateStatus);
 	  } //end of if((crateStatus & 0xC) != 0x0)    
 }

//this function process the alerts informations send by the crate controller (ELMB)
crateControllerAlerts(string controllerAlertPath, int alertType)
{
	int crate, channel, card, parameter;
	float parameterValue, IV_volt, IV_current;
	string alert_message, channelPath, cardPath, parameterPath, local_time_date;
	dyn_string HV_parameters, LV_parameters, slotMapToCard;
	
	string systemName = getSystemName();
	
	HV_parameters = makeDynString("HVchVolt", "HVchCurr");
	LV_parameters = makeDynString("MOch_Tm0", "MOch_Tm1", "LVchStat");
	//this map the slots on the crate to LV and HV cards (slot0-> LVcard00, slot1->HVcard00, slot2->LVcard01...etc.)
	slotMapToCard = makeDynString("LV_card00", "HV_card00", "LV_card01", "LV_card02", "HV_card01", "LV_card03", "LV_card04", 
	                              "HV_card02", "LV_card05", "LV_card06", "HV_card03", "LV_card07", "LV_card08", "HV_card04", 
	                              "LV_card09", "LV_card10", "HV_card05", "LV_card11");
	
	//get current local date and time
    local_time_date = formatTime("%H:%M:%S %d/%m/%Y", getCurrentTime());
   
	//find out wich crate is in alert
	sscanf(controllerAlertPath, systemName+"Crate%d.Controller.CCieEcod.Recv:original..value", crate);
	//DebugN("\n\n\n\n==================== controllerAlertPath = ", controllerAlertPath, "alertType = ", alertType, "crate = ", crate);

	switch(alertType)
	   {
	       //1) 0xFF00: some (LV or HV) card is missing
	       case 65280: 
	          //get the number of the card in alert
	          strreplace(controllerAlertPath, "CCieEcod.Recv:original..value", "CCieEcod1.Recv:online..value");
	          dpGet(controllerAlertPath, card);
	          
	          //send a messeage to DAQ
	          strreplace(controllerAlertPath, "CCieEcod1.Recv:online..value", "AlertToDaq:original..value");	          
	          sprintf(cardPath, systemName+"Crate%02d.%s", crate, slotMapToCard[card]);
	          alert_message = "ELMB Alert Mesg   | "+cardPath+"          | "+local_time_date+" | This card is missing";
	          dpSet(controllerAlertPath, alert_message);
	          //write the alert message to the history file
   	       	  fprintf(alertHistoryFile, "%s\n", alert_message);
   	       	  //increment the counter of lines in the history file and open a new if necessary
              alertHistoryFileCounter();
	       break;
	       
	       //2)  0xFF01: some parameter in a channel is in alert
	       case 65281:
	          //get the number of the channel in alert
	          strreplace(controllerAlertPath, "CCieEcod.Recv:original..value", "CCieEcod1.Recv:online..value");
	          dpGet(controllerAlertPath, channel);
	          //DebugN("===================== channel = ", channel);
	          //find out the number of the channel and if it is LV or HV parameter
	          if(channel-128 >= 0)
	            {
	               //then this is an HV parameter
	               channel = channel - 128; //convetion
	               //find out wich HV parameter is in alert
	               strreplace(controllerAlertPath, "CCieEcod1.Recv:online..value", "CCieEcod2.Recv:online..value");
	               dpGet(controllerAlertPath, parameter);
	               //DebugN("===================== parameter = ", parameter);
	               parameter = parameter - 128; //convetion
	               //get the parameter value
	               sprintf(parameterPath, systemName+"Crate%02d.Channel%02d.%s.Recv:online..value",
	                                                                   crate, channel, HV_parameters[parameter+1]);
	               dpGet(parameterPath, parameterValue);
	               strreplace(parameterPath, ".Recv:online..value", "");
	               
	               //message to be sent DAQ
	               sprintf(alert_message, "ELMB Alert Mesg   | %s | %s | T Alarm  | %5.2f",
	                                                                    parameterPath, local_time_date, parameterValue);
	            }
	          else
	            {
	               //then this is an LV parameter
	               //find out wich HV parameter is in alert
	               strreplace(controllerAlertPath, "CCieEcod1.Recv:online..value", "CCieEcod2.Recv:online..value");
	               dpGet(controllerAlertPath, parameter);
	               //get the parameter value
	               sprintf(parameterPath, systemName+"Crate%02d.Channel%02d.%s.Recv:online..value", crate, channel, LV_parameters[parameter+1]);
	               dpGet(parameterPath, parameterValue);
	               strreplace(parameterPath, ".Recv:online..value", "");
	               
	               //message to be sent DAQ
	               sprintf(alert_message, "ELMB Alert Mesg   | %s | %s | T Alarm  | %5.2f",
	                                                                    parameterPath, local_time_date, parameterValue);
	            }
	          //DebugN("===================== alert_message = ", alert_message);
	          //send a messeage to DAQ
	          strreplace(controllerAlertPath, "CCieEcod2.Recv:online..value", "AlertToDaq:original..value");
	          dpSet(controllerAlertPath, alert_message);
	          //write the alert message to the history file
   	       	  fprintf(alertHistoryFile, "%s\n", alert_message);
   	       	  //increment the counter of lines in the history file and open a new if necessary
              alertHistoryFileCounter();
	       break;
	       
	       //3)  0xFF02: IV curve read out in alert
	       case 65282:
	          //get the number of the channel in alert
	          strreplace(controllerAlertPath, "CCieEcod.Recv:original..value", "CCieEcod1.Recv:online..value");
	          dpGet(controllerAlertPath, channel);
	          //get the actual volt and current values (IV curve point)
	          sprintf(channelPath, systemName+"Crate%02d.Channel%02d", crate, channel);
	          dpGet(channelPath+".HVchVolt.Recv:online..value", IV_volt, 
	                channelPath+".HVchCurr.Recv:online..value", IV_current);
	          
	          //message to be sent DAQ
	          sprintf(alert_message, "ELMB Alert Mesg   | %s          | %s | IV Curve Alarm, V = %5.2f, I = %7.2f",
	                                                                    channelPath, local_time_date, IV_volt, IV_current);

	          //send  messeage to DAQ
	          strreplace(controllerAlertPath, "CCieEcod1.Recv:online..value", "AlertToDaq:original..value");
	          dpSet(controllerAlertPath, alert_message);
	          //write the alert message to the history file
   	       	  fprintf(alertHistoryFile, "%s\n", alert_message);
   	       	  //increment the counter of lines in the history file and open a new if necessary
              alertHistoryFileCounter();	          
	       break;
	       
	       default:
	       break;
	   }
}

//this functon increments the counter of lines in the alerthistory file and open a new one if the one of
//the following two conditions is fullfilled:
//1) the number of line exeeded a given number (say 1000 lines)
//2) the actual file has been opend for more than one hour 
alertHistoryFileCounter()
{
   int delta_time;
   
   //Rk: some of the variables here are global (see above)
   
   // increment the number of lines in the alert history file
   number_of_lines = number_of_lines + 1;
   //time since the lats file was open
   delta_time = fabs(hour(fileOpeningTime)-hour(getCurrentTime())); 
   //open an other file if the conditions are fullfilled
   if(delta_time>=nHours)
     {      
   	 	// close and reopen a new file
     	fclose(alertHistoryFile);
     	fileOpeningTime = getCurrentTime();
        alertHistoryFileName = formatTime(alertFileName+"_%Hh.txt", fileOpeningTime);
     	alertHistoryFile = fopen(alertHistoryFileName, "w");
     	
        //print the column tiles line
fprintf(alertHistoryFile, 
"  COMMENTS           PVSS DATA POINT ELEMENT ADDRESSES      TIME AND DATE    CHAN W/A CNTR  LIMITS   DPE VALUES\n\n");

        // reset the counters
     	number_of_lines = 0;
        secondary_files_index = 0;
     }
   else if(number_of_lines>fileLenght)
   	 {
   	    // close and reopen a new file
     	fclose(alertHistoryFile);
        fileOpeningTime = getCurrentTime();
     	alertHistoryFileName = formatTime(alertFileName+"_%Hh", fileOpeningTime);
     	secondary_files_index = secondary_files_index + 1;
     	sprintf(alertHistoryFileName, "%s_%02d.txt" , alertHistoryFileName, secondary_files_index);
     			        alertHistoryFile = fopen(alertHistoryFileName, "w");
     	
        //print the column tiles line
fprintf(alertHistoryFile, 
"  COMMENTS           PVSS DATA POINT ELEMENT ADDRESSES      TIME AND DATE    CHAN W/A CNTR  LIMITS   DPE VALUES\n\n");
        // reset the counter
        number_of_lines = 0;
   	 }
}  	 		        
//this function allows to close and open (another) alarm history file. this is may be need for debuging:
//when has then to change the value of: SCTmops1:Alrm.Indx:_original.._value, where this function
//is connected.
closeAlertHistoryFile(string dpeIndex, int index)
 { 
   	string new_FileName;

    //the index is used to label the file  
   if(index > 0)
     { 
   	   //close the actuel alarm file (for debuging)
   	   fclose(alertHistoryFile);
   	 
   	   //open a new file. the name should be different from the one of the 
   	   //closed file. thus the use of index
       fileOpeningTime = getCurrentTime();
       alertHistoryFileName = formatTime(alertFileName+"_%Hh", fileOpeningTime);
	   //one wants to have to digit in the new name
       sprintf(new_FileName,"%s_%02d.txt" , alertHistoryFileName, index);
       alertHistoryFile = fopen(new_FileName, "w");
     
//print the column tiles line
fprintf(alertHistoryFile, 
"  COMMENTS           PVSS DATA POINT ELEMENT ADDRESSES      TIME AND DATE    CHAN W/A CNTR  LIMITS   DPE VALUES\n\n");
     }
 }





