From 8e42527cd0e8e5a0067d5f06fd0fd1d989213a8d Mon Sep 17 00:00:00 2001 From: kellergoech <38539019+kellergoech@users.noreply.github.com> Date: Thu, 9 Apr 2026 11:25:36 +0200 Subject: [PATCH 01/10] Add shared_procimg to run_plc function Shared Procimg can now also be actrivated when using the run_plc function --- src/revpimodio2/modio.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/revpimodio2/modio.py b/src/revpimodio2/modio.py index ff7fa47..046e0ee 100644 --- a/src/revpimodio2/modio.py +++ b/src/revpimodio2/modio.py @@ -1530,7 +1530,7 @@ class RevPiModIODriver(RevPiModIOSelected): ) -def run_plc(func, cycletime=50, replace_io_file=None, debug=True, procimg=None, configrsc=None): +def run_plc(func, cycletime=50, replace_io_file=None, debug=True, procimg=None, configrsc=None, shared_procimg=False): """ Run Revoluton Pi as real plc with cycle loop and exclusive IO access. @@ -1557,6 +1557,7 @@ def run_plc(func, cycletime=50, replace_io_file=None, debug=True, procimg=None, debug=debug, procimg=procimg, configrsc=configrsc, + shared_procimg=shared_procimg ) rpi.handlesignalend() return rpi.cycleloop(func, cycletime) From 79dd172f3111ac440a1f7ce665215f96738694fc Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Wed, 17 Apr 2024 07:15:05 +0200 Subject: [PATCH 02/10] feat: Add counter reset function to the MIO module Due to the new firmware 1.10 on the MIO module, the GPIOs that were configured as counters can now also be reset to 0. With this change, the .reset() function in RevPiModIO is added to the respective counter IOs. --- src/revpimodio2/device.py | 23 +++++++++++++++++++++-- src/revpimodio2/modio.py | 3 +++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/revpimodio2/device.py b/src/revpimodio2/device.py index 7f24cbc..347024a 100644 --- a/src/revpimodio2/device.py +++ b/src/revpimodio2/device.py @@ -354,8 +354,10 @@ class Device(object): elif bool(dict_io[key][7]): # Use IOBase for bit values io_new = IOBase(self, dict_io[key], iotype, "little", False) - elif isinstance(self, DioModule) and dict_io[key][3] in self._lst_counter: - # Counter IO on a DI or DIO + elif (isinstance(self, DioModule) or isinstance(self, MioModule)) and dict_io[key][ + 3 + ] in self._lst_counter: + # Counter IO on a DI, DIO or MIO module io_new = IntIOCounter( self._lst_counter.index(dict_io[key][3]), self, @@ -2030,6 +2032,23 @@ class DioModule(Device): super().__init__(parentmodio, dict_device, simulator=simulator) +class MioModule(Device): + """Represents a MIO module.""" + + __slots__ = "_lst_counter" + + def __init__(self, parentmodio, dict_device, simulator=False): + """ + Extended device class to recognize IntIOCounter. + + :rev: :func:`Device.__init__()` + """ + # String list of byte addresses that are a counter. + self._lst_counter = list(map(str, range(9, 17, 2))) + + super().__init__(parentmodio, dict_device, simulator=simulator) + + class RoModule(Device): """Relais output (RO) module with""" diff --git a/src/revpimodio2/modio.py b/src/revpimodio2/modio.py index 046e0ee..a34f0de 100644 --- a/src/revpimodio2/modio.py +++ b/src/revpimodio2/modio.py @@ -403,6 +403,9 @@ class RevPiModIO(object): elif pt == ProductType.RO: # RO dev_new = devicemodule.RoModule(self, device, simulator=self._simulator) + elif pt == ProductType.MIO: + # MIO + dev_new = devicemodule.MioModule(self, device, simulator=self._simulator) else: # All other IO devices dev_new = devicemodule.Device(self, device, simulator=self._simulator) From b4d23d4e8e6819e4df113fbd9b60b0a78ec5a397 Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Fri, 28 Aug 2026 12:24:36 +0200 Subject: [PATCH 03/10] style: Format code with black Signed-off-by: Sven Sager --- src/revpimodio2/__about__.py | 1 + src/revpimodio2/__init__.py | 1 + src/revpimodio2/_internal.py | 1 + src/revpimodio2/app.py | 1 + src/revpimodio2/device.py | 1 + src/revpimodio2/errors.py | 1 + src/revpimodio2/helper.py | 1 + src/revpimodio2/io.py | 1 + src/revpimodio2/modio.py | 13 +++++++++++-- src/revpimodio2/netio.py | 1 + src/revpimodio2/pictory.py | 1 + src/revpimodio2/summary.py | 1 + 12 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/revpimodio2/__about__.py b/src/revpimodio2/__about__.py index cc03ee0..15aaeef 100644 --- a/src/revpimodio2/__about__.py +++ b/src/revpimodio2/__about__.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- """Metadata of package.""" + __author__ = "Sven Sager " __copyright__ = "Copyright (C) 2023 Sven Sager" __license__ = "LGPLv2" diff --git a/src/revpimodio2/__init__.py b/src/revpimodio2/__init__.py index 656c4a4..ff6f8fe 100644 --- a/src/revpimodio2/__init__.py +++ b/src/revpimodio2/__init__.py @@ -12,6 +12,7 @@ With the defined names, the desired data is accessed directly. The user can register functions as events for all IOs. The module executes these when data changes. """ + __all__ = [ "IOEvent", "RevPiModIO", diff --git a/src/revpimodio2/_internal.py b/src/revpimodio2/_internal.py index afb2b82..d14ddc3 100644 --- a/src/revpimodio2/_internal.py +++ b/src/revpimodio2/_internal.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- """Internal functions and values for this package.""" + __author__ = "Sven Sager" __copyright__ = "Copyright (C) 2023 Sven Sager" __license__ = "LGPLv2" diff --git a/src/revpimodio2/app.py b/src/revpimodio2/app.py index 446e9c7..b7234ed 100644 --- a/src/revpimodio2/app.py +++ b/src/revpimodio2/app.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- """Maps the App section from piCtory.""" + __author__ = "Sven Sager" __copyright__ = "Copyright (C) 2023 Sven Sager" __license__ = "LGPLv2" diff --git a/src/revpimodio2/device.py b/src/revpimodio2/device.py index 347024a..15d34e7 100644 --- a/src/revpimodio2/device.py +++ b/src/revpimodio2/device.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- """Module for managing devices.""" + __author__ = "Sven Sager" __copyright__ = "Copyright (C) 2023 Sven Sager" __license__ = "LGPLv2" diff --git a/src/revpimodio2/errors.py b/src/revpimodio2/errors.py index 121ab3e..da225a3 100644 --- a/src/revpimodio2/errors.py +++ b/src/revpimodio2/errors.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- """Error classes of RevPiModIO.""" + __author__ = "Sven Sager" __copyright__ = "Copyright (C) 2023 Sven Sager" __license__ = "LGPLv2" diff --git a/src/revpimodio2/helper.py b/src/revpimodio2/helper.py index ba415a5..9f5a1e7 100644 --- a/src/revpimodio2/helper.py +++ b/src/revpimodio2/helper.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- """RevPiModIO helper classes and tools.""" + __author__ = "Sven Sager" __copyright__ = "Copyright (C) 2023 Sven Sager" __license__ = "LGPLv2" diff --git a/src/revpimodio2/io.py b/src/revpimodio2/io.py index 130e9f6..e7ca912 100644 --- a/src/revpimodio2/io.py +++ b/src/revpimodio2/io.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- """RevPiModIO module for managing IOs.""" + __author__ = "Sven Sager" __copyright__ = "Copyright (C) 2023 Sven Sager" __license__ = "LGPLv2" diff --git a/src/revpimodio2/modio.py b/src/revpimodio2/modio.py index a34f0de..0683759 100644 --- a/src/revpimodio2/modio.py +++ b/src/revpimodio2/modio.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- """RevPiModIO main class for piControl0 access.""" + __author__ = "Sven Sager" __copyright__ = "Copyright (C) 2023 Sven Sager" __license__ = "LGPLv2" @@ -1533,7 +1534,15 @@ class RevPiModIODriver(RevPiModIOSelected): ) -def run_plc(func, cycletime=50, replace_io_file=None, debug=True, procimg=None, configrsc=None, shared_procimg=False): +def run_plc( + func, + cycletime=50, + replace_io_file=None, + debug=True, + procimg=None, + configrsc=None, + shared_procimg=False, +): """ Run Revoluton Pi as real plc with cycle loop and exclusive IO access. @@ -1560,7 +1569,7 @@ def run_plc(func, cycletime=50, replace_io_file=None, debug=True, procimg=None, debug=debug, procimg=procimg, configrsc=configrsc, - shared_procimg=shared_procimg + shared_procimg=shared_procimg, ) rpi.handlesignalend() return rpi.cycleloop(func, cycletime) diff --git a/src/revpimodio2/netio.py b/src/revpimodio2/netio.py index 0d56db9..422d8c5 100644 --- a/src/revpimodio2/netio.py +++ b/src/revpimodio2/netio.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- """RevPiModIO main class for network access.""" + __author__ = "Sven Sager" __copyright__ = "Copyright (C) 2023 Sven Sager" __license__ = "LGPLv2" diff --git a/src/revpimodio2/pictory.py b/src/revpimodio2/pictory.py index b8d1839..e746753 100644 --- a/src/revpimodio2/pictory.py +++ b/src/revpimodio2/pictory.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- """Pictory aliases for IO values.""" + __author__ = "Théo Rozier" __copyright__ = "Copyright (C) 2023 Sven Sager" __license__ = "LGPLv2" diff --git a/src/revpimodio2/summary.py b/src/revpimodio2/summary.py index 51e34da..ad8c1dd 100644 --- a/src/revpimodio2/summary.py +++ b/src/revpimodio2/summary.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- """Maps the Summary section from piCtory.""" + __author__ = "Sven Sager" __copyright__ = "Copyright (C) 2023 Sven Sager" __license__ = "LGPLv2" From 18773b0fa2686db7d9fa0dd00069d88914f70598 Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Fri, 28 Aug 2026 12:29:38 +0200 Subject: [PATCH 04/10] chore: Increase to RC1 of upcoming Release 2.9.0 Signed-off-by: Sven Sager --- src/revpimodio2/__about__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/revpimodio2/__about__.py b/src/revpimodio2/__about__.py index 15aaeef..1a22831 100644 --- a/src/revpimodio2/__about__.py +++ b/src/revpimodio2/__about__.py @@ -4,4 +4,4 @@ __author__ = "Sven Sager " __copyright__ = "Copyright (C) 2023 Sven Sager" __license__ = "LGPLv2" -__version__ = "2.8.1" +__version__ = "2.9.0rc1" From a347620a584e7899748739eaec8187975f0b3d24 Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Tue, 1 Sep 2026 07:50:26 +0200 Subject: [PATCH 05/10] fix: Update `reset` method to return a boolean indicating success Signed-off-by: Sven Sager --- src/revpimodio2/io.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/revpimodio2/io.py b/src/revpimodio2/io.py index e7ca912..2a05b16 100644 --- a/src/revpimodio2/io.py +++ b/src/revpimodio2/io.py @@ -1131,8 +1131,12 @@ class IntIOCounter(IntIO): # Load base class super().__init__(parentdevice, valuelist, iotype, byteorder, signed) - def reset(self) -> None: - """Resets the counter of the input.""" + def reset(self) -> bool: + """ + Resets the counter of the input. + + :return: True if reset was successful, False otherwise + """ if self._parentdevice._modio._monitoring: raise RuntimeError("can not reset counter, while system is in monitoring mode") if self._parentdevice._modio._simulator: @@ -1146,6 +1150,7 @@ class IntIOCounter(IntIO): ioctl(self._parentdevice._modio._myfh, 19220, self.__ioctl_arg) except Exception as e: self._parentdevice._modio._gotioerror("iorst", e) + return False elif hasattr(self._parentdevice._modio._myfh, "ioctl"): # IOCTL over network @@ -1154,6 +1159,7 @@ class IntIOCounter(IntIO): self._parentdevice._modio._myfh.ioctl(19220, self.__ioctl_arg) except Exception as e: self._parentdevice._modio._gotioerror("net_iorst", e) + return False else: # Simulate IOCTL in file @@ -1162,6 +1168,9 @@ class IntIOCounter(IntIO): self._parentdevice._modio._simulate_ioctl(19220, self.__ioctl_arg) except Exception as e: self._parentdevice._modio._gotioerror("file_iorst", e) + return False + + return True class IntIOReplaceable(IntIO): From f86527b5fd8ecd8c054d4510918dcc1be21481e0 Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Tue, 1 Sep 2026 08:36:26 +0200 Subject: [PATCH 06/10] feat: Return -1 to indicate an error in `get_switching_cycles` method The old behavior was the return of the maximum value. However, this can also be a valid value. Now all positive values are valid and a negative value of -1 describes an error in the query. close #37 Signed-off-by: Sven Sager --- src/revpimodio2/io.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/revpimodio2/io.py b/src/revpimodio2/io.py index 2a05b16..e153233 100644 --- a/src/revpimodio2/io.py +++ b/src/revpimodio2/io.py @@ -1285,7 +1285,8 @@ class RelaisOutput(IOBase): This function is only available locally on a Revolution Pi. This function cannot be used via RevPiNetIO. - :return: Integer of switching cycles as single value or tuple of all + :return: Integer of switching cycles as single value or tuple of all. The + value -1 indicates an error. """ # Using ioctl request K+29 = 19229 if self._parentdevice._modio._run_on_pi: @@ -1298,10 +1299,14 @@ class RelaisOutput(IOBase): self.__ioctl_arg, ) except Exception as e: - # If not implemented, we return the max value and set an error - ioctl_return_value = b"\xff" * struct.calcsize(self.__ioctl_arg_format) self._parentdevice._modio._gotioerror("rocounter", e) + # To report an error, return -1 values + if self._bitaddress == -1: + return -1, -1, -1, -1 + else: + return -1 + elif hasattr(self._parentdevice._modio._myfh, "ioctl"): # IOCTL over network """ From 15b8d037728bcf675c2d65824121e1a57da3c983 Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Tue, 1 Sep 2026 08:36:40 +0200 Subject: [PATCH 07/10] test: Return -1 to indicate an error in `get_switching_cycles` method The old behavior was the return of the maximum value. However, this can also be a valid value. Now all positive values are valid and a negative value of -1 describes an error in the query. Signed-off-by: Sven Sager --- tests/io_tests/config_ro_multi.rsc | 309 ++++++++++++++++++++++++++++ tests/io_tests/config_ro_single.rsc | 239 +++++++++++++++++++++ tests/io_tests/test_ios.py | 27 +++ 3 files changed, 575 insertions(+) create mode 100644 tests/io_tests/config_ro_multi.rsc create mode 100644 tests/io_tests/config_ro_single.rsc diff --git a/tests/io_tests/config_ro_multi.rsc b/tests/io_tests/config_ro_multi.rsc new file mode 100644 index 0000000..d58b8bc --- /dev/null +++ b/tests/io_tests/config_ro_multi.rsc @@ -0,0 +1,309 @@ +{ + "App": { + "name": "PiCtory", + "version": "2.17.3", + "saveTS": "20260901080641", + "language": "en", + "layout": { + "north": { + "size": 70, + "initClosed": false, + "initHidden": false + }, + "south": { + "size": 353, + "initClosed": false, + "initHidden": false, + "children": { + "layout1": { + "east": { + "size": 500, + "initClosed": false, + "initHidden": false + } + } + } + }, + "east": { + "size": 70, + "initClosed": true, + "initHidden": false, + "children": {} + }, + "west": { + "size": 340, + "initClosed": false, + "initHidden": false, + "children": { + "layout1": {} + } + } + } + }, + "Summary": { + "inpTotal": 7, + "outTotal": 8 + }, + "Devices": [ + { + "GUID": "fa3b69a8-77f1-7f15-d9f0-339646253ace", + "id": "device_RevPiConnect5_20240315_1_0_001", + "type": "BASE", + "productType": "138", + "position": "0", + "name": "RevPi Connect 5", + "bmk": "RevPi Connect 5", + "inpVariant": 0, + "outVariant": 0, + "comment": "This is a RevPi Connect 5 Device", + "offset": 0, + "inp": { + "0": [ + "RevPiStatus", + "0", + "8", + "0", + true, + "0000", + "", + "" + ], + "1": [ + "RevPiIOCycle", + "0", + "8", + "1", + true, + "0001", + "", + "" + ], + "2": [ + "RS485ErrorCnt", + "0", + "16", + "2", + false, + "0002", + "", + "" + ], + "3": [ + "Core_Temperature", + "0", + "8", + "4", + false, + "0003", + "", + "" + ], + "4": [ + "Core_Frequency", + "0", + "8", + "5", + false, + "0004", + "", + "" + ] + }, + "out": { + "0": [ + "RevPiReservedByte", + "0", + "8", + "6", + false, + "0005", + "", + "" + ], + "1": [ + "RS485ErrorLimit1", + "10", + "16", + "7", + false, + "0006", + "", + "" + ], + "2": [ + "RS485ErrorLimit2", + "1000", + "16", + "9", + false, + "0007", + "", + "" + ], + "3": [ + "RevPiLED", + "0", + "16", + "11", + true, + "0008", + "", + "" + ] + }, + "mem": {}, + "extend": {} + }, + { + "GUID": "53c792e0-ec3d-8047-bb0c-1afa6772873f", + "id": "device_RevPiRO_20231018_1_0_001", + "type": "LEFT_RIGHT", + "productType": "137", + "position": "32", + "name": "RevPi RO", + "bmk": "RevPi RO", + "inpVariant": 0, + "outVariant": 0, + "comment": "", + "offset": 13, + "inp": { + "0": [ + "Status", + "0", + "8", + "0", + false, + "0000", + "", + "" + ] + }, + "out": { + "0": [ + "RelayOutput_1", + "0", + "1", + "1", + true, + "0001", + "", + "0" + ], + "1": [ + "RelayOutput_2", + "0", + "1", + "1", + true, + "0002", + "", + "1" + ], + "2": [ + "RelayOutput_3", + "0", + "1", + "1", + true, + "0003", + "", + "2" + ], + "3": [ + "RelayOutput_4", + "0", + "1", + "1", + true, + "0004", + "", + "3" + ], + "4": [ + "RelayOutputPadding_5", + "0", + "1", + "1", + true, + "0005", + "", + "4" + ], + "5": [ + "RelayOutputPadding_6", + "0", + "1", + "1", + true, + "0006", + "", + "5" + ], + "6": [ + "RelayOutputPadding_7", + "0", + "1", + "1", + true, + "0007", + "", + "6" + ], + "7": [ + "RelayOutputPadding_8", + "0", + "1", + "1", + true, + "0008", + "", + "7" + ] + }, + "mem": { + "0": [ + "RelayCycleWarningThreshold_1", + "0", + "32", + "2", + false, + "0009", + "", + "" + ], + "1": [ + "RelayCycleWarningThreshold_2", + "0", + "32", + "6", + false, + "0010", + "", + "" + ], + "2": [ + "RelayCycleWarningThreshold_3", + "0", + "32", + "10", + false, + "0011", + "", + "" + ], + "3": [ + "RelayCycleWarningThreshold_4", + "0", + "32", + "14", + false, + "0012", + "", + "" + ] + }, + "extend": {} + } + ], + "Connections": [] +} diff --git a/tests/io_tests/config_ro_single.rsc b/tests/io_tests/config_ro_single.rsc new file mode 100644 index 0000000..a899aca --- /dev/null +++ b/tests/io_tests/config_ro_single.rsc @@ -0,0 +1,239 @@ +{ + "App": { + "name": "PiCtory", + "version": "2.17.3", + "saveTS": "20260901080758", + "language": "en", + "layout": { + "north": { + "size": 70, + "initClosed": false, + "initHidden": false + }, + "south": { + "size": 353, + "initClosed": false, + "initHidden": false, + "children": { + "layout1": { + "east": { + "size": 500, + "initClosed": false, + "initHidden": false + } + } + } + }, + "east": { + "size": 70, + "initClosed": true, + "initHidden": false, + "children": {} + }, + "west": { + "size": 340, + "initClosed": false, + "initHidden": false, + "children": { + "layout1": {} + } + } + } + }, + "Summary": { + "inpTotal": 7, + "outTotal": 8 + }, + "Devices": [ + { + "GUID": "fa3b69a8-77f1-7f15-d9f0-339646253ace", + "id": "device_RevPiConnect5_20240315_1_0_001", + "type": "BASE", + "productType": "138", + "position": "0", + "name": "RevPi Connect 5", + "bmk": "RevPi Connect 5", + "inpVariant": 0, + "outVariant": 0, + "comment": "This is a RevPi Connect 5 Device", + "offset": 0, + "inp": { + "0": [ + "RevPiStatus", + "0", + "8", + "0", + true, + "0000", + "", + "" + ], + "1": [ + "RevPiIOCycle", + "0", + "8", + "1", + true, + "0001", + "", + "" + ], + "2": [ + "RS485ErrorCnt", + "0", + "16", + "2", + false, + "0002", + "", + "" + ], + "3": [ + "Core_Temperature", + "0", + "8", + "4", + false, + "0003", + "", + "" + ], + "4": [ + "Core_Frequency", + "0", + "8", + "5", + false, + "0004", + "", + "" + ] + }, + "out": { + "0": [ + "RevPiReservedByte", + "0", + "8", + "6", + false, + "0005", + "", + "" + ], + "1": [ + "RS485ErrorLimit1", + "10", + "16", + "7", + false, + "0006", + "", + "" + ], + "2": [ + "RS485ErrorLimit2", + "1000", + "16", + "9", + false, + "0007", + "", + "" + ], + "3": [ + "RevPiLED", + "0", + "16", + "11", + true, + "0008", + "", + "" + ] + }, + "mem": {}, + "extend": {} + }, + { + "GUID": "53c792e0-ec3d-8047-bb0c-1afa6772873f", + "id": "device_RevPiRO_20231018_1_0_001", + "type": "LEFT_RIGHT", + "productType": "137", + "position": "32", + "name": "RevPi RO", + "bmk": "RevPi RO", + "inpVariant": 0, + "outVariant": 1, + "comment": "", + "offset": 13, + "inp": { + "0": [ + "Status_i02", + "0", + "8", + "0", + false, + "0000", + "", + "" + ] + }, + "out": { + "0": [ + "RelayOutputs", + "0", + "8", + "1", + true, + "0001", + "", + "" + ] + }, + "mem": { + "0": [ + "RelayCycleWarningThreshold_1_i02", + "0", + "32", + "2", + false, + "0002", + "", + "" + ], + "1": [ + "RelayCycleWarningThreshold_2_i02", + "0", + "32", + "6", + false, + "0003", + "", + "" + ], + "2": [ + "RelayCycleWarningThreshold_3_i02", + "0", + "32", + "10", + false, + "0004", + "", + "" + ], + "3": [ + "RelayCycleWarningThreshold_4_i02", + "0", + "32", + "14", + false, + "0005", + "", + "" + ] + }, + "extend": {} + } + ], + "Connections": [] +} diff --git a/tests/io_tests/test_ios.py b/tests/io_tests/test_ios.py index c8488b1..edd36fb 100644 --- a/tests/io_tests/test_ios.py +++ b/tests/io_tests/test_ios.py @@ -105,3 +105,30 @@ class TestIos(TestRevPiModIO): self.assertEqual(rpi.device[65]._ba_devdata[32:38], b"\x20\x00\x00\x00\x00\x00") rpi.io.OutBit_48.value = True self.assertEqual(rpi.device[65]._ba_devdata[32:38], b"\x20\x00\x00\x00\x00\x80") + + def test_get_switching_cycles(self): + rpi = self.modio(configrsc="config_ro_multi.rsc") + self.assertEqual(rpi.io.RelayOutput_1.get_switching_cycles(), 0) + self.assertEqual(rpi.io.RelayOutput_2.get_switching_cycles(), 0) + self.assertEqual(rpi.io.RelayOutput_3.get_switching_cycles(), 0) + self.assertEqual(rpi.io.RelayOutput_4.get_switching_cycles(), 0) + + # This will use ioctl calls + rpi._run_on_pi = True + + with self.assertWarnsRegex(RuntimeWarning, r"'rocounter' and count \d"): + self.assertEqual(rpi.io.RelayOutput_1.get_switching_cycles(), -1) + self.assertEqual(rpi.io.RelayOutput_2.get_switching_cycles(), -1) + self.assertEqual(rpi.io.RelayOutput_3.get_switching_cycles(), -1) + self.assertEqual(rpi.io.RelayOutput_4.get_switching_cycles(), -1) + self.assertEqual(rpi.ioerrors, 4) + + rpi = self.modio(configrsc="config_ro_single.rsc") + self.assertEqual(rpi.io.RelayOutputs.get_switching_cycles(), (0, 0, 0, 0)) + + # This will use ioctl calls + rpi._run_on_pi = True + + with self.assertWarnsRegex(RuntimeWarning, r"'rocounter' and count \d"): + self.assertEqual(rpi.io.RelayOutputs.get_switching_cycles(), (-1, -1, -1, -1)) + self.assertEqual(rpi.ioerrors, 1) From 7fbf32f61068582ae06c24a4634520424fbb1790 Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Tue, 1 Sep 2026 08:40:41 +0200 Subject: [PATCH 08/10] chore: Update IDE configuration for Black formatting tool integration Signed-off-by: Sven Sager --- .idea/misc.xml | 3 --- .idea/pyLspTools.xml | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 .idea/pyLspTools.xml diff --git a/.idea/misc.xml b/.idea/misc.xml index ada67d1..b35f69e 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,9 +1,6 @@ - diff --git a/.idea/pyLspTools.xml b/.idea/pyLspTools.xml new file mode 100644 index 0000000..400aa9d --- /dev/null +++ b/.idea/pyLspTools.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file From 01729506cb06c5456579ec10dbf603b3aa5e09fc Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Tue, 1 Sep 2026 08:40:55 +0200 Subject: [PATCH 09/10] chore: Increase to RC2 of upcoming Release 2.9.0 Signed-off-by: Sven Sager --- src/revpimodio2/__about__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/revpimodio2/__about__.py b/src/revpimodio2/__about__.py index 1a22831..af3612d 100644 --- a/src/revpimodio2/__about__.py +++ b/src/revpimodio2/__about__.py @@ -4,4 +4,4 @@ __author__ = "Sven Sager " __copyright__ = "Copyright (C) 2023 Sven Sager" __license__ = "LGPLv2" -__version__ = "2.9.0rc1" +__version__ = "2.9.0rc2" From e54a1ccffc89fa2795c2ee1af2fcdc6eb13ee1bc Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Tue, 1 Sep 2026 13:49:42 +0200 Subject: [PATCH 10/10] chore: Bump version to 2.9.0 Signed-off-by: Sven Sager --- src/revpimodio2/__about__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/revpimodio2/__about__.py b/src/revpimodio2/__about__.py index af3612d..01a540c 100644 --- a/src/revpimodio2/__about__.py +++ b/src/revpimodio2/__about__.py @@ -4,4 +4,4 @@ __author__ = "Sven Sager " __copyright__ = "Copyright (C) 2023 Sven Sager" __license__ = "LGPLv2" -__version__ = "2.9.0rc2" +__version__ = "2.9.0"