Exemple #1
0
        /// <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);
        }
Exemple #2
0
        /// <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
        // -------- --- ------- ------ ---------------------------------------
        // 08/21/06 AF  7.35.00 N/A     Created
        // 09/05/06 AF  7.35.00         Corrected the order of the data in the
        //                             procedure parameters
        // 10/04/06 AF  7.40.00 N/A     Moved from CENTRON_AMI.cs
        // 07/31/07 KRC 8.10.16 3058    Adding more detailed errors;
        // 01/23/12 RCG 2.53.33 191589 Adding the Device Class to the parameter list in order to support Gas Ranger Extended FW DL
        // 05/10/12 JJJ 2.60.xx        Tweaking FW Type so Register sees ChoiceConnect FW as RFLAN FW

        private FWDownloadResult EnterFirmwareDownloadMode(string strFilePath)
        {
            //Construct the parameters for mfg proc 37 and execute the procedure
            FileInfo fi = new FileInfo(strFilePath);
            bool     bIsThirdPartyFWDownload = this is M2_Gateway == false && VersionChecker.CompareTo(FWRevision, CENTRON_AMI.VERSION_LITHIUM_3_12) >= 0;

            byte[] bybuf        = new byte[FW_HEADER_LENGTH];
            byte[] byParameters = null;
            byte[] byImageSize  = new byte[IMAGE_SIZE_FIELD_LEN];
            byte[] byChunkSize  = new byte[CHUNK_SIZE_FIELD_LEN];
            byte[] ProcResponse;
            ProcedureResultCodes ProcResult = ProcedureResultCodes.INVALID_PARAM;
            FWDownloadResult     FWResult   = FWDownloadResult.UNKNOWN_DRIVER_ERROR;

            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, FW_HEADER_LENGTH);
                fs.Close();

                if (bIsThirdPartyFWDownload == true)
                {
                    byParameters = new byte[INIT_FW_DOWNLOAD_THIRD_PARTY_LEN];
                }
                else
                {
                    byParameters = new byte[INIT_FW_DOWNLOAD_PARAM_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);

                // if MSM ChoiceConnect meter and ChoiceConnect FWDL request, spoof RFLAN FWDL
                CENTRON_AMI AmiDevice = this as CENTRON_AMI;
                if (AmiDevice != null &&
                    byParameters[6] == (byte)FirmwareType.ChoiceConnectFW &&
                    AmiDevice.IsChoiceConnectMsmMeter)
                {
                    byParameters[6] = (byte)FirmwareType.RFLANFW;
                }

                // image size
                byImageSize = BitConverter.GetBytes((int)fi.Length);
                Array.Copy(byImageSize, 0, byParameters, 11, IMAGE_SIZE_FIELD_LEN);

                // chunk size -- 64 or 128 bytes; hard coded here to 128
                byChunkSize = BitConverter.GetBytes(BLOCK_SIZE);
                Array.Copy(byChunkSize, 0, byParameters, 15, CHUNK_SIZE_FIELD_LEN);

                if (bIsThirdPartyFWDownload == true)
                {
                    // The Device Class is a required parameter for 3rd Party Firmware Downloads
                    // The meter needs this 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 = 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 (Exception e)
            {
                // Log it and pass it up
                m_Logger.WriteException(this, e);
                throw (e);
            }


            return(FWResult);
        }