/// <summary> /// Builds the pending table header /// </summary> /// <param name="strmPSEM">Stream to which the data is written</param> /// <param name="bSelfRead">tells whether or not to perform a self read /// before table is activated</param> /// <param name="bDemandReset">tells whether or not to perform a demand /// reset before table is activated</param> /// <param name="byMfgEventCode">Mfg assigned code identifying event for /// activating pending table</param> /// <param name="eCode">Event code for status bitfield. 2 => non-time activated</param> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ --------------------------------------- // 08/16/06 AF 7.35.00 N/A Created // 10/04/06 AF 7.40.00 N/A Moved from CENTRON_AMI.cs // 06/08/07 RCG 8.10.07 Changed to call BuildEventRecord protected void BuildPendingHeader(ref MemoryStream strmPSEM, bool bSelfRead, bool bDemandReset, byte byMfgEventCode, PendingEventRecord.PendingEventCode eCode) { PendingEventRecord EventRecord = new PendingEventRecord(); // Build the event record EventRecord = BuildPendingEventRecord(bSelfRead, bDemandReset, byMfgEventCode, eCode); // Write the event record to the stream strmPSEM.Write(EventRecord.EntireRecord, (int)strmPSEM.Position, EventRecord.EntireRecord.Length); }
/// <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> /// Builds a PendingEventRecord object for a Non Time Activated pending event /// with the specified parameters. /// </summary> /// <param name="bSelfRead">Whether or not a Self Read should be performed on activation.</param> /// <param name="bDemandReset">Whether or not a Demand Reset should be performed on activation.</param> /// <param name="byMfgEventCode">The manufacturer event code for the pending event.</param> /// <param name="eCode">The event code for the pending event.</param> /// <returns>The EventRecord object.</returns> // Revision History // MM/DD/YY Who Version Issue# Description // -------- --- ------- ------ ------------------------------------------- // 06/07/07 RCG 8.10.07 Created // 02/05/09 AF -.--.00 Changed the access modifier from protected to public // for automated firmware testing project public PendingEventRecord BuildPendingEventRecord(bool bSelfRead, bool bDemandReset, byte byMfgEventCode, PendingEventRecord.PendingEventCode eCode) { PendingEventRecord EventRecord = new PendingEventRecord(); ASCIIEncoding AE = new ASCIIEncoding(); byte[] abyManufacturer = new byte[5]; // Set up the event selector bitfield EventRecord.EventCode = eCode; EventRecord.PerformSelfRead = bSelfRead; EventRecord.PerformDemandReset = bDemandReset; // Copy the manufacturer ID to the device storage AE.GetBytes(MANUFACTURER).CopyTo(abyManufacturer, 0); // Copy the manufaturer event code abyManufacturer[abyManufacturer.Length - 1] = byMfgEventCode; EventRecord.EventStorage = abyManufacturer; return(EventRecord); }
/// <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 // -------- --- ------- ------ --------------------------------------- // 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/07/14 jrf 3.50.32 419257 Modified to use a dynamic FWDL block size based on the negotiated // PSEM packet size. // public FWDownloadResult DownloadFWNoActivate(string path, PendingEventRecord.PendingEventCode eventCode) { FWDownloadResult Result = FWDownloadResult.UNKNOWN_DRIVER_ERROR; PSEMResponse ProtocolResponse = PSEMResponse.Ok; byte byEventNumber = 0; ushort idTable = (ushort)CANSIDevice.FWDLTableIds.RegisterFWTbl | CANSIDevice.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.ICSFW: { byEventNumber = CANSIDevice.COMM_EVENT_NUMBER; idTable = (ushort)CANSIDevice.FWDLTableIds.CommModuleFWTbl | CANSIDevice.PENDING_BIT; break; } default: { throw new NotImplementedException("Table not yet supported"); } } m_ANSIDevice.BuildPendingHeader(ref streamHeader, false, false, byEventNumber, eventCode); 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 (intIndex = 0; (intIndex < usNumberChunks) && (PSEMResponse.Ok == ProtocolResponse); intIndex++) { // The last chunk could be smaller if (usNumberChunks - 1 == intIndex) { usSendSize = (ushort)(streamFile.Length % m_ANSIDevice.FWDLBlockSize); // If no remainder then it is a full packet if (0 == usSendSize) { usSendSize = m_ANSIDevice.FWDLBlockSize; } } streamHeader.Position = 0; streamPSEM.Position = 0; streamPSEM.SetLength(0); streamHeader.WriteTo(streamPSEM); streamPSEM.Write(bybuffer, intIndex * m_ANSIDevice.FWDLBlockSize, usSendSize); ProtocolResponse = m_PSEM.OffsetWrite((ushort)idTable, intIndex * m_ANSIDevice.FWDLBlockSize, streamPSEM.ToArray()); m_ANSIDevice.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) { Result = FWDownloadResult.WRITE_ERROR; } m_ANSIDevice.OnHideProgress(new EventArgs()); } } catch (Exception e) { // Log it and pass it up m_ANSIDevice.OnHideProgress(new EventArgs()); m_Logger.WriteException(this, e); throw e; } 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); }