private void ActionCompletedHandler(CommunicationAction action, bool success)
        {
            lock (this)        //lock to ensure we don't accidentally get other callbacks while handling this one
            {
                if (IsRunning) //always need to check this in case we are getting callbacks after we complete
                {
                    CurrentAction = null;

                    action.ActionCompletedEvent -= this.ActionCompletedHandler;

                    OnActionCompleted(action, success);
                }
            }
        }
        protected virtual void OnActionCompleted(CommunicationAction action, bool success)
        {
            if (success)
            {
                success = StartNextAction();

                if (CurrentAction == null)
                {
                    OperationCompleted(true);
                }
            }
            else
            {
                OperationCompleted(false);
            }
        }
        protected override void OnActionStarted(CommunicationAction action)
        {
#if LOG_PERFORMANCE
            CommInterface.DisplayStatusMessage("OnActionStarted started at " + DateTime.Now.ToString("hh:mm:ss.fff"), StatusMessageType.DEV);
#endif
            base.OnActionStarted(action);

            //ignore actions not started by this code
            if (action == mMyLastStartedAction)
            {
                //done after the ActionCompletedHandler so the next message is sent before we process updates
                if ((mState == State.ReadVariables) && (mLastReadData != null))
                {
                    var regionsReadEventCopy = RegionsRead;

                    if (regionsReadEventCopy != null)
                    {
                        var updatedRegions = new List <TaggedMemoryImage>(mLastReadData.Count);

                        var dataIter = mLastReadData.GetEnumerator();

                        //update newly read regions
                        foreach (var curRegion in mSynchronizedRegions)
                        {
                            if (!dataIter.MoveNext())
                            {
                                break;
                            }

                            dataIter.Current.CopyTo(curRegion.RawData, 0);
                            updatedRegions.Add(curRegion);
                        }

                        regionsReadEventCopy(updatedRegions);
                    }

                    mLastReadData = null;
                }
            }

#if LOG_PERFORMANCE
            CommInterface.DisplayStatusMessage("OnActionStarted finished at " + DateTime.Now.ToString("hh:mm:ss.fff"), StatusMessageType.DEV);
#endif
        }
 protected virtual void OnActionStarted(CommunicationAction action)
 {
 }
        protected override void OnActionCompleted(CommunicationAction action, bool success)
        {
#if LOG_PERFORMANCE
            CommInterface.DisplayStatusMessage("OnActionCompleted started at " + DateTime.Now.ToString("hh:mm:ss.fff"), StatusMessageType.DEV);
#endif
            //ignore actions not started by this code
            if (action == mMyLastStartedAction)
            {
                if (action.CompletedWithoutCommunicationError)
                {
                    if (success)
                    {
                        if ((mState == State.DefineVariables) && (mDataLogAction.ReadMode == ExtendedDataLoggingDefineReadVariables.Mode.Define))
                        {
                            mState = State.ReadVariables;
                            mExtendedDataLoggingSetup = true;
                            mLastReadData             = null;

                            CommInterface.DisplayStatusMessage("ECU reports " + mDataLogAction.NumVariablesDefined + " variables were defined for data logging.", StatusMessageType.USER);
                        }
                        else if ((mState == State.ReadVariables) && (mDataLogAction.ReadMode == ExtendedDataLoggingDefineReadVariables.Mode.Read))
                        {
                            mLastReadData = new List <byte[]>(mDataLogAction.ReadVariableData.Count());

                            foreach (var data in mDataLogAction.ReadVariableData)
                            {
                                mLastReadData.Add(data);
                            }
                        }
                    }
                    else
                    {
                        if (mState == State.DefineVariables)
                        {
                            if (mDataLogAction.DefineFailureResponseCode == (byte)KWP2000ResponseCode.ServiceNotSupported)
                            {
                                CommInterface.DisplayStatusMessage("Failed to define data logged variables with the ECU. Extended data logging protocol does not appear to have been setup.", StatusMessageType.USER);

                                if (!mExtendedDataLoggingSetup)
                                {
                                    CommInterface.DisplayStatusMessage("Setting up extended data logging protocol.", StatusMessageType.USER);
                                    ShouldRelocateMessageHandlingTable = true;
                                    success = true;
                                }
                            }
                            else
                            {
                                CommInterface.DisplayStatusMessage("Failed to define data logged variables with the ECU.", StatusMessageType.USER);
                            }
                        }
                        else if (mState == State.ReadVariables)
                        {
                            CommInterface.DisplayStatusMessage("Failed to read data logged variables from the ECU.", StatusMessageType.USER);
                        }
                    }
                }
            }

            mMyLastStartedAction = null;

            base.OnActionCompleted(action, success);

#if LOG_PERFORMANCE
            CommInterface.DisplayStatusMessage("OnActionCompleted finished at " + DateTime.Now.ToString("hh:mm:ss.fff"), StatusMessageType.DEV);
#endif
        }