/// <summary>
        /// Attempts to retrieve the Psu Power. This method
        /// calls down to the Chassis Manager with SendReceive
        /// </summary>
        private PsuPowerPacket GetPsuPower(byte psuId)
        {
            // Initialize return packet
            PsuPowerPacket returnPacket = new PsuPowerPacket();

            returnPacket.CompletionCode = CompletionCode.UnspecifiedError;
            returnPacket.PsuPower       = 0;

            byte[] powerValue = new byte[2];
            try
            {
                PsuPowerResponse myResponse = new PsuPowerResponse();
                myResponse = (PsuPowerResponse)this.SendReceive(this.PsuDeviceType, this.PsuId, new PsuRequest((byte)PmBusCommand.READ_POUT, (byte)PmBusResponseLength.READ_POUT), typeof(PsuPowerResponse));

                if (myResponse.CompletionCode != 0)
                {
                    returnPacket.CompletionCode = (CompletionCode)myResponse.CompletionCode;
                }
                else
                {
                    returnPacket.CompletionCode = CompletionCode.Success;
                    powerValue = myResponse.PsuPower;
                    byte[] convertedPowerValue = null;
                    PmBus.PmBusLinearDataFormatConverter(ref powerValue, out convertedPowerValue);
                    powerValue            = convertedPowerValue;
                    returnPacket.PsuPower = System.BitConverter.ToInt32(powerValue, 0);
                }
            }
            catch (System.Exception ex)
            {
                returnPacket.CompletionCode = CompletionCode.UnspecifiedError;
                returnPacket.PsuPower       = 0;
                Tracer.WriteError(this.PsuId, DeviceType.Psu, ex);
            }
            return(returnPacket);
        }
        /// <summary>
        /// Attempts to retrieve the Psu Power. This method
        /// calls down to the Chassis Manager with SendReceive
        /// </summary>
        private PsuPowerPacket GetPsuPower(byte psuId)
        {
            // Initialize return packet
            PsuPowerPacket returnPacket = new PsuPowerPacket();
            returnPacket.CompletionCode = CompletionCode.UnspecifiedError;
            returnPacket.PsuPower = 0;

            byte[] powerValue = new byte[2];
            try
            {
                PsuPowerResponse myResponse = new PsuPowerResponse();
                myResponse = (PsuPowerResponse)this.SendReceive(this.PsuDeviceType, this.PsuId, new PsuRequest((byte)PmBusCommand.READ_POUT,(byte)PmBusResponseLength.READ_POUT), typeof(PsuPowerResponse));

                if (myResponse.CompletionCode != 0)
                {
                    returnPacket.CompletionCode = (CompletionCode)myResponse.CompletionCode;
                }
                else
                {
                    returnPacket.CompletionCode = CompletionCode.Success;
                    powerValue = myResponse.PsuPower;
                    byte[] convertedPowerValue = null;
                    PmBus.PmBusLinearDataFormatConverter(ref powerValue, out convertedPowerValue);
                    powerValue = convertedPowerValue;
                    returnPacket.PsuPower = System.BitConverter.ToInt32(powerValue, 0);
                }
            }
            catch (System.Exception ex)
            {
                returnPacket.CompletionCode = CompletionCode.UnspecifiedError;
                returnPacket.PsuPower = 0;
                Tracer.WriteError(this.PsuId, DeviceType.Psu, ex);
            }
            return returnPacket;
        }
        /// <summary>
        /// Attempt to resolve Psu Faults
        /// </summary>
        private static Dictionary <byte, PsuAlertFaultStatus> PsuAlertRemediate(Dictionary <byte, PsuAlertFaultType> psuFailures)
        {
            Dictionary <byte, PsuAlertFaultStatus> failedPsu = new Dictionary <byte, PsuAlertFaultStatus>();

            foreach (KeyValuePair <byte, PsuAlertFaultType> psu in psuFailures)
            {
                // If firmware update is in progress, skip this PSU
                if (ChassisState.PsuFwUpdateInProgress[psu.Key - 1])
                {
                    continue;
                }

                lock (ChassisState.psuLock[psu.Key - 1])
                {
                    // Log PSU faults
                    ChassisState.Psu[psu.Key - 1].LogPsuFaultStatus();

                    // Clear PSU faults, which will clear PSU_ALERT
                    CompletionCode clearAlert = ClearPsuFault(psu.Key);
                    if (clearAlert != CompletionCode.Success)
                    {
                        // PSU clear faults failed. Log failure and continue to next PSU.
                        failedPsu.Add(psu.Key, PsuAlertFaultStatus.PsuClearFaultFailed);
                        Tracer.WriteError("PsuAlertRemediate: ClearPsuFault failed on PsuId: {0}", psu.Key);
                        continue;
                    }

                    if (psu.Value == PsuAlertFaultType.PsuFailure)
                    {
                        // Check that the PSU is on
                        PsuStatusPacket psuStatus = ChassisState.Psu[psu.Key - 1].GetPsuStatus();
                        if (psuStatus.CompletionCode != CompletionCode.Success)
                        {
                            failedPsu.Add(psu.Key, PsuAlertFaultStatus.PsuFault);
                            Tracer.WriteError("PsuAlertRemediate: GetPsuStatus on PSU ({0}) failed with return code {1}",
                                              psu.Key, psuStatus.CompletionCode);
                        }
                        else
                        {
                            if (psuStatus.PsuStatus == (byte)Contracts.PowerState.ON)
                            {
                                // Check PSU power output
                                PsuPowerPacket power = ChassisState.Psu[psu.Key - 1].GetPsuPower();
                                if ((power.CompletionCode == CompletionCode.Success) && (power.PsuPower != 0))
                                {
                                    Tracer.WriteInfo("PsuStatus clear faults succeeded.  Psu: {0} drawing power: {1} Watts",
                                                     psu.Key, power.PsuPower);
                                }
                                else
                                {
                                    // PSU is not outputting power.
                                    failedPsu.Add(psu.Key, PsuAlertFaultStatus.PsuNoOutputPower);
                                    Tracer.WriteError("PsuAlertRemediate failed Psu.  PsuId: {0} Psu Error State: {1}",
                                                      psu.Key, PsuAlertFaultStatus.PsuNoOutputPower.ToString());
                                }
                            }
                            else
                            {
                                // PSU is turned off.
                                failedPsu.Add(psu.Key, PsuAlertFaultStatus.PsuPowerOff);
                                Tracer.WriteError("PsuAlertRemediate failed Psu.  PsuId: {0} Psu Error State: {1}",
                                                  psu.Key, PsuAlertFaultStatus.PsuPowerOff.ToString());
                            }
                        }
                    }
                    else if ((ConfigLoaded.BatteryMonitoringEnabled) && (ChassisState.Psu[(psu.Key - 1)] is EmersonPsu))
                    {
                        // convert psu from base class object
                        EmersonPsu emersonPsu = (EmersonPsu)ChassisState.Psu[(psu.Key - 1)];

                        if (psu.Value == PsuAlertFaultType.BatteryFault)
                        {
                            // clear battery fault status
                            CompletionCode clearFault = emersonPsu.ClearBatteryFaultIndicator();

                            if (clearFault == CompletionCode.Success)
                            {
                                EmersonPsu.BatteryFaultIndicatorPacket faultIndicator = emersonPsu.GetBatteryFaultIndicator();

                                if (faultIndicator.BatteryFault == 1)
                                {
                                    if (!failedPsu.ContainsKey(emersonPsu.PsuId))
                                    {
                                        // Psu Clear faults did not succeed.
                                        failedPsu.Add(psu.Key, PsuAlertFaultStatus.BatteryFault);
                                    }
                                    Tracer.WriteError("PsuAlertRemediate failed to clear battery fault. PsuId: {0} Battery Error State: {1}",
                                                      psu.Key, PsuAlertFaultStatus.BatteryFault.ToString());
                                }
                            }
                        }
                        else if (psu.Value == PsuAlertFaultType.OnBattery && ConfigLoaded.NumBatteries > 0)
                        {
                            // Check if we need to trigger delegate to process battery status
                            if (ConfigLoaded.ProcessBatteryStatus)
                            {
                                double sumBatteryChargeLevel      = 0;
                                ChassisEnergyStorageStatus status = null;

                                // list to store battery charge levels
                                List <string> batteryStates = new List <string>();

                                // battery present or not, set to true if even one battery is present.
                                // default to false
                                bool isBatteryPresent = false;

                                // Calculate average battery charge level
                                for (int index = 1; index <= ConfigLoaded.NumBatteries; index++)
                                {
                                    status = ChassisState.GetEnergyStorageStatus((byte)index);

                                    // Add to the list battery charge levels
                                    batteryStates.Add(status.State.ToString());

                                    // If even one battery is present, set flag to true
                                    if (status.Present)
                                    {
                                        isBatteryPresent = true;
                                    }

                                    // If battery state is not unknown, add up the charge level.
                                    if (status.State != EnergyStorageState.Unknown)
                                    {
                                        sumBatteryChargeLevel += status.PercentCharge;
                                    }
                                }

                                double avgChargeLevel = (sumBatteryChargeLevel / ConfigLoaded.NumBatteries);

                                // Process battery status if battery discharge time is greater than the allowed discharge time
                                // from app.config( default 35 seconds) or Average battery charge level is below a given threshold value.
                                if (BatteryDischargeTimer.Elapsed > new System.TimeSpan(0, 0, ConfigLoaded.BatteryDischargeTimeInSecs) ||
                                    avgChargeLevel < ConfigLoaded.BatteryChargeLevelThreshold)
                                {
                                    // Invoke method to trigger NVDIMM backup for critical battery status
                                    ThreadPool.QueueUserWorkItem(new WaitCallback(ChassisManagerInternal.ProcessCriticalBatteryStatus));
                                }

                                // Calculate backup energy available per blade and per NVDIMM
                                double bladeEnergy = (ConfigLoaded.NumPsus * BATT_POUT_MAX * BATT_OP_TIME_100_LOAD * avgChargeLevel) /
                                                     ConfigLoaded.Population;
                                double nvdimmEnergy = (ConfigLoaded.NumPsus * BATT_POUT_EXTENDED * BATT_OP_TIME_75W_LOAD) /
                                                      (ConfigLoaded.Population * ConfigLoaded.NvDimmPerBlade);
                                // Scale the values
                                bladeEnergy  = bladeEnergy / ENERGY_STORAGE_SCALING_JOULES;
                                nvdimmEnergy = nvdimmEnergy / ENERGY_STORAGE_SCALING_JOULES;

                                // Send battery status to BMC, check returned completion code for success
                                Dictionary <byte, CompletionCode> results = WcsBladeFacade.BroadcastSetEnergyStorage
                                                                                (isBatteryPresent, GetBatteryStateToBroadcast(batteryStates), ENERGY_STORAGE_SCALING_JOULES, (ushort)bladeEnergy, (byte)nvdimmEnergy);

                                // Check if broadcast failed for any blade, if yes log error.
                                for (int index = 1; index <= ConfigLoaded.Population; index++)
                                {
                                    CompletionCode code;

                                    if (results.TryGetValue((byte)index, out code))
                                    {
                                        // If completion code returned is not success
                                        if (code != CompletionCode.Success)
                                        {
                                            Tracer.WriteError("PsuMonitor: ProcessBatteryStatus: " +
                                                              "Failed to update battery status to BMC for blade: " + index +
                                                              ", completion code returned: " + code);
                                        }
                                    }
                                    else
                                    {
                                        // If blade entry does not exist.
                                        Tracer.WriteError("PsuMonitor: ProcessBatteryStatus : " +
                                                          "Failed to update battery status to BMC for blade: " + index);
                                    }
                                }
                            }
                        }
                    }
                } // lock...
            }     // foreach...

            return(failedPsu);
        }