/// <summary>
        /// Delegate that executes the firmware update.
        /// </summary>
        /// <param name="stateInfo">
        /// FirmwareUpdateInfo object passed as generic object to WaitCallback method.
        /// </param>
        private void ExecuteFirmwareUpdate(Object stateInfo)
        {
            FirmwareUpdateInfo fwUpdateInfo = (FirmwareUpdateInfo)stateInfo;
            bool enteredFwUpgradeMode = false;
            CompletionCode result = CompletionCode.Success;
            int psuI2CPacketHandleTimeMs = fwUpdateInfo.primaryImage ? psuPriI2CPacketHandleTimeMs : psuSecI2CPacketHandleTimeMs;

            // Update flag to signal that PSU FW update is in progress so that:
            // 1. PSU is not falsely signaled as faulty by PSU monitoring code
            // 2. Other code do not try and access PSU as this can cause FW update failures
            ChassisState.PsuFwUpdateInProgress[this.PsuId - 1] = true;

            lock (ChassisState.psuLock[this.PsuId - 1])
            {
                try
                {
                    fwUpdateStatus = FwUpdateStatusEnum.InProgress;

                    // Read file into memory. The image file is only a few hundred kilobytes so it won't consume much memory.
                    fwUpdateStage = FwUpdateStageEnum.ReadFirmwareImageFile;
                    string[] fwImage = File.ReadAllLines(fwUpdateInfo.fwFilepath);
                    // Remove leading ':'
                    for (int i = 0; i < fwImage.Length; i++)
                    {
                        fwImage[i] = fwImage[i].Remove(0, 1);
                    }

                    // Extract model ID from the firmware image;
                    fwUpdateStage = FwUpdateStageEnum.ExtractModelId;
                    byte[] modelId = ExtractModelId(fwImage, fwUpdateInfo.primaryImage);
                    if (modelId == null)
                    {
                        result = CompletionCode.UnspecifiedError;
                    }

                    // Enter Programming Mode
                    // PSU will verify password, turn off power output and switch to bootloader mode
                    if (result == CompletionCode.Success)
                    {
                        fwUpdateStage = FwUpdateStageEnum.EnterFirmwareUpgradeMode;
                        result = EnterFirmwareUpgradeMode(fwUpdateInfo.primaryImage);
                    }

                    // Model ID Validation
                    // Send model ID to PSU.
                    // PSU will verify model ID and erase current firmware image
                    if (result == CompletionCode.Success)
                    {
                        // Wait for PSU to turn off output and enter programming mode
                        Thread.Sleep(psuEnterProgrammingModeTimeMs);
                        enteredFwUpgradeMode = true;

                        fwUpdateStage = FwUpdateStageEnum.SendModelId;
                        result = SendModelId(modelId);
                    }

                    // Check status for Model ID verification
                    if (result == CompletionCode.Success)
                    {
                        // Wait for PSU to erase program memory
                        Thread.Sleep(psuProgramEraseTimeMs);

                        FirmwareUpdateStatusPacket response = GetFirmwareUpdateStatus();
                        if (response.CompletionCode != CompletionCode.Success)
                        {
                            result = CompletionCode.UnspecifiedError;
                            Tracer.WriteWarning("ExecuteFirmwareUpdate(): GetFirmwareUpdateStatus Failure after sending model ID: Completion Code: {0}",
                                response.CompletionCode);
                        }
                        else
                        {
                            if (response.UpdateStatus != PsuFwUpdateStatus.FlashEraseOK)
                            {
                                result = CompletionCode.UnspecifiedError;
                                Tracer.WriteWarning("ExecuteFirmwareUpdate(): Model ID verification failed with status: {0}",
                                    response.UpdateStatus.ToString());
                            }
                        }
                    }

                    // Write new firmware image to PSU
                    if (result == CompletionCode.Success)
                    {
                        // Wait for PSU I2C Packet Handling Time
                        Thread.Sleep(psuI2CPacketHandleTimeMs);
                        fwUpdateStage = FwUpdateStageEnum.WriteFirmwareImage;
                        result = WriteFirmwareImage(fwImage, fwUpdateInfo.primaryImage);
                    }

                    // Read back firmware image and verify that the image was written correctly
                    if (result == CompletionCode.Success)
                    {
                        fwUpdateStage = FwUpdateStageEnum.VerifyFirmwareImage;
                        result = VerifyFirmwareImage(fwImage, fwUpdateInfo.primaryImage);
                    }

                    // Exit programming mode
                    if (result == CompletionCode.Success)
                    {
                        fwUpdateStage = FwUpdateStageEnum.ExitFirmwareUpgradeMode;
                        result = ExitFirmwareUpgradeMode();
                    }

                    if (result == CompletionCode.Success)
                    {
                        // Update firmware upgrade status
                        fwUpdateStage = FwUpdateStageEnum.Completed;
                        fwUpdateStatus = FwUpdateStatusEnum.Success;
                    }
                    else
                    {
                        if (enteredFwUpgradeMode)
                        {
                            ExitFirmwareUpgradeMode();
                        }
                        fwUpdateStatus = FwUpdateStatusEnum.Failed;
                        Tracer.WriteWarning("ExecuteFirmwareUpdate failed at stage: {0} with completion code: {1}",
                            fwUpdateStage.ToString(), result);
                    }

                    ChassisState.PsuFwUpdateInProgress[this.PsuId - 1] = false;
                    return;
                }
                catch (Exception ex)
                {
                    if (enteredFwUpgradeMode)
                    {
                        ExitFirmwareUpgradeMode();
                    }
                    fwUpdateStatus = FwUpdateStatusEnum.Failed;
                    Tracer.WriteWarning("ExecuteFirmwareUpdate failed at stage: {0} with exception: {1}",
                        fwUpdateStage.ToString(), ex.Message);
                    ChassisState.PsuFwUpdateInProgress[this.PsuId - 1] = false;
                    return;
                }
            }
        }
        /// <summary>
        /// Writes firmware image to the PSU
        /// </summary>
        /// <param name="fwImage">String array containing the firmware image</param>
        /// <param name="primaryImage">
        /// True:  Firmware image is for primary controller. 
        /// False: Firmware image is for secondary controller. 
        /// <returns>Completion Code.</returns>
        private CompletionCode WriteFirmwareImage(string[] fwImage, bool primaryImage)
        {
            CompletionCode result = CompletionCode.UnspecifiedError;

            // Determine the start/end offsets for the image file
            string startOffset = primaryImage ? priFwWriteStartOffset : secFwWriteStartOffset;
            string endOffset = primaryImage ? priFwEndOffset : secFwEndOffset;
            byte endRomPage = primaryImage ? priFwEndPage : secFwEndPage;
            // Determine the proper time delays for primary/secondary controller
            int psuI2CPacketHandleTimeMs = primaryImage ? psuPriI2CPacketHandleTimeMs : psuSecI2CPacketHandleTimeMs;
            int psuBlockProgramWriteTimeMs = primaryImage ? psuPriBlockProgramWriteTimeMs : psuSecBlockProgramWriteTimeMs;

            Tracer.WriteInfo("WriteFirmwareImage(): Primary Image: {0}", primaryImage);

            // Find index of first line of the firmware image file
            int dataIdx = Array.FindIndex<string>(fwImage, p => p.StartsWith(startOffset));
            if (dataIdx == -1)
            {
                Tracer.WriteWarning("WriteFirmwareImage: Cannot find start of firmware image file. Primary Image: {0}", primaryImage);
                return result;
            }

            int blockIdx = 0;
            string tmpStr;
            StringBuilder fwDataStr;
            byte[] fwDataByteArr;
            byte romPage = 0;

            bool writeComplete = false;
            while (!writeComplete)
            {
                // Check validity of each line of the firmware image file
                tmpStr = fwImage[dataIdx];
                if ((string.IsNullOrEmpty(tmpStr)) || (tmpStr.Length != fwImageDataLineLength))
                {
                    Tracer.WriteWarning("WriteFirmwareImage: Invalid line in firmware image file. Data index: {0} Line value: {1}",
                        dataIdx, tmpStr);
                    result = CompletionCode.UnspecifiedError;
                    return result;
                };

                // Extract low/high 8 bytes of the payload and write to PSU
                for (int i = 0; i < 2; i++)
                {
                    // Remove hex checksum, 8 bytes of payload (low or high), record type and data length
                    fwDataStr = new StringBuilder(tmpStr).Remove(40, 2).Remove(24 - 16*i, 16).Remove(6, 2).Remove(0, 2);

                    // Convert to byte array and update low byte of address
                    fwDataByteArr = Ipmi.IpmiSharedFunc.HexStringToByteArray(fwDataStr.ToString());
                    fwDataByteArr[1] = (byte)(fwDataByteArr[1] + (i*8));

                    // Write to PSU
                    result = WriteProgramMemory(fwDataByteArr, false);
                    if (result != CompletionCode.Success)
                    {
                        Tracer.WriteWarning("WriteFirmwareImage: Error writing to program memory: Completion Code: " + result +
                            " Data index: " + dataIdx + " Line value: " + fwDataStr.ToString());
                        return result;
                    }
                    // Wait for PSU I2C Packet Handling Time
                    Thread.Sleep(psuI2CPacketHandleTimeMs);
                }

                dataIdx++;
                blockIdx++;
                if (blockIdx == 16)
                {
                    blockIdx = 0;
                    // Wait for PSU to write block every 16 lines
                    Thread.Sleep(psuBlockProgramWriteTimeMs);
                }

                // Check write status
                FirmwareUpdateStatusPacket response = GetFirmwareUpdateStatus();
                if (response.CompletionCode != CompletionCode.Success)
                {
                    fwUpdateStatus = FwUpdateStatusEnum.Failed;
                    Tracer.WriteWarning("WriteFirmwareImage: GetFirmwareUpdateStatus Failure. Completion Code: " + response.CompletionCode +
                        " Data index: " + dataIdx + " Line value: " + tmpStr);
                    result = response.CompletionCode;
                    return result;
                }
                else
                {
                    if (response.UpdateStatus != PsuFwUpdateStatus.NoError)
                    {
                        fwUpdateStatus = FwUpdateStatusEnum.Failed;
                        Tracer.WriteWarning("WriteFirmwareImage: Write failed with status: " + response.UpdateStatus.ToString() +
                            " Data index: " + dataIdx + " Line value: " + tmpStr);
                        result = CompletionCode.UnspecifiedError;
                        return result;
                    }
                }
                // Wait for PSU I2C Packet Handling Time
                Thread.Sleep(psuI2CPacketHandleTimeMs);

                // Check if we are at the end of the ROM page
                if (tmpStr.StartsWith(pageEndOffset))
                {
                    // Next line in firmware image file contains the ROM page update data
                    tmpStr = fwImage[dataIdx];
                    if ((string.IsNullOrEmpty(tmpStr)) || (tmpStr.Length != fwImageRomPageLineLength))
                    {
                        Tracer.WriteWarning("WriteFirmwareImage: Invalid ROM page update line in firmware image file. Data index: {0} Line value: {1}",
                            dataIdx, tmpStr);
                        result = CompletionCode.UnspecifiedError;
                        return result;
                    };

                    // Remove hex checksum, record type and data length
                    // Convert to byte array and update low byte of address
                    fwDataByteArr = Ipmi.IpmiSharedFunc.HexStringToByteArray(tmpStr.Remove(12, 2).Remove(6, 2).Remove(0, 2));
                    fwDataByteArr[1] = (byte)(fwDataByteArr[1] + 4);

                    // Write to PSU
                    result = WriteProgramMemory(fwDataByteArr, true);
                    if (result != CompletionCode.Success)
                    {
                        Tracer.WriteWarning("WriteFirmwareImage: Error writing ROM page to program memory: Completion Code: " + result +
                            " Data index: " + dataIdx + " Line value: " + tmpStr);
                        return result;
                    }
                    dataIdx++;
                    romPage++;
                    // Wait for PSU I2C Packet Handling Time
                    Thread.Sleep(psuI2CPacketHandleTimeMs);
                }

                // Check if we are at the end of the file
                if ((tmpStr.StartsWith(endOffset)) && (romPage == endRomPage))
                {
                    writeComplete = true;
                }
            }

            result = CompletionCode.Success;
            return result;
        }