/* 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.
/*--------------------------------------------------------------------------*/

main()
{
  dpSet("SCTmops1:Warn.Indx:_original.._value", 2);  /* System Warn_Thresold*/
  dpSet("SCTmops1:Alrm.Indx:_original.._value", 1);  /* System alrm_Thresold*/
  dpConnect("InitAlertControl", FALSE, "SCTmops1:Host.Stat:_online.._value");
}

//this function simply connect and disconnect another function: warningAlarmActions
InitAlertControl(string Dapo, int Stat)
 { 
 	int stat, syss;
 	string log_dir_path;
/*
   dpGet("SCTmops1:Host.Stat:_original.._value", stat);
   dpGet("SCTmops1:Syst.Stat:_original.._value", syss);
   if(((stat & 0xC) == 0xC) &&                        // Syst will go to 'Active'
     (((syss & 0xC) == 0x0) || ((syss & 0xC) == 0x4)))// from 'Off' or 'Config'
*/
 if(Stat)
   	 {
   	 	//get log directory path (to put alarm hystory files there)
	    log_dir_path = getPath(LOG_REL_PATH);
       	setWarningActions(log_dir_path+"AlertsHistory.txt", 10000, 1);
       	Debug("\n  ALERT CONTROL SCRIPT STARTED...\n");
   	 }
   	else
   	 {
   	 	dpQueryConnectSingle("warningAlarmActions", "identifier");
	   	dpDisconnect("closeAlertHistoryFile", "SCTmops1:Alrm.Indx:_original.._value");
   	 }
 }

//this function do some initilisations and connect the alarm actions functions to channels and cards...etc.
setWarningActions(string alertsHistoryFileName, int alertsHistoryFileLenght, int hours)
 { 
   int success, crateState, LV_cardState, channelState, alarmRange;
   int icrate, ilvcard, 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, channelMax;
   
   string systemName, cratePath, lvcardPath, channelPath, query;
   dyn_string channelParametersNames, LV_cardParametersNames;

   //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        CHANNEL W/A COUNTER   DPE VALUES\n\n");
 
   systemName = getSystemName(); 
   
   //get the system configuration (find how many crate are used)
   dpGet("SCTmops1:Hmax.Numb:_original.._value"  , hostMax);
   dpGet("SCTmops1:Nmax.Numb:_original.._value"  , nodeMax);
   dpGet("SCTmops1:Pmax.Numb:_original.._value"  , portMax);
   dpGet("SCTmops1:Umax.Numb:_original.._value"  , unitMax);
   dpGet("SCTmops1:Cmax.Numb:_original.._value"  , channelMax);

   lvcardMax = 12; //to be replaced later (wait for info from Serguey!!)
   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)
     	  { 
            //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", alarmRange);
               				 //increment the alert counters accordingly
               				 if(alarmRange==2 || alarmRange==4)//warn ranges
               					{
               					   channelWarningCounter = channelWarningCounter + 1;
               					}
               				 else if(alarmRange==1 || alarmRange==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, "identifier", 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", alarmRange);
               				    //increment the LV alarm counters accordingly
               				    if(alarmRange==2 || alarmRange==4)//warn ranges
               				      {
               					     LV_cardWarningCounter = LV_cardWarningCounter + 1;
               				      }
               				    else if(alarmRange==1 || alarmRange==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, "identifier", query);
   				       }//end of if((LV_cardState...)

                  }//end for(ilvcard=0; ic...)
           				             				  
//print the number of warn/alrm in each crate
fprintf(alertHistoryFile, 
"                                  Number of  Warnings in  Crate %2d  at Start: %5d \n", icrate, crateWarningCounter);
fprintf(alertHistoryFile, 
"                                  Number of   Alarms  in  Crate %2d  at Start: %5d \n\n", icrate, crateAlarmCounter);

			   //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);
          }//end of if((crateState & 0xC) > 0x0)
     }//end of for(icrate=0; icrate < crateMax; icrate++)
    
   //print the total number of warn/alrm in the system
   fprintf(alertHistoryFile, 
   "                                  Number of Warnings in the System at Start: %5d \n", systemWarningCounter);
   fprintf(alertHistoryFile, 
   "                                  Number of  Alarms  in the System at Start: %5d \n\n", systemAlarmCounter);
    
   //close the alarm history file (for debuging)
   dpConnect("closeAlertHistoryFile",FALSE, "SCTmops1:Alrm.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;
   int    increment, delta_time;
   float  alarmValue;
   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];

   // 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 4 blancs 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", alarmValue);
   			    
   			      fprintf(alertHistoryFile, "%s    |      %5d         |    %.3f\n",
   			  		               alert_message, channelWarningCounter, alarmValue);
   			      // 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        CHANNEL W/A COUNTER   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        CHANNEL W/A COUNTER   DPE VALUES\n\n");
     			       // reset the counter
        		       number_of_lines = 0;
   	 		        }
   			    }//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", alarmValue);
   			      fprintf(alertHistoryFile, "%s    |      %5d         |    %.3f\n",
   			      							alert_message, channelAlarmCounter, alarmValue);
   			      // increment the number of lines in the alarm 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 condition are fullfilled
   			      if(delta_time>=nHours)
   	 		        {      
   	 			       // 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        CHANNEL W/A COUNTER   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        CHANNEL W/A COUNTER   DPE VALUES\n\n");

		              // reset the counter
        		      number_of_lines = 0;
   	 		       }
   		 	    }//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);
  //****************************
 }

//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 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        CHANNEL W/A COUNTER   DPE VALUES\n\n");
     }
 }




