'************************************************************************************************************************
' File: GroundFault.vb              Programmer: Ting Chan      Date: December 8, 2004
'
' Description:
' This form provides modules of detecting/isolating ground fault on 400V and 48V busses.  
'
' Routines in this file:
' GFDetection()
'
' Revision History:
' 12-15-2004 Added ground fault detection conditions to GFDetection() by Ting Chan, UWEE
' 12-30-2004 Modified GFDetection() to ThreadVersionGFDetection() to include Multi-threading by John Elliott, APL
' 01-06-2005 Moved ThreadVersionGFDetection() and CheckGfWorkerThread() from PMACSmain.vb to GroundFault.vb by Ting Chan, UWEE
' 04-28-2005 Modified various many lines of code to fix the thread conflict error that only
'            occurred in the .exe program.  Modified the child thread so that it no longer directly
'            updates the GUI display controls.  Also implemented a technique to make sure
'            only one thread at a time was executing critical sections of code by using the
'            System.Threading.Interlocked.Increment() synchronization method.  Also added          
'            routine updateGroundFaultSwitchGraphics().
'
'************************************************************************************************************************

Option Strict Off
Option Explicit On 
Imports System.Math
Module GroundFault

#Region "Ground Fault Detection"

    '****************************************************************************
    ' ThreadVersionGFDetection()    Programmer: John Elliott   Date:12-30-2004
    '
    ' Version of GFDetection() routine that has been modified for use
    ' in conjunction with an independent worker thread.
    '
    ' Adapted from Ting's GFDetection() routine.  Main change was just
    ' to add the new global variable mostRecentGFCurrent.
    '
    ' Peforms ground fault detection to check if the ground fault current on the
    ' 400V or 48V busses has exceeded the ground fault current settings.
    ' The ground fault current settings can be viewed and changed in
    ' PMACSextload.vb or PMACSgroundfault.vb.
    '
    ' Note that ThreadVersionGFDetection() is called from routine
    ' CheckGfWorkerThread() which is an independent thread that
    ' runs concurrenlty with the main parent thread of the client
    ' program.
    '
    ' Note that we may need to modify this so that most of the
    ' screen update stuff is done in the parent thread to avoid
    ' possible resource conflicts between threads.  But for now
    ' try as it is since in preliminary testing it seems to work OK.
    '
    ' See also routines:
    ' Sub CopyNewSoapGroundFaultValuesAndUpdateGUIdisplay() 'jbe new 04-06-2005
    '
    '
    ' Input Parameters:
    ' globalGFbusSoapRotateCounter     - Global counter from 1 to 5 to indcate which of the 5 busses is being
    '                                    tested next for Ground Fault current.
    '
    ' Output Parameters:
    ' mostRecentGFCurrent   - Global integer to hold the new measurement of Ground
    '                         Fault current for 1 of the 5 busses.
    '
    'Revision History:
    '1-5-2005 Add ground fault detection conditions to GFDetection() by Ting Chan, UWEE
    '1-5-2005 move ThreadVersionGFDetection() from PMACSmain form to GroundFault.vb by Ting Chan, UWEE
    '04-06-2005 jbe: Removed all references to controls on the GUI forms.  Reason for doing this was because
    '           this routine is called from a child thread and we want to try to eliminate thread conflicts.  ?????See routine copyGfBusDataAndUpdateDisplays() John Elliott.
    '           Also eliminated myString as an input parameter.
    '           Command Button GFTesting_Click() "Test Ground Fault Detection" may need 
    '           to be modified to support the new version of the child thread to do Ground fault testing?
    '           Command Button GFRestart_Click() "Restart Ground Fault Monitoring" may need
    '           to be modified to support the new version of the child thread to do Ground fault testing?
    '           Command Button GFIsolate_Click() "Isolate Ground Fault" may need
    '           to be modified to support the new version of the child thread to do Ground fault testing?
    '
    '****************************************************************************

    Public Sub ThreadVersionGFDetection() 'jbe Modified 04-06-2005.

        'jbeOld Public Sub ThreadVersionGFDetection(ByVal myString???? As String)

        Dim ws As New edu.washington.apl.pmacs.load_service
        Dim myGFCurrent As Integer
        Dim myDateTime As String
        Dim myMicrosec As String
        Dim response As Short
        'Dim mstrName As Object
        Dim localGFbusSoapRotateCounter As Integer
        Dim tstart As Double 'jbe: Start time for implementing a time-out if program gets stuck. New 4-6-2005.
        Dim elapsed As Double 'jbe: Elapsed time for implementing a time-out if program gets stuck.  New 4-6-2005.
        Dim myPrompt As String 'jbe: Work string for message box prompt.
        Dim myString As String 'jbe: Work string for SOAP method argument.

        'jbe: Get time in seconds since midnight to nearest 50 msec.
        tstart = Microsoft.VisualBasic.Timer  'jbe  New 4-6-2005.

        'jbe: Loop until no other thread is doing a critical code section.
        While lockCriticalCodeCount > 0 'jbe New 4-6-2005.

            'jbe: Some other thread has locked a critical section of code.
            '     We only want to allow one thread to be doing critical sections of code
            '     at one time.  
            'jbe: Note that none of the thread safe critical sections of code in the PMACS
            '     GUI do any IO or time consuming CPU activity.  Therefore, it is OK to
            '     just loop and wait for another thread to finish its critical code section
            '     since it will not hang up the program for more than a few milli

            elapsed = System.Math.Abs(tstart - Microsoft.VisualBasic.Timer) 'jbe New 4-6-2005.

            If elapsed > 30 Then  'jbe New 4-6-2005.
                'jbe: Have looped for more than 30 seconds.
                '     Should never occur.
                '     Program somehow got stuck in the loop.  So show error message.
                myPrompt = "Error in Sub ThreadVersionGFDetection()." + vbCrLf + vbCrLf 'jbe New 4-6-2005.
                myPrompt = myPrompt + "Should never occur." + vbCrLf 'jbe New 4-6-2005.
                myPrompt = myPrompt + "Critical thread safe code has been locked for more than 30 seconds." + vbCrLf 'jbe New 4-6-2005.
                response = MsgBox(myPrompt, 0, "Error Just BEFORE Critical Code Section For Thread Synchronization") 'jbe New 4-6-2005.
                globalLastGFbusSoapRotateCounter = 9999 'jbe New 4-6-2005.

                'jbe: We may want to abort the program here.  But for now just exit routine and
                '     hope the program recovers and that this error never occurs.
                '     I am not sure but we may need to resset global handshake flags here???? 
                Exit Sub 'jbe New 4-6-2005.
            End If 'jbe New 4-6-2005.

        End While 'loop the other thread has completed executing its critical section of code. 'jbe New 4-6-2005.

        '************************************************************************************** 
        '**************** Critical section of code starts here. *******************************
        '**************************************************************************************

        'jbe: Below is the "Interlocked" keyword.  The variable 'locks' is incremented
        '     using the special 'Increment' method of the 'Interlocked' class so that
        '     the change to the variable is done as an 'atomic' operation so that another
        '     thread cannot sneak in and change the value while the current thread is
        '     simultaneously trying to change it.
        '
        '     In other parts of the code, the program will have if statements to only
        '     allow critical sections of code to execute if variable 'locks' is non-zero 
        '     so that only one thread at a time can make changes to certain variables and controls.
        '     This may help avoid lockups and failures to repaint, etcetera.
        System.Threading.Interlocked.Increment(lockCriticalCodeCount) 'jbe New 4-6-2005.

        'jbe: Increment the rotating counter so that we will rotate through the data 
        '     types (1 through 5) and get a different type on the next call to the 
        '     Ground Fault SOAP method by the child worker thread.  
        'tc:  NEW 06-07-05 rotate thru only 1-4 (exclude test)
        globalGFbusSoapRotateCounter = globalGFbusSoapRotateCounter + 1
        If globalGFbusSoapRotateCounter <= 1 Then 'jbe New 4-6-2005.
            globalGFbusSoapRotateCounter = 1 'jbe New 4-6-2005.
        ElseIf globalGFbusSoapRotateCounter > 4 Then 'tc: NEW 6-7-2005
            globalGFbusSoapRotateCounter = 1 'jbe New 4-6-2005.
        End If 'jbe New 4-6-2005.

        'jbe: Make local copy of global GF rotate counter.
        localGFbusSoapRotateCounter = globalGFbusSoapRotateCounter

        'jbe: Set the global flag ChildThreadHasGotNewValues false so that we
        '     know that it is OK to overwrite the structures used to store the
        '     new values.
        'tc: Should have been GroundFaultChildThreadHasGotNewValues instead of 
        '    ChildThreadHasGotNewValues
        'modified 06-02-05
        'GroundFaultChildThreadHasGotNewValues = False
        'ChildThreadHasGotNewValues = False

        'jbe: Decrement the lock code count so other threads will know it is safe
        '     to execute critical code sections.  
        System.Threading.Interlocked.Decrement(lockCriticalCodeCount)

        '************************************************************************************** 
        '**************** End of critical section of code. ************************************
        '**************************************************************************************

        'jbe: Assign a string corresponding to the rotating counter to use as the 
        '     argument in the call to the SOAP Ground Fault check method.
        If localGFbusSoapRotateCounter = 1 Then  'jbe New 4-6-2005.
            'Check the 400V return bus.
            myString = "v400"
        ElseIf localGFbusSoapRotateCounter = 2 Then
            'Check the 400V return bus.
            myString = "v400r"
        ElseIf localGFbusSoapRotateCounter = 3 Then
            'Check the 48V bus.
            myString = "v48"
        ElseIf localGFbusSoapRotateCounter = 4 Then
            'Check the 48V return bus.
            myString = "v48r"
            'ElseIf localGFbusSoapRotateCounter = 5 Then    'tc: Comment out on 6-7-2005
            'Perform ground fault testing.
            'myString = "test"
        Else
            'jbe: Should never get here, but just in case set the string to something valid.
            myString = "v400"
        End If  'jbe New 4-6-2005.

        'jbe: Call the SOAP method to check Ground Fault current which may take as long as 2 seconds
        '     or more.  Put return value is a local since this is NOT a thread safe section of
        '     code.  (We could have put the following call in a thread safe section of code but
        '     since the call may take 2 seconds it would cause the child thread to pause the
        '     program for 2 seconds since we only a single "thread safe protected" section of code
        '     to run at one time.

        myGFCurrent = ws.checkGF(myString)

        'jbe: Get ready to transfer the return value of the Ground Fault current to a global variable in 
        '     a thread safe section of code to avoid thread conflicts.

        'jbe: Get time in seconds since midnight to nearest 50 msec.
        tstart = Microsoft.VisualBasic.Timer 'jbe New 4-6-2005.

        'jbe: Loop until no other thread is doing a critical code section.
        While lockCriticalCodeCount > 0  'jbe New 4-6-2005.

            'jbe: Some other thread has locked a critical section of code.
            '     We only want to allow one thread to be doing critical sections of code
            '     at one time.  
            'jbe: Note that none of the thread safe critical sections of code in the PMACS
            '     GUI do any IO or time consuming CPU activity.  Therefore, it is OK to
            '     just loop and wait for another thread to finish its critical code section
            '     since it will not hang up the program for more than a few milli

            elapsed = System.Math.Abs(tstart - Microsoft.VisualBasic.Timer)

            If elapsed > 30 Then
                'jbe: Have looped for more than 30 seconds.
                '     Should never occur.
                '     Program somehow got stuck in the loop.  So show error message.
                myPrompt = "Error in Sub ThreadVersionGFDetection() while transferring Ground Fault current to global variable." + vbCrLf + vbCrLf
                myPrompt = myPrompt + "Should never occur." + vbCrLf
                myPrompt = myPrompt + "Critical thread safe code has been locked for more than 30 seconds." + vbCrLf
                response = MsgBox(myPrompt, 0, "Error Just BEFORE Critical Code Section For Thread Synchronization")
                globalLastGFbusSoapRotateCounter = 9999

                'jbe: We may want to abort the program here.  But for now just exit routine and
                '     hope the program recovers and that this error never occurs.
                '     I am not sure but we may need to resset global handshake flags here???? 
                Exit Sub
            End If

        End While 'loop until the other thread has completed executing its critical section of code. 'jbe New 4-6-2005.


        '************************************************************************************** 
        '**************** Second critical section of code starts here. ************************
        '**************************************************************************************

        'jbe: Below is the "Interlocked" keyword.  The variable 'locks' is incremented
        '     using the special 'Increment' method of the 'Interlocked' class so that
        '     the change to the variable is done as an 'atomic' operation so that another
        '     thread cannot sneak in and change the value while the current thread is
        '     simultaneously trying to change it.
        '
        '     In other parts of the code, the program will have if statements to only
        '     allow critical sections of code to execute if variable 'locks' is non-zero 
        '     so that only one thread at a time can make changes to certain variables and controls.
        '     This may help avoid lockups and failures to repaint, etcetera.
        System.Threading.Interlocked.Increment(lockCriticalCodeCount)

        'ground fault current could be negative, therefore, need to check the magnitude of the current
        'jbe: (This is just taking the absolute value I think.  Could have used System.Math.Abs() instead).
        'If myGFCurrent < 0 Then
        'myGFCurrent = myGFCurrent * (-1)
        'End If
        myGFCurrent = Abs(myGFCurrent)

        'jbe: For debug only, add a rotating integer value from 0 to 9 so we can
        '     see if the current is really updating on the screen.
        'debugCurrentDummy = debugCurrentDummy + 1 'jbe: debug only.
        'If debugCurrentDummy > 9 Then  'jbe: debug only.
        'debugCurrentDummy = 0 'jbe: debug only.
        'End If 'jbe: debug only.

        'jbe: Transfer the new ground fault current value from the local to a global
        '     variable withing this thread safe code section.  This global value will
        '     be used elsewhere by the parent thread to update the GUI display.
        globalGFCurrent = myGFCurrent
        ''''globalGFCurrent = myGFCurrent + debugCurrentDummy 'jbe debug only, remove later.

        'jbe: Set the global integer globalLastGFbusSoapRotateCounter to indicate what 
        '     type of data was most recently received.  This value will later be 
        '     be used elsewhere by the parent thread to update the GUI display.  
        globalLastGFbusSoapRotateCounter = globalGFbusSoapRotateCounter 'jbe New 4-6-2005.

        'jbe: Not sure if we still need following anymore?
        '???? mostRecentGFCurrent = myGFCurrent 

        'jbe: Set the global flag ChildThreadHasGotNewValues true so that the
        '     parent thread knows that the child thread has gotten a new value for 
        '     the Ground Fault current.  In the parent thread, the Ground Fault
        '     timer event handler will see detect that ChildThreadHasGotNewValues is true
        '     then display the Ground Fault current on the GUI and then set the global
        '     flag wantToInvokeSoapGroundFaultCheckMethod true to cause another
        '     Ground Fault measurement to be invoked here by the child process.
        GroundFaultChildThreadHasGotNewValues = True

        'jbe: Decrement the lock code count so other threads will know it is safe
        '     to execute critical code sections.
        System.Threading.Interlocked.Decrement(lockCriticalCodeCount)

        '************************************************************************************** 
        '**************** End of Second critical section of code. *****************************
        '**************************************************************************************

    End Sub 'end ThreadVersionGFDetection() CopyNewSoapGroundFaultValuesAndUpdateGUIdisplay(). 

#End Region

#Region "Ground Fault Isolation"
    '****************************************************************************
    'Peform ground fault isolation on the 400V or 48V bus if a ground fault is
    'detected.If the operator decides to isolate the ground fault, all loads on 
    'the faulted bus will be switch to OFF position. Then each load will be turned 
    'ON and check to see whether ther is a fault or not.
    '****************************************************************************
    Public Sub GFIsolation()
        Dim ws As New edu.washington.apl.pmacs.load_service
        'Dim myExtLoadUpdateType48 As New edu.washington.apl.pmacs.loadUpdateType
        'Dim myExtLoadListType48 As edu.washington.apl.pmacs.loadListType
        'Dim myExtLoadUpdateType400 As New edu.washington.apl.pmacs.loadUpdateType
        'Dim myExtLoadListType400 As edu.washington.apl.pmacs.loadListType
        Dim myExtLoadUpdateType As New edu.washington.apl.pmacs.loadUpdateType
        Dim myExtLoadListType As edu.washington.apl.pmacs.loadListType
        Dim myGFCurrent As Integer
        Dim myString As String
        Dim result As String
        Dim i As Integer
        If Science.FaultedBus = "400V" Or Science.FaultedBus = "400V Return" Then
            'If the fault is on 400V or 400V return bus
            'turn off all loads first
            For i = 0 To 7
                myString = "/1/external/" + CStr(i + 1) + "/v400"
                myExtLoadUpdateType.state = 0
                result = ws.setLoad(myString, myExtLoadUpdateType)
            Next i

        ElseIf Science.FaultedBus = "48V" Or Science.FaultedBus = "48V Return" Then
            'If the fault is on 48V or 48V return bus
            'turn off all loads first
            For i = 0 To 7
                myString = "/1/external/" + CStr(i + 1) + "/v48"
                myExtLoadUpdateType.state = 0
                result = ws.setLoad(myString, myExtLoadUpdateType)
            Next i
        End If
    End Sub
#End Region

#Region "ground fault thread"

    '**************************************************************************************************************
    ' CheckGfWorkerThread()    Programmer: John Elliott   Date: 12-30-2004
    '
    ' This routine runs in an independent thread separately from the thread of the
    ' main PMACS client parent thread.  This routine will loop forever
    ' and call the SOAP method checkGf() and then wait for it to return
    ' the Ground Fault current to be returned.
    '
    ' I am not sure if best strategy is to let this worker thread loop forever or
    ' to exit the thread and start a new worker thread for each request.
    ' But for now I will choose to implement the strategy of letting the worker thread
    ' loop forever.  Note that the worker thread seems to terminate automatically
    ' when the main parent thread aborts so we don't have to do anything special
    ' to get rid of it.
    '
    ' See also routines:
    ' ThreadVersionGFDetection() - Routine called here that does the actual call to
    '                              the SOAP method to check if the ground fault current on the
    '                              400V or 48V busses has exceeded the ground fault current settings.
    '                              jbe: Modified 04-06-2005 to remove all references to controls on GUI display.
    '                              which may have caused thread conflicts.
    ' LoadDataWorkerThread()     - Another child thread that retrieves several kinds of general 
    '                              SOAP data.
    '
    '
    ' Input Parameters:
    ' lockCriticalCodeCount         - Global integer which when non-zero indicates that one of the threads 
    '                                 is executing a critical section of code.  Only one critical 
    '                                 section of code should be allowed to run at any time.  This was 
    '                                 needed for thread synchronization to prevent errors such as the 
    '                                 big red 'X' in the datagrids and incomplete repaint of controls on 
    '                                 the forms.  jbe new 04-06-2005 
    ' wantAbortGfCheckThread        - Global flag which if true it tells the GF worker thread to abort itself.
    ' busStringForGroundFaultMeasure - Global string containing the name of one of the 4 busses
    '                                  such as "v400", "v400r", "v48", "v48r", "test".   
    '                                  Used in call to SOAP method to get the Ground Fault current.
    '
    ' Output Parameters:
    ' GroundFaultChildThreadHasGotNewValues  - Global flag which if true means the Ground Fault child thread has gotten
    '                                          return values from the SOAP method to do the Ground Fault check.
    ' globalLastGFbusSoapRotateCounter       - Global to store the previous value of globalGFbusSoapRotateCounter.
    '
    ' Input and Output Parameters:
    ' wantGFchildThreadToInvokeSoapMethod    - Second global flag for use with the child thread that does the ground 
    '                                          fault checking.  When this flag is false it means the parent thread 
    '                                          wants the child thread to just wait in an idle loop until the parent 
    '                                          thread needs it to do something.  When this flag is true the parent 
    '                                          thread wants the child thread to invoke the SOAP Ground Fault Check 
    '                                          method and the parent thread will set other global variables to tell
    '                                          the child what input parameters to use.  
    '
    ' Revision History:
    ' 1-5-2005   Delete the line threadGfMeasure.Sleep(100) by Ting Chan, UWEE
    ' 04-06-2005 Removed all references to control displays from ThreadVersionGFDetection()
    '            and place in a separate routine.  See routine copyGfBusDataAndUpdateDisplays(). John Elliott.
    '            I was not sure what to do with the line "Call GFInitialize(Science)" so I commented this
    '            line out for now. John Elliott, APL.
    '
    '**************************************************************************************************************

    Public Sub CheckGfWorkerThread() 'jbe modified 4-6-2005

        Dim i As Long 'jbe: Work variable.
        Dim myPrompt As String 'error string
        Dim response As Integer 'jbe: Work variable.
        Dim tstart As Double 'jbe: Start time for implementing a time-out if program gets stuck.
        Dim elapsed As Double 'jbe: Elapsed time for implementing a time-out if program gets stuck.

        'jbe: Local flag variable to hold local copy of global flag wantGFchildThreadToInvokeSoapMethod.
        Dim localWantGFchildThreadToInvokeSoapMethod As Boolean

        'jbe: This child thread routine will loop continuously until global wantAbortGfCheckThread is set true.
loopAgain:
        'let the ground fault checking thread to wait 5 seconds before next check
        PMACSmain.DefInstance.threadGfMeasure.Sleep(5000)

        If wantPauseGfCheckThread Then  'jbe new 5-2-2005
            'jbe new: User wants to temporarily discontinue the sequencing
            'through the Ground Fault tests.
            'CheckGfWorkerThread.sleep(50) 'jbe new (???Not sure of syntax???)
            GoTo loopAgain  'jbe new 5-2-2005
        End If 'jbe new 5-2-2005

        If wantAbortGfCheckThread Then
            Exit Sub  'jbe new, get out of inifinite loop so worker thread will terminate.
        End If 'jbe new

        'jbe: I am not sure if the following 3 lines cause thread conflicts or not so I am
        '     commenting these lines out.  They were just debug only anyway.
        'jbeCommentOut--  LabelDebugThreads.Text = "debugThreadCount =" + Str$(debugThreadCount)
        'jbeCommentOut--  PMACSmain.DefInstance.LabelDebugThreads.Text = "busStrGF=" + busStringForGroundFaultMeasure
        'jbeCommentOut--  PMACSgroundfault.DefInstance.LabelDebugThreads.Text = "busStrGF=" + busStringForGroundFaultMeasure

        tstart = Microsoft.VisualBasic.Timer     'jbe: Get time in seconds since midnight to nearest 50 msec.

        'jbe: Loop until no other thread is doing a critical code section.
        While lockCriticalCodeCount > 0

            'jbe: Some other thread has locked a critical section of code.
            '     We only want to allow one thread to be doing critical sections of code
            '     at one time.  
            'jbe: Note that none of the thread safe critical sections of code in the PMACS
            '     GUI do any IO or time consuming CPU activity.  Therefore, it is OK to
            '     just loop and wait for another thread to finish its critical code section
            '     since it will not hang up the program for more than a few milliseconds.

            elapsed = System.Math.Abs(tstart - Microsoft.VisualBasic.Timer)

            If elapsed > 30 Then
                'jbe: Have looped for more than 30 seconds.
                '     Should never occur.  Program somehow got stuck in the loop.
                '     So show error message.
                myPrompt = "Error in Sub CheckGfWorkerThread() that is the child thread." + vbCrLf + vbCrLf
                myPrompt = myPrompt + "Should never occur." + vbCrLf
                myPrompt = myPrompt + "Critical thread safe code has been locked for more than 30 seconds." + vbCrLf
                response = MsgBox(myPrompt, 0, "Error Just BEFORE Critical Code Section For Thread Synchronization")
                globalLastGFbusSoapRotateCounter = 9999

                'jbe: We may want to abort the program here.  But for now just exit routine and
                '     hope the program recovers and that this error never occurs.
                '     I am not sure but we may need to resset global handshake flags here???? 
                Exit Sub
            End If

        End While 'Loop until the other thread has completed executing its critical section of code.

        '************************************************************************************** 
        '**************** Critical section of code starts here. *******************************
        '**************************************************************************************

        'jbe: Below is the "Interlocked" keyword.  The variable 'locks' is incremented
        '     using the special 'Increment' method of the 'Interlocked' class so that
        '     the change to the variable is done as an 'atomic' operation so that another
        '     thread cannot sneak in and change the value while the current thread is
        '     simultaneously trying to change it.
        '
        '     In other parts of the code, the program will have if statements to only
        '     allow critical sections of code to execute if variable 'locks' is non-zero 
        '     so that only one thread at a time can make changes to certain variables and controls.
        '     This may help avoid lockups and failures to repaint, etcetera.
        System.Threading.Interlocked.Increment(lockCriticalCodeCount)

        localWantGFchildThreadToInvokeSoapMethod = wantGFchildThreadToInvokeSoapMethod

        'jbe: Decrement global lockCriticalCodeCount so other threads 
        '     will be allowed to execute their own critical code sections.
        System.Threading.Interlocked.Decrement(lockCriticalCodeCount)

        '************************************************************************************** 
        '**************** Critical section of code ENDS here. *********************************
        '**************************************************************************************

        If localWantGFchildThreadToInvokeSoapMethod Then

            Try 'jbe: Not sure if this 'Try' clause is needed anymore as of 4-6-2005 since everything is now done in the 
                ' in the routine ThreadVersionGFDetection().  But does not seem to hurt.

                'jbeTemporaryCommentOut--  'PMACSgroundfault.DefInstance.LabelDebugThreads.Text = "busStrGF=" + busStringForGroundFaultMeasure

                ' Perform ground fault detection to check if the ground fault current on the
                ' 400V or 48V busses has exceeded the ground fault current settings.
                ' The ground fault current settings can be viewed and changed in
                ' PMACSextload.vb or PMACSgroundfault.vb.
                ' jbe: I have modified routine ThreadVersionGFDetection() below to remove 
                '      all references to controls on GUI display.
                'jbeOLD--- Call ThreadVersionGFDetection(busStringForGroundFaultMeasure)
                
                Call ThreadVersionGFDetection() 'jbe: Modified 04-06-2005
                GotGFData = True

                'display GF settings on external load screen
                'jbe: Not sure where to put the following lines of code so I will temporarily comment
                '     them out 04-06-2005. ????
                '     I dont't think we should call GFInitialize() from within child thread since this
                '     may cause thread conflict errors.            '
                '     Maybe move these lines to the main GF display routine???
                'jbeCommentOut--  If activeFlag = False Then
                'jbeCommentOut--  Call GFInitialize(Science)
                'jbeCommentOut--  End If


            Catch err As Exception
                GotGFData = False
                myPrompt = "Error in getting Ground Fault Data over network...." + vbCrLf + vbCrLf
                myPrompt = myPrompt + "Possible reasons include the following:" + vbCrLf
                myPrompt = myPrompt + "1. Server could be offline." + vbCrLf
                myPrompt = myPrompt + "2. Network cable could be disconnected." + vbCrLf + vbCrLf
                myPrompt = myPrompt + "Exact text of exception error information is as follows:" + vbCrLf
                myPrompt = myPrompt + err.ToString()
                'response = MsgBox(myPrompt, 0, "Error Getting Ground Fault Data")
                'MessageBox.Show(err.Message, err.InnerException.ToString, MessageBoxButtons.OK, MessageBoxIcon.Error)
            End Try
        End If
        GoTo loopAgain 'jbe: Loop forever or until global flag says to abort thread.

    End Sub 'end CheckGfWorkerThread()


    '**********************************************************************************************************
    ' updateGroundFaultSwitchGraphics()   Programmer: John Elliott  Date 04-06-2005
    '
    ' Routine to update the graphic switch symbols that indicate to the user which of the
    ' voltage busses is running the Ground Fault current measurement test.
    ' The Ground Fault current measurement test is invoked by a child thread.
    ' This routine also provides a textbox to show status lines versus time of
    ' day so that the user can see the recent history of Ground Fault currents, 
    ' spot spikes, determine update rate, etcetera.
    '
    ' WARNING: Do not call updateGroundFaultSwitchGraphics() from within a child thread routine.
    ' This may have been a cause of thread conflict errors we had in March 2005.
    '
    '
    ' See also routines:
    ' updateGroundFaultSwitchGraphics() -
    ' CheckGfWorkerThread()      - Routine which is the actual child thread that invokes CheckGfWorkerThread() 
    '                              that actually calls the Ground Fault check SOAP method.
    ' ThreadVersionGFDetection() - Routine called from CheckGfWorkerThread() that actually calls the Ground 
    '                              Fault check SOAP method.
    ' CopyNewSoapGroundFaultValuesAndUpdateGUIdisplay() - Routine to copy new Ground Fault current measurement 
    '                              values from the global storage structure to a local structure and the use 
    '                              these new values to update the Groudn Fault GUI display controls.    
    '
    '
    ' Input Parameters:
    ' globalGFbusSoapRotateCounter     - Global counter from 1 to 5 to indcate which of the 5 busses is being
    '                                    tested next for Ground Fault current..
    ' globalLastGFbusSoapRotateCounter - Previous value of globalGFbusSoapRotateCounter.  (I am not sure if
    '                                    we should use globalGFbusSoapRotateCounter or globalGFbusSoapRotateCounter
    '                                    to show the switch that is closed presently?????)
    ' globalGFCurrent                  - Global for most recent Ground Fault current measurement.
    '                                    ????Is this one measurement behind what is displayed by
    '                                    switch symbol position graphics.???
    '
    ' Modification Record:
    '
    '****************************************************************************

    Sub updateGroundFaultSwitchGraphics() 'jbe new 04-06-2005

        Dim localGFbusSoapRotateCounter As Integer 'jbe: Holds copy of global Soap Ground Fault selection test Rotate counter.
        Dim DisplayBus As String    'string for showing which bus is being checked, display only
        Dim myPrompt As String 'jbe: Work variable.
        Dim response As Integer 'jbe: Work variable.
        Dim myString As String 'jbe: Work string.
        Dim LocalGFstatusStr As String 'jbe: Work string for displaying status info in textbox.
        Dim LocalGFstatusStrB As String 'jbe: Work string for displaying extra status info in textbox.

        Dim tstart As Double 'jbe: Start time for implementing a time-out if program gets stuck.
        Dim elapsed As Double 'jbe: Elapsed time for implementing a time-out if program gets stuck.

        'jbe: Get time in seconds since midnight to nearest 50 msec.
        tstart = Microsoft.VisualBasic.Timer

        'jbe: Loop until no other thread is doing a critical code section.
        While lockCriticalCodeCount > 0

            'jbe: Some other thread has locked a critical section of code.
            '     We only want to allow one thread to be doing critical sections of code
            '     at one time.  
            'jbe: Note that none of the thread safe critical sections of code in the PMACS
            '     GUI do any IO or time consuming CPU activity.  Therefore, it is OK to
            '     just loop and wait for another thread to finish its critical code section
            '     since it will not hang up the program for more than a few milliseconds.

            elapsed = System.Math.Abs(tstart - Microsoft.VisualBasic.Timer)

            If elapsed > 30 Then
                'jbe: Have looped for more than 30 seconds.
                '     Should never occur.
                '     Program somehow got stuck in the loop.  So show error message.
                myPrompt = "Error in Sub updateGroundFaultSwitchGraphics()." + vbCrLf + vbCrLf
                myPrompt = myPrompt + "Should never occur." + vbCrLf
                myPrompt = myPrompt + "Critical thread safe code has been locked for more than 30 seconds." + vbCrLf
                response = MsgBox(myPrompt, 0, "Error Just BEFORE Critical Code Section For Thread Synchronization")
                globalLastGFbusSoapRotateCounter = 9999

                'jbe: We may want to abort the program here.  But for now just exit routine and
                '     hope the program recovers and that this error never occurs.
                Exit Sub
            End If

        End While 'loop the other thread has completed executing its critical section of code.

        '************************************************************************************** 
        '**************** Critical section of code starts here. *******************************
        '**************************************************************************************

        'jbe: Below is the "Interlocked" keyword.  The variable 'locks' is incremented
        '     using the special 'Increment' method of the 'Interlocked' class so that
        '     the change to the variable is done as an 'atomic' operation so that another
        '     thread cannot sneak in and change the value while the current thread is
        '     simultaneously trying to change it.
        '
        '     In other parts of the code, the program will have if statements to only
        '     allow critical sections of code to execute if variable 'locks' is non-zero 
        '     so that only one thread at a time can make changes to certain variables and controls.
        '     This may help avoid lockups and failures to repaint, etcetera.
        System.Threading.Interlocked.Increment(lockCriticalCodeCount)

        'jbe: Create a local copy of the global value of globalGFbusSoapRotateCounter.
        localGFbusSoapRotateCounter = globalGFbusSoapRotateCounter

        'jbe: Decrement the lock critical code count so other threads will know it is safe
        '     to execute critical code sections.
        System.Threading.Interlocked.Decrement(lockCriticalCodeCount)

        '************************************************************************************** 
        '**************** End of critical section of code. ************************************
        '**************************************************************************************

        'jbe: Assign a string corresponding to the rotating counter to use as the 
        '     argument in the call to the SOAP Ground Fault check method.
        '    (??? Not sure if we should use a local copy of globalLastGFbusSoapRotateCounter instead???).
        If localGFbusSoapRotateCounter = 1 Then  'jbe New 4-6-2005.
            'Check the 400V return bus.
            myString = "v400"
            DisplayBus = "400V"
        ElseIf localGFbusSoapRotateCounter = 2 Then
            'Check the 400V return bus.
            myString = "v400r"
            DisplayBus = "400 Com"
        ElseIf localGFbusSoapRotateCounter = 3 Then
            'Check the 48V bus. 
            myString = "v48"
            DisplayBus = "48V"
        ElseIf localGFbusSoapRotateCounter = 4 Then
            'Check the 48V return bus.
            myString = "v48r"
            DisplayBus = "48 Com"
            'ElseIf localGFbusSoapRotateCounter = 5 Then    'tc: Comment out on 6-7-2005
            'Perform ground fault testing.
            'myString = "test"
        Else
            'jbe: Should never get here, but just in case set the string to something valid.
            myString = "v400"
        End If                         'jbe New 4-6-2005.

        LocalGFstatusStrB = " unknown"

        'jbe: Make it appear that all 5 switches are in the open position so
        '     that in the code a little further down only one of the 5 switches will be closed.
        '     (or only switches C closed and E closed for myString = "test").
        '     This used to be done in another section of code but did not appear to
        '     work correctly.  New 04-06-2005.
        PMACSgroundfault.DefInstance.GFSwitchAOpen.Visible = True 'jbe new 04-06-2005
        PMACSgroundfault.DefInstance.GFSwitchAClose.Visible = False 'jbe new 04-06-2005
        PMACSgroundfault.DefInstance.GFSwitchBOpen.Visible = True 'jbe new 04-06-2005
        PMACSgroundfault.DefInstance.GFSwitchBClose.Visible = False 'jbe new 04-06-2005
        PMACSgroundfault.DefInstance.GFSwitchCOpen.Visible = True 'jbe new 04-06-2005
        PMACSgroundfault.DefInstance.GFSwitchCClose.Visible = False 'jbe new 04-06-2005
        PMACSgroundfault.DefInstance.GFSwitchDOpen.Visible = True 'jbe new 04-06-2005
        PMACSgroundfault.DefInstance.GFSwitchDClose.Visible = False 'jbe new 04-06-2005
        PMACSgroundfault.DefInstance.GFSwitchEOpen.Visible = True 'jbe new 04-06-2005
        PMACSgroundfault.DefInstance.GFSwitchEClose.Visible = False 'jbe new 04-06-2005

        'See which bus is being checked for ground fault and display the switches
        If myString = "v400" Then
            'checking the 400V bus
            'close switch B
            PMACSgroundfault.DefInstance.GFSwitchBOpen.Visible = False
            PMACSgroundfault.DefInstance.GFSwitchBClose.Visible = True

            'Show grounf fault current on PMACSextload window
            PMACSextload.DefInstance.GFHigh400.Text = CStr(globalGFCurrent) + " uA"

            LocalGFstatusStrB = " Closed B "
            PMACSgroundfault.DefInstance.LabelGFBus.Text = "400V Bus"
        ElseIf myString = "v400r" Then
            'checking the 400V return bus
            'close switch A
            PMACSgroundfault.DefInstance.GFSwitchAOpen.Visible = False
            PMACSgroundfault.DefInstance.GFSwitchAClose.Visible = True

            'Show grounf fault current on PMACSextload window
            PMACSextload.DefInstance.GFLow400.Text = CStr(globalGFCurrent) + " uA"

            LocalGFstatusStrB = " Closed A "
            PMACSgroundfault.DefInstance.LabelGFBus.Text = "400 Com Bus"
        ElseIf myString = "v48" Then
            'checking the 48V bus
            'close switch D
            PMACSgroundfault.DefInstance.GFSwitchDOpen.Visible = False
            PMACSgroundfault.DefInstance.GFSwitchDClose.Visible = True

            'Show grounf fault current on PMACSextload window
            PMACSextload.DefInstance.GFHigh48.Text = CStr(globalGFCurrent) + " uA"

            LocalGFstatusStrB = " Closed D "
            PMACSgroundfault.DefInstance.LabelGFBus.Text = "48V Bus"
        ElseIf myString = "v48r" Then
            'checking the 48V return bus
            'close switch C
            PMACSgroundfault.DefInstance.GFSwitchCOpen.Visible = False
            PMACSgroundfault.DefInstance.GFSwitchCClose.Visible = True

            'Show grounf fault current on PMACSextload window
            PMACSextload.DefInstance.GFLow48.Text = CStr(globalGFCurrent) + " uA"

            LocalGFstatusStrB = " Closed C "
            PMACSgroundfault.DefInstance.LabelGFBus.Text = "48 Com Bus"
        ElseIf myString = "test" Then
            'performing ground fault testing
            'close both switches C and E
            PMACSgroundfault.DefInstance.GFSwitchCOpen.Visible = False
            PMACSgroundfault.DefInstance.GFSwitchCClose.Visible = True
            LocalGFstatusStrB = " Closed C AND E "
            PMACSgroundfault.DefInstance.GFSwitchEOpen.Visible = False
            PMACSgroundfault.DefInstance.GFSwitchEClose.Visible = True
            PMACSgroundfault.DefInstance.LabelGFBus.Text = "Ground Fault Detection (Testing)"
        Else
            LocalGFstatusStrB = " BAD "
        End If


        'jbe: Show status lines versus time of day in text box so user can see recent history
        '     of Ground Fault currents, spot spikes, determine update rate, etcetera.

        LocalGFstatusStr = PMACSgroundfault.DefInstance.TextBoxGroundFaultStatus.Text + vbCrLf 'jbe New 04-06-2005
        LocalGFstatusStr = LocalGFstatusStr + "  " + SystemUTCTime + "  "
        LocalGFstatusStr = LocalGFstatusStr + LocalGFstatusStrB + "  "
        LocalGFstatusStr = LocalGFstatusStr + " Ground Fault current for " + DisplayBus + " was "
        LocalGFstatusStr = LocalGFstatusStr + Str$(globalGFCurrent) + " uA  "

        'display GF current on PMACSgroundfault window
        PMACSgroundfault.DefInstance.GFCurrent.Text = CStr(globalGFCurrent) + " uA"


        If Len(LocalGFstatusStr) > 30000 Then
            'jbe: Prevent string from getting too long and slowing down program.
            LocalGFstatusStr = Right$(LocalGFstatusStr, 1000)
        End If

        PMACSgroundfault.DefInstance.TextBoxGroundFaultStatus.Text = LocalGFstatusStr
        PMACSgroundfault.DefInstance.TextBoxGroundFaultStatus.SelectionStart = Len(LocalGFstatusStr)
        PMACSgroundfault.DefInstance.TextBoxGroundFaultStatus.ScrollToCaret() 'jbe: Show bottom line in textbox.


        'jbe: Not sure if we really need a refresh here but does not hurt.
        PMACSgroundfault.DefInstance.Refresh() 'jbe new 04-06-2005

    End Sub 'end updateGroundFaultSwitchGraphics() 'jbe new 04-06-2005

#End Region

End Module

