# HG changeset patch # User Tomaz Orac # Date 1592315632 -7200 # Node ID 45f1ff6a7f877b018df7895e48b7c3b86b12de42 # Parent 556935640ec068c53457441dafadf778a666b6ad# Parent 8b612b357679cd074b099c9ab2c59fc99b884206 Merge diff -r 556935640ec0 -r 45f1ff6a7f87 ConfigTreeNode.py --- a/ConfigTreeNode.py Tue Jun 16 11:12:36 2020 +0200 +++ b/ConfigTreeNode.py Tue Jun 16 15:53:52 2020 +0200 @@ -678,6 +678,3 @@ raise UserAddressedException(message) -class UserAddressedException(Exception): - pass - diff -r 556935640ec0 -r 45f1ff6a7f87 POULibrary.py --- a/POULibrary.py Tue Jun 16 11:12:36 2020 +0200 +++ b/POULibrary.py Tue Jun 16 15:53:52 2020 +0200 @@ -26,6 +26,10 @@ from __future__ import absolute_import from weakref import ref +# Exception type for problems that user has to take action in order to fix +class UserAddressedException(Exception): + pass + class POULibrary(object): def __init__(self, CTR, LibName, TypeStack): @@ -59,6 +63,11 @@ # Pure python or IEC libs doesn't produce C code return ((""), [], False), "" + def FatalError(self, message): + """ Raise an exception that will trigger error message intended to + the user, but without backtrace since it is not a software error """ + + raise UserAddressedException(message) def SimplePOULibraryFactory(path): class SimplePOULibrary(POULibrary): diff -r 556935640ec0 -r 45f1ff6a7f87 ProjectController.py --- a/ProjectController.py Tue Jun 16 11:12:36 2020 +0200 +++ b/ProjectController.py Tue Jun 16 15:53:52 2020 +0200 @@ -63,7 +63,8 @@ import targets from runtime.typemapping import DebugTypesSize, UnpackDebugBuffer from runtime import PlcStatus -from ConfigTreeNode import ConfigTreeNode, XSDSchemaErrorMessage, UserAddressedException +from ConfigTreeNode import ConfigTreeNode, XSDSchemaErrorMessage +from POULibrary import UserAddressedException base_folder = paths.AbsParentDir(__file__) @@ -1441,7 +1442,8 @@ PlcStatus.Stopped: {"_Run": True, "_Transfer": True, "_Connect": False, - "_Disconnect": True}, + "_Disconnect": True, + "_Repair": True}, PlcStatus.Empty: {"_Transfer": True, "_Connect": False, "_Disconnect": True}, @@ -1978,6 +1980,13 @@ "shown": False, }, { + "bitmap": "Disconnect", + "name": _("Disconnect"), + "tooltip": _("Disconnect from PLC"), + "method": "_Disconnect", + "shown": False, + }, + { "bitmap": "Repair", "name": _("Repair"), "tooltip": _("Repair broken PLC"), @@ -1985,13 +1994,6 @@ "shown": False, }, { - "bitmap": "Disconnect", - "name": _("Disconnect"), - "tooltip": _("Disconnect from PLC"), - "method": "_Disconnect", - "shown": False, - }, - { "bitmap": "IDManager", "name": _("ID Manager"), "tooltip": _("Manage secure connection identities"), diff -r 556935640ec0 -r 45f1ff6a7f87 runtime/PLCObject.py --- a/runtime/PLCObject.py Tue Jun 16 11:12:36 2020 +0200 +++ b/runtime/PLCObject.py Tue Jun 16 15:53:52 2020 +0200 @@ -451,17 +451,27 @@ self.PythonThreadCond.notify() self.PythonThreadCondLock.release() + def _fail(msg): + self.LogMessage(0, msg) + self.PLCStatus = PlcStatus.Broken + self.StatusChange() + + def PreStartPLC(self): + """ + Here goes actions to be taken just before PLC starts, + with all libraries and python object already created. + For example : restore saved proprietary parameters + """ + pass + @RunInMain def StartPLC(self): - def fail(msg): - self.LogMessage(0, msg) - self.PLCStatus = PlcStatus.Broken - self.StatusChange() - if self.PLClibraryHandle is None: if not self.LoadPLC(): - fail(_("Problem starting PLC : can't load PLC")) + self._fail(_("Problem starting PLC : can't load PLC")) + + self.PreStartPLC() if self.CurrentPLCFilename is not None and self.PLCStatus == PlcStatus.Stopped: c_argv = ctypes.c_char_p * len(self.argv) @@ -472,7 +482,7 @@ self.PythonThreadCommand("Activate") self.LogMessage("PLC started") else: - fail(_("Problem starting PLC : error %d" % res)) + self._fail(_("Problem starting PLC : error %d" % res)) @RunInMain def StopPLC(self): @@ -510,7 +520,7 @@ @RunInMain def SeedBlob(self, seed): blob = (mkstemp(dir=self.tmpdir) + (hashlib.new('md5'),)) - _fobj, _path, md5sum = blob + _fd, _path, md5sum = blob md5sum.update(seed) newBlobID = md5sum.digest() self.blobs[newBlobID] = blob @@ -523,17 +533,17 @@ if blob is None: return None - fobj, _path, md5sum = blob + fd, _path, md5sum = blob md5sum.update(data) newBlobID = md5sum.digest() - os.write(fobj, data) + os.write(fd, data) self.blobs[newBlobID] = blob return newBlobID @RunInMain def PurgeBlobs(self): - for fobj, _path, _md5sum in self.blobs.values(): - os.close(fobj) + for fd, _path, _md5sum in self.blobs.values(): + os.close(fd) self._init_blobs() def _BlobAsFile(self, blobID, newpath): @@ -542,8 +552,11 @@ if blob is None: raise Exception(_("Missing data to create file: {}").format(newpath)) - fobj, path, _md5sum = blob - os.close(fobj) + fd, path, _md5sum = blob + fobj = os.fdopen(fd) + fobj.flush() + os.fsync(fd) + fobj.close() shutil.move(path, newpath) def _extra_files_log_path(self): @@ -599,9 +612,6 @@ # Create new PLC file self._BlobAsFile(plc_object, new_PLC_filename) - # Store new PLC filename based on md5 key - open(self._GetMD5FileName(), "w").write(md5sum) - # Then write the files log = open(extra_files_log, "w") for fname, blobID in extrafiles: @@ -609,6 +619,12 @@ self._BlobAsFile(blobID, fpath) log.write(fname+'\n') + # Store new PLC filename based on md5 key + with open(self._GetMD5FileName(), "w") as f: + f.write(md5sum) + f.flush() + os.fsync(f.fileno()) + # Store new PLC filename self.CurrentPLCFilename = NewFileName except Exception: