← Back to dashboard

File view

plc_inputs.lib

1
//$Id: ism_inputs.lib,v 1.3 2008-07-28 19:18:59 charlie Exp $
2
/*
3
   $Log: ism_inputs.lib,v $
4
5
6
*/
7
8
/*** BeginHeader */
9
10
#ifndef	__ISM_INPUT_
11
#define	__ISM_INPUT_
12
13
/**************************
14
- Pressure Input Spec -
15
16
ISM Pression Input
17
47K Res on Pressure Switch
18
	OPEN - Low Pressure
19
   Closed - High Pressure
20
21
LDN Pressure Input
22
47k Res on Low Switch
23
	OPEN - Low Pressure
24
   CLOSED - MID PRESSURE
25
100k Res on High Switch
26
	CLOSED - High Pressure
27
28
**************************/
29
30
31
/*** EndHeader */
32
33
/*** BeginHeader
34
35
InitializeInputs,
36
InputRegScan,
37
GetInputArray,
38
GetInputWord,
39
ReAuth
40
41
*/
42
43
//Define constants for input scanner ****************************************************
44
45
#define  INPUT_RD_BIT   2
46
#define  INPUT0_RD_ADR  ((~4) & (0xf))
47
#define  INPUT1_RD_ADR  ((~4) & (0xf))
48
#define  INPUT2_RD_ADR  ((~1) & (0xf))
49
50
//Function prototypes *******************************************************************
51
52
nodebug void		InitializeInputs ();				// initialize port to read inputs
53
nodebug int			InputRead ();								// scan keyboard for active key
54
nodebug int			InputACRead ();								// scan keyboard for active key
55
nodebug void		InputRegScan ();						// signal program to presence of active key
56
nodebug int*		GetInputArray ();           // get the array of input states
57
nodebug int*		GetACInputArray ();
58
nodebug int			GetInputWord ();            // get the current debounced input word
59
nodebug int			GetACInputWord ();
60
nodebug void 		InputHandler();							// Process inputs into ism channels
61
nodebug void		UpdateLeadChannel(int prod);	// Move lead channel to next turbine
62
nodebug int 		testInput(int bit);							// Test input bit status
63
		  int			ReAuth(int ProdNum);
64
65
/*** EndHeader */
66
67
//Define input handler variables ********************************************************
68
int	Inputs [N_INPUTS];									//input status array
69
int	CurrentInput;								//condition of input register
70
Ms		InputTmr[N_INPUTS];
71
72
int	AC_Inputs [N_AC_INPUTS];
73
int	CurrentACInputs;
74
Ms		InputACTmr[N_INPUTS];
75
76
Ms		DisableAuthProd[N_PROD];
77
78
#if SCH2
79
   int ManualReturn;
80
	Ms  ReturnFlowTime;
81
#endif
82
83
//Initialize ports used by input handler ************************************************
84
85
void InitializeInputs ()
86
{
87
	int i;
88
	//ibRegister arguments come from AUTOPAK_CONSTANTS.LIB
89
	printf("Init Inputs ...\n");
90
	WrPortI (IbRegister (INPUT_RD_BIT), NULL, (ONE_WAIT | READ_STROBE | PERMIT_WRITE));
91
	BitWrPortI (PEFR, &PEFRShadow, 1, INPUT_RD_BIT);
92
	BitWrPortI (PEDDR, &PEDDRShadow, 1, INPUT_RD_BIT);
93
   for (i = 0 ; i < sizeof(AC_Inputs)/sizeof(int) ; i++) AC_Inputs[i] = INPUT_INACTIVE;
94
   for (i = 0 ; i < N_AC_INPUTS ; i++) InputACTmr[i] = 0;
95
   CurrentACInputs = 0; //InputACRead();
96
97
	for (i = 0 ; i < sizeof(Inputs)/sizeof(int) ; i++) Inputs[i] = INPUT_INACTIVE;
98
   for (i = 0 ; i < N_INPUTS ; i++) InputTmr[i] = 0;
99
	CurrentInput = 0;
100
101
   for (i = 0 ; i < N_PROD ; i++) DisableAuthProd[i] = 0;
102
103
   #if SCH2
104
   	ManualReturn = 0;
105
   #endif
106
107
   InputRegScan();
108
   InputHandler();
109
110
}
111
112
//Get the array of input states *********************************************************
113
114
int* GetInputArray() {return Inputs;}
115
116
//Get the array of input states *********************************************************
117
118
int* GetACInputArray() {return AC_Inputs;}
119
120
//Get the current debounced input word **************************************************
121
122
int GetInputWord() {return CurrentInput;}
123
124
//Get the current debounced input word **************************************************
125
126
int GetACInputWord() {return CurrentACInputs;}
127
128
//Scan input register for active input **************************************************
129
130
int InputRead ()
131
{
132
	int result;
133
	int ea;
134
	int flip;
135
	int i;
136
	result = 0;
137
138
	ea = ExternalAddress(INPUT_RD_BIT);
139
	ea += INPUT0_RD_ADR;
140
141
	result =  ~RdPortE(ea) & 0xff;
142
143
	result |= ((~RdPortE(ea)& 0xff) << 8);
144
145
	flip = 0;
146
	for (i = 0 ; i < N_INPUTS ; i++)
147
	{
148
		flip |= ((result >> (N_INPUTS-1-i)) & 1) << i;
149
	}
150
	flip = (flip & 0x0f) | ((result & 0x0f) << 4);
151
152
	return flip;
153
}
154
155
//Scan input register for active input **************************************************
156
int InputACRead ()
157
{
158
	int result;
159
	int ea;
160
	int flip;
161
	int i;
162
	result = 0;
163
164
	ea = ExternalAddress(INPUT_RD_BIT);
165
	ea += INPUT2_RD_ADR;
166
167
   result = (~RdPortE(ea)& 0xff);
168
   flip = result;
169
170
	return flip;
171
}
172
173
//Signal program to presence of active input ********************************************
174
void InputRegScan ()
175
{
176
	int	i;												//incrementing variable
177
	int	mask;											//register and'g mask
178
	int	Test1;										//local temp variable
179
	int	Test2;										//local temp variable
180
181
	for (i = 0 ; i < N_INPUTS ; i++)                 //resolve any edge conditions
182
	{
183
		if (Inputs[i] == INPUT_LEAD_EDGE)
184
    	Inputs[i] = INPUT_ACTIVE;
185
		if ((Inputs[i] == INPUT_TRAIL_EDGE) && (MS_TIMER >= InputTmr[i] + PSDLY))
186
    			   Inputs[i] = INPUT_INACTIVE;
187
	}
188
189
	Test1 = InputRead ();							//save immediate input state
190
	if (CurrentInput != Test1)						//test for change in input register
191
	{
192
		MsDelay (20);									//delay for 20 ms
193
		Test2 = InputRead ();						//save immediate input state
194
		if (Test1 == Test2)							//test for stable change in input register
195
		{
196
			mask = 1;									//set mask
197
			for (i=0; i<N_INPUTS; i++)						//test each input bit
198
			{
199
				if ((CurrentInput^Test2)&mask)	//test for changed bit
200
				{
201
					if (Test2 & mask)
202
						Inputs [i] = INPUT_LEAD_EDGE;		//set leading edge indicator
203
					else
204
					{
205
						Inputs [i] = INPUT_TRAIL_EDGE;	//set trailing edge indicator
206
					   InputTmr[i] = MS_TIMER;
207
					}
208
				}
209
				else
210
				{
211
					if (Test2 & mask)
212
						Inputs [i] = INPUT_ACTIVE;			//set still active indicator
213
					else if (MS_TIMER >= InputTmr[i] + PSDLY)
214
						Inputs [i] = INPUT_INACTIVE;		//set still inactive indicator
215
				}
216
				mask <<= 1;								//shift mask bit left one place
217
			}
218
			CurrentInput = Test2;					//update current state of inputs
219
		}
220
	}
221
222
   for (i = 0 ; i < N_AC_INPUTS ; i++)                 //resolve any edge conditions
223
	{
224
		if (AC_Inputs[i] == INPUT_LEAD_EDGE)
225
    		AC_Inputs[i] = INPUT_ACTIVE;
226
		if ((AC_Inputs[i] == INPUT_TRAIL_EDGE) && (MS_TIMER >= InputACTmr[i] + AUTHDLY))
227
    			   AC_Inputs[i] = INPUT_INACTIVE;
228
	}
229
230
	Test1 = InputACRead ();							//save immediate input state
231
	if (CurrentACInputs != Test1)						//test for change in input register
232
	{
233
		MsDelay (20);									//delay for 20 ms
234
		Test2 = InputACRead ();						//save immediate input state
235
		if (Test1 == Test2)							//test for stable change in input register
236
		{
237
			mask = 1;									//set mask
238
			for (i=0; i<N_AC_INPUTS; i++)						//test each input bit
239
			{
240
				if ((CurrentACInputs^Test2)&mask)	//test for changed bit
241
				{
242
					if (Test2 & mask)
243
						AC_Inputs [i] = INPUT_LEAD_EDGE;		//set leading edge indicator
244
					else
245
					{
246
						AC_Inputs [i] = INPUT_TRAIL_EDGE;	//set trailing edge indicator
247
						InputACTmr[i] = MS_TIMER;
248
					}
249
				}
250
				else
251
				{
252
					if (Test2 & mask)
253
						AC_Inputs [i] = INPUT_ACTIVE;			//set still active indicator
254
					else if (MS_TIMER >= InputACTmr[i] + AUTHDLY)
255
						AC_Inputs [i] = INPUT_INACTIVE;		//set still inactive indicator
256
				}
257
				mask <<= 1;								//shift mask bit left one place
258
			}
259
			CurrentACInputs = Test2;					//update current state of inputs
260
		}
261
	}
262
}
263
264
// InputHandler **********************************************************************
265
266
// Check the status of inputs, disable time, and resets and sets the corresponding
267
// bits in the channel structure.
268
269
void InputHandler()
270
{
271
	int i;												// Counter
272
  int j;												// Counter
273
  int result;										// Status Flag
274
  int InputStatus;							// Current input word
275
  struct tm snapshotTod;				// Current time of day
276
  int CurrentTime;						// dec of current time
277
  int StartTime;							// dec of start time
278
  int EndTime;								// dec of end time
279
  int sumpResult;							// flag for positive sump alarm in a product
280
281
282
   if (Config.SiteConfigFlag)
283
   {
284
   //InputStatus = GetInputWord();																						// Get current inputs
285
286
  // Scan and set pressure flags
287
  // works for both ISM and PLC  PLC: On is mid pressure
288
  for (i=0 ; i < N_PRES_INPUTS ; i++)																					// Loop through pressure inputs
289
  {
290
		if (Channel[i].NeverLeadFlag)
291
    		Channel[i].PresFlag = ON;
292
      else if (!Channel[i].NoReadIS)
293
      {
294
	         if (Inputs[Channel[i].IOPS] == INPUT_INACTIVE)                                         // If input low
295
	      			Channel[i].PresFlag = OFF;                                                                         // Pressure high
296
	    	else
297
	      		Channel[i].PresFlag = ON;
298
      }																						// Pressure low
299
  }
300
301
  // Scan and set sump alarm flag
302
303
	if (!Config.Sump.NoSumpFlag)
304
	{
305
	   for (i=0 ; i < Config.N_Turbines ; i++)
306
	   {
307
	         if (Inputs[Channel[i].IOPS + SUMP_OFFSET] == INPUT_INACTIVE)
308
	            Config.Sump.Status[i] = ON;
309
	         else
310
	            Config.Sump.Status[i] = OFF;
311
312
	      if (Config.Sump.ShutDnFlag)
313
	      {
314
	         if (Config.Sump.PerProdFlag)
315
	         {
316
	            if (i == Channel[i].Prod->FirstTurbine)
317
	               sumpResult = 0;
318
319
	            if (Config.Sump.Status[i] == ON)
320
	            {
321
	             for (j = Channel[i].Prod->FirstTurbine ;
322
	                  j < Channel[i].Prod->FirstTurbine + Channel[i].Prod->N_Turbines ;
323
	                  j ++)
324
	               {
325
	                  Channel[j].SumpAlmFlag = ON;
326
	                 sumpResult = 1;
327
	               }
328
	            }
329
	            else if (!sumpResult)
330
	            {
331
	               for (j = Channel[i].Prod->FirstTurbine ;
332
	                  j < Channel[i].Prod->FirstTurbine + Channel[i].Prod->N_Turbines ;
333
	                  j ++)
334
	               {
335
	                  Channel[j].SumpAlmFlag = OFF;
336
	               }
337
	            }
338
	         }
339
	         else
340
	         {
341
	            if (Config.Sump.Status[i] == ON)
342
	               Channel[i].SumpAlmFlag = ON;
343
	            else
344
	               Channel[i].SumpAlmFlag = OFF;
345
	         }
346
	      }
347
	      else
348
	         Channel[i].SumpAlmFlag = OFF;
349
	   }
350
	}
351
	else
352
	{
353
	   for (i = 0 ; i < N_ISM ; i++)
354
	      Channel[i].SumpAlmFlag = OFF;
355
	   for (i = 0 ; i < N_SUMP_INPUTS ; i++)
356
	      Config.Sump.Status[i] = OFF;
357
358
	}
359
360
	// LDN High pressure switch
361
	   for (i=0 ; i < Config.N_Turbines ; i++)
362
	   {
363
	      if (Inputs[Channel[i].IOPS + SUMP_OFFSET] == SUMP_CLOSED && !Channel[i].NoReadIS)
364
	         Channel[i].PresFlag += 1;
365
	   }
366
	
367
368
	#if MODBUS_M_ON
369
	   for (i=0 ; i < Config.N_Turbines ; i++) {
370
	      if (Channel[i].LDN->ErrorCnt < NUM_LDN_COMM_RETRIES) {
371
         	#if MODBUS_S_ON
372
	      		SetAlarmReg(SENSOR_OUTS, Channel[i].Prod->Idx, i, 0);
373
	         #endif
374
	         Channel[i].SensorOutFlag = 0;
375
	         Channel[i].LDN->Pressure = (float)GetLDNReg(Channel[i].Idx, PRESSURE) / 100.0;
376
	         
377
            if (Channel[i].LDN->Pressure < 0.0)   Channel[i].LDN->Pressure = 0.0;
378
            if (Channel[i].LDN->Pressure > 320.0) Channel[i].LDN->Pressure = 320.0;
379
	         if (Channel[i].LDN->Pressure <= Channel[i].LowPressure)
380
	            Channel[i].PresFlag = PRES_LOW;
381
	         else if (Channel[i].LDN->Pressure >= Channel[i].HighPressure)
382
	            Channel[i].PresFlag = PRES_HIGH;
383
	         else
384
	            Channel[i].PresFlag = PRES_MED;
385
	      }
386
	      else {
387
	      	Channel[i].SensorOutFlag = 1;
388
	      	if (Channel[i].LDN->ErrorCnt > NUM_LDN_COMM_RETRIES)
389
	      		 Channel[i].LDN->ErrorCnt = NUM_LDN_COMM_RETRIES;
390
	         #if MODBUS_S_ON
391
	            SetAlarmReg(SENSOR_OUTS, Channel[i].ProductID-1, i, 1);
392
	            //printf("MB SENSOR_OUT: %d\n", GetAlarmReg(SENSOR_OUTS, Channel[i].ProductID-1));
393
	         #endif         
394
	      }
395
	   }
396
	#endif
397
398
	#if MODBUS_M_ON == 0
399
	  for (i=0 ; i < N_PRES_INPUTS ; i++)
400
	  {
401
	      if (AC_Inputs[SO_OFFSET - Channel[i].IOPS - 1] == INPUT_INACTIVE && !Channel[i].NeverLeadFlag)
402
	         Channel[i].SensorOutFlag = 1;
403
	      else
404
	         Channel[i].SensorOutFlag = 0;
405
	  }
406
	#endif
407
408
	#if FLOWSWITCH
409
      for (i=0 ; i < N_PRES_INPUTS ; i++)
410
      {
411
         #if SCH2
412
         	if (i == 0)
413
            {
414
            	Channel[0].FlowFlag = Inputs[i + SUMP_OFFSET] == SUMP_CLOSED ? 1 : 0;
415
               Channel[1].FlowFlag = Inputs[i + SUMP_OFFSET] == SUMP_CLOSED ? 1 : 0;
416
            }
417
         #endif
418
	      #if MODBUS_S_ON
419
            SetStatusReg(FLOW_SWITCH, 0, i, Inputs[i + SUMP_OFFSET] == SUMP_CLOSED ? 1 : 0);
420
            SetStatusReg(SUMP_SENSOR, 0, i, Inputs[i + SUMP_OFFSET] == SUMP_CLOSED ? 1 : 0);
421
            // Sump Sensor needs to be moved to the sump section
422
	      #endif
423
      }
424
   #endif
425
426
  // Scan Auth Inputs and set channels
427
428
	for (i=0 ; i < Config.N_Products ; i++)		// Loop through products
429
  	{
430
      if (DisableAuthProd[i] + AUTH_DIS_TIME <= MS_TIMER)
431
      {
432
      	DisableAuthProd[i] = 0;
433
	      result = 0;
434
	      j = Product[i].LeadTurbine;
435
	      #if MODBUS_S_ON
436
	         SetStatusReg(AUTH_INPUTS, i, j, AC_Inputs[Channel[j].IOChannel] != 0);
437
	      #endif
438
	      if (AC_Inputs[Channel[j].IOChannel] != 0)                // If auth present
439
	      {
440
	         #if DISABLE_INPUT
441
	            if (j != Product[i].FirstTurbine + Product[i].N_Turbines - 1)
442
	               result++;
443
	         #else
444
	            #if COMM_AUTH_OR
445
	               if (Config.ModBus.ActivityTimer + MODBUS_COMM_TO <= SEC_TIMER)
446
	                  result++;
447
	            #else
448
	               result++;
449
	            #endif
450
	         #endif
451
	      }
452
	      j = Channel[j].NextStage;
453
	      while (j != Product[i].LeadTurbine)
454
	      {
455
	         #if MODBUS_S_ON
456
	            SetStatusReg(AUTH_INPUTS, i, j, AC_Inputs[Channel[j].IOChannel] != 0);
457
	         #endif
458
	         if (AC_Inputs[Channel[j].IOChannel] != 0)                  // If auth present
459
	         {
460
	            #if DISABLE_INPUT
461
	               if (j != Product[i].FirstTurbine + Product[i].N_Turbines - 1)
462
	                  result++;
463
	            #else
464
	               #if COMM_AUTH_OR
465
	                  if (Config.ModBus.ActivityTimer + MODBUS_COMM_TO <= SEC_TIMER)
466
	                     result++;
467
	               #else
468
	                     result++;
469
	               #endif
470
	            #endif
471
	         }
472
	         j = Channel[j].NextStage;
473
	      }
474
	      #if MODBUS_S_ON
475
	         if (GetWrControlReg(AUTH_REQUESTS, i))
476
	            result++;
477
	      #endif
478
         #if SCH2
479
   			// If no Comm, respond to backup level float
480
	         if (Config.ModBus.ActivityTimer + MODBUS_COMM_TO <= SEC_TIMER)
481
	         {
482
            	if(Inputs[3 + SUMP_OFFSET] == SUMP_OPEN)
483
            	{
484
               	result = 0;
485
						ManualReturn = 0;
486
               	Product[i].ReturnFuel = 1;
487
               }
488
               else if (ManualReturn)
489
               {
490
               	// Uncomment to read flow switch on manual return pump
491
               	//if (!(Inputs[1 + SUMP_OFFSET] == SUMP_OPEN && SEC_TIMER - ReturnFlowTime > FLOW_DELAY))
492
               		result++;
493
               }
494
               else if (Inputs[2 + SUMP_OFFSET] == SUMP_CLOSED)
495
               {
496
               	Product[i].ReturnFuel = 0;
497
                  ManualReturn = 1;
498
                  ReturnFlowTime = SEC_TIMER;
499
               	result++;
500
               }
501
               else
502
               	Product[i].ReturnFuel = 0;
503
504
               Product[i].FilterFlag = 0;
505
               if (AC_Inputs[1] != 0)
506
               	result--;
507
	         }
508
            else
509
            {
510
            	Product[i].ReturnFuel = 0;
511
               ManualReturn = 0;
512
               #if MODBUS_S_ON
513
	         		SetStatusReg(AUTH_INPUTS, i, j, AC_Inputs[2] != 0);
514
	      		#endif
515
	            if (AC_Inputs[1] != 0 && AC_Inputs[2] != 0)
516
	               Product[i].FilterFlag = 1;
517
	            else
518
	               Product[i].FilterFlag = 0;
519
            }
520
         #endif
521
      	
522
      }
523
      else
524
      	result = 0;					// No auth if in auth disable
525
      // First time auth goes away
526
	   if (!Product[i].Authorize && result > 0)
527
	      UpdateLeadChannel(i);
528
529
      // Auth Cascade options
530
	   if (result)
531
	   {
532
	      if (Product[i].AutoAuthFlag == AUTH_CASCADE)                                                      // Rotate in next lead channel
533
	         Product[i].Authorize = Product[i].N_RunTurbines;
534
         else if (Product[i].AutoAuthFlag == AUTH_DEMAND)
535
         	Product[i].Authorize = 1;
536
	      else
537
	      {
538
	         if (result > Product[i].N_RunTurbines)
539
	         	Product[i].Authorize = Product[i].N_RunTurbines;
540
	         else
541
	         	Product[i].Authorize = result;                                             // Set auth bit in product
542
	      }
543
	   }
544
      else
545
      	Product[i].Authorize = result;
546
	}
547
  	if (Config.TestCnl > -1)
548
  	{
549
  		if (Inputs[(Channel[Config.TestCnl].IOChannel + AUTH_OFFSET)] != 0)
550
  			Channel[Config.TestCnl].Authorize = 1;
551
   	else
552
   		Channel[Config.TestCnl].Authorize = 0;
553
   }
554
555
   #if RESET_ALL_INPUT
556
      if (Config.N_Turbines < N_AUTH_INPUTS)
557
      {
558
			if (AC_Inputs[AUTH_OFFSET + N_AUTH_INPUTS - 1] == INPUT_LEAD_EDGE)
559
         {
560
            for (i = 0 ; i < Config.N_Turbines ; i++)
561
	         	Channel[i].ResetPbFlag = 1;
562
         }
563
      }
564
   #endif
565
566
	// Scan Disable times and set flags
567
	GetTimeOfDay(&snapshotTod);																										// Get current time
568
  	CurrentTime = snapshotTod.tm_hour*100 + snapshotTod.tm_min*100 / 60;									// Calc dec of time
569
	for (i=0 ; i < Config.N_Products ; i++)																				// Loop through products
570
  	{
571
  		StartTime = Product[i].DisStartTimeHours*100 + Product[i].DisStartTimeMin*100 / 60;	// Calc dec of start time
572
		EndTime = Product[i].DisEndTimeHours*100 + Product[i].DisEndTimeMin*100 / 60;				// Calc dec of end time
573
   	if (StartTime == 0 && EndTime == 0)
574
   		result = 0;
575
   	else if (EndTime <= StartTime)																										// If disable time crosses midnight
576
    	{
577
    		if ((CurrentTime >= StartTime) || (CurrentTime <= EndTime))								// Check to see if in disable window
578
				result = 1;																															// Set flag
579
      	else
580
      		result = 0;																															// If not, clear flag
581
    	}
582
    	else if (CurrentTime >= StartTime && CurrentTime <= EndTime)								// Check to see if in disable window
583
			result = 1;																																// Set flag
584
    	else
585
    		result = 0;
586
587
      #if DISABLE_INPUT
588
      	if (AC_Inputs[Channel[Product[i].FirstTurbine + Product[i].N_Turbines - 1].IOChannel] != 0)
589
         	result = 2;
590
      #endif																														// If not, clear flag
591
592
      for (j = Product[i].FirstTurbine ;                                                              // Loop through turbines in product
593
       		j < Product[i].FirstTurbine + Product[i].N_Turbines ;
594
      		j++)
595
   		Channel[j].DisableFlag = result;  																			// Set flag within channels
596
  }
597
}
598
}
599
600
// UpdateLeadChannel *****************************************************************
601
602
// Points lead turbine to next turbine in linked list.
603
604
void UpdateLeadChannel(int prod) {
605
	                                                                              
606
	int j;
607
	int i;
608
	int EndTurbine;
609
	int LastStage;
610
	int RotateFlag;
611
	int count;
612
	int TestType;
613
   int TestActive;
614
615
	count = 0;
616
617
	if (!Product[prod].RotateFlag)
618
		RotateFlag = 0;
619
	else if (Config.TestCnl > -1)  {
620
		if (Channel[Config.TestCnl].Prod->Idx == prod)
621
			RotateFlag = 0;
622
		else
623
			RotateFlag = 1;
624
   }
625
	else
626
		RotateFlag = 1;
627
628
	if (RotateFlag) {
629
		TestType = Channel[Product[prod].LeadTurbine].PrecTest.Type;              		// Record precision test type
630
      TestActive = Channel[Product[prod].LeadTurbine].PrecTest.Status;              // Record if test is active
631
      Channel[Product[prod].LeadTurbine].PrecTest.Status = PT_INACTIVE;             // Clear precision test
632
		Product[prod].LeadTurbine = Channel[Product[prod].LeadTurbine].NextStage;     // Set lead to next in list
633
		if (Channel[Product[prod].LeadTurbine].NeverLeadFlag)                         // If channel cant be lead
634
			Product[prod].LeadTurbine = Product[prod].FirstTurbine;                    // Set lead to first turbine in product
635
		while ((Channel[Product[prod].LeadTurbine].ByPass || 
636
				  Channel[Product[prod].LeadTurbine].AlarmFlag != NO_ALARM) &&
637
				  count <= Product[prod].N_Turbines) {
638
			Product[prod].LeadTurbine = Channel[Product[prod].LeadTurbine].NextStage;
639
			count++;
640
  		}
641
	EndTurbine = Product[prod].N_Turbines + Product[prod].FirstTurbine - 1;
642
	j = Product[prod].LeadTurbine;
643
	i = 1;
644
645
	for (i = 1 ; i <= Product[prod].N_LeadTurbines ; i++) {
646
		if (j+1 <= EndTurbine && j+1 >= Product[prod].FirstTurbine)
647
			Channel[j].NextStage = j+1;
648
		else
649
			Channel[j].NextStage = Product[prod].FirstTurbine;
650
		LastStage = j;
651
		j = Channel[j].NextStage;
652
	}
653
654
		if (Product[prod].N_LeadTurbines < Product[prod].N_Turbines) {
655
			j = Product[prod].FirstTurbine + Product[prod].N_LeadTurbines;
656
			Channel[LastStage].NextStage = j;
657
  			while (i <= Product[prod].N_Turbines) {
658
				if (j == EndTurbine)
659
					Channel[j].NextStage = Product[prod].LeadTurbine;
660
				else
661
					Channel[j].NextStage = j+1;
662
				j = Channel[j].NextStage;
663
				i++;
664
			}
665
		}
666
667
		for (j = Product[prod].FirstTurbine ; j <= EndTurbine ; j++) {
668
			if (j == Product[prod].LeadTurbine) {
669
				Channel[j].LeadFlag = ON;                       
670
         	if (TestActive == PT_PENDING) {
671
	            Channel[j].PrecTest.Status = PT_PENDING;
672
	            Channel[j].PrecTest.Type = TestType;
673
            }
674
         }
675
         else
676
				Channel[j].LeadFlag = OFF;                     
677
		}
678
	}
679
}
680
681
// Test Input Bit ********************************************************************
682
683
int testInput(int bit)
684
{
685
	int result;
686
	result = GetInputWord() & BitToMask(bit);
687
	return result;
688
}
689
690
// ReAuth ****************************************************************************
691
692
int ReAuth(int ProdNum)
693
{
694
	DisableAuthProd[ProdNum] = MS_TIMER;
695
}
696
697
//End of input handler ***************************************************************
698
699
/*** BeginHeader */
700
701
#endif
702
703
/*** EndHeader */