lpcmanager

LPCCommand : switch to wx.Timer instead of regular python timer for the rapidfire protection. With regular python timers, some refresh order could pile eventloop when interacting with the GUI while doing initial loading of signals.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor
#based on the plcopen standard.
#
#Copyright (C) 2015: Yvan ROCH
#
#See COPYING file for copyrights details.
#
#This library is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public
#License as published by the Free Software Foundation; either
#version 2.1 of the License, or (at your option) any later version.
#
#This library is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
#General Public License for more details.
#
#You should have received a copy of the GNU General Public
#License along with this library; if not, write to the Free Software
#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#-------------------------------------------------------------------------------
# Firmware Updater for the host (the IDE)
#-------------------------------------------------------------------------------
"""
Class which controls the firmware update on the remote PLC
See also TargetFirmwareUpdater
"""
import os
import hashlib
UPDATE_SCRIPT_TIMEOUT = 600
class HostFirmwareUpdater(object):
# Create a new HostFirmwareUpdater
def __init__(self, controller, firmwareImagePath, updateType, chunksSize, dialog):
self.Reset()
self.firmwareImagePath = firmwareImagePath
self.updateType = updateType
self.chunksSize = chunksSize
self.controller = controller
self.dialog = dialog
self.controller.logger.write(_("HostFirmwareUpdater init.\n"))
# Reset HostFirmwareUpdater internal variables
def Reset(self):
self.Running = 0
def update(self):
self.controller.logger.write(_("HostFirmwareUpdater update.\n"))
self.firmwareImageFile = open(self.firmwareImagePath, "rb")
# Read the image file
self.imageData = self.firmwareImageFile.read()
self.firmwareImageFileSize = os.stat(self.firmwareImagePath).st_size
self.controller.logger.write(_("Firmware image %s size: %d\n")%(self.firmwareImagePath, self.firmwareImageFileSize))
# Note Pyro exceptions are already caught by catcher_func and PyroCatcher in PyroProxyProxy
# Create the necessary files on the target
self._CreateFirmwareImageFileSizeFile()
self._CreateFirmwareImageFileSizeMD5File()
self._CreateFirmwareImageFileMD5File()
# start the update script
status, textError = self.controller._connector.RunUpdateScript(self.updateType)
if not status :
raise Exception(textError)
# The update script is now running: Feeding the update script with firmware image data
self._RunFeedPipe()
def _CreateFirmwareImageFileSizeFile(self):
# Note Pyro exceptions are already caught by catcher_func and PyroCatcher in PyroProxyProxy
status, textError = self.controller._connector.CreateFirmwareImageFileSizeFile(self.firmwareImageFileSize)
if not status :
raise Exception(textError)
def _CreateFirmwareImageFileSizeMD5File(self):
# Note Pyro exceptions are already caught by catcher_func and PyroCatcher in PyroProxyProxy
self.firmwareImageFileMD5Size = hashlib.md5("%s\n"%self.firmwareImageFileSize).hexdigest()
self.controller.logger.write(_("Firmware image size md5: %s\n")%(self.firmwareImageFileMD5Size))
status, textError = self.controller._connector.CreateFirmwareImageFileSizeMD5File(self.firmwareImageFileMD5Size)
if not status :
raise Exception(textError)
def _CreateFirmwareImageFileMD5File(self):
# Note Pyro exceptions are already caught by catcher_func and PyroCatcher in PyroProxyProxy
self.firmwareImageFileMD5 = hashlib.md5(self.imageData).hexdigest()
self.controller.logger.write(_("Firmware image %s md5: %s\n")%(self.firmwareImagePath, self.firmwareImageFileMD5))
status, textError = self.controller._connector.CreateFirmwareImageFileMD5File(self.firmwareImageFileMD5)
if not status :
raise Exception(textError)
def _RunFeedPipe(self):
# Check if a multiple chunks transfer is needed
if self.firmwareImageFileSize <= self.chunksSize :
# Only a single chunk transfer is needed
isLastChunk = True
chunksSize = self.firmwareImageFileSize
self.controller.logger.write(_("Single chunk transfer\n"))
else:
# Multiple chunks transfer is needed
isLastChunk = False
chunksSize = self.chunksSize
self.controller.logger.write(_("Multiple chunks transfer\n"))
# Start the image transfer
transferedBytes = 0
while transferedBytes < self.firmwareImageFileSize:
# User feedback as percentage
keepGoing, _skip = self.dialog.Update(
transferedBytes * 100 / self.firmwareImageFileSize)
if not keepGoing:
status = False
textError = _("Canceled")
raise Exception(textError)
chunkData = self.imageData[transferedBytes:transferedBytes + chunksSize]
status, textError = self.controller._connector.RunFeedPipe(chunkData, isLastChunk, chunksSize)
if not status :
break
transferedBytes = transferedBytes + chunksSize
# Detect if the next chunk is the last chunk
if (self.firmwareImageFileSize - transferedBytes) <= self.chunksSize:
isLastChunk = True
chunksSize = self.firmwareImageFileSize - transferedBytes
# Check the transfer and the update status
if not status :
raise Exception(textError)
else:
self.dialog.Update(100,_("Firmware update successful."))
self.controller.logger.write(_("Firmware update log: \n\n") + textError + "\nFirmware update successful.\n")
def RebootTarget(self):
self.controller._connector.RebootTarget()