/// <summary>
        /// Attempts to clear the Psu error status. This method
        /// calls down to the Chassis Manager with SendReceive
        /// </summary>
        private CompletionCode SetPsuClearFaults(byte psuId)
        {
            CompletionCode returnPacket = new CompletionCode();

            returnPacket = CompletionCode.UnspecifiedError;

            try
            {
                PsuChassisResponse myResponse = new PsuChassisResponse();
                myResponse = (PsuChassisResponse)this.SendReceive(this.PsuDeviceType, this.PsuId, new PsuRequest((byte)PmBusCommand.CLEAR_FAULTS, (byte)PmBusResponseLength.CLEAR_FAULTS), typeof(PsuChassisResponse));

                // check for completion code
                if (myResponse.CompletionCode != 0)
                {
                    returnPacket = (CompletionCode)myResponse.CompletionCode;
                }
                else
                {
                    returnPacket = CompletionCode.Success;
                }
            }
            catch (System.Exception ex)
            {
                returnPacket = CompletionCode.UnspecifiedError;
                Tracer.WriteError(this.PsuId, DeviceType.Psu, ex);
            }

            return(returnPacket);
        }
        /// <summary>
        /// Attempts to clear the Psu error status. This method
        /// calls down to the Chassis Manager with SendReceive
        /// </summary>
        private CompletionCode SetPsuClearFaults(byte psuId)
        {
            CompletionCode returnPacket = new CompletionCode();
            returnPacket = CompletionCode.UnspecifiedError;

            try
            {
                PsuChassisResponse myResponse = new PsuChassisResponse();
                myResponse = (PsuChassisResponse)this.SendReceive(this.PsuDeviceType, this.PsuId, new PsuRequest((byte)PmBusCommand.CLEAR_FAULTS, (byte)PmBusResponseLength.CLEAR_FAULTS), typeof(PsuChassisResponse));

                // check for completion code
                if (myResponse.CompletionCode != 0)
                {
                    returnPacket = (CompletionCode)myResponse.CompletionCode;
                }
                else
                {
                    returnPacket = CompletionCode.Success;
                }
            }
            catch (System.Exception ex)
            {
                returnPacket = CompletionCode.UnspecifiedError;
                Tracer.WriteError(this.PsuId, DeviceType.Psu, ex);
            }

            return returnPacket;
        }
        /// <summary>
        /// Enter Bootloader mode for in-system firmware upgrade. This method
        /// calls down to the Chassis Manager with SendReceive
        /// </summary>
        /// <param name="primaryImage">
        /// True:  Firmware image is for primary controller. 
        /// False: Firmware image is for secondary controller. 
        /// </param>
        /// <returns>Completion Code.</returns>
        private CompletionCode EnterFirmwareUpgradeMode(bool primaryImage)
        {
            CompletionCode returnPacket = new CompletionCode();
            returnPacket = CompletionCode.UnspecifiedError;

            // Determine password for entering programming mode
            byte[] cmdPayload = primaryImage ? priFwUpgradeModePassword : secFwUpgradeModePassword;

            try
            {
                Tracer.WriteInfo("EnterFirmwareUpgradeMode(): Sending command to PSU.");

                PsuChassisResponse myResponse = new PsuChassisResponse();
                myResponse = (PsuChassisResponse)this.SendReceive(this.PsuDeviceType, this.PsuId,
                    new EnterFirmwareUpgradeModeRequest(this.PsuId, cmdPayload, primaryImage), typeof(PsuChassisResponse));

                if (myResponse.CompletionCode != 0)
                {
                    returnPacket = (CompletionCode)myResponse.CompletionCode;
                    Tracer.WriteWarning("EnterFirmwareUpgradeMode Failure: Completion Code: {0}", returnPacket);
                }
                else
                {
                    returnPacket = CompletionCode.Success;
                }
            }
            catch (System.Exception ex)
            {
                returnPacket = CompletionCode.UnspecifiedError;
                Tracer.WriteError("EnterFirmwareUpgradeMode Exception: " + ex);
            }

            return returnPacket;
        }
        /// <summary>
        /// Exit Bootloader mode and restart firmware. This method
        /// calls down to the Chassis Manager with SendReceive
        /// </summary>
        /// <returns>Completion Code.</returns>
        private CompletionCode ExitFirmwareUpgradeMode()
        {
            CompletionCode returnPacket = new CompletionCode();
            returnPacket = CompletionCode.UnspecifiedError;

            // Password for exiting programming mode (same for primary and secondary controllers)
            byte[] cmdPayload = secFwUpgradeModePassword;

            try
            {
                Tracer.WriteInfo("ExitFirmwareUpgradeMode(): Sending command to PSU.");

                PsuChassisResponse myResponse = new PsuChassisResponse();
                myResponse = (PsuChassisResponse)this.SendReceive(this.PsuDeviceType, this.PsuId,
                    new ExitFirmwareUpgradeModeRequest(this.PsuId, cmdPayload), typeof(PsuChassisResponse));

                if (myResponse.CompletionCode != 0)
                {
                    returnPacket = (CompletionCode)myResponse.CompletionCode;
                    Tracer.WriteWarning("ExitFirmwareUpgradeMode Failure: Completion Code: {0}", returnPacket);
                }
                else
                {
                    returnPacket = CompletionCode.Success;
                }
            }
            catch (System.Exception ex)
            {
                returnPacket = CompletionCode.UnspecifiedError;
                Tracer.WriteError("ExitFirmwareUpgradeMode Exception: " + ex);
            }

            return returnPacket;
        }
        /// <summary>
        /// Write data to program memory. This method
        /// calls down to the Chassis Manager with SendReceive
        /// </summary>
        /// <param name="data">The data.
        /// For firmware image data (isDataRomPage == false), the payload format is as follows (offset, length):
        /// - Address offset: (0, 2) - offset to write the data
        /// - Data: (2, 8)        
        /// 
        /// For ROM page data (isDataRomPage == true), the payload format is as follows (offset, length):
        /// - Address bytes: (0, 2)
        /// - Page bytes: (2, 2)        
        /// 
        /// </param>
        /// <param name="isDataRomPage">
        /// True: data[] contains the ROM page data
        /// False: data[] contains FW image data
        /// </param>
        /// <returns>Completion Code.</returns>
        private CompletionCode WriteProgramMemory(byte[] data, bool isDataRomPage)
        {
            CompletionCode returnPacket = new CompletionCode();
            returnPacket = CompletionCode.UnspecifiedError;

            try
            {
                PsuChassisResponse myResponse = new PsuChassisResponse();

                if (isDataRomPage)
                {
                    // Write ROM Page
                    myResponse = (PsuChassisResponse)this.SendReceive(this.PsuDeviceType, this.PsuId,
                        new PsuWriteProgramMemoryRomPageRequest(this.PsuId, data), typeof(PsuChassisResponse));
                }
                else
                {
                    // Write FW image data
                    myResponse = (PsuChassisResponse)this.SendReceive(this.PsuDeviceType, this.PsuId,
                        new PsuWriteProgramMemoryFwRequest(this.PsuId, data), typeof(PsuChassisResponse));
                }

                if (myResponse.CompletionCode != 0)
                {
                    returnPacket = (CompletionCode)myResponse.CompletionCode;
                    Tracer.WriteWarning("WriteProgramMemory Failure: Completion Code: {0}", returnPacket);
                }
                else
                {
                    returnPacket = CompletionCode.Success;
                }
            }
            catch (System.Exception ex)
            {
                returnPacket = CompletionCode.UnspecifiedError;
                Tracer.WriteError("WriteProgramMemory Exception: " + ex);
            }

            return returnPacket;
        }
        /// <summary>
        /// Update ROM Page Address for reading program memory. This method
        /// calls down to the Chassis Manager with SendReceive
        /// </summary>
        /// <param name="romPage">The ROM page.</param>
        /// <returns>Completion Code.</returns>
        private CompletionCode SendRomPage(byte romPage)
        {
            CompletionCode returnPacket = new CompletionCode();
            returnPacket = CompletionCode.UnspecifiedError;

            try
            {
                PsuChassisResponse myResponse = new PsuChassisResponse();
                myResponse = (PsuChassisResponse)this.SendReceive(this.PsuDeviceType, this.PsuId,
                    new PsuSendRomPageRequest(this.PsuId, romPage), typeof(PsuChassisResponse));

                if (myResponse.CompletionCode != 0)
                {
                    returnPacket = (CompletionCode)myResponse.CompletionCode;
                    Tracer.WriteWarning("SendRomPage Failure: Completion Code: {0}", returnPacket);
                }
                else
                {
                    returnPacket = CompletionCode.Success;
                }
            }
            catch (System.Exception ex)
            {
                returnPacket = CompletionCode.UnspecifiedError;
                Tracer.WriteError("SendRomPage Exception: " + ex);
            }

            return returnPacket;
        }
        /// <summary>
        /// Send Model_ID to PSU for verification
        /// </summary>
        /// <param name="modelId">The 8-byte PSU model Id extracted from the FW image file.
        /// This ensures target HEX file matches the PSU primary/secondary controller.
        /// </param>
        /// <returns>Completion Code.</returns>
        private CompletionCode SendModelId(byte[] modelId)
        {
            CompletionCode returnPacket = new CompletionCode();
            returnPacket = CompletionCode.UnspecifiedError;

            try
            {
                Tracer.WriteInfo("SendModelId(): Sending command to PSU.");

                PsuChassisResponse myResponse = new PsuChassisResponse();
                myResponse = (PsuChassisResponse)this.SendReceive(this.PsuDeviceType, this.PsuId,
                    new PsuSendModelIdRequest(this.PsuId, modelId), typeof(PsuChassisResponse));

                if (myResponse.CompletionCode != 0)
                {
                    returnPacket = (CompletionCode)myResponse.CompletionCode;
                    Tracer.WriteWarning("SendModelId Failure: Completion Code: {0}", returnPacket);
                }
                else
                {
                    returnPacket = CompletionCode.Success;
                }
            }
            catch (System.Exception ex)
            {
                returnPacket = CompletionCode.UnspecifiedError;
                Tracer.WriteError("SendModelId Exception: " + ex);
            }

            return returnPacket;
        }
        /// <summary>
        /// Read program memory. This method
        /// calls down to the Chassis Manager with SendReceive
        /// </summary>
        /// <param name="address">The address to read</param>
        /// <param name="packetWaitTimeMs">Wait time in ms between each I2C transaction</param>
        /// <returns></returns>
        private ReadProgramMemoryPacket ReadProgramMemory(short address, int packetWaitTimeMs)
        {
            // Initialize return packet
            ReadProgramMemoryPacket returnPacket = new ReadProgramMemoryPacket();
            returnPacket.CompletionCode = CompletionCode.UnspecifiedError;

            // Extract address to read
            byte[] cmdPayload = new byte[2] { (byte)((address & 0xFF00) >> 8), (byte)(address & 0xFF) };

            try
            {
                PsuChassisResponse psuChassisResponse = new PsuChassisResponse();
                ReadProgramMemoryResponse response = new ReadProgramMemoryResponse();

                // First send address to read
                psuChassisResponse = (PsuChassisResponse)this.SendReceive(this.PsuDeviceType, this.PsuId,
                    new PsuReadProgramMemoryTargetAddressRequest(this.PsuId, cmdPayload), typeof(PsuChassisResponse));

                // If address was written successfully, read memory data
                if (psuChassisResponse.CompletionCode == 0)
                {
                    // Wait for PSU I2C Packet Handling Time
                    Thread.Sleep(packetWaitTimeMs);
                    response = (ReadProgramMemoryResponse)this.SendReceive(this.PsuDeviceType, this.PsuId,
                        new PsuRequest((byte)PmBusCommand.READ_MEMORY, (byte)PmBusResponseLength.READ_MEMORY), typeof(ReadProgramMemoryResponse));
                }

                if (response.CompletionCode == 0)
                {
                    returnPacket.CompletionCode = CompletionCode.Success;
                    returnPacket.Data = new byte[response.Data.Length];
                    Buffer.BlockCopy(response.Data, 0, returnPacket.Data, 0, response.Data.Length);
                }
                else
                {
                    returnPacket.CompletionCode = (CompletionCode)response.CompletionCode;
                    Tracer.WriteWarning("ReadProgramMemory Failure: Completion Code: {0}", returnPacket.CompletionCode);
                }
            }
            catch (System.Exception ex)
            {
                returnPacket.CompletionCode = CompletionCode.UnspecifiedError;
                Tracer.WriteError("ReadProgramMemory Exception: " + ex);
            }

            return returnPacket;
        }
        /// <summary>
        /// Set the Battery Extended Operation Mode. 
        /// </summary>
        private CompletionCode SetBatteryExtendedOperationMode(byte psuId, bool toEnable)
        {
            CompletionCode returnPacket = new CompletionCode();
            returnPacket = CompletionCode.UnspecifiedError;

            // Command payload to set battery extended operation mode
            byte cmdPayload = ((toEnable) ? enableBatteryExtendedOperation: disableBatteryExtendedOperation);

            try
            {
                PsuChassisResponse myResponse = new PsuChassisResponse();
                myResponse = (PsuChassisResponse)this.SendReceive(this.PsuDeviceType, this.PsuId,
                    new PsuBytePayloadRequest((byte)PmBusCommand.EXTENDED_BATTERY, (byte)cmdPayload, (byte)0), typeof(PsuChassisResponse));

                if (myResponse.CompletionCode != 0)
                {
                    returnPacket = (CompletionCode)myResponse.CompletionCode;
                    Tracer.WriteWarning("SetBatteryExtendedOperationMode({0}) failed with CompletionCode ({1})", this.PsuId, returnPacket);
                }
                else
                {
                    returnPacket = CompletionCode.Success;
                }
            }
            catch (System.Exception ex)
            {
                returnPacket = CompletionCode.UnspecifiedError;
                Tracer.WriteError("SetBatteryExtendedOperationMode Exception: " + ex);
            }
            return returnPacket;
        }