/// <summary> /// Validates the DES Keys /// </summary> // Revision History // MM/DD/YY Who Version ID Number Description // -------- --- ------- -- ------ ------------------------------------------- // 09/17/09 RCG 2.30.00 Created // 09/19/14 jrf 4.00.63 WR 534158 Modified way test details are set. private void ValidateDESKeys() { string Details = ""; string Reason = ""; bool Skipped = File.Exists(m_strProgramFile) == false || EDLFile.IsEDLFile(m_strProgramFile) == false; ProcedureResultCodes ValidationResult = ProcedureResultCodes.COMPLETED; if (IsAborted == false) { foreach (CENTRON_AMI.DESKeys KeyType in Enum.GetValues(typeof(CENTRON_AMI.DESKeys))) { if (Skipped == false) { ValidationResult = m_AmiDevice.ValidateDESKeys(m_strProgramFile, KeyType); Details = GetSecurityValidationDetails(ValidationResult); if (ProcedureResultCodes.INVALID_PARAM == ValidationResult) { Details += ", " + TestResources.KeyNotConsistentWithProgram; } } else { Reason = TestResources.ReasonProgramFileNeededToValidate; Details = TestResources.NoProgram; } AddTestDetail(KeyType.ToDescription(), GetResultString(Skipped, ProcedureResultCodes.COMPLETED == ValidationResult), Details, Reason); } } }
/// <summary> /// Configures the meter to use the specified base energies /// </summary> /// <param name="baseEnergies">The base energy values to use.</param> /// <returns>The result of the procedure call</returns> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ --------------------------------------- // 03/22/11 RCG 2.50.12 N/A Created public override ProcedureResultCodes ConfigureBaseEnergies(List <BaseEnergies> baseEnergies) { ProcedureResultCodes Result = ProcedureResultCodes.UNRECOGNIZED_PROC; byte[] ProcResponse = null; byte[] ProcParam = new byte[6]; // Validate the energies parameter if (baseEnergies == null) { throw new ArgumentNullException("baseEnergies"); } else if (baseEnergies.Count > ProcParam.Length) { throw new ArgumentException("Only " + ProcParam.Length.ToString(CultureInfo.InvariantCulture) + " energies may be configured", "baseEnergies"); } // Add the energy values for (int iIndex = 0; iIndex < baseEnergies.Count; iIndex++) { ProcParam[iIndex] = (byte)baseEnergies[iIndex]; } Result = ExecuteProcedure(Procedures.CONFIGURE_BASE_ENERGIES, ProcParam, out ProcResponse); // Give the meter a second to make sure that the base changes before we do anything else Thread.Sleep(1000); return(Result); }
/// <summary> /// Validates the enhanced security keys /// </summary> // Revision History // MM/DD/YY Who Version ID Number Description // -------- --- ------- -- ------ ------------------------------------------- // 09/17/09 RCG 2.30.00 Created // 09/19/14 jrf 4.00.63 WR 534158 Modified way test details are set. private void ValidateEnhancedSecurityKeys() { CXMLOpenWaySystemSettings SystemSettings = new CXMLOpenWaySystemSettings(""); bool Skipped = File.Exists(SystemSettings.EnhancedSecurityFilePath) == false; string Details = ""; string Reason = ""; ProcedureResultCodes ValidationResult = ProcedureResultCodes.COMPLETED; if (IsAborted == false) { foreach (CENTRON_AMI.EnhancedKeys KeyType in Enum.GetValues(typeof(CENTRON_AMI.EnhancedKeys))) { if (Skipped == false) { ValidationResult = m_AmiDevice.ValidateEnhancedSecurityKey(SystemSettings.EnhancedSecurityFilePath, KeyType); Details = GetSecurityValidationDetails(ValidationResult); if (ProcedureResultCodes.INVALID_PARAM == ValidationResult) { Details += ", " + TestResources.KeyNotConsistentWithSecurityFile; } } else { Reason = TestResources.ReasonProgramFileNeededToValidate; Details = TestResources.NoProgram; } AddTestDetail(KeyType.ToDescription(), GetResultString(Skipped, ProcedureResultCodes.COMPLETED == ValidationResult), Details, Reason); } } }
/// <summary> /// Queries the meter for the first 20 missing blocks for a firmware /// download pending table. /// </summary> /// <param name="eFWType">Firmware type (0 = Register, 1 = RFLAN, /// 2 = Zigbee)</param> /// <param name="iNumberOfBlocksReceived"></param> /// <param name="lstMissingBlocks"></param> /// <returns>Result code written to table 08 after the procedure is /// initiated</returns> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ --------------------------------------- // 02/05/10 jrf 2.40.12 N/A Created // public ProcedureResultCodes GetFirstTwentyMissingBlocks(FirmwareType eFWType, out int iNumberOfBlocksReceived, out List <int> lstMissingBlocks) { ProcedureResultCodes ProcResult = ProcedureResultCodes.INVALID_PARAM; byte[] ProcResponse; int iBlockNumber = 0; ProcResult = GetFirstTwentyMissingBlocks(eFWType, out ProcResponse); lstMissingBlocks = new List <int>(); iNumberOfBlocksReceived = 0; if (ProcedureResultCodes.COMPLETED == ProcResult) { iNumberOfBlocksReceived = ProcResponse[0] | (ProcResponse[1] << 8); for (int iIndex = 2; iIndex < 42; iIndex += 2) { iBlockNumber = ProcResponse[iIndex] | (ProcResponse[iIndex + 1] << 8); if (0 != iBlockNumber) { lstMissingBlocks.Add(iBlockNumber); } } } return(ProcResult); }
/// <summary> /// Calls standard procedure 2 - save configuration /// </summary> /// <returns>the result of the procedure call</returns> // Revision History // MM/DD/YY Who Version Issue# Description // -------- --- ------- ------ ------------------------------------------- // 03/18/13 AF 2.80.08 TR7578 Created // public ProcedureResultCodes SaveConfiguration() { ProcedureResultCodes ProcResult = ProcedureResultCodes.DEVICE_SETUP_CONFLICT; byte[] ProcResponse; byte[] ProcParam = new byte[0]; ProcResult = ExecuteProcedure(Procedures.SAVE_CONFIGURATION, ProcParam, out ProcResponse); return(ProcResult); }
/// <summary> /// Clears a specific pending table by the table id /// </summary> /// <param name="TableID">the pending table to be cleared</param> /// <returns>the result of the procedure call</returns> // Revision History // MM/DD/YY Who Version ID Number Description // -------- --- ------- -- ------ -------------------------------------------- // 12/06/17 AF 4.73.00 Task 469254 Created // public ProcedureResultCodes ClearPendingTableByTableID(UInt16 TableID) { ProcedureResultCodes ProcResult = ProcedureResultCodes.INVALID_PARAM; byte[] ProcResponse; byte[] ProcParam = new byte[2]; Array.Copy(BitConverter.GetBytes((UInt16)TableID), ProcParam, 2); ProcResult = ExecuteProcedure(Procedures.CLEAR_PENDING_TABLE_BY_ID, ProcParam, out ProcResponse); return(ProcResult); }
/// <summary> /// Activates the pending table with the specified Event Record /// </summary> /// <param name="pendingEvent">The Event Record for the event to activate</param> /// <returns>ProcedureResultCodes</returns> // Revision History // MM/DD/YY Who Version Issue# Description // -------- --- ------- ------ ------------------------------------------- // 05/07/07 RCG 8.10.07 Created public ProcedureResultCodes ActivatePendingTable(PendingEventRecord pendingEvent) { ProcedureResultCodes ProcResult = ProcedureResultCodes.INVALID_PARAM; byte[] ProcResponse; ProcResult = ExecuteProcedure(Procedures.ACTIVATE_PENDING_TABLE, pendingEvent.EntireRecord, out ProcResponse); return(ProcResult); }
/// <summary> /// Clears the pending table with the specified Event Record /// </summary> /// <param name="pendingEvent">The Event Record for the event to clear</param> /// <returns>ProcedureResultCodes</returns> // Revision History // MM/DD/YY Who Version Issue# Description // -------- --- ------- ------ ------------------------------------------- // 05/07/07 RCG 8.10.07 Created public ProcedureResultCodes ClearPendingTable(PendingEventRecord pendingEvent) { ProcedureResultCodes ProcResult = ProcedureResultCodes.INVALID_PARAM; byte[] ProcResponse; ProcResult = ExecuteProcedure(Procedures.CLEAR_SPECIFIC_PENDING_TABLE, pendingEvent.EntireRecord, out ProcResponse); return(ProcResult); }
/// <summary> /// Activates all pending tables in the meter. /// </summary> /// <returns>The result of the procedure.</returns> // Revision History // MM/DD/YY Who Version Issue# Description // -------- --- ------- ------ ------------------------------------------- // 11/05/08 RCG 2.00.03 122067 Created public ProcedureResultCodes ActivateAllPendingTables() { ProcedureResultCodes ProcResult = ProcedureResultCodes.INVALID_PARAM; byte[] ProcResponse; byte[] ProcParam = new byte[0]; ProcResult = ExecuteProcedure(Procedures.ACTIVATE_ALL_PENDING_TABLES, ProcParam, out ProcResponse); return(ProcResult); }
/// <summary> /// This method activates the firmware download's pending table. /// </summary> /// <param name="FWType">The type of firmware to activate.</param> /// <returns>The result of the activate pending table procedure.</returns> // Revision History // MM/DD/YY Who Version ID Number Description // -------- --- ------- -- ------ ------------------------------------------- // 07/09/13 jrf 2.80.51 TC 15063 Created. // 08/24/16 PGH 4.70.15 701952 Added HAN OTA Firmware // public ProcedureResultCodes ActivateFW(FirmwareType FWType) { ProcedureResultCodes ProcResult = ProcedureResultCodes.INVALID_PARAM; byte byEventNumber = REGISTER_EVENT_NUMBER; switch (FWType) { case FirmwareType.RegisterFW: case FirmwareType.M2GTWY: case FirmwareType.DisplayFW: { byEventNumber = REGISTER_EVENT_NUMBER; break; } case FirmwareType.ZigbeeFW: { byEventNumber = ZIGBEE_EVENT_NUMBER; break; } case FirmwareType.RFLANFW: case FirmwareType.PLANFW: case FirmwareType.CiscoCommFW: case FirmwareType.CiscoCfgFW: case FirmwareType.ChoiceConnectFW: case FirmwareType.ICSFW: { byEventNumber = COMM_EVENT_NUMBER; break; } case FirmwareType.HAN_OTA_FW: case FirmwareType.HANDevFW: { byEventNumber = HAN_DEV_EVENT_NUMBER; break; } default: { throw new ArgumentException("Invalid Parameter", "FWType"); } } // Activate the pending table ProcResult = ActivatePendingTable(false, false, byEventNumber, PendingEventRecord.PendingEventCode.NonTimeTrigger); return(ProcResult); }
/// <summary> /// Reconfigures SiteScan information /// </summary> /// <param name="serviceType">The new service type to use.</param> /// <param name="nominalVoltage">The new nominal voltage to use.</param> /// <returns>The result of the reconfigure</returns> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ --------------------------------------- // 04/29/09 RCG 2.20.03 N/A Created public SiteScanReconfigResult ReconfigureSiteScan(ServiceTypes serviceType, float nominalVoltage) { CloseConfigErrors Errors = CloseConfigErrors.None; ProcedureResultCodes ProcResult = ProcedureResultCodes.COMPLETED; PSEMResponse Response = PSEMResponse.Ok; SiteScanReconfigResult ReconfigResult = SiteScanReconfigResult.SUCCESS; // First make sure we have read the SiteScan config so we have the correct data. Response = SiteScanConfig.Read(); if (Response == PSEMResponse.Ok) { // Open the config so that we can write to it. ProcResult = OpenConfig(); if (ProcResult == ProcedureResultCodes.COMPLETED) { // Set the new values. SiteScanConfig.ServiceType = serviceType; SiteScanConfig.NominalVoltage = nominalVoltage; // Write the new values Response = SiteScanConfig.Write(); if (Response == PSEMResponse.Ok) { ProcResult = CloseConfig(CloseConfigOptions.SiteScan, out Errors); } } } if (ProcResult == ProcedureResultCodes.NO_AUTHORIZATION) { ReconfigResult = SiteScanReconfigResult.SECURITY_ERROR; } else if (ProcResult != ProcedureResultCodes.COMPLETED) { ReconfigResult = SiteScanReconfigResult.ERROR; } if (Response == PSEMResponse.Isc) { ReconfigResult = SiteScanReconfigResult.SECURITY_ERROR; } else if (Response != PSEMResponse.Ok) { ReconfigResult = SiteScanReconfigResult.PROTOCOL_ERROR; } return(ReconfigResult); }
/// <summary> /// This method resets the C12.22 stack. /// </summary> /// <returns>The result of the procedure.</returns> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ --------------------------------------- // 03/18/10 jrf 2.40.26 Created public ProcedureResultCodes ResetC1222Stack() { ProcedureResultCodes ProcResult = ProcedureResultCodes.INVALID_PARAM; byte[] ProcParam; byte[] ProcResponse; ProcParam = new byte[1]; ProcParam[0] = (byte)RFLANDebugProcedures.C1222_STACK_RESET; ProcResult = m_AMIDevice.ExecuteProcedure(Procedures.RFLAN_DEBUG_PROCEDURE, ProcParam, out ProcResponse); return(ProcResult); }
/// <summary> /// This method resets RFLAN MCU /// </summary> /// <returns>The result of the procedure.</returns> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ --------------------------------------- // 06/08/10 MMD 2.41.07 Created public ProcedureResultCodes ResetRFLANMCU() { ProcedureResultCodes ProcResult = ProcedureResultCodes.INVALID_PARAM; byte[] ProcParam; byte[] ProcResponse; ProcParam = new byte[1]; ProcParam[0] = (byte)RFLANProcedure.RESET_RFLAN_MCU; ProcResult = m_AMIDevice.ExecuteProcedure(Procedures.RFLAN_PROCEDURE, ProcParam, out ProcResponse); return(ProcResult); }
/// <summary> /// This method forces a NET registration. /// </summary> /// <returns>The result of the procedure.</returns> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ --------------------------------------- // 03/18/10 jrf 2.40.26 Created public ProcedureResultCodes ForceNetRegistration() { ProcedureResultCodes ProcResult = ProcedureResultCodes.INVALID_PARAM; byte[] ProcParam; byte[] ProcResponse; ProcParam = new byte[1]; ProcParam[0] = (byte)RFLANProcedure.FORCE_NET_REGISTER; ProcResult = m_AMIDevice.ExecuteProcedure(Procedures.RFLAN_PROCEDURE, ProcParam, out ProcResponse); return(ProcResult); }
/// <summary> /// Queries the meter for the first 20 missing blocks for a firmware /// download pending table. /// </summary> /// <param name="eFWType">Firmware type (0 = Register, 1 = RFLAN, /// 2 = Zigbee)</param> /// <param name="ProcResponse">byte array containing the response from /// the meter</param> /// <returns>Result code written to table 08 after the procedure is /// initiated</returns> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ --------------------------------------- // 10/02/06 AF 7.40.00 N/A Created // 10/04/06 AF 7.40.00 N/A Moved from CENTRON_AMI.cs // protected ProcedureResultCodes GetFirstTwentyMissingBlocks(FirmwareType eFWType, out byte[] ProcResponse) { ProcedureResultCodes ProcResult = ProcedureResultCodes.INVALID_PARAM; byte[] byParameters = new byte[1]; // The procedure takes 1 parameter byParameters[0] = (byte)eFWType; ProcResult = ExecuteProcedure(Procedures.GET_FIRST_20_MISSING_BLOCKS, byParameters, out ProcResponse); return(ProcResult); }
/// <summary> /// Clears a specific pending table by calling standard procedure 15 /// </summary> /// <param name="bSelfRead">Whether or not a self read should be performed /// before activation</param> /// <param name="bDemandReset">Whether or not a demand reset should be /// performed before activation</param> /// <param name="byMfgEventCode">Mfg assigned code identifying event for /// activating pending table</param> /// <param name="eCode">Event code for status bitfield. Use this field /// to identify the pending table</param> /// <returns>ProcedureResultCodes</returns> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ --------------------------------------- // 08/25/06 AF 7.35.00 N/A Created // 09/01/06 AF 7.35.00 Corrected code to copy stream to array // 10/04/06 AF 7.40.00 N/A Moved from CENTRON_AMI.cs // 06/08/07 RCG 8.10.07 Changed to call ClearPendingTable with PendingEventRecord protected ProcedureResultCodes ClearPendingTable(bool bSelfRead, bool bDemandReset, byte byMfgEventCode, PendingEventRecord.PendingEventCode eCode) { ProcedureResultCodes ProcResult = ProcedureResultCodes.INVALID_PARAM; PendingEventRecord EventRecord; // Build the event record EventRecord = BuildPendingEventRecord(bSelfRead, bDemandReset, byMfgEventCode, eCode); // Clear the pending table ProcResult = ClearPendingTable(EventRecord); return(ProcResult); }
/// <summary> /// Calls the procedures needed to populate the ICM event tables (2521 and 2524). Does not read the tables. /// </summary> /// <returns>The result of the procedure calls</returns> // Revision History // MM/DD/YY Who Version ID Issue# Description // -------- --- ------- -- ------ ------------------------------------------- // 03/14/14 AF 3.50.49 WR 464163 Created so that we can populate the event table without reading it // public ProcedureResultCodes SetUpForICMEvents() { ProcedureResultCodes Result = ProcedureResultCodes.UNRECOGNIZED_PROC; ICSCommModule ICSModule = CommModule as ICSCommModule; byte[] commandResponse; if (ICSModule != null) { if (ICSModule.FilterICSEvents() == ProcedureResultCodes.COMPLETED) { Result = ICSModule.UpdateEventTables(new DateTime(1970, 1, 1), DateTime.MaxValue, out commandResponse); } } return(Result); }
/// <summary> /// Translates a ProcedureResultCodes into a FWDownloadResult ///</summary> /// <param name="ProcResult">Table 08 results codes</param> /// <returns>FWDownloadResult</returns> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ --------------------------------------- // 11/15/13 AF 3.50.03 Class re-architecture - Cloned from CENTRON_AMI // 01/06/14 DLG 3.50.19 Class re-architecture - Moved from ICS_Gateway to // CommonFirmwareDownload. // private FWDownloadResult TranslateProcedureResult(ProcedureResultCodes ProcResult) { FWDownloadResult Result; switch (ProcResult) { case ProcedureResultCodes.COMPLETED: { Result = FWDownloadResult.SUCCESS; break; } case ProcedureResultCodes.INVALID_PARAM: { Result = FWDownloadResult.INVALID_CONFIG; break; } case ProcedureResultCodes.UNRECOGNIZED_PROC: { Result = FWDownloadResult.UNSUPPORTED_OPERATION; break; } case ProcedureResultCodes.TIMING_CONSTRAINT: { Result = FWDownloadResult.DEVICE_BUSY; break; } case ProcedureResultCodes.NO_AUTHORIZATION: { Result = FWDownloadResult.SECURITY_ERROR; break; } default: { Result = FWDownloadResult.WRITE_ERROR; break; } } return(Result); }
/// <summary> /// Displays the details for a security validation. /// </summary> /// <param name="ValidationResult">The result of the security validation.</param> /// <returns>Details from security validation.</returns> // Revision History // MM/DD/YY Who Version ID Number Description // -------- --- ------- -- ------ ------------------------------------------- // 09/23/14 jrf 4.00.63 WR 534158 Modified way test details are set. private string GetSecurityValidationDetails(ProcedureResultCodes ValidationResult) { string Details = ""; if (ProcedureResultCodes.COMPLETED == ValidationResult) { Details = TestResources.Valid; } else if (ProcedureResultCodes.INVALID_PARAM == ValidationResult) { Details = TestResources.Invalid; } else { Details = TestResources.ValidationFailed; } return(Details); }
/// <summary> /// This method sets the preferred cell ID for the RFLAN. The comm module /// will try for this cell for about 10 minutes before it will clear the cell /// ID out and try all cells. /// </summary> /// <param name="uiCellID">The preferred cell ID.</param> /// <returns>The result of the procedure.</returns> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ --------------------------------------- // 03/18/10 jrf 2.40.26 Created // 02/17/14 jrf 3.00.35 460349 Updated method. public ProcedureResultCodes SetPreferredCellID(UInt32 uiCellID) { ProcedureResultCodes ProcResult = ProcedureResultCodes.INVALID_PARAM; MemoryStream ProcParam = new MemoryStream(5); byte[] ProcResponse; uint uiParam2 = 0; uint uiParam3 = 0; BinaryWriter ParamWriter = new BinaryWriter(ProcParam); ParamWriter.Write((byte)RFLANDebugProcedures.SET_PREFERRED_CELL); ParamWriter.Write(uiCellID); ParamWriter.Write(uiParam2); ParamWriter.Write(uiParam3); ProcResult = m_AMIDevice.ExecuteProcedure(Procedures.RFLAN_DEBUG_PROCEDURE, ProcParam.ToArray(), out ProcResponse); return(ProcResult); }
/// <summary> /// Gets the current LED Quantity /// </summary> /// <returns>The currently pulsing quantity or null if the procedure fails.</returns> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ --------------------------------------- // 03/07/11 RCG 2.50.06 N/A Created public LEDQuantity GetCurrentPolyLEDQuantity() { LEDQuantity CurrentQuantity = null; ProcedureResultCodes Result = ProcedureResultCodes.UNRECOGNIZED_PROC; byte[] ProcResponse = null; byte[] ProcParam = new byte[] { 0x00, 0x00, 0x00, 0x80, 0x00, 0x00 }; MemoryStream ResponseStream = null; PSEMBinaryReader ResponseReader = null; Result = ExecuteProcedure(Procedures.POLY_LED_RECONFIGURE, ProcParam, out ProcResponse); if (Result == ProcedureResultCodes.COMPLETED && ProcResponse != null && ProcResponse.Length >= 4) { ResponseStream = new MemoryStream(ProcResponse); ResponseReader = new PSEMBinaryReader(ResponseStream); CurrentQuantity = new LEDQuantity(ResponseReader.ReadUInt32()); } return(CurrentQuantity); }
/// <summary> /// Validates the HAN keys /// </summary> // Revision History // MM/DD/YY Who Version ID Number Description // -------- --- ------- -- ------ ------------------------------------------- // 09/17/09 RCG 2.30.00 Created // 09/19/14 jrf 4.00.63 WR 534158 Modified way test details are set. // 05/23/17 CFB 4.72.00 WR 741323 Removed validation of HAN link key as it is no longer used in the meter private void ValidateHANKeys() { string NetworkKey = (string)CRegistryHelper.GetApplicationValue("GasPro", "Key"); string LinkKey = (string)CRegistryHelper.GetApplicationValue("GasPro", "GlobalLinkKey"); ProcedureResultCodes ValidationResult = ProcedureResultCodes.COMPLETED; string Details = ""; if (IsAborted == false) { //Network Key validation ValidationResult = m_AmiDevice.ValidateHANSecurityKeys(NetworkKey, CENTRON_AMI.HANKeys.NetworkKey); Details = GetSecurityValidationDetails(ValidationResult); if (ProcedureResultCodes.INVALID_PARAM == ValidationResult) { Details += ", " + TestResources.KeyNotConsistentWithRegistry; } AddTestDetail(TestResources.HANNetworkKey, GetResultString(ProcedureResultCodes.COMPLETED == ValidationResult), Details); } }
/// <summary> /// Clears the sitescan snapshots in the meter. This is not supported by /// the Vectron. /// </summary> /// <returns>A ItronDeviceResult</returns> // Revision History // MM/DD/YY Who Version Issue# Description // -------- --- ------- ------ --------------------------------------------- // 02/21/07 mrj 8.00.13 Created // ItronDeviceResult ISiteScan.ClearSiteScanSnapshots() { ItronDeviceResult Result = ItronDeviceResult.SUCCESS; ProcedureResultCodes ProcResult = ProcedureResultCodes.INVALID_PARAM; byte[] ProcParam; byte[] ProcResponse; ProcParam = new byte[0]; // No parameters for this procedure ProcResult = ExecuteProcedure(Procedures.CLEAR_SITESCAN_SNAPSHOTS, ProcParam, out ProcResponse); switch (ProcResult) { case ProcedureResultCodes.COMPLETED: { //Success Result = ItronDeviceResult.SUCCESS; break; } case ProcedureResultCodes.NO_AUTHORIZATION: { //Isc error Result = ItronDeviceResult.SECURITY_ERROR; break; } default: { //General Error Result = ItronDeviceResult.ERROR; break; } } return(Result); }
/// <summary> /// Implements the ISiteScan interface. Resets the diagnostic counters /// </summary> /// Revision History /// MM/DD/YY who Version Issue# Description /// -------- --- ------- ------ --------------------------------------- /// 05/24/06 mrj 7.30.00 N/A Created /// ItronDeviceResult ISiteScan.ResetDiagCounters() { ItronDeviceResult Result = ItronDeviceResult.ERROR; byte[] ProcResponse; ProcedureResultCodes ProcResult = ProcedureResultCodes.INVALID_PARAM; //Execute the reset conters MFG procedure byte[] byParameter = BitConverter.GetBytes((uint)Reset_Counter_Types.RESET_NUM_DIAG_COUNTERS); ProcResult = ExecuteProcedure(Procedures.RESET_COUNTERS, byParameter, out ProcResponse); switch (ProcResult) { case ProcedureResultCodes.COMPLETED: { //Success Result = ItronDeviceResult.SUCCESS; break; } case ProcedureResultCodes.NO_AUTHORIZATION: { //Isc error Result = ItronDeviceResult.SECURITY_ERROR; break; } default: { //General Error Result = ItronDeviceResult.ERROR; break; } } return(Result); }
/// <summary> /// Gets the current pulse weight /// </summary> /// <returns>The current pulse weight or null if the procedure fails</returns> // Revision History // MM/DD/YY Who Version ID Number Description // -------- --- ------- -- ------ -------------------------------------------- // 01/15/15 AF 4.00.92 WR 535491 Created // 03/25/15 AF 4.10.09 WR 573774 The scale factor for the response depends on the meter class // public float?GetCurrentPolyPulseWeight() { float?PulseWeight = null; ProcedureResultCodes Result = ProcedureResultCodes.UNRECOGNIZED_PROC; byte[] ProcResponse = null; byte[] ProcParam = new byte[] { 0x00, 0x00, 0x00, 0x80, 0x00, 0x00 }; MemoryStream ResponseStream = null; PSEMBinaryReader ResponseReader = null; Result = ExecuteProcedure(Procedures.POLY_LED_RECONFIGURE, ProcParam, out ProcResponse); if (Result == ProcedureResultCodes.COMPLETED && ProcResponse != null && ProcResponse.Length >= 6) { ResponseStream = new MemoryStream(ProcResponse); ResponseReader = new PSEMBinaryReader(ResponseStream); ResponseReader.ReadUInt32(); PulseWeight = (float)(ResponseReader.ReadUInt16()) / (float)DetermineEnergyDivisor(); // Scale factor depends on the meter class } return(PulseWeight); }
/// <summary> /// Reconfigures the LED Quantity on a Polyphase meter. /// </summary> /// <param name="quantity">The quantity to reconfigure.</param> /// <param name="pulseWeight">The pulse weight to use. Note: The pulse weight will be divided by 40 to get the actual value.</param> /// <returns>The result of the procedure call.</returns> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ --------------------------------------- // 03/07/11 RCG 2.50.06 N/A Created public ProcedureResultCodes ReconfigurePolyLEDQuantity(LEDQuantity quantity, ushort pulseWeight) { ProcedureResultCodes Result = ProcedureResultCodes.UNRECOGNIZED_PROC; byte[] ProcResponse = null; MemoryStream ParameterStream = new MemoryStream(new byte[6]); PSEMBinaryWriter ParameterWriter = new PSEMBinaryWriter(ParameterStream); ParameterWriter.Write(quantity.QuantityID); if (VersionChecker.CompareTo(FWRevision, VERSION_HYDROGEN_3_10) == 0) { // 3.10 builds had a bug in this procedure so we need to set this based on the Meter Class ParameterWriter.Write(CalculatePulseWeightValueForLEDReconfigureBug(pulseWeight)); } else { ParameterWriter.Write(pulseWeight); } Result = ExecuteProcedure(Procedures.POLY_LED_RECONFIGURE, ParameterStream.ToArray(), out ProcResponse); return(Result); }
/// <summary> /// Performs a manufacturer procedure 37 to tell the meter to get ready for /// firmware download /// </summary> /// <param name="strFilePath">path to the f/w file to download</param> /// <returns>ProcedureResultCodes</returns> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ --------------------------------------- // 11/15/13 AF 3.50.03 Class re-architecture - Cloned from CENTRON_AMI // 01/06/14 DLG 3.50.19 Class re-architecture - Moved from ICS_Gateway to // CommonFirmwareDownload. // 02/03/14 AF 3.50.30 TQ9508 We needed to reverse the order of the bytes in the device class // before adding it to the parameter list // 02/07/14 jrf 3.50.32 419257 Modified to use a dynamic FWDL block size based on the negotiated // PSEM packet size. // private FWDownloadResult EnterFirmwareDownloadMode(string strFilePath) { //Construct the parameters for mfg proc 37 and execute the procedure FileInfo fi = new FileInfo(strFilePath); byte[] bybuf = new byte[CANSIDevice.FW_HEADER_LENGTH]; byte[] byParameters = null; byte[] byImageSize = new byte[CANSIDevice.IMAGE_SIZE_FIELD_LEN]; byte[] byChunkSize = new byte[CANSIDevice.CHUNK_SIZE_FIELD_LEN]; byte[] ProcResponse; ProcedureResultCodes ProcResult = ProcedureResultCodes.INVALID_PARAM; FWDownloadResult FWResult = FWDownloadResult.UNKNOWN_DRIVER_ERROR; ICommModVersions CommModVers = m_ANSIDevice as ICommModVersions; try { m_Logger.WriteLine(Logger.LoggingLevel.Functional, "Initiating Firmware Download"); // Most of the procedure parameters are in the f/w file header FileStream fs = new FileStream(strFilePath, FileMode.Open, FileAccess.Read, FileShare.Read); fs.Read(bybuf, 0, CANSIDevice.FW_HEADER_LENGTH); fs.Close(); byParameters = new byte[CANSIDevice.INIT_FW_DOWNLOAD_THIRD_PARTY_LEN]; byParameters.Initialize(); // CRC LSB first byParameters[0] = bybuf[1]; byParameters[1] = bybuf[0]; // Retrieve the parameters out of the header Array.Copy(bybuf, 5, byParameters, 2, 9); // image size byImageSize = BitConverter.GetBytes((int)fi.Length); Array.Copy(byImageSize, 0, byParameters, 11, CANSIDevice.IMAGE_SIZE_FIELD_LEN); byChunkSize = BitConverter.GetBytes(m_ANSIDevice.FWDLBlockSize); Array.Copy(byChunkSize, 0, byParameters, 15, CANSIDevice.CHUNK_SIZE_FIELD_LEN); // Add the device class // The meter needs the Device Class in the reverse order that it is stored in the firmware file byParameters[17] = bybuf[17]; byParameters[18] = bybuf[16]; byParameters[19] = bybuf[15]; byParameters[20] = bybuf[14]; ProcResult = m_ANSIDevice.ExecuteProcedure(Procedures.INITIATE_FW_LOADER_SETUP, byParameters, out ProcResponse); if (ProcedureResultCodes.INVALID_PARAM == ProcResult) { // The Firmware load did not work. At some point during development they added // more detail in the Response, so we can read the byte and see what the error is switch (ProcResponse[0]) { case 1: FWResult = FWDownloadResult.FW_IMAGE_TOO_BIG; break; case 2: FWResult = FWDownloadResult.HW_REVISION_OUTSIDE_RANGE; break; case 3: FWResult = FWDownloadResult.HW_VERSION_OUTSIDE_RANGE; break; case 10: FWResult = FWDownloadResult.FW_TYPE_IS_INVALID; break; case 11: FWResult = FWDownloadResult.ZIGBEE_FW_TYPE_INVALID; break; default: FWResult = FWDownloadResult.INVALID_CONFIG; break; } } else { FWResult = TranslateProcedureResult(ProcResult); } } catch (PSEMException PSEMExp) { //TODO - This does not catch the error for same version when the device is an ITRU if (CommModVers != null) { if (PSEMResponse.Err == PSEMExp.PSEMResponse && (byte)FirmwareType.ICSFW == byParameters[6] && CommModVers.CommModuleVersion == byParameters[2] && CommModVers.CommModuleRevision == byParameters[3] && CommModVers.CommModuleBuild == byParameters[4]) { //This is how an attempt to download the same OW ICS comm module firmware //version will fail. FWResult = FWDownloadResult.ICS_SAME_VERSION_REJECTION; } } else { // Log it and pass it up m_Logger.WriteException(this, PSEMExp); throw (PSEMExp); } } catch (Exception e) { // Log it and pass it up m_Logger.WriteException(this, e); throw (e); } return(FWResult); }
public FWDownloadResult DownloadFW(string path, ref ushort usBlockIndex, bool blnRetry = false, bool blnActivate = true) { FWDownloadResult Result = FWDownloadResult.UNKNOWN_DRIVER_ERROR; ProcedureResultCodes ProcResult = ProcedureResultCodes.INVALID_PARAM; PSEMResponse ProtocolResponse = PSEMResponse.Ok; byte byEventNumber = 0; ushort idTable = (ushort)CANSIDevice.FWDLTableIds.CommModuleFWTbl | CANSIDevice.PENDING_BIT; ushort usNumberChunks = 0; //A non-zero starting block means we are need to pick up were we left off. bool blnResumeFWDL = (0 != usBlockIndex); System.IO.FileStream streamFile; System.IO.MemoryStream streamHeader = new System.IO.MemoryStream(); System.IO.MemoryStream streamPSEM = new System.IO.MemoryStream(); try { if (true == blnResumeFWDL) { Result = FWDownloadResult.SUCCESS; m_Logger.WriteLine(Logger.LoggingLevel.Functional, "Resuming Firmware Download @ Block " + usBlockIndex.ToString()); } else { // Tell the meter to enter firmware download mode Result = EnterFirmwareDownloadMode(path); } if (FWDownloadResult.SUCCESS != Result) { m_Logger.WriteLine(Logger.LoggingLevel.Detailed, "Initiate F/W Download procedure failed with result = " + Result); } else { // Meter is ready to receive the firmware file streamFile = new System.IO.FileStream(path, System.IO.FileMode.Open, FileAccess.Read); byte[] bybuffer = new byte[streamFile.Length]; streamFile.Read(bybuffer, 0, (int)streamFile.Length); streamFile.Position = 0; switch (bybuffer[9]) { case (byte)FirmwareType.ICSFW: { byEventNumber = CANSIDevice.COMM_EVENT_NUMBER; idTable = (ushort)CANSIDevice.FWDLTableIds.CommModuleFWTbl | CANSIDevice.PENDING_BIT; break; } default: { throw new NotImplementedException("Table not supported"); } } m_ANSIDevice.BuildPendingHeader(ref streamHeader, false, false, byEventNumber, PendingEventRecord.PendingEventCode.NonTimeTrigger); usNumberChunks = (ushort)(streamFile.Length / m_ANSIDevice.FWDLBlockSize); if (streamFile.Length != m_ANSIDevice.FWDLBlockSize * usNumberChunks) { usNumberChunks++; } m_ANSIDevice.OnShowProgress(new ShowProgressEventArgs(1, usNumberChunks + 1, "Firmware Download", "Downloading...")); ushort usSendSize = m_ANSIDevice.FWDLBlockSize; for (; (usBlockIndex < usNumberChunks) && (PSEMResponse.Ok == ProtocolResponse); usBlockIndex++) { // The last chunk could be smaller if (usNumberChunks - 1 == usBlockIndex) { usSendSize = (ushort)(streamFile.Length % m_ANSIDevice.FWDLBlockSize); // If no remainder then it is a full packet if (0 == usSendSize) { usSendSize = m_ANSIDevice.FWDLBlockSize; } } m_Logger.WriteLine(Logger.LoggingLevel.Functional, "Firmware Download - Sending Block " + usBlockIndex.ToString()); streamHeader.Position = 0; streamPSEM.Position = 0; streamPSEM.SetLength(0); streamHeader.WriteTo(streamPSEM); streamPSEM.Write(bybuffer, usBlockIndex * m_ANSIDevice.FWDLBlockSize, usSendSize); ProtocolResponse = m_PSEM.OffsetWrite((ushort)idTable, usBlockIndex * m_ANSIDevice.FWDLBlockSize, streamPSEM.ToArray()); m_ANSIDevice.OnStepProgress(new ProgressEventArgs()); } // Translate Protocol result Result = TranslateProtocolResult(ProtocolResponse); streamFile.Close(); //Check on success and then activate the table if (PSEMResponse.Ok == ProtocolResponse) { ProcResult = ProcedureResultCodes.COMPLETED; if (ProcResult == ProcedureResultCodes.COMPLETED) { if (true == blnActivate) { m_Logger.WriteLine(Logger.LoggingLevel.Functional, "Activating Firmware Download"); // Activate the pending table using mfg proc 69 ProcResult = m_ANSIDevice.ActivateFWDLTable(idTable, (byte)FirmwareType.ICSFW, bybuffer[5], bybuffer[6], bybuffer[7], bybuffer[8]); Result = TranslateProcedureResult(ProcResult); } } else { //TODO - not sure this is the correct error Result = FWDownloadResult.SECURITY_ERROR; } m_ANSIDevice.OnStepProgress(new ProgressEventArgs()); } else //PSEMResponse.Ok != ProtocolResponse { //Decrement the block index so we make sure we restart on the block that we failed on. usBlockIndex--; Result = FWDownloadResult.WRITE_ERROR; } m_ANSIDevice.OnHideProgress(new EventArgs()); } } catch (Exception e) { m_Logger.WriteException(this, e); if (false == blnRetry) { // Log it and pass it up m_ANSIDevice.OnHideProgress(new EventArgs()); throw e; } else { Result = FWDownloadResult.WRITE_ERROR; } } return(Result); }
/// <summary> /// Downloads the firmware file to the meter and activates it. /// The activation will cause the meter to drop the psem task so meter log off must /// follow this function call on success. This method supports resuming /// a previous failed FWDL. /// </summary> /// <param name="path">Complete file path of the firmware file</param> /// <param name="usBlockIndex">Dual purpose parameter. The passed in value indicates /// which block to begin downloading. The passed out parameter indicates which block to /// resume downloading in case there was a failure. This can then passed in again to /// restart the download at the point where it left off.</param> /// <param name="blnRetry">Whether or not to leave the FWDL in a state /// to permit subsequent retries at point of faliure. If false the pending table /// will be cleared on failure.</param> /// <param name="blnActivate">Whether or not to activate the firmware.</param> /// <returns>Itron.Metering.Device.FWDownloadResult</returns> // Revision History // MM/DD/YY who Version ID Number Description // -------- --- ------- -- ------ --------------------------------------- // 08/28/06 AF 7.35.00 N/A Created // 09/15/06 AF 7.35.00 N/A Added Catch for TimeOutException // 10/18/06 AF 7.40.00 N/A Removed wait within the main loop // 05/13/08 AF 1.50.24 Removed IFirmwareDownload from the method name // 04/19/10 AF 2.40.39 Added M2 Gateway support // 08/18/11 AF 2.52.05 Added support for authentication using a hash code // 08/26/11 AF 2.52.08 Added support for Cisco f/w // 09/22/11 AF 2.52.21 N/A Added support for Cisco config file f/w d/l - TODO remove when no longer needed // 10/12/11 AF 2.53.00 Changed the Cisco Comm fw enum name // 03/22/12 JJJ 2.60.xx Added support for ChoiceConnect FW // 05/10/12 JJJ 2.60.xx Tweaked FW Type passed to AuthenticateFWDL if ChoiceConnect, make RFLAN // 04/19/13 jrf 2.80.21 TQ 7639 Adding support for ICS comm module FWDL. // 07/08/13 jrf 2.80.51 TC 13201 Created to support retries of FWDL. // 07/15/13 jrf 2.80.?? TC 15062 Added parameter to control activation. // 08/22/13 jrf 2.85.26 WR 420902 Decrementing the block index on a failed block write, so // on a retry we will start back on the correct block. // 11/07/13 AF 3.50.02 TQ9508,9514 Have to activate the pending table using mfg proc 69 rather than std proc 13 // for I-210 and kV2c ICM firmware // 11/15/13 AF 3.50.03 Class re-architecture - removed code specific to ICS_Gateway // 12/02/13 jrf 3.50.10 Refactored code used to modify the FWType byte to it's own method. // 02/07/14 jrf 3.50.32 WR 419257 Modified to use a dynamic FWDL block size based on the negotiated // PSEM packet size. // 08/24/16 PGH 4.70.15 701952 Added HAN OTA Firmware // 02/06/17 AF 4.71.07 743128 Added supported for ICM modem firmware // 03/10/17 AF 4.71.09 749833 Renamed the firmware type because 37 is for Verizon LTE only // 12/05/17 AF 4.73.00 Task 469253 Added back the verizon modem fwdl // 12/06/17 AF 4.73.00 Task 469254 Added ATT/Rogers modem fwdl // public FWDownloadResult DownloadFW(string path, ref ushort usBlockIndex, bool blnRetry = false, bool blnActivate = true) { FWDownloadResult Result = FWDownloadResult.UNKNOWN_DRIVER_ERROR; ProcedureResultCodes ProcResult = ProcedureResultCodes.INVALID_PARAM; PSEMResponse ProtocolResponse = PSEMResponse.Ok; byte byEventNumber = 0; ushort idTable = (ushort)PendingTableIds.RegisterFWTbl | PENDING_BIT; ushort usNumberChunks = 0; //A non-zero starting block means we are need to pick up were we left off. bool blnResumeFWDL = (0 != usBlockIndex); System.IO.FileStream streamFile; System.IO.MemoryStream streamHeader = new System.IO.MemoryStream(); System.IO.MemoryStream streamPSEM = new System.IO.MemoryStream(); try { if (true == blnResumeFWDL) { Result = FWDownloadResult.SUCCESS; } else { // Tell the meter to enter firmware download mode Result = EnterFirmwareDownloadMode(path); } if (FWDownloadResult.SUCCESS != Result) { m_Logger.WriteLine(Logger.LoggingLevel.Detailed, "Initiate F/W Download procedure failed with result = " + Result); } else { // Meter is ready to receive the firmware file streamFile = new System.IO.FileStream(path, System.IO.FileMode.Open, FileAccess.Read); byte[] bybuffer = new byte[streamFile.Length]; streamFile.Read(bybuffer, 0, (int)streamFile.Length); streamFile.Position = 0; switch (bybuffer[9]) { case (byte)FirmwareType.RegisterFW: case (byte)FirmwareType.M2GTWY: case (byte)FirmwareType.DisplayFW: { byEventNumber = REGISTER_EVENT_NUMBER; idTable = (ushort)PendingTableIds.RegisterFWTbl | PENDING_BIT; break; } case (byte)FirmwareType.ZigbeeFW: { byEventNumber = ZIGBEE_EVENT_NUMBER; idTable = (ushort)PendingTableIds.HANModuleFWTbl | PENDING_BIT; break; } case (byte)FirmwareType.RFLANFW: case (byte)FirmwareType.PLANFW: case (byte)FirmwareType.CiscoCommFW: case (byte)FirmwareType.CiscoCfgFW: case (byte)FirmwareType.ChoiceConnectFW: case (byte)FirmwareType.ICSFW: case (byte)FirmwareType.ICS_MODEM_FW_Sierra_Verizon_LTE: case (byte)FirmwareType.ICS_MODEM_FW_Sierra_ATT_Rogers_Bell_LTE: { byEventNumber = COMM_EVENT_NUMBER; idTable = (ushort)PendingTableIds.CommModuleFWTbl | PENDING_BIT; break; } case (byte)FirmwareType.HAN_OTA_FW: case (byte)FirmwareType.HANDevFW: { byEventNumber = HAN_DEV_EVENT_NUMBER; idTable = (ushort)PendingTableIds.HANDeviceFWTbl | PENDING_BIT; break; } default: { throw new NotImplementedException("Table not supported"); } } BuildPendingHeader(ref streamHeader, false, false, byEventNumber, PendingEventRecord.PendingEventCode.NonTimeTrigger); usNumberChunks = (ushort)(streamFile.Length / FWDLBlockSize); if (streamFile.Length != FWDLBlockSize * usNumberChunks) { usNumberChunks++; } OnShowProgress(new ShowProgressEventArgs(1, usNumberChunks + 1, "Firmware Download", "Downloading...")); ushort usSendSize = FWDLBlockSize; for (; (usBlockIndex < usNumberChunks) && (PSEMResponse.Ok == ProtocolResponse); usBlockIndex++) { // The last chunk could be smaller if (usNumberChunks - 1 == usBlockIndex) { usSendSize = (ushort)(streamFile.Length % FWDLBlockSize); // If no remainder then it is a full packet if (0 == usSendSize) { usSendSize = FWDLBlockSize; } } streamHeader.Position = 0; streamPSEM.Position = 0; streamPSEM.SetLength(0); streamHeader.WriteTo(streamPSEM); streamPSEM.Write(bybuffer, usBlockIndex * FWDLBlockSize, usSendSize); ProtocolResponse = m_PSEM.OffsetWrite((ushort)idTable, usBlockIndex * FWDLBlockSize, streamPSEM.ToArray()); OnStepProgress(new ProgressEventArgs()); } // Translate Protocol result Result = TranslateProtocolResult(ProtocolResponse); streamFile.Close(); //Check on success and then activate the table if (PSEMResponse.Ok == ProtocolResponse) { if (FWDLLogSupported) { //Construct the hash code and call the procedure to authenticate CENTRON_AMI_FW_File FWFile = new CENTRON_AMI_FW_File(path); byte[] FWHashCode = FWFile.HashCode; if ((bybuffer[9] != (byte)FirmwareType.ICSFW) && (bybuffer[9] != (byte)FirmwareType.ICS_MODEM_FW_Sierra_Verizon_LTE)) { //Some devices may require this byte to be adjusted. bybuffer[9] = SelectFWTypeByte(bybuffer[9]); ProcResult = AuthenticateFWDL(idTable, bybuffer[9], FWHashCode); } else //Skip authenticate for ICS comm module and modem FWDL { ProcResult = ProcedureResultCodes.COMPLETED; } } else { ProcResult = ProcedureResultCodes.COMPLETED; } if (ProcResult == ProcedureResultCodes.COMPLETED) { if (true == blnActivate) { // Activate the pending table using std proc 13 ProcResult = ActivatePendingTable(false, false, byEventNumber, PendingEventRecord.PendingEventCode.NonTimeTrigger); Result = TranslateProcedureResult(ProcResult); } } else { if (false == blnRetry) { //We couldn't authenticate using the hash code so activation will fail ProcResult = ClearPendingTable(false, false, byEventNumber, PendingEventRecord.PendingEventCode.NonTimeTrigger); } //TODO - not sure this is the correct error Result = FWDownloadResult.SECURITY_ERROR; } OnStepProgress(new ProgressEventArgs()); } else //PSEMResponse.Ok != ProtocolResponse { //Decrement the block index so we make sure we restart on the block that we failed on. usBlockIndex--; if (false == blnRetry) { // Write failed, so clear the pending table ProcResult = ClearPendingTable(false, false, byEventNumber, PendingEventRecord.PendingEventCode.NonTimeTrigger); } Result = FWDownloadResult.WRITE_ERROR; } OnHideProgress(new EventArgs()); } } catch (Exception e) { if (false == blnRetry) { // Log it and pass it up OnHideProgress(new EventArgs()); m_Logger.WriteException(this, e); throw e; } else { Result = FWDownloadResult.WRITE_ERROR; } } return(Result); }
/// <summary> /// Downloads the firmware file to the device but does NOT /// activate. On download failure, the pending table is cleared. /// </summary> /// <param name="path">Complete path to the firmware file</param> /// <param name="eventCode">event code activation method</param> /// <returns>FWDownloadResult</returns> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ --------------------------------------- // 10/05/06 AF 7.35.00 N/A Created // 10/18/06 AF 7.40.00 N/A Removed wait within the main loop // 05/13/08 AF 1.50.24 Removed IFirmwareDownload from the method name // 04/19/10 AF 2.40.39 Added M2 Gateway support // 03/21/12 JJJ 2.60.xx Added support for ChoiceConnect FW // 08/17/12 AF 2.60.55 Added support for RF Mesh FW and RF Mesh Config // 02/07/14 jrf 3.50.32 419257 Modified to use a dynamic FWDL block size based on the negotiated // PSEM packet size. // 06/15/15 mah 4.50.140 577669 Added a retry if a busy response was received // 08/24/16 PGH 4.70.15 701952 Added HAN OTA Firmware public FWDownloadResult DownloadFWNoActivate(string path, PendingEventRecord.PendingEventCode eventCode) { FWDownloadResult Result = FWDownloadResult.UNKNOWN_DRIVER_ERROR; ProcedureResultCodes ProcResult = ProcedureResultCodes.INVALID_PARAM; PSEMResponse ProtocolResponse = PSEMResponse.Ok; byte byEventNumber = 0; ushort idTable = (ushort)PendingTableIds.RegisterFWTbl | PENDING_BIT; ushort usNumberChunks = 0; ushort intIndex; System.IO.FileStream streamFile; System.IO.MemoryStream streamHeader = new System.IO.MemoryStream(); System.IO.MemoryStream streamPSEM = new System.IO.MemoryStream(); try { Result = EnterFirmwareDownloadMode(path); if (FWDownloadResult.SUCCESS != Result) { m_Logger.WriteLine(Logger.LoggingLevel.Detailed, "Initiate F/W Download procedure failed with result = " + Result); } else { // Meter is ready to receive the firmware file streamFile = new System.IO.FileStream(path, System.IO.FileMode.Open, FileAccess.Read); byte[] bybuffer = new byte[streamFile.Length]; streamFile.Read(bybuffer, 0, (int)streamFile.Length); streamFile.Position = 0; switch (bybuffer[9]) { case (byte)FirmwareType.RegisterFW: case (byte)FirmwareType.M2GTWY: case (byte)FirmwareType.DisplayFW: { byEventNumber = REGISTER_EVENT_NUMBER; idTable = (ushort)PendingTableIds.RegisterFWTbl | PENDING_BIT; break; } case (byte)FirmwareType.ZigbeeFW: { byEventNumber = ZIGBEE_EVENT_NUMBER; idTable = (ushort)PendingTableIds.HANModuleFWTbl | PENDING_BIT; break; } case (byte)FirmwareType.RFLANFW: case (byte)FirmwareType.PLANFW: case (byte)FirmwareType.CiscoCommFW: case (byte)FirmwareType.CiscoCfgFW: case (byte)FirmwareType.ChoiceConnectFW: { byEventNumber = COMM_EVENT_NUMBER; idTable = (ushort)PendingTableIds.CommModuleFWTbl | PENDING_BIT; break; } case (byte)FirmwareType.HAN_OTA_FW: case (byte)FirmwareType.HANDevFW: { byEventNumber = HAN_DEV_EVENT_NUMBER; idTable = (ushort)PendingTableIds.HANDeviceFWTbl | PENDING_BIT; break; } default: { throw new NotImplementedException("Table not yet supported"); } } BuildPendingHeader(ref streamHeader, false, false, byEventNumber, eventCode); usNumberChunks = (ushort)(streamFile.Length / FWDLBlockSize); if (streamFile.Length != FWDLBlockSize * usNumberChunks) { usNumberChunks++; } OnShowProgress(new ShowProgressEventArgs(1, usNumberChunks + 1, "Firmware Download", "Downloading...")); ushort usSendSize = FWDLBlockSize; for (intIndex = 0; (intIndex < usNumberChunks) && (PSEMResponse.Ok == ProtocolResponse); intIndex++) { // The last chunk could be smaller if (usNumberChunks - 1 == intIndex) { usSendSize = (ushort)(streamFile.Length % FWDLBlockSize); // If no remainder then it is a full packet if (0 == usSendSize) { usSendSize = FWDLBlockSize; } } streamHeader.Position = 0; streamPSEM.Position = 0; streamPSEM.SetLength(0); streamHeader.WriteTo(streamPSEM); streamPSEM.Write(bybuffer, intIndex * FWDLBlockSize, usSendSize); ProtocolResponse = m_PSEM.OffsetWrite((ushort)idTable, intIndex * FWDLBlockSize, streamPSEM.ToArray()); // WR 577669 - The fwdl process is failing on ICS meters with a device busy status. The intent of the next // paragraph is to recognize that the meter may be off doing other operations when we first tried to download // a block. if (ProtocolResponse == PSEMResponse.Bsy) { // Wait for the device to complete it's current task, then retry to download the same block Thread.Sleep(1500); // 1.5 seconds is an arbitary value - the intent is to give the meter enough time to // complete it's work ProtocolResponse = m_PSEM.OffsetWrite((ushort)idTable, intIndex * FWDLBlockSize, streamPSEM.ToArray()); } OnStepProgress(new ProgressEventArgs()); } // Translate Protocol result Result = TranslateProtocolResult(ProtocolResponse); streamFile.Close(); // If any write failed, give up and clear the pending table if (PSEMResponse.Ok != ProtocolResponse) { // Write failed, so clear the pending table ProcResult = ClearPendingTable(false, false, byEventNumber, PendingEventRecord.PendingEventCode.NonTimeTrigger); Result = FWDownloadResult.WRITE_ERROR; } OnHideProgress(new EventArgs()); } } catch (Exception e) { // Log it and pass it up OnHideProgress(new EventArgs()); m_Logger.WriteException(this, e); throw e; } return(Result); }