/// <summary> /// Reads the specified table from the meter. /// </summary> /// <param name="usTableID">The table ID for the table to read.</param> /// <param name="MeterTables">The tables object to read the table into.</param> /// <returns>PSEMResponse code.</returns> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ --------------------------------------- // 10/19/06 RCG 7.40.00 Created // 01/11/07 RCG 8.00.05 Removed code that would do a full read since // the meter no longer supports full reads of 64 protected PSEMResponse ReadTable(ushort usTableID, ref CentronTables MeterTables) { MemoryStream PSEMDataStream; PSEMResponse PSEMResult = PSEMResponse.Ok; byte[] byaData; int iReadAttempt = 0; bool bRetry = true; while (bRetry) { switch (usTableID) { case 64: { if (PSEMResult == PSEMResponse.Ok) { PSEMResult = ReadTable64(ref MeterTables); } break; } case 2152: { if (PSEMResult == PSEMResponse.Ok) { PSEMResult = ReadTable2152(ref MeterTables); } break; } default: { if (0x0800 == usTableID) { PSEMResult = PSEMResponse.Ok; } PSEMResult = m_PSEM.FullRead(usTableID, out byaData); if (PSEMResult == PSEMResponse.Ok) { PSEMDataStream = new MemoryStream(byaData); MeterTables.SavePSEMStream(usTableID, PSEMDataStream); } break; } } iReadAttempt++; if (iReadAttempt < 3 && (PSEMResult == PSEMResponse.Bsy || PSEMResult == PSEMResponse.Dnr)) { bRetry = true; System.Threading.Thread.Sleep(1000); } else { bRetry = false; } } return(PSEMResult); }
/// <summary> /// Reads Table 2152 /// </summary> /// <param name="MeterTables">The tables for the meter.</param> /// <returns>The PSEM response for communications.</returns> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ ------------------------------------------- // 05/15/08 RCG 1.50.24 N/A Created protected PSEMResponse ReadTable2152(ref CentronTables MeterTables) { PSEMResponse PSEMResult = PSEMResponse.Ok; MemoryStream PSEMDataStream; byte[] byaData; CentronTables TempTables = new CentronTables(); uint uiMaxOffsetReadBytes; uint uiReadMemorySize; uint uiNumberOfReads; uint uiBytesToRead; uint uiCurrentOffset; uint uiBlockOffset; uint uiBlockLength; uint uiMaxBlocksToRead; uint uiMaxBytesToRead; ushort usValidBlocks; ushort usNumberIntervals; ushort usNewValidBlocks; ushort usNewNumberIntervals; ushort usNewLastBlock; int iBlockToRead; // This must be initialized to false or you will break the retry logic. bool bBlocksReRead = false; object objData; // Since Voltage Monitoring Data can be very large (144k) it may not be able // to be read completely when doing a full read so we need to break // it up into multiple offset reads. Table 2149 must be read prior to this. if (MeterTables.IsCached((long)CentronTblEnum.MFGTBL101_MEMORY_LEN, null) == true) { uiMaxOffsetReadBytes = (m_PSEM.PacketSize - PACKET_OVERHEAD_SIZE) * PACKETS_PER_READ; // Because offset reads can be only up to ushort.MaxValue, limit to that if needed. if (uiMaxOffsetReadBytes > ushort.MaxValue) { uiMaxOffsetReadBytes = ushort.MaxValue; } MeterTables.GetValue(CentronTblEnum.MFGTBL103_NBR_VALID_BLOCKS, null, out objData); usValidBlocks = (ushort)objData; MeterTables.GetValue(CentronTblEnum.MFGTBL103_NBR_VALID_INT, null, out objData); usNumberIntervals = (ushort)objData; // Determine the size of a Voltage monitoring data block MeterTables.GetFieldOffset((long)CentronTblEnum.MFGTBL104_VM_DATA, new int[] { 0 }, out uiBlockOffset, out uiBlockLength); // Determine how many blocks can be read in an offset read uiMaxBlocksToRead = uiMaxOffsetReadBytes / uiBlockLength; uiMaxBytesToRead = uiMaxBlocksToRead * uiBlockLength; // Determine total amount to read uiReadMemorySize = usValidBlocks * uiBlockLength; // Determine how many reads need to be done uiNumberOfReads = usValidBlocks / uiMaxBlocksToRead; // Add in a read for any remaining data if (usValidBlocks % uiMaxBlocksToRead > 0) { uiNumberOfReads++; } uiCurrentOffset = 0; for (uint iIndex = 0; iIndex < uiNumberOfReads && PSEMResult == PSEMResponse.Ok; iIndex++) { uiBytesToRead = uiReadMemorySize - uiCurrentOffset; if (uiBytesToRead > uiMaxBytesToRead) { uiBytesToRead = uiMaxBytesToRead; } PSEMResult = m_PSEM.OffsetRead(2152, (int)uiCurrentOffset, (ushort)uiBytesToRead, out byaData); if (PSEMResult == PSEMResponse.Ok) { PSEMDataStream = new MemoryStream(byaData); MeterTables.SavePSEMStream(2152, PSEMDataStream, uiCurrentOffset); uiCurrentOffset += uiBytesToRead; } OnStepProgress(new ProgressEventArgs()); } // Reread table 63 and make sure no new intervals have occurred while reading CentronTables.CopyTable(0, MeterTables, TempTables); CentronTables.CopyTable(1, MeterTables, TempTables); CentronTables.CopyTable(2148, MeterTables, TempTables); CentronTables.CopyTable(2149, MeterTables, TempTables); CentronTables.CopyTable(2150, MeterTables, TempTables); do { ReadTable(2151, ref TempTables); TempTables.GetValue(CentronTblEnum.MFGTBL103_NBR_VALID_BLOCKS, null, out objData); usNewValidBlocks = (ushort)objData; TempTables.GetValue(CentronTblEnum.MFGTBL103_NBR_VALID_INT, null, out objData); usNewNumberIntervals = (ushort)objData; if (usNewNumberIntervals != usNumberIntervals || usNewValidBlocks != usValidBlocks) { // This will limit us to only two tries at this. (if it is already true it will be set // to false which means we won't try this again.) bBlocksReRead = !bBlocksReRead; // A new interval has occurred so we need to reread atleast one block CentronTables.CopyTable(2151, TempTables, MeterTables); MeterTables.GetValue(CentronTblEnum.MFGTBL103_LAST_BLOCK_ELEMENT, null, out objData); usNewLastBlock = (ushort)objData; // Determine the offset of the block iBlockToRead = (int)usNewLastBlock; MeterTables.GetFieldOffset((long)CentronTblEnum.MFGTBL104_VM_DATA, new int[] { iBlockToRead }, out uiBlockOffset, out uiBlockLength); PSEMResult = m_PSEM.OffsetRead(2152, (int)uiBlockOffset, (ushort)uiBlockLength, out byaData); if (PSEMResult == PSEMResponse.Ok) { PSEMDataStream = new MemoryStream(byaData); MeterTables.SavePSEMStream(2152, PSEMDataStream, uiBlockOffset); // Now if there was also a new block we need to reread the previous block as well. if (usNewValidBlocks != usValidBlocks) { if (usNewLastBlock - 1 < 0) { iBlockToRead = usNewValidBlocks - 1; } else { iBlockToRead = usNewLastBlock - 1; } // Determine the offset of the block MeterTables.GetFieldOffset((long)CentronTblEnum.MFGTBL104_VM_DATA, new int[] { iBlockToRead }, out uiBlockOffset, out uiBlockLength); PSEMResult = m_PSEM.OffsetRead(2152, (int)uiBlockOffset, (ushort)uiBlockLength, out byaData); if (PSEMResult == PSEMResponse.Ok) { PSEMDataStream = new MemoryStream(byaData); MeterTables.SavePSEMStream(2152, PSEMDataStream, uiBlockOffset); } } } // Make sure that we save the new data to the old. usValidBlocks = usNewValidBlocks; usNumberIntervals = usNewNumberIntervals; } else // No new interval occurred { bBlocksReRead = false; } } while (bBlocksReRead == true); } else { throw new Exception("Table 2149 must be read prior to Table 2152."); } return(PSEMResult); }
/// <summary> /// Gets the device information from the meter. /// </summary> // Revision History // MM/DD/YY Who Version ID Number Description // -------- --- ------- -- ------ ------------------------------------------- // 08/28/09 RCG 2.30.00 Created // 09/19/14 jrf 4.00.63 WR 534158 Modified to use the CANSIDevice.CreateDevice() // method to instantiate the correct device and switched // to store the name of the meter instead of device class. // 10/31/14 jrf 4.00.82 WR 542694 Added support for identifying Bridge meter with signed authorizaion. private TestRun GetDeviceInfo() { CXMLOpenWaySystemSettings SystemSettings = new CXMLOpenWaySystemSettings(""); CPSEM PSEM = new CPSEM(m_Comm); PSEMResponse Response = PSEMResponse.Ok; string strModel = null; TestRun NewTestRun = new TestRun(); string MeterType = ""; Response = PSEM.Identify(); if (Response == PSEMResponse.Ok) { Response = PSEM.Negotiate(CPSEM.DEFAULT_MAX_PACKET_LEGNTH, CPSEM.DEFAULT_MAX_NUMBER_OF_PACKETS, m_uiBaudRate); } if (Response == PSEMResponse.Ok) { Response = PSEM.Logon("", CPSEM.DEFAULT_HH_PRO_USER_ID); } if (Response == PSEMResponse.Ok) { CTable00 Table0 = new CTable00(PSEM); CTable01 Table1 = new CTable01(PSEM, Table0.StdVersion); strModel = Table1.Model; if (strModel == AMI_CENT) { CANSIDevice ANSIDevice = CANSIDevice.CreateDevice(m_Comm, PSEM, Settings.Default.AuthenticationKey); CENTRON_AMI AMIDevice = ANSIDevice as CENTRON_AMI; if (null != AMIDevice) { if (SystemSettings.UseSignedAuthorization && AMIDevice.SignedAuthorizationState != null && AMIDevice.SignedAuthorizationState.Value != FeatureState.Disabled && Settings.Default.AuthenticationKey != null) { // Use Signed Authenticaiton AMIDevice.Authenticate(Settings.Default.AuthenticationKey); } else { // Use standard security AMIDevice.Security(GetPasswords()); } MeterType = AMIDevice.MeterName; if (AMIDevice.CommModule != null) { m_strMeterID = AMIDevice.CommModule.ElectronicSerialNumber; } } } } try { PSEM.Logoff(); PSEM.Terminate(); } catch (Exception) { // Make sure we log off. } // Handle any errors that may have occurred if (Response != PSEMResponse.Ok) { throw new PSEMException(PSEMException.PSEMCommands.PSEM_READ, Response, Resources.ErrorRetrievingDeviceIdentification); } else if (strModel != AMI_CENT) { throw new InvalidOperationException(Resources.MeterTypeNotSupported); } // Set up the TestRun results NewTestRun.MeterType = MeterType; NewTestRun.MeterID = m_strMeterID; NewTestRun.TestDate = DateTime.Now; NewTestRun.ProgramName = m_strProgramFile; NewTestRun.SWVersion = Application.ProductVersion; return(NewTestRun); }
/// <summary> /// Runs the test. /// </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 Using new method to set test result string. // 10/02/14 jrf 4.00.66 WR 431248 Making sure if logon is called and exception occurs then a logoff is // attempted so other tests may continue if possible. // 10/13/14 jrf 4.00.72 WR 537980 Skipping test on sealed canadian meter. public override Test RunTest() { CXMLOpenWayUserAccessPolicy UserAccess = new CXMLOpenWayUserAccessPolicy(); bool bIsUserAllowed = UserAccess.CheckUserAccess(CXMLOpenWayUserAccessPolicy.FunctionalCapability.ResetActivityStatus); PSEMResponse Response = PSEMResponse.Ok; m_TestResults = new Test(); m_TestResults.Name = TestName; m_bTestPassed = true; try { Response = LogonToDevice(); if (true == m_AmiDevice.IsSealedCanadian) { m_bTestSkipped = true; m_TestResults.Reason = TestResources.ReasonActivityStatusSealedCanadian; } else if (false == bIsUserAllowed) { m_bTestSkipped = true; m_TestResults.Reason = TestResources.ReasonActivityStatusPermissions; } else if (Response == PSEMResponse.Ok) { ClearDemandResetCount(); ClearOutageCount(); ClearProgrammedCount(); ClearInversionTampers(); ClearRemovalTampers(); ClearSiteScanDiagCounts(); ClearEventLogs(); Thread.Sleep(1000); ShowCounters(); } else { m_TestResults.Reason = TestResources.ReasonLogonFailed; m_bTestPassed = false; } } catch (Exception e) { throw (e); } finally { if (m_AmiDevice != null) { m_AmiDevice.Logoff(); } } // Set the final result. m_TestResults.Result = GetTestResultString(m_bTestSkipped, m_bTestPassed); return(m_TestResults); }
/// <summary> /// Reads the table from the meter. /// </summary> /// <returns>The result of the read request.</returns> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ ------------------------------------------- // 06/17/09 MMD N/A Created public override PSEMResponse Read() { m_Logger.WriteLine(Logger.LoggingLevel.Detailed, "OpenWayMFGTable2170.Read"); PSEMResponse Result = base.Read(); //Populate the member variables that represent the table if (PSEMResponse.Ok == Result) { m_DataStream.Position = 0; try { m_usPulseWeightNormal = m_Reader.ReadUInt16(); } catch (Exception) { // If an exception occurs populate the default value m_usPulseWeightNormal = 0; } try { m_uiPulseQuantityNormal = m_Reader.ReadUInt32(); } catch (Exception) { // If an exception occurs populate the default value m_uiPulseQuantityNormal = 0; } try { m_usPulseWeightAlt = m_Reader.ReadUInt16(); } catch (Exception) { // If an exception occurs populate the default value m_usPulseWeightAlt = 0; } try { m_uiPulseQuantityAlt = m_Reader.ReadUInt32(); } catch (Exception) { // If an exception occurs populate the default value m_uiPulseQuantityAlt = 0; } try { m_usPulseWeightTest = m_Reader.ReadUInt16(); } catch (Exception) { // If an exception occurs populate the default value m_usPulseWeightTest = 0; } try { m_uiPulseQuantityTest = m_Reader.ReadUInt32(); } catch (Exception) { // If an exception occurs populate the default value m_uiPulseQuantityTest = 0; } try { m_usPulseWeightTestAlt = m_Reader.ReadUInt16(); } catch (Exception) { // If an exception occurs populate the default value m_usPulseWeightTestAlt = 0; } try { m_uiPulseQuantityTestAlt = m_Reader.ReadUInt32(); } catch (Exception) { // If an exception occurs populate the default value m_uiPulseQuantityTestAlt = 0; } try { m_byappPowerCalcMethod = m_Reader.ReadByte(); } catch (Exception) { // If an exception occurs populate the default value m_byappPowerCalcMethod = 0; } try { m_byDummy = m_Reader.ReadByte(); } catch (Exception) { // If an exception occurs populate the default value m_byDummy = 0; } } return(Result); }
/// <summary> /// Downloads the firmware file to the meter and activates it. /// On download failure, the pending table is cleared. The activation /// will cause the meter to drop the psem task so meter log off must /// follow this function call /// </summary> /// <param name="path">Complete file path of the firmware file</param> /// <returns>Itron.Metering.Device.FWDownloadResult</returns> // Revision History // MM/DD/YY who Version Issue# 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 // public FWDownloadResult DownloadFW(string path) { 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 { // 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: { byEventNumber = COMM_EVENT_NUMBER; idTable = (ushort)PendingTableIds.CommModuleFWTbl | PENDING_BIT; break; } 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 / BLOCK_SIZE); if (streamFile.Length != BLOCK_SIZE * usNumberChunks) { usNumberChunks++; } OnShowProgress(new ShowProgressEventArgs(1, usNumberChunks + 1, "Firmware Download", "Downloading...")); ushort usSendSize = BLOCK_SIZE; for (intIndex = 0; (intIndex < usNumberChunks) && (PSEMResponse.Ok == ProtocolResponse); intIndex++) { // The last chunk could be smaller if (usNumberChunks - 1 == intIndex) { usSendSize = (ushort)(streamFile.Length % BLOCK_SIZE); // If no remainder then it is a full packet if (0 == usSendSize) { usSendSize = BLOCK_SIZE; } } streamHeader.Position = 0; streamPSEM.Position = 0; streamPSEM.SetLength(0); streamHeader.WriteTo(streamPSEM); streamPSEM.Write(bybuffer, intIndex * BLOCK_SIZE, usSendSize); ProtocolResponse = m_PSEM.OffsetWrite((ushort)idTable, intIndex * BLOCK_SIZE, 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 MSM ChoiceConnect meter and ChoiceConnect FWDL request, spoof RFLAN FWDL CENTRON_AMI AmiDevice = this as CENTRON_AMI; if (AmiDevice != null && bybuffer[9] == (byte)FirmwareType.ChoiceConnectFW && AmiDevice.IsChoiceConnectMsmMeter) { bybuffer[9] = (byte)FirmwareType.RFLANFW; } ProcResult = AuthenticateFWDL(idTable, bybuffer[9], FWHashCode); } else { ProcResult = ProcedureResultCodes.COMPLETED; } if (ProcResult == ProcedureResultCodes.COMPLETED) { // Activate the pending table ProcResult = ActivatePendingTable(false, false, byEventNumber, PendingEventRecord.PendingEventCode.NonTimeTrigger); Result = TranslateProcedureResult(ProcResult); } else { //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 { // 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); }
public ConfigurationError Logon(ushort usUserID, String strUserName, string strPassword, string strSerialPort, uint uiBaudRate) { PSEMResponse PSEMResult = new PSEMResponse(); // Set up the serial port if (!m_SerialPort.IsOpen) { try { // Open the Serial Port m_SerialPort.OpenPort(strSerialPort); } #region SerialPort Open catch statements catch (InvalidOperationException) { // The port is already open return(ConfigurationError.UNABLE_TO_OPEN_PORT); } catch (ArgumentException) { // The port name is invalid return(ConfigurationError.UNABLE_TO_OPEN_PORT); } catch (IOException) { // The port is in an invalid state return(ConfigurationError.UNABLE_TO_OPEN_PORT); } catch (UnauthorizedAccessException) { // Port access was denied return(ConfigurationError.UNABLE_TO_OPEN_PORT); } #endregion // Log on to the meter try { PSEMResult = m_PSEM.Identify(); if (PSEMResult == PSEMResponse.Ok) { PSEMResult = m_PSEM.Negotiate(512, 254, uiBaudRate); } if (PSEMResult == PSEMResponse.Ok) { PSEMResult = m_PSEM.Logon(strUserName, usUserID); } if (PSEMResult == PSEMResponse.Ok) { PSEMResult = m_PSEM.Security(strPassword); } if (PSEMResult != PSEMResponse.Ok) { // TODO: Add additional error translations // Translate the PSEM error code return(AMIConfigureDevice.InterpretPSEMResult(PSEMResult)); } } catch (TimeOutException) { // The meter has timed out so return an error m_SerialPort.ClosePort(); return(ConfigurationError.TIMEOUT); } } else { // The serial port is already open so we can not continue logging on return(ConfigurationError.UNABLE_TO_OPEN_PORT); } return(ConfigurationError.SUCCESS); }
/// <summary> /// Reads Table 2524 (mfg 476) /// </summary> /// <param name="MeterTables">The meter tables object</param> /// <returns>The result of the read</returns> // Revision History // MM/DD/YY Who Version Issue# Description // -------- --- ------- ------ ------------------------------------------- // 06/27/13 AF 2.80.44 TR7648 Created // 07/16/13 AF 2.80.53 WR417522 Adjusted the size of the offset reads to make sure that each // reads an even multiple of entries. // 06/19/15 AF 4.20.14 591427 Calculate the table size instead of retrieving from the CE dlls // 07/23/15 AF 4.20.18 597509 The number of entries from table 2521 might not be correct so read from 2524 // public PSEMResponse ReadTable2524(ref CentronTables MeterTables) { PSEMResponse PSEMResult = PSEMResponse.Ok; MemoryStream PSEMDataStream; byte[] PSEMData; uint TableSize = 0; uint CurrentOffset = 0; uint NumberUnreadEntriesOffset; uint NumberUnreadEntriesLength; ushort NumberICSEntries = 0; uint HeaderSize; object objData; uint SizeOfEntry = ICS_LOG_RCD_BASIC; bool blnEventNumberFlag = false; if (MeterTables.IsCached((long)CentronTblEnum.MFGTBL473_EVENT_NUMBER_FLAG, null)) { MeterTables.GetValue((long)CentronTblEnum.MFGTBL473_EVENT_NUMBER_FLAG, null, out objData); blnEventNumberFlag = (bool)objData; } if (MeterTables.IsCached((long)CentronTblEnum.MFGTBL473_ICS_DATA_LENGTH, null)) { MeterTables.GetValue((long)CentronTblEnum.MFGTBL473_ICS_DATA_LENGTH, null, out objData); SizeOfEntry += (byte)objData; } if (blnEventNumberFlag) { SizeOfEntry += sizeof(UInt16); } MeterTables.GetFieldOffset((long)CentronTblEnum.MFGTBL476_NBR_UNREAD_ENTRIES, null, out NumberUnreadEntriesOffset, out NumberUnreadEntriesLength); HeaderSize = NumberUnreadEntriesOffset + NumberUnreadEntriesLength; // Read the header PSEMResult = m_PSEM.OffsetRead(2524, 0, (ushort)HeaderSize, out PSEMData); if (PSEMResult == PSEMResponse.Ok) { PSEMDataStream = new MemoryStream(PSEMData); MeterTables.SavePSEMStream(2524, PSEMDataStream, 0); CurrentOffset += HeaderSize; ushort BytesToRead; if (MeterTables.IsCached((long)CentronTblEnum.MFGTBL476_NBR_VALID_ENTRIES, null)) { MeterTables.GetValue((long)CentronTblEnum.MFGTBL476_NBR_VALID_ENTRIES, null, out objData); NumberICSEntries = (ushort)objData; } TableSize = HeaderSize + (SizeOfEntry * NumberICSEntries); // Read the entries while (CurrentOffset < TableSize) { if ((TableSize - CurrentOffset) < MAX_ENTRIES_IN_ONE_READ * SizeOfEntry) { BytesToRead = (ushort)(TableSize - CurrentOffset); } else { BytesToRead = (ushort)(MAX_ENTRIES_IN_ONE_READ * SizeOfEntry); } PSEMResult = m_PSEM.OffsetRead(2524, (int)CurrentOffset, BytesToRead, out PSEMData); if (PSEMResult == PSEMResponse.Ok) { PSEMDataStream = new MemoryStream(PSEMData); MeterTables.SavePSEMStream(2524, PSEMDataStream, CurrentOffset); CurrentOffset += BytesToRead; } else { break; } } } return(PSEMResult); }
/// <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 // -------- --- ------- -- ------ --------------------------------------- // 11/15/13 AF 3.50.03 Class re-architecture - Cloned from CENTRON_AMI // 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)FWDLTableIds.CommModuleFWTbl | 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.ICSFW: { byEventNumber = COMM_EVENT_NUMBER; idTable = (ushort)FWDLTableIds.CommModuleFWTbl | PENDING_BIT; break; } default: { throw new NotImplementedException("Table not supported"); } } BuildPendingHeader(ref streamHeader, false, false, byEventNumber, PendingEventRecord.PendingEventCode.NonTimeTrigger); usNumberChunks = (ushort)(streamFile.Length / BLOCK_SIZE); if (streamFile.Length != BLOCK_SIZE * usNumberChunks) { usNumberChunks++; } OnShowProgress(new ShowProgressEventArgs(1, usNumberChunks + 1, "Firmware Download", "Downloading...")); ushort usSendSize = BLOCK_SIZE; for (; (usBlockIndex < usNumberChunks) && (PSEMResponse.Ok == ProtocolResponse); usBlockIndex++) { // The last chunk could be smaller if (usNumberChunks - 1 == usBlockIndex) { usSendSize = (ushort)(streamFile.Length % BLOCK_SIZE); // If no remainder then it is a full packet if (0 == usSendSize) { usSendSize = BLOCK_SIZE; } } streamHeader.Position = 0; streamPSEM.Position = 0; streamPSEM.SetLength(0); streamHeader.WriteTo(streamPSEM); streamPSEM.Write(bybuffer, usBlockIndex * BLOCK_SIZE, usSendSize); ProtocolResponse = m_PSEM.OffsetWrite((ushort)idTable, usBlockIndex * BLOCK_SIZE, 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) { ProcResult = ProcedureResultCodes.COMPLETED; if (ProcResult == ProcedureResultCodes.COMPLETED) { if (true == blnActivate) { // Activate the pending table using mfg proc 69 ProcResult = ActivateFWDLTable(idTable, (byte)FirmwareType.ICSFW, bybuffer[5], bybuffer[6], bybuffer[7]); Result = TranslateProcedureResult(ProcResult); } } else { //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--; 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> /// This method updates the IO configuration in the meter. /// </summary> /// <param name="IOConfig">KYZ configuration data object.</param> /// <returns>The result of the configuration.</returns> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ --------------------------------------- // 04/22/09 jrf 2.20.02 n/a Created // 04/19/10 AF 2.40.39 Made virtual for M2 Gateway override // 07/08/10 jrf 2.42.02 157552 Setting the CPC reset bit on close config to fix // LED lock issue. // public virtual ItronDeviceResult ConfigureIO(KYZData IOConfig) { byte[] ProcParam = new byte[0]; byte[] ProcResponse; ProcedureResultCodes ProcResult = ProcedureResultCodes.INVALID_PARAM; PSEMResponse Result = PSEMResponse.Err; ItronDeviceResult ConfigResult = ItronDeviceResult.ERROR; CTable2048_OpenWay OW2048 = Table2048 as CTable2048_OpenWay; CENTRON_AMI_IOConfig IOTable = OW2048.IOConfig as CENTRON_AMI_IOConfig; // Open the Config ProcResult = ExecuteProcedure(Procedures.OPEN_CONFIG_FILE, ProcParam, out ProcResponse); // Execute Write of IO Table in 2048 if (ProcedureResultCodes.COMPLETED == ProcResult) { IOTable.IOData = IOConfig; Result = IOTable.Write(); } else if (ProcedureResultCodes.NO_AUTHORIZATION == ProcResult) { Result = PSEMResponse.Isc; } else { m_Logger.WriteLine(Logger.LoggingLevel.Detailed, "Open config procedure failed with result = " + ProcResult); Result = PSEMResponse.Err; } if (Result == PSEMResponse.Ok) { // Close the Config // Data reset bits - we don't want to reset any data, so // just initialize them to 0 ProcParam = new byte[4]; ProcParam.Initialize(); // Okay we do want to reset data if we are a HW2.0 Poly. Need to do this to // prevent the worm on the display from freezing. if (0 == VersionChecker.CompareTo(HWRevisionFiltered, HW_VERSION_2_5) || 0 == VersionChecker.CompareTo(HWRevisionFiltered, HW_VERSION_2_6)) { //We need to reset CPC MemoryStream ParamStream = new MemoryStream(ProcParam); BinaryWriter BinWriter = new BinaryWriter(ParamStream); BinWriter.Write((uint)CloseConfigOptions.CPC); } ProcResult = ExecuteProcedure(Procedures.CLOSE_CONFIG_FILE, ProcParam, out ProcResponse); if (ProcedureResultCodes.COMPLETED != ProcResult) { ConfigResult = ItronDeviceResult.ERROR; } else { ConfigResult = ItronDeviceResult.SUCCESS; } } else { if (Result == PSEMResponse.Isc) { ConfigResult = ItronDeviceResult.SECURITY_ERROR; } else { ConfigResult = ItronDeviceResult.ERROR; } } return(ConfigResult); }
/// <summary> /// Runs the test. /// </summary> // Revision History // MM/DD/YY Who Version ID Number Description // -------- --- ------- -- ------ ------------------------------------------- // 09/17/09 RCG 2.30.00 Created // 12/09/09 jrf 2.30.26 Removing upper nibble of hardware version before // displaying for PrismLite devices. // 02/19/13 AF 2.70.69 322427 Show InterPAN Mode only for pre-Lithium meters // 09/19/14 jrf 4.00.63 WR 534158 Using new method to set test result string and // modified way test details are set. // 10/02/14 jrf 4.00.66 WR 431248 Making sure if logon is called and exception occurs then a logoff is // attempted so other tests may continue if possible. public override Test RunTest() { PSEMResponse Response = PSEMResponse.Ok; string strValue = ""; m_TestResults = new Test(); m_TestResults.Name = TestName; m_bTestPassed = true; try { Response = LogonToDevice(); if (Response == PSEMResponse.Ok) { if (IsAborted == false) { AddTestDetail(TestResources.MeterID, TestResources.OK, m_AmiDevice.UnitID); AddTestDetail(TestResources.SerialNumber, TestResources.OK, m_AmiDevice.SerialNumber); AddTestDetail(TestResources.MFGSerialNumber, TestResources.OK, m_AmiDevice.MFGSerialNumber); if (m_AmiDevice.CommModule != null) { strValue = m_AmiDevice.CommModule.ElectronicSerialNumber; } else { strValue = TestResources.NotAvailable; } AddTestDetail(TestResources.ElectronicSerialNumber, TestResources.OK, strValue); } if (IsAborted == false) { CheckRegisterFWVersion(); CheckRFLANFWVersion(); CheckZigBeeFWVersion(); CheckDisplayFWVersion(); float fltHWRev = m_AmiDevice.HWRevision; // If this is a PrismLite device we need to ignore the upper nibble of the hardware version if (((byte)(fltHWRev) & PRISM_LITE_HW_MASK) == PRISM_LITE_HW_MASK) { fltHWRev -= (float)PRISM_LITE_HW_MASK; } AddTestDetail(TestResources.HardwareVersion, TestResources.OK, fltHWRev.ToString("F3", CultureInfo.CurrentCulture)); } if (IsAborted == false) { AddTestDetail(TestResources.TimeZone, TestResources.OK, m_AmiDevice.TimeZoneOffset.Hours + ":00"); AddTestDetail(TestResources.DeviceTime, TestResources.OK, m_AmiDevice.DeviceTime.ToString("G", CultureInfo.CurrentCulture)); AddTestDetail(TestResources.TOUEnabled, TestResources.OK, m_AmiDevice.TOUEnabled.ToString(CultureInfo.CurrentCulture)); AddTestDetail(TestResources.DSTEnabled, TestResources.OK, m_AmiDevice.DSTEnabled.ToString(CultureInfo.CurrentCulture)); for (int iIndex = 0; iIndex < m_AmiDevice.DST.Count; iIndex++) { AddTestDetail(TestResources.DSTFromDate + (iIndex + 1).ToString(CultureInfo.CurrentCulture), TestResources.OK, m_AmiDevice.DST[iIndex].FromDate.ToString("G", CultureInfo.CurrentCulture)); AddTestDetail(TestResources.DSTToDate + (iIndex + 1).ToString(CultureInfo.CurrentCulture), TestResources.OK, m_AmiDevice.DST[iIndex].ToDate.ToString("G", CultureInfo.CurrentCulture)); } } if (IsAborted == false) { AddTestDetail(TestResources.MinutesOnBattery, TestResources.OK, m_AmiDevice.NumberOfMinutesOnBattery.ToString(CultureInfo.CurrentCulture)); AddTestDetail(TestResources.DateLastProgrammed, TestResources.OK, m_AmiDevice.DateProgrammed.ToString("G", CultureInfo.CurrentCulture)); AddTestDetail(TestResources.DateOfLastDemandReset, TestResources.OK, m_AmiDevice.DateLastDemandReset.ToString("G", CultureInfo.CurrentCulture)); AddTestDetail(TestResources.DateOfLastOutage, TestResources.OK, m_AmiDevice.DateLastOutage.ToString("G", CultureInfo.CurrentCulture)); AddTestDetail(TestResources.DateOfLastTest, TestResources.OK, m_AmiDevice.DateLastTestMode.ToString("G", CultureInfo.CurrentCulture)); if ((m_AmiDevice is OpenWayBasicPoly == true) || (m_AmiDevice is OpenWayAdvPoly == true)) { AddTestDetail(TestResources.NormalKh, TestResources.OK, (m_AmiDevice.NormalKh / 40.0).ToString("F3", CultureInfo.CurrentCulture)); } else { AddTestDetail(TestResources.NormalKh, TestResources.OK, (m_AmiDevice.NormalKh / 10.0).ToString("F3", CultureInfo.CurrentCulture)); } } if (IsAborted == false) { CheckLPRunning(); CheckDeviceErrors(); GetRFLANMac(); if (m_AmiDevice.CommModule != null) { RFLANCommModule RFLANModule = m_AmiDevice.CommModule as RFLANCommModule; if (RFLANModule != null) { strValue = RFLANModule.CommModuleLevel; } else { strValue = TestResources.NotAvailable; } } else { strValue = TestResources.NotAvailable; } AddTestDetail(TestResources.RFLANSynchLevel, TestResources.OK, strValue); } if (IsAborted == false) { AddTestDetail(TestResources.HANMACAddress, TestResources.OK, m_AmiDevice.HANServerMACAddr); AddTestDetail(TestResources.HANSecurityProfile, TestResources.OK, m_AmiDevice.HANSecurityProfile); if (VersionChecker.CompareTo(m_AmiDevice.FWRevision, CENTRON_AMI.VERSION_3_12_LITHIUM) < 0) { AddTestDetail(TestResources.InterPANMode, TestResources.OK, m_AmiDevice.InterPANMode); } AddTestDetail(TestResources.ZigBeeEnabled, TestResources.OK, ConvertYesOrNo(m_AmiDevice.IsZigBeeEnabled)); AddTestDetail(TestResources.ANSIC1218OverZigBeeEnabled, TestResources.OK, ConvertYesOrNo(m_AmiDevice.IsC1218OverZigBeeEnabled)); AddTestDetail(TestResources.ZigBeePrivateProfileEnabled, TestResources.OK, ConvertYesOrNo(m_AmiDevice.IsZigBeePrivateProfileEnabled)); AddTestDetail(TestResources.EnhancedBlurtsEnabled, TestResources.OK, ConvertYesOrNo(m_AmiDevice.MeterKey_EnhancedBlurtsSupported)); AddTestDetail(TestResources.AdvancedPolyMeter, TestResources.OK, ConvertYesOrNo(m_AmiDevice.MeterKey_AdvancedPolySupported)); } } else { m_TestResults.Reason = TestResources.ReasonLogonFailed; m_bTestPassed = false; } } catch (Exception e) { throw (e); } finally { if (m_AmiDevice != null) { m_AmiDevice.Logoff(); } } // Set the final result. m_TestResults.Result = GetTestResultString(m_bTestSkipped, m_bTestPassed); return(m_TestResults); }
/// <summary> /// Runs the test. /// </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 Using new method to set test result string and // modified way test details are set. // 10/02/14 jrf 4.00.66 WR 431248 Making sure if logon is called and exception occurs then a logoff is // attempted so other tests may continue if possible. public override Test RunTest() { PSEMResponse Response = PSEMResponse.Ok; m_TestResults = new Test(); m_TestResults.Name = TestName; m_bTestPassed = true; m_ulMACAddress = 0; m_byChannel = 0; m_bC1218OverZigBeeEnabled = false; try { // First we need to log on and get the HAN MAC address, channel, and ZigBee state optically Response = LogonToDevice(); if (Response == PSEMResponse.Ok) { try { m_ulMACAddress = m_AmiDevice.HANMACAddress; AddTestDetail(TestResources.HANMACAddress, TestResources.OK, m_ulMACAddress.ToString("X16", CultureInfo.InvariantCulture)); m_byChannel = m_AmiDevice.HANChannel; AddTestDetail(TestResources.HANChannel, TestResources.OK, m_byChannel.ToString(CultureInfo.InvariantCulture)); m_bJoiningEnabled = m_AmiDevice.IsHANJoiningEnabled; AddTestDetail(TestResources.HANJoiningEnabled, TestResources.OK, ConvertYesOrNo(m_bJoiningEnabled)); m_bC1218OverZigBeeEnabled = m_AmiDevice.IsC1218OverZigBeeEnabled; AddTestDetail(TestResources.SupportsANSIC1218OverZigBee, TestResources.OK, ConvertYesOrNo(m_bC1218OverZigBeeEnabled)); m_bZigBeeEnabled = m_AmiDevice.IsZigBeeEnabled; AddTestDetail(TestResources.ZigBeeEnabled, TestResources.OK, ConvertYesOrNo(m_bZigBeeEnabled)); m_bPrivateProfileEnabled = m_AmiDevice.IsZigBeePrivateProfileEnabled; AddTestDetail(TestResources.ZigBeePrivateProfileEnabled, TestResources.OK, ConvertYesOrNo(m_bPrivateProfileEnabled)); } catch (Exception) { m_TestResults.Reason = TestResources.ReasonFailedToGetHANInfo; m_bTestPassed = false; } } else { m_TestResults.Reason = TestResources.ReasonLogonFailed; m_bTestPassed = false; } } catch (Exception e) { throw (e); } finally { if (m_AmiDevice != null) { m_AmiDevice.Logoff(); } } if (true == m_bTestPassed) { // Try to log on via ZigBee. TestZigBeeConnection(); } else { AddTestDetail(TestResources.AllowedANSIC1218Connection, GetResultString(true, false), m_TestResults.Reason); } // Set the final result. m_TestResults.Result = GetTestResultString(m_bTestSkipped, m_bTestPassed); // This test like to cause communications problems with tests that follow // Giving the meter a little time to recover should help. Thread.Sleep(10000); return(m_TestResults); }
/// <summary> /// Implements the ICustomSchedule interface. Reconfigures the Custom Schedule /// based on the provided schedule. /// </summary> /// <param name="sPathName"></param> /// <param name="sScheduleName"></param> /// <param name="bWriteUserData2"></param> /// <returns>CSReconfigResult</returns> /// Revision History /// MM/DD/YY who Version Issue# Description /// -------- --- ------- ------ --------------------------------------------- /// 05/31/06 mrj 7.30.00 N/A Created /// CSReconfigResult ICustomSchedule.Reconfigure(string sPathName, string sScheduleName, bool bWriteUserData2) { ProcedureResultCodes ProcResult = ProcedureResultCodes.INVALID_PARAM; CSReconfigResult Result = CSReconfigResult.ERROR; byte[] ProcParam; byte[] ProcResponse; PSEMResponse PSEMResult = PSEMResponse.Ok; try { m_Logger.WriteLine(Logger.LoggingLevel.Functional, "Starting Custom Schedule Reconfigure"); //Check to make sure the meter is configured correctly before performing //the reconfigure if (((ICustomSchedule)this).CustomScheduleConfigured) { if (!((ICustomSchedule)this).MultipleCustomScheduleConfigured) { //Schedule is valid write the custom schedule dates to the //billing schedule (custom schedule) config block of table 2048 Result = WriteCustomSchedule(sPathName, sScheduleName); if (CSReconfigResult.SUCCESS == Result || CSReconfigResult.SUCCESS_SCHEDULE_TRUNCATED == Result) { //Set the schedule name to user data 2 (Sentinel only) if (bWriteUserData2 && !Table2048.BillingSchedConfig.ScheduleNameSupported) { //Write schedule name to user data 2 if the System Manager option //is set and the meter is a SENTINEL (schedule name is not supported //in CS config block) Table2048.ConstantsConfig.UserData2 = sScheduleName; } //Send the MFG procedure to open the config file (2048) ProcParam = new byte[0]; ProcResult = ExecuteProcedure(Procedures.OPEN_CONFIG_FILE, ProcParam, out ProcResponse); if (ProcedureResultCodes.NO_AUTHORIZATION == ProcResult) { //Return ISC PSEMResult = PSEMResponse.Isc; } else if (ProcedureResultCodes.COMPLETED != ProcResult) { //We had a problem with this procedure PSEMResult = PSEMResponse.Err; } //NOTE: 2048 must be written in sequential order //Write the User Data 2, custom schedule name, to the meter if (bWriteUserData2 && !Table2048.BillingSchedConfig.ScheduleNameSupported && PSEMResponse.Ok == PSEMResult) { //Write schedule name to user data 2 if the System Manager option //is set and the meter is a SENTINEL PSEMResult = Table2048.ConstantsConfig.Write(); } //Write the billing schedule (custom schedule) config block to the //meter if (PSEMResponse.Ok == PSEMResult) { PSEMResult = Table2048.BillingSchedConfig.Write(); } //Send the MFG procedure to close the config file (2048), which tell the meter to //do the reconfigure if (PSEMResponse.Ok == PSEMResult) { ProcParam = new byte[4]; ProcParam.Initialize(); //No reset bits needed ProcResult = ExecuteProcedure(Procedures.CLOSE_CONFIG_FILE, ProcParam, out ProcResponse); if (ProcedureResultCodes.INVALID_PARAM == ProcResult) { //The procedure finished but there was an invalid parameter //error. Most likely because the user is at level 3 if (4 == ProcResponse.Length) { //Read the result data MemoryStream TempStream = new MemoryStream(ProcResponse); BinaryReader TempBReader = new BinaryReader(TempStream); uint uiResultData = TempBReader.ReadUInt32(); if (CLOSE_CONFIG_CONST_ERROR_MASK == (uint)(uiResultData & CLOSE_CONFIG_CONST_ERROR_MASK) || CLOSE_CONFIG_BILL_ERROR_MASK == (uint)(uiResultData & CLOSE_CONFIG_BILL_ERROR_MASK)) { //The user is level 3, which does not support reconfiguring //the custom schedule, return security error Result = CSReconfigResult.SECURITY_ERROR; } else { //The reconfigure failed Result = CSReconfigResult.ERROR; } } else { //The reconfigure failed Result = CSReconfigResult.ERROR; } } else if (ProcedureResultCodes.COMPLETED != ProcResult) { //The reconfigure failed Result = CSReconfigResult.ERROR; } m_Logger.WriteLine(Logger.LoggingLevel.Detailed, "Reconfig Custom Schedule Result = " + ProcResult); } else if (PSEMResponse.Isc == PSEMResult) { //Return security error Result = CSReconfigResult.SECURITY_ERROR; } else { //The reconfigure failed Result = CSReconfigResult.ERROR; } } } else { //Multiple Custom Schedules is configured so return an error. This //should never happen since HH-Pro will not call this method when //MCS is enabled. Result = CSReconfigResult.ERROR_MCS_ENALBED; } } else { //This should never happen since HH-Pro will not call unless configured Result = CSReconfigResult.ERROR; } } catch (Exception e) { // Log it and pass it up m_Logger.WriteException(this, e); throw (e); } return(Result); }
/// <summary> /// Creates an EDL file with the specified sections. /// </summary> /// <param name="FileName">Path to the file where the EDL file will be written.</param> /// <param name="IncludedSections">The sections to include in the EDL file.</param> /// <returns>CreateEDLResult Code.</returns> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ --------------------------------------- // 04/25/08 RCG 1.50.19 Created // 07/06/10 AF 2.42.02 Made virtual for use in the M2 Gateway public override CreateEDLResult CreateEDLFromMeter(string FileName, EDLSections IncludedSections) { CentronTables MeterTables = new CentronTables(); List <ushort> TablesToRead; int iFileNameStart; string strDirectory; CreateEDLResult Result = CreateEDLResult.SUCCESS; PSEMResponse PSEMResult = PSEMResponse.Ok; // First check to make sure we can create the file iFileNameStart = FileName.LastIndexOf(@"\", StringComparison.Ordinal); if (iFileNameStart > 0) { strDirectory = FileName.Substring(0, iFileNameStart); if (Directory.Exists(strDirectory) == false) { Result = CreateEDLResult.INVALID_PATH; } } // Make sure we will be able to write to the file if (Result == CreateEDLResult.SUCCESS && File.Exists(FileName) == true) { FileInfo OutputFile = new FileInfo(FileName); if ((OutputFile.Attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) { Result = CreateEDLResult.INVALID_PATH; } } if (Result == CreateEDLResult.SUCCESS) { // Read the data from the meter TablesToRead = GetTablesToRead(IncludedSections); OnShowProgress(new ShowProgressEventArgs(1, TablesToRead.Count, "Creating EDL file...", "Creating EDL file...")); foreach (ushort TableID in TablesToRead) { if (PSEMResult == PSEMResponse.Ok) { // Read the table if it exists if ((Table00.IsTableUsed(TableID) == true)) { if (MeterTables.GetTableDependencies(TableID).Contains(TableID) || MeterTables.GetTableLength(TableID) > 0) { PSEMResult = ReadTable(TableID, ref MeterTables); if (PSEMResult == PSEMResponse.Bsy || PSEMResult == PSEMResponse.Dnr || PSEMResult == PSEMResponse.Iar || PSEMResult == PSEMResponse.Onp || PSEMResult == PSEMResponse.Err) { // We can't read the table but we should be able to continue we just need to // clear out anything that is there. MeterTables.ClearTable(TableID); PSEMResult = PSEMResponse.Ok; } } } OnStepProgress(new ProgressEventArgs()); } } if (PSEMResult == PSEMResponse.Isc) { Result = CreateEDLResult.SECURITY_ERROR; } else if (PSEMResult != PSEMResponse.Ok) { Result = CreateEDLResult.PROTOCOL_ERROR; } } #if (WindowsCE) //The saving of the EDL file on the handheld can take over 6 seconds so we need //to send a wait before. m_PSEM.Wait(CPSEM.MAX_WAIT_TIME); #endif // Generate the EDL file if (Result == CreateEDLResult.SUCCESS) { XmlWriterSettings WriterSettings = new XmlWriterSettings(); WriterSettings.Encoding = Encoding.ASCII; WriterSettings.Indent = true; WriterSettings.CheckCharacters = false; XmlWriter EDLWriter = XmlWriter.Create(FileName, WriterSettings); MeterTables.SaveEDLFile(EDLWriter, null, AllowTableExport, AllowFieldExport); System.Threading.Thread.Sleep(2000); } OnHideProgress(new EventArgs()); 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> /// <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 // public FWDownloadResult DownloadFWNoActivate(string path) { 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.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, PendingEventRecord.PendingEventCode.NonTimeTrigger); usNumberChunks = (ushort)(streamFile.Length / BLOCK_SIZE); if (streamFile.Length != BLOCK_SIZE * usNumberChunks) { usNumberChunks++; } OnShowProgress(new ShowProgressEventArgs(1, usNumberChunks + 1, "Firmware Download", "Downloading...")); ushort usSendSize = BLOCK_SIZE; for (intIndex = 0; (intIndex < usNumberChunks) && (PSEMResponse.Ok == ProtocolResponse); intIndex++) { // The last chunk could be smaller if (usNumberChunks - 1 == intIndex) { usSendSize = (ushort)(streamFile.Length % BLOCK_SIZE); // If no remainder then it is a full packet if (0 == usSendSize) { usSendSize = BLOCK_SIZE; } } streamHeader.Position = 0; streamPSEM.Position = 0; streamPSEM.SetLength(0); streamHeader.WriteTo(streamPSEM); streamPSEM.Write(bybuffer, intIndex * BLOCK_SIZE, usSendSize); ProtocolResponse = m_PSEM.OffsetWrite((ushort)idTable, intIndex * BLOCK_SIZE, 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); }
/// <summary> /// Reads the specified table from the meter. /// </summary> /// <param name="usTableID">The table ID for the table to read.</param> /// <param name="MeterTables">The tables object to read the table into.</param> /// <returns>PSEMResponse code.</returns> // Revision History // MM/DD/YY Who Version Issue# Description // -------- --- ------- -------- ------------------------------------------- // 11/21/13 DLG 3.50.07 No WR Overriding to handle ICS related tables // 05/08/14 AF 3.50.91 WR503773 Added a case for table 2242 // 05/09/14 AF 3.50.91 WR503773 Removed the case for table 2242. We should be consistent with // CENTRON_AMI which also does not have a case for 2242. // 06/11/14 AF 4.00.25 WR442864 Added back the case for table 2242, due to test failures // 07/23/15 jrf 4.20.18 598314 Removing code that is duplicated from base class and // calling base.ReadTable(...) in default case to handle those cases. public override PSEMResponse ReadTable(ushort usTableID, ref CentronTables MeterTables) { PSEMResponse PSEMResult = PSEMResponse.Ok; int iReadAttempt = 0; bool bRetry = true; while (bRetry) { switch (usTableID) { case 2508: { if (PSEMResult == PSEMResponse.Ok) { PSEMResult = m_ICSTableReader.ReadTable2508(ref MeterTables); } break; } case 2511: { if (PSEMResult == PSEMResponse.Ok) { PSEMResult = m_ICSTableReader.ReadTable2511(ref MeterTables); } break; } case 2524: { if (PSEMResult == PSEMResponse.Ok) { PSEMResult = m_ICSTableReader.ReadTable2524(ref MeterTables); } break; } default: { PSEMResult = base.ReadTable(usTableID, ref MeterTables); iReadAttempt = 3; //Skipping retries since they will be handled in base class break; } } iReadAttempt++; if (iReadAttempt < 3 && (PSEMResult == PSEMResponse.Bsy || PSEMResult == PSEMResponse.Dnr)) { bRetry = true; System.Threading.Thread.Sleep(1000); } else { bRetry = false; } } return(PSEMResult); }
/// <summary> /// This method just downloads the firmware file blocks to the device for a /// given range of blocks. Use 1-based indexing for blocks. /// </summary> /// <param name="path">Complete path to the firmware file</param> /// <param name="usStartBlock">The first block to download.</param> /// <param name="usEndBlock">The last block to download.</param> /// <returns>FWDownloadResult</returns> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ --------------------------------------- // 01/20/10 jrf 2.40.08 N/A Created // 03/22/12 JJJ 2.60.xx Added support for ChoiceConnect FW // public FWDownloadResult DownloadFWBlocks(string path, ushort usStartBlock, ushort usEndBlock) { FWDownloadResult Result = FWDownloadResult.SUCCESS; PSEMResponse ProtocolResponse = PSEMResponse.Ok; byte byEventNumber = 0; ushort idTable = (ushort)PendingTableIds.RegisterFWTbl | PENDING_BIT; ushort usNumberChunks = 0; ushort usIndex; System.IO.FileStream streamFile; System.IO.MemoryStream streamHeader = new System.IO.MemoryStream(); System.IO.MemoryStream streamPSEM = new System.IO.MemoryStream(); try { 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: { 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.ChoiceConnectFW: { byEventNumber = COMM_EVENT_NUMBER; idTable = (ushort)PendingTableIds.CommModuleFWTbl | PENDING_BIT; break; } case (byte)FirmwareType.DisplayFW: { //TODO - Firmware wants to use the same event number. Need to test //that it works byEventNumber = REGISTER_EVENT_NUMBER; idTable = (ushort)PendingTableIds.RegisterFWTbl | PENDING_BIT; break; } 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, PendingEventRecord.PendingEventCode.NonTimeTrigger); usNumberChunks = (ushort)(streamFile.Length / BLOCK_SIZE); if (streamFile.Length != BLOCK_SIZE * usNumberChunks) { usNumberChunks++; } OnShowProgress(new ShowProgressEventArgs(1, usNumberChunks + 1, "Firmware Download", "Downloading...")); ushort usSendSize = BLOCK_SIZE; //Make sure the start block is not less than 1 if (usStartBlock < 1) { usStartBlock = 1; } //Make sure the end block is not greater than the actual number of FW blocks. if (usEndBlock > usNumberChunks) { usEndBlock = usNumberChunks; } for (usIndex = (ushort)(usStartBlock - 1); (usIndex < usEndBlock) && (PSEMResponse.Ok == ProtocolResponse); usIndex++) { // The last chunk could be smaller if (usNumberChunks - 1 == usIndex) { usSendSize = (ushort)(streamFile.Length % BLOCK_SIZE); // If no remainder then it is a full packet if (0 == usSendSize) { usSendSize = BLOCK_SIZE; } } streamHeader.Position = 0; streamPSEM.Position = 0; streamPSEM.SetLength(0); streamHeader.WriteTo(streamPSEM); streamPSEM.Write(bybuffer, usIndex * BLOCK_SIZE, usSendSize); ProtocolResponse = m_PSEM.OffsetWrite((ushort)idTable, usIndex * BLOCK_SIZE, streamPSEM.ToArray()); OnStepProgress(new ProgressEventArgs()); } // Translate Protocol result Result = TranslateProtocolResult(ProtocolResponse); streamFile.Close(); OnHideProgress(new EventArgs()); } catch (Exception e) { // Log it and pass it up OnHideProgress(new EventArgs()); m_Logger.WriteException(this, e); throw e; } return(Result); }
/// <summary> /// Runs the test. /// </summary> // Revision History // MM/DD/YY Who Version ID Number Description // -------- --- ------- -- ------ ------------------------------------------- // 09/17/09 RCG 2.30.00 Created // 08/15/12 MAH 2.60.54 WR 201902 Added more time between switch operations to allow the meter to recharge its capacitor // 09/19/14 jrf 4.00.63 WR 534158 Using new method to set test result string and also checking user permissions. // 10/02/14 jrf 4.00.66 WR 431248 Making sure if logon is called and exception occurs then a logoff is // attempted so other tests may continue if possible. // 04/27/15 jrf 4.20.03 WR 574470 Increased wait between disconnect/connect to allow capacitor more time to charge // for hw 2.0 meter. public override Test RunTest() { PSEMResponse Response = PSEMResponse.Ok; CXMLOpenWayUserAccessPolicy UserAccess = new CXMLOpenWayUserAccessPolicy(); bool bIsUserAllowed = UserAccess.CheckUserAccess(CXMLOpenWayUserAccessPolicy.FunctionalCapability.MeterSwitchOperations); m_TestResults = new Test(); m_TestResults.Name = TestName; m_bTestPassed = true; try { Response = LogonToDevice(); if (false == bIsUserAllowed) { m_bTestSkipped = true; m_TestResults.Reason = TestResources.ReasonSwitchOperationPermissions; } else if (Response == PSEMResponse.Ok) { // First make sure the meter supports connect disconnect. if (m_AmiDevice.IsServiceLimitingTablePresent && m_AmiDevice.DisconnectHardwareExists && m_AmiDevice.IsDisconnectHardwareFunctioning) { DisconnectMeter(); if (IsAborted == false) { m_AmiDevice.SendWait(); // Thread.Sleep(2000); // MAH - 8/15/12 - Increased the time between switch operations to allow the capacitor to recharge //Thread.Sleep(12500); // jrf - 4/27/15 - Increased the time between switch operations slightly more to allow the capacitor // to recharge for HW 2.0 meter. Thread.Sleep(15000); } CheckStatus(false); ConnectMeter(); if (IsAborted == false) { m_AmiDevice.SendWait(); Thread.Sleep(2000); } CheckStatus(true); } else { // Disconnect is not supported m_bTestSkipped = true; m_TestResults.Reason = TestResources.ReasonDisconnectNotSupported; } } else { m_TestResults.Reason = TestResources.ReasonLogonFailed; m_bTestPassed = false; } } catch (Exception e) { throw (e); } finally { if (m_AmiDevice != null) { m_AmiDevice.Logoff(); } } // Set the final result. m_TestResults.Result = GetTestResultString(m_bTestSkipped, m_bTestPassed); return(m_TestResults); }
/// <summary> /// Performs a full read of this table. The table will be marked as /// Loaded if the read succeeds. /// </summary> /// <overloads>Read(ushort Offset, ushort Count)</overloads> /// <returns>protocol response</returns> /// // Revision History // MM/DD/YY who Version ID Number Description // -------- --- ------- -- ------ --------------------------------------- // 06/08/06 mcm 7.30.00 N/A Created // 03/05/08 KRC 1.50.00 Adding Exception if PSEM is not valid // 11/15/11 RCG 2.53.06 Adding code to display a message if we get a data size mismatch // 11/07/12 jrf 2.70.36 WR 240583 Adding ability to ignore a table size mismatch under special circumstances. // 06/12/13 AF 2.80.37 Corrected spelling error in logger entry // 07/18/13 jrf 2.80.54 WR 417794 Modifying to only resize table when sizes differ. // public virtual PSEMResponse Read() { PSEMResponse Result = PSEMResponse.Iar; int iReadAttempt = 0; bool bRetry = true; while (bRetry) { if (m_PSEM != null) { byte[] Data; Result = m_PSEM.FullRead(m_TableID, out Data); if (PSEMResponse.Ok == Result) { if (true == m_blnAllowAutomaticTableResizing && 0 < Data.Length && m_Data.Length != Data.Length) { m_Logger.WriteLine(Logger.LoggingLevel.Detailed, "Resizing Table " + m_TableID.ToString(CultureInfo.InvariantCulture) + " based on data received. Original Length: " + m_Size.ToString(CultureInfo.InvariantCulture) + " New Length: " + Data.Length.ToString(CultureInfo.InvariantCulture)); //Special case where table size is not known in advance and determination //of this knowledge proves to be more complex and time consuming than worth while. //Tables that allow this need to take care to only read as much data as retrieved. ChangeTableSize((uint)Data.Length); } if (m_Data.Length == Data.Length) { Array.Copy(Data, 0, m_Data, 0, m_Data.Length); m_TableState = TableState.Loaded; m_ExpirationTimer.Change(m_iTimeout, 0); // mcm 3/9/2007 - SCR 2553: reposition stream for cases // where the table might be read mulitple times. m_DataStream.Position = 0; } else { Result = PSEMResponse.Err; m_Logger.WriteLine(Logger.LoggingLevel.Detailed, "Data size mismatch. Expected Length: " + m_Size.ToString(CultureInfo.InvariantCulture) + " Received Length: " + Data.Length.ToString(CultureInfo.InvariantCulture)); } } } else { throw (new NotImplementedException("This Operation is not supported with a file")); } iReadAttempt++; if (iReadAttempt < 3 && (Result == PSEMResponse.Bsy || Result == PSEMResponse.Dnr)) { bRetry = true; System.Threading.Thread.Sleep(1000); } else { bRetry = false; } } return(Result); }