diff --git a/revpimodio2/device.py b/revpimodio2/device.py index bc4898a..57ec747 100644 --- a/revpimodio2/device.py +++ b/revpimodio2/device.py @@ -129,6 +129,7 @@ class Device(object): "_offset", "_position", "_producttype", "_selfupdate", \ "_slc_devoff", "_slc_inp", "_slc_inpoff", "_slc_mem", \ "_slc_memoff", "_slc_out", "_slc_outoff", "_shared_procimg", \ + "_shared_write", \ "bmk", "catalognr", "comment", "extend", \ "guid", "id", "inpvariant", "outvariant", "type" @@ -148,6 +149,7 @@ class Device(object): self.__my_io_list = [] self._selfupdate = False self._shared_procimg = parentmodio._shared_procimg + self._shared_write = [] # Wertzuweisung aus dict_device self._name = dict_device.get("name") @@ -511,6 +513,8 @@ class Device(object): :param activate: Set True to activate process image sharing """ + with self._filelock: + self._shared_write.clear() self._shared_procimg = True if activate else False def syncoutputs(self) -> bool: diff --git a/revpimodio2/helper.py b/revpimodio2/helper.py index 3a49896..d80f033 100644 --- a/revpimodio2/helper.py +++ b/revpimodio2/helper.py @@ -536,7 +536,20 @@ class ProcimgWriter(Thread): for dev in self._modio._lst_refresh: with dev._filelock: - if self._modio._monitoring or dev._shared_procimg: + if self._modio._monitoring: + # Inputs und Outputs in Puffer + dev._ba_devdata[:] = bytesbuff[dev._slc_devoff] + if self.__eventwork \ + and len(dev._dict_events) > 0 \ + and dev._ba_datacp != dev._ba_devdata: + self.__check_change(dev) + + elif dev._shared_procimg: + for io in dev._shared_write: + if not io._write_to_procimg(): + raise IOError("error on _write_to_procimg") + dev._shared_write.clear() + # Inputs und Outputs in Puffer dev._ba_devdata[:] = bytesbuff[dev._slc_devoff] if self.__eventwork \ diff --git a/revpimodio2/io.py b/revpimodio2/io.py index b9ac368..c0fb554 100644 --- a/revpimodio2/io.py +++ b/revpimodio2/io.py @@ -532,6 +532,80 @@ class IOBase(object): raise ValueError("Value must be ") self._export = 2 + int(value) + def _write_to_procimg(self) -> bool: + """ + Write value of io directly to the process image. + + :return: True after successful write operation + """ + if not self._parentdevice._shared_procimg: + raise RuntimeError("device is not marked for shared_procimg") + + # note: Will not be removed from _shared_write on direct call + + if self._bitshift: + # Write single bit to process image + value = \ + self._parentdevice._ba_devdata[self._slc_address.start] & \ + self._bitshift + if self._parentdevice._modio._run_on_pi: + # IOCTL auf dem RevPi + with self._parentdevice._modio._myfh_lck: + try: + # Set value durchführen (Funktion K+16) + ioctl( + self._parentdevice._modio._myfh, + 19216, + self.__bit_ioctl_on if value + else self.__bit_ioctl_off + ) + except Exception as e: + self._parentdevice._modio._gotioerror("ioset", e) + return False + + elif hasattr(self._parentdevice._modio._myfh, "ioctl"): + # IOCTL über Netzwerk + with self._parentdevice._modio._myfh_lck: + try: + self._parentdevice._modio._myfh.ioctl( + 19216, + self.__bit_ioctl_on if value + else self.__bit_ioctl_off + ) + except Exception as e: + self._parentdevice._modio._gotioerror( + "net_ioset", e) + return False + + else: + # IOCTL in Datei simulieren + try: + # Set value durchführen (Funktion K+16) + self._parentdevice._modio._simulate_ioctl( + 19216, + self.__bit_ioctl_on if value + else self.__bit_ioctl_off + ) + except Exception as e: + self._parentdevice._modio._gotioerror("file_ioset", e) + return False + + else: + value = bytes(self._parentdevice._ba_devdata[self._slc_address]) + with self._parentdevice._modio._myfh_lck: + try: + self._parentdevice._modio._myfh.seek( + self._get_address() + ) + self._parentdevice._modio._myfh.write(value) + if self._parentdevice._modio._buffedwrite: + self._parentdevice._modio._myfh.flush() + except IOError as e: + self._parentdevice._modio._gotioerror("ioset", e) + return False + + return True + def get_defaultvalue(self): """ Gibt die Defaultvalue von piCtory zurueck. @@ -624,54 +698,14 @@ class IOBase(object): # Versuchen egal welchen Typ in Bool zu konvertieren value = bool(value) - if self._parentdevice._shared_procimg: - # Direktes Schreiben der Outputs - - if self._parentdevice._modio._run_on_pi: - # IOCTL auf dem RevPi - with self._parentdevice._modio._myfh_lck: - try: - # Set value durchführen (Funktion K+16) - ioctl( - self._parentdevice._modio._myfh, - 19216, - self.__bit_ioctl_on if value - else self.__bit_ioctl_off - ) - except Exception as e: - self._parentdevice._modio._gotioerror("ioset", e) - return - - elif hasattr(self._parentdevice._modio._myfh, "ioctl"): - # IOCTL über Netzwerk - with self._parentdevice._modio._myfh_lck: - try: - self._parentdevice._modio._myfh.ioctl( - 19216, - self.__bit_ioctl_on if value - else self.__bit_ioctl_off - ) - except Exception as e: - self._parentdevice._modio._gotioerror( - "net_ioset", e) - return - - else: - # IOCTL in Datei simulieren - try: - # Set value durchführen (Funktion K+16) - self._parentdevice._modio._simulate_ioctl( - 19216, - self.__bit_ioctl_on if value - else self.__bit_ioctl_off - ) - except Exception as e: - self._parentdevice._modio._gotioerror("file_ioset", e) - return - # Für Bitoperationen sperren self._parentdevice._filelock.acquire() + if self._parentdevice._shared_procimg \ + and self not in self._parentdevice._shared_write: + # Mark this IO for write operations + self._parentdevice._shared_write.append(self) + # Hier gibt es immer nur ein byte, als int holen int_byte = self._parentdevice._ba_devdata[self._slc_address.start] @@ -704,18 +738,11 @@ class IOBase(object): ) ) - if self._parentdevice._shared_procimg: - with self._parentdevice._modio._myfh_lck: - try: - self._parentdevice._modio._myfh.seek( - self._get_address() - ) - self._parentdevice._modio._myfh.write(value) - if self._parentdevice._modio._buffedwrite: - self._parentdevice._modio._myfh.flush() - except IOError as e: - self._parentdevice._modio._gotioerror("ioset", e) - return + if self._parentdevice._shared_procimg \ + and self not in self._parentdevice._shared_write: + with self._parentdevice._filelock: + # Mark this IO as changed + self._parentdevice._shared_write.append(self) self._parentdevice._ba_devdata[self._slc_address] = value diff --git a/revpimodio2/modio.py b/revpimodio2/modio.py index 9dc87f4..0553dab 100644 --- a/revpimodio2/modio.py +++ b/revpimodio2/modio.py @@ -1227,13 +1227,21 @@ class RevPiModIO(object): mylist = [dev] global_ex = None - workokay = True for dev in mylist: - if dev._shared_procimg: + if dev._selfupdate: + # Do not update this device continue - elif not dev._selfupdate: - dev._filelock.acquire() + dev._filelock.acquire() + + if dev._shared_procimg: + for io in dev._shared_write: + if not io._write_to_procimg(): + global_ex = IOError( + "error on shared procimg while write" + ) + dev._shared_write.clear() + else: # Outpus auf Bus schreiben self._myfh_lck.acquire() try: @@ -1241,23 +1249,22 @@ class RevPiModIO(object): self._myfh.write(dev._ba_devdata[dev._slc_out]) except IOError as e: global_ex = e - workokay = False finally: self._myfh_lck.release() - dev._filelock.release() + dev._filelock.release() if self._buffedwrite: try: self._myfh.flush() except IOError as e: global_ex = e - workokay = False - if not workokay: + if global_ex: self._gotioerror("writeprocimg", global_ex) + return False - return workokay + return True debug = property(_get_debug, _set_debug) configrsc = property(_get_configrsc) diff --git a/setup.py b/setup.py index 7d695f6..df503b9 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ setup( license="LGPLv3", name="revpimodio2", - version="2.5.5", + version="2.5.5a", packages=["revpimodio2"], python_requires="~=3.2",