lpcmanager

Parents d235774932fa
Children f8f43d6ab8b5
Added files in runtime folder from beremiz runtime and HostFirmwareUpdater from beremiz to LPCManager.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/HostFirmwareUpdater.py Wed Jan 25 11:00:27 2017 +0100
@@ -0,0 +1,154 @@
+#!/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
+import threading
+from time import sleep
+import wx
+
+TARGET_UPDATE_SCRIPT = "/opt/beremiz/update.sh"
+WAIT_BEFORE_FEED_SEC = 5
+UPDATE_SCRIPT_TIMEOUT = 600
+
+class HostFirmwareUpdater(object):
+
+ # Create a new HostFirmwareUpdater
+ def __init__(self, _connector, firmwareImagePath, updateType, chunksSize, reboot, logger):
+ self.Reset()
+ self._connector = _connector
+ self.firmwareImagePath = firmwareImagePath
+ self.updateType = updateType
+ self.chunksSize = chunksSize
+ self.reboot = reboot
+ self.logger = logger
+ self.logger.write(_("HostFirmwareUpdater init.\n"))
+ self.threadUpdateScript = None
+ self.runUpdateScriptStatus = None
+ self.runUpdateScriptTextError = None
+
+ # Reset HostFirmwareUpdater internal variables
+ def Reset(self):
+ self.Running = 0
+
+ def update(self):
+ self.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.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()
+ # Create and start the thread for the update script
+ self.threadUpdateScript = threading.Thread(target=self._RunUpdateScript)
+ self.threadUpdateScript.start()
+ # Waiting some time for the update script launching
+ self.logger.write(_("Waiting %s s until the update script is running...\n")%WAIT_BEFORE_FEED_SEC)
+ sleep(WAIT_BEFORE_FEED_SEC)
+ # The update script is now running: Feeding the update script with firmware image data
+ self._RunFeedPipe()
+ # Wait the end of the script
+ self.threadUpdateScript.join(timeout = UPDATE_SCRIPT_TIMEOUT)
+ # Here, the update is successful, reboot?
+ if self.reboot:
+ self._RebootTarget()
+
+ def _CreateFirmwareImageFileSizeFile(self):
+ # Note Pyro exceptions are already caught by catcher_func and PyroCatcher in PyroProxyProxy
+ status, textError = self._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.logger.write(_("Firmware image size md5: %s\n")%(self.firmwareImageFileMD5Size))
+ status, textError = self._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.logger.write(_("Firmware image %s md5: %s\n")%(self.firmwareImagePath, self.firmwareImageFileMD5))
+ status, textError = self._connector.CreateFirmwareImageFileMD5File(self.firmwareImageFileMD5)
+ if not status :
+ raise Exception(textError)
+
+ def _RunUpdateScript(self):
+ # Put the update script run status in class attributes because,
+ # since we are in a child thread, exceptions thrown in this one are painful to catch.
+ # The update script run status will be checked on joining this thread.
+ self.runUpdateScriptStatus, self.runUpdateScriptTextError = self._connector.RunUpdateScript(self.updateType)
+
+ 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.logger.write(_("Single chunk transfer\n"))
+ else:
+ # Multiple chunks transfer is needed
+ isLastChunk = False
+ chunksSize = self.chunksSize
+ self.logger.write(_("Multiple chunks transfer\n"))
+
+ # Start the image transfer
+ transferedBytes = 0
+ while transferedBytes < self.firmwareImageFileSize:
+ chunkData = self.imageData[transferedBytes:transferedBytes + chunksSize]
+ self.logger.write(_("Transfer chunk, size: %d\n")%(chunksSize))
+ status, textError = self._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 :
+ if self.runUpdateScriptTextError != "" and not self.runUpdateScriptStatus:
+ textError = "Update script message: " + self.runUpdateScriptTextError + "\n" + textError
+ raise Exception(textError)
+ else:
+ self.logger.write(_("Firmware update log: \n\n") + textError + "\nFirmware update successful.")
+
+ def _RebootTarget(self):
+ self._connector.RebootTarget()