44 Commits

Author SHA1 Message Date
Sven Sager
f3ffdd8eaa fix(io): Fix ios1 dbus policy
Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-03-11 15:12:45 +01:00
Sven Sager
f4eff16ab6 refactor: Update type annotations
Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-27 15:42:15 +01:00
Sven Sager
d95a65c18c test(dbus): Update bus_address for BusProvider clases
Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-27 15:42:15 +01:00
Sven Sager
2b22c103c8 fixup: Integrate NotifyDriverReset handling for ios1
Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-27 15:42:15 +01:00
Sven Sager
794089a5b5 refactor: Simplify D-Bus handling by using address-based connections
Replaced direct `SystemBus` and `SessionBus` instances with
address-based D-Bus connections. BusProviders will open their own bus
connections and close it at the end.

Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-27 15:39:02 +01:00
Sven Sager
5dfd8b9f2f feat: Add published event to bus providers for thread synchronization
Introduced a threading `Event` named `published` in `bus_provider_ios1`
and `bus_provider_middleware1` modules to signal successful D-Bus
publishing.

Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-06 18:52:29 +01:00
Sven Sager
4ea8d6bc9a feat: Add monitoring and automatic restart for bus provider threads
Implemented checks in `MiddlewareDaemon` to monitor the status of
`bp_middleware1` and `bp_ios1` threads. Added automatic restarts for
non-alive threads using `dbus_start`.

Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-06 18:23:55 +01:00
Sven Sager
fdaf7b3ac6 refactor: Restructure and rename bus provider modules and classes
Renamed and moved `BusProvider` and `BusProviderIo` to
`BusProviderMiddleware1` and `BusProviderIos1` respectively for better
clarity and modular organization. Updated all related imports and
references accordingly.

Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-06 18:23:01 +01:00
Sven Sager
3dbad93975 feat: Add bus_filter to dbus_stop for selective stopping
Enhanced the `dbus_stop` method in `MiddlewareDaemon` to support an
optional `bus_filter` parameter, allowing selective stopping of bus
providers. Updated imports to include `List` from `typing`.

Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-06 18:23:01 +01:00
Sven Sager
cf90b2dd55 refactor: Rename bus provider attributes for clarity
Replaced `bus_provider` and `io_bus_provider` with `bp_middleware1` and
`bp_ios1` to improve naming consistency and readability in
`MiddlewareDaemon`.

Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-06 18:23:01 +01:00
Sven Sager
4bd8fa74a9 refactor: Add helper functions for D-Bus connections and bus handling
Replaced direct D-Bus initialization with
`get_new_system_dbus_connection` and `get_new_session_dbus_connection`
helper functions. This functions will create a new connection to use
separate busses.

Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-06 17:25:51 +01:00
Sven Sager
bf5bef114c chore: Reformat with black
Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-06 16:53:02 +01:00
Sven Sager
2c08829a13 feat(io): Replace property with method to get IOs of a device
Introduced methods for retrieving input and output object paths in the
`InterfaceDevice` class. Removed `inp` and `out` properties in favor of
these methods.

Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-06 08:59:36 +01:00
Sven Sager
ce1a25ac0e feat(io): Add EmitsChangedSignal annotations to device properties
Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-06 08:50:02 +01:00
Sven Sager
f387b0a836 refactor(io): Rename GetIO method to GetByName in IO manager
Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-06 08:43:11 +01:00
Sven Sager
10ad65a62c refactor(io): Update get_*_object_path to accept objects instead
Modified `get_io_object_path` and `get_device_object_path` functions to
accept full `IOBase` and `Device` objects instead of string identifiers.
All properties are available in case of changing the object path format.

Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-06 08:41:29 +01:00
Sven Sager
0e69ef432b refactor(io): Simplify InterfaceDeviceManager and device handling
Streamlined device management by introducing a dedicated `object_path`
property in `InterfaceDevice`. Refactored `InterfaceDeviceManager` to
use this property and accept a list of `InterfaceDevice` instances,
removing direct `RevPiModIO` dependencies. Updated D-Bus publishing to
reflect the new structure.

Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-06 08:36:39 +01:00
Sven Sager
35dbed0798 refactor(io): Rename Get method to GetIO in IOManager interface
Updated method name in D-Bus interface and backend to do not use the
same name as org.freedesktop.DBus.Properties. Som libs will map all
methods of a node to an object for direct calling. If the names are the
same, you have to filter the interface.

Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-05 16:23:27 +01:00
Sven Sager
1842bbd2f5 feat(io): Emit property change signals for byteorder and signedness
Added `PropertiesChanged` signals for `byteorder` and `signed` property
updates. Updated D-Bus interface annotations to specify change signal
behavior for properties. Simplified `emit_io_change` implementation.

Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-05 16:12:15 +01:00
Sven Sager
3d64cd5837 refactor(io): Simplify generation of io object path
Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-05 16:11:32 +01:00
Sven Sager
5528f6dff4 doc(io): Update io_controller.py example file
Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-04 16:06:48 +01:00
Sven Sager
6372ed4e7f feat(io): Add Set* (Byteorder, Signed, Value) methods to IO interface
Introduced `SetByteorder` and `SetSigned` methods in both the `Input`
and `Output` D-Bus interfaces, and added the `SetValue` method
specifically for the `Output` interface. Implemented corresponding
methods in the backend.

Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-04 15:20:34 +01:00
Sven Sager
710d7b2078 feat(io): Add GetByName and GetByPosition methods to DeviceManager
Introduced `GetByName` and `GetByPosition` methods in the D-Bus
interface and implementation for retrieving device object paths by name
or position. Updated `GetAllDevices` return type to `ao`.

Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-04 15:20:34 +01:00
Sven Sager
8ee5e0836f feat(io): Add position property to InterfaceDevice
Introduced a new `position` property with read access in the D-Bus
interface and implemented its corresponding method.

Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-04 15:20:34 +01:00
Sven Sager
6f1bd7f7ea refactor(io): Rename IO event methods to signal methods for clarity
Renamed `ActivateIoEvents` to `ActivateIoSignals` and
`DeactivateIoEvents` to `DeactivateIoSignals` in both the D-Bus
interface and implementation to better align with D-Bus signal
semantics.

Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-04 15:20:34 +01:00
Sven Sager
785569c86b fix(io): Do not read/wirte process image while device is in self-update
Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-04 15:20:34 +01:00
Sven Sager
415e8502f7 fix(io): Handle large integer values with fallback to raw byte arrays
Added a fallback mechanism to handle cases where integer values exceed
valid range by using raw byte arrays (`ay`). Updated D-Bus methods and
properties to support this behavior.

Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-04 15:20:34 +01:00
Sven Sager
b16331cf84 feat(io): Add bitaddress property to IO interfaces
Introduced the `bitaddress` property with read-write access to `Input`
and `Output` D-Bus interfaces. Implemented corresponding property
methods.

Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-04 15:20:34 +01:00
Sven Sager
a2d1531e77 feat(io): Simplify IO interface hierarchy and unify property handling
Replaced specific IO interface classes (`InterfaceInpBool`,
`InterfaceInpInt`, etc.) with generic `InterfaceInput` and
`InterfaceOutput` classes to simplify the hierarchy.

Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-04 15:20:34 +01:00
Sven Sager
bbbbd3e0e1 fix(io): Add argument names to D-Bus methods for input/output paths
Updated `GetAllInputs` and `GetAllOutputs` methods in the D-Bus
interface to include explicit argument names (`object-path-list`) and
adjusted their types to `ao` not strings.

Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-03 08:54:56 +01:00
Sven Sager
a43fc764c6 doc: Add D-Bus data types documentation
Added a new `docs/dbus.md` file with an overview of standardized D-Bus
data types and their signatures. Updated `README.md` with a reference to
the documentation.

Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-03 08:03:37 +01:00
Sven Sager
0716169a03 feat(io): Add min_value and max_value properties to IOs
Added `min_value` and `max_value` properties to integer IOs for
determining value ranges. Updated D-Bus interface with corresponding
properties.

Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-03 08:03:37 +01:00
Sven Sager
77a3fbb16c feat(io): Add inp and out properties to InterfaceDeviceManager
Added `inp` and `out` properties for accessing input and output paths in
`InterfaceDeviceManager`. Updated D-Bus interface with corresponding
properties.

Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-02 17:06:34 +01:00
Sven Sager
037e9c05ac style(io): Reformatted with black
Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-02 17:06:34 +01:00
Sven Sager
66c8c9851b refactor(io): Replace _get_io_path method with get_io_path utility
The `_get_io_path` method was removed from `InterfaceIoManager` and
replaced with the `get_io_path` utility function from `ios1_helper.py`
to reduce redundancy and improve code reusability.

Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-02 17:06:34 +01:00
Sven Sager
afdae78336 feat(io): Add new IO properties and corresponding methods
Added `address`, `byteorder`, and `length` properties to D-Bus
interfaces for IOs. Implemented corresponding property methods in
`ios1_helper.py`.

Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-02-02 17:06:33 +01:00
Sven Sager
4dd4c814b5 fix(io): Add property methods on integer IOs
Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-01-30 13:26:21 +01:00
Sven Sager
b8b99ed3b0 feat(io): Add InterfaceDevice class for device handling via D-Bus
Introduced the `InterfaceDevice` class, enabling detailed device
property access through D-Bus. Updated `bus_provider_io` to include
device interfaces in the D-Bus provider.

Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-01-30 13:06:15 +01:00
Sven Sager
b68f1ffb36 feat(io): Add InterfaceDeviceManager to D-Bus bus provider
Integrated the InterfaceDeviceManager class into the com.revolutionpi
.ios1 D-Bus bus provider. This addition enables managing device paths
and querying all devices via D-Bus.

Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-01-30 12:29:08 +01:00
Marc Kittner
ffd04a0410 fix: Use variant_type instead of hard coded boolean
Signed-off-by: Marc Kittner <m.kittner@kunbus.com>
2026-01-30 11:26:15 +01:00
Sven Sager
549cddf594 feat(io): Integrate com.revolutionpi.ios1 bus to daemon
Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-01-16 14:27:41 +01:00
Sven Sager
f56db7ab1c doc(io): Add IO example program
Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-01-16 14:27:41 +01:00
Sven Sager
208b391aa9 feat(io): Add dbus policy for com.revolutionpi.ios1 bus
Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-01-16 14:27:41 +01:00
Sven Sager
917ab7ab1f feat(io): Add dbus bus com.revolutionpi.ios1
Signed-off-by: Sven Sager <s.sager@kunbus.com>
2026-01-16 14:27:41 +01:00
29 changed files with 873 additions and 38 deletions

View File

@@ -7,3 +7,8 @@ SPDX-License-Identifier: GPL-2.0-or-later
# Middleware for Revolution Pi # Middleware for Revolution Pi
This middleware will support D-Bus as IPC interface. This middleware will support D-Bus as IPC interface.
## D-Bus
See [docs/dbus.md](docs/dbus.md) for an overview of the standard D-Bus data
types.

View File

@@ -0,0 +1,19 @@
<!-- /usr/share/dbus-1/system.d/com.revolutionpi.ios1.conf -->
<busconfig>
<!-- Allow full access to root as the bus owner -->
<policy user="root">
<allow own="com.revolutionpi.ios1"/>
<allow send_destination="com.revolutionpi.ios1"/>
<allow receive_sender="com.revolutionpi.ios1"/>
</policy>
<!-- System group picontrol -->
<policy group="picontrol">
<allow send_destination="com.revolutionpi.ios1"/>
</policy>
<!-- Standard-Policy -->
<policy context="default">
<deny send_destination="com.revolutionpi.ios1"/>
</policy>
</busconfig>

View File

@@ -0,0 +1,65 @@
# -*- coding: utf-8 -*-
# SPDX-FileCopyrightText: 2025 KUNBUS GmbH
# SPDX-License-Identifier: GPL-2.0-or-later
"""Switches 14 outputs on a DIO to the same value as the first input."""
from time import perf_counter
from gi.repository import GLib
from pydbus import SystemBus
detected_signal = False
timestamp = perf_counter()
# Get system bus
bus = SystemBus()
# Get IoManager interface on ios1 bus
iface_io_manager = bus.get(
"com.revolutionpi.ios1",
"/com/revolutionpi/ios1",
)["com.revolutionpi.ios1.IoManager"]
# Query object path of RevPiLED output
path_revpi_led = iface_io_manager.Get("RevPiLED")
# Get Output interface in the queried object path.
out_RevPiLED = bus.get("com.revolutionpi.ios1", path_revpi_led)["com.revolutionpi.ios1.Output"]
# Get all 14 outputs
lst_path_outputs = [iface_io_manager.Get(f"O_{i}") for i in range(1, 15)]
lst_out_outputs = [
bus.get("com.revolutionpi.ios1", path)["com.revolutionpi.ios1.Output"]
for path in lst_path_outputs
]
def signal_handler(io_name, io_value):
global timestamp
print(f"Signal received: {io_name} = {io_value}")
if io_name == "O_14":
print(f"Time since input detection: {perf_counter() - timestamp}")
elif io_name == "I_1":
timestamp = perf_counter()
out_RevPiLED.SetValue(GLib.Variant("i", io_value))
for output in lst_out_outputs:
output.SetValue(GLib.Variant("b", io_value))
# Start change detection to fire signals on dbus
iface_io_manager.ActivateIoSignals()
iface_io_manager.onIoChanged = signal_handler
try:
loop = GLib.MainLoop()
loop.run()
except KeyboardInterrupt:
pass
# Stop change detection
iface_io_manager.DeactivateIoSignals()

51
docs/dbus.md Normal file
View File

@@ -0,0 +1,51 @@
<!--
SPDX-FileCopyrightText: 2026 KUNBUS GmbH <support@kunbus.com>
SPDX-License-Identifier: GPL-2.0-or-later
-->
# D-Bus
## Datentypen
Hier ist eine **Liste der standardisierten DBus-Datentypen** (Signaturen), wie
sie u. a. in Introspection/XML (`type="..."`) verwendet werden.
## Basis-Typen (Basic Types)
| Signatur | Bedeutung |
|----------|-------------------------------------|
| `y` | Byte (unsigned 8-bit) |
| `b` | Boolean |
| `n` | Int16 (signed) |
| `q` | UInt16 (unsigned) |
| `i` | Int32 (signed) |
| `u` | UInt32 (unsigned) |
| `x` | Int64 (signed) |
| `t` | UInt64 (unsigned) |
| `d` | Double (IEEE 754) |
| `s` | String (UTF8) |
| `o` | Object Path |
| `g` | Signature (Typ-Signatur als String) |
## Container-Typen (Compound/Container)
| Form | Bedeutung | Beispiel |
|------------|-------------------------------------------------|---------------------------------|
| `aX` | Array von `X` | `as` = Array von Strings |
| `(XYZ...)` | Struct/Tupel | `(is)` = (Int32, String) |
| `{KV}` | Dict-Entry (nur innerhalb eines Arrays erlaubt) | `a{sv}` = Dict String → Variant |
## Spezial-Typ
| Signatur | Bedeutung |
|----------|---------------------------------------------------|
| `v` | Variant (beliebiger Typ, zur Laufzeit festgelegt) |
## Häufig genutzte Kombis (Praxis)
- `as` → Liste von Strings
- `ao` → Liste von Object Paths
- `a{sv}` → „Properties“-Map (String → Variant), sehr verbreitet bei
`org.freedesktop.DBus.Properties`
- `a{ss}` → String → String Map

View File

@@ -2,6 +2,7 @@
# SPDX-FileCopyrightText: 2025 KUNBUS GmbH # SPDX-FileCopyrightText: 2025 KUNBUS GmbH
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
"""Metadata of package.""" """Metadata of package."""
__author__ = "Sven Sager" __author__ = "Sven Sager"
__copyright__ = "Copyright (C) 2025 KUNBUS GmbH" __copyright__ = "Copyright (C) 2025 KUNBUS GmbH"
__license__ = " GPL-2.0-or-later" __license__ = " GPL-2.0-or-later"

View File

@@ -2,4 +2,5 @@
# SPDX-FileCopyrightText: 2025 KUNBUS GmbH # SPDX-FileCopyrightText: 2025 KUNBUS GmbH
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
"""Package: revpi_middleware.""" """Package: revpi_middleware."""
from .__about__ import __author__, __copyright__, __license__, __version__ from .__about__ import __author__, __copyright__, __license__, __version__

View File

@@ -2,4 +2,5 @@
# SPDX-FileCopyrightText: 2025 KUNBUS GmbH # SPDX-FileCopyrightText: 2025 KUNBUS GmbH
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
"""CLI commands to control revpi_middleware.""" """CLI commands to control revpi_middleware."""
from ..__about__ import __author__, __copyright__, __license__, __version__ from ..__about__ import __author__, __copyright__, __license__, __version__

View File

@@ -5,6 +5,7 @@
This module provides the foundation for the RevPi middleware CLI commands This module provides the foundation for the RevPi middleware CLI commands
and argument parsing setup. and argument parsing setup.
""" """
from logging import getLogger from logging import getLogger
from . import cli_config, cli_picontrol from . import cli_config, cli_picontrol

View File

@@ -1,6 +1,7 @@
# SPDX-FileCopyrightText: 2025 KUNBUS GmbH # SPDX-FileCopyrightText: 2025 KUNBUS GmbH
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
"""Command-Line for the picontrol object of CLI.""" """Command-Line for the picontrol object of CLI."""
from argparse import ArgumentParser from argparse import ArgumentParser
from logging import getLogger from logging import getLogger
@@ -16,7 +17,7 @@ def add_subparsers(parent_parser: ArgumentParser):
"action", "action",
choices=["enable", "disable", "status", "available", "list-features"], choices=["enable", "disable", "status", "available", "list-features"],
help="Action to be executed: enable, disable, status or available. " help="Action to be executed: enable, disable, status or available. "
"To get all available features, use 'list-features'.", "To get all available features, use 'list-features'.",
) )
parent_parser.add_argument( parent_parser.add_argument(
"feature", "feature",

View File

@@ -1,6 +1,7 @@
# SPDX-FileCopyrightText: 2025 KUNBUS GmbH # SPDX-FileCopyrightText: 2025 KUNBUS GmbH
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
"""Command-Line for the picontrol object of CLI.""" """Command-Line for the picontrol object of CLI."""
from argparse import ArgumentParser from argparse import ArgumentParser
from logging import getLogger from logging import getLogger

View File

@@ -1,6 +1,7 @@
# SPDX-FileCopyrightText: 2025 KUNBUS GmbH # SPDX-FileCopyrightText: 2025 KUNBUS GmbH
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
"""D-Bus helper functions for cli commands.""" """D-Bus helper functions for cli commands."""
from enum import Enum from enum import Enum
from threading import Thread from threading import Thread
from time import sleep from time import sleep

View File

@@ -4,11 +4,16 @@
"""Main daemon of revpi-middleware.""" """Main daemon of revpi-middleware."""
from logging import getLogger from logging import getLogger
from os import getuid, environ
from threading import Event from threading import Event
from time import perf_counter from time import perf_counter
from typing import List
from gi.repository import Gio
from . import proginit as pi from . import proginit as pi
from .dbus_middleware1.bus_provider import BusProvider from .dbus_ios1 import BusProviderIos1
from .dbus_middleware1 import BusProviderMiddleware1
log = getLogger(__name__) log = getLogger(__name__)
@@ -25,7 +30,8 @@ class MiddlewareDaemon:
self._reconfigure = False self._reconfigure = False
self._running = True self._running = True
self.bus_provider = None self.bp_middleware1 = None
self.bp_ios1 = None
self._configure() self._configure()
log.debug("leave MiddlewareDaemon.__init__") log.debug("leave MiddlewareDaemon.__init__")
@@ -37,24 +43,55 @@ class MiddlewareDaemon:
log.debug("leave MiddlewareDaemon._configure") log.debug("leave MiddlewareDaemon._configure")
@staticmethod
def _get_bus_address() -> str:
if pi.pargs.use_session_bus:
environ_name = "DBUS_SESSION_BUS_ADDRESS"
bus_address = Gio.dbus_address_get_for_bus_sync(Gio.BusType.SESSION)
else:
environ_name = "DBUS_SYSTEM_BUS_ADDRESS"
bus_address = Gio.dbus_address_get_for_bus_sync(Gio.BusType.SYSTEM)
return environ.get(environ_name, bus_address)
def dbus_start(self): def dbus_start(self):
log.debug("enter MiddlewareDaemon.dbus_start") log.debug("enter MiddlewareDaemon.dbus_start")
if self.bus_provider and self.bus_provider.is_alive():
return
self.bus_provider = BusProvider(use_system_bus=not pi.pargs.use_session_bus) dbus_middleware1_running = self.bp_middleware1 and self.bp_middleware1.is_alive()
self.bus_provider.start() if not dbus_middleware1_running:
self.bp_middleware1 = BusProviderMiddleware1(self._get_bus_address())
self.bp_middleware1.start()
dbus_ios1_running = self.bp_ios1 and self.bp_ios1.is_alive()
if not dbus_ios1_running:
if self.bp_middleware1.published.wait(timeout=10.0):
self.bp_ios1 = BusProviderIos1(self._get_bus_address())
self.bp_ios1.start()
else:
log.error("dbus middleware1 provider thread is not alive - can not start ios1 bus")
log.debug("leave MiddlewareDaemon.dbus_start") log.debug("leave MiddlewareDaemon.dbus_start")
def dbus_stop(self): def dbus_stop(self, bus_filter: List[object] = None):
log.debug("enter MiddlewareDaemon.dbus_stop") log.debug("enter MiddlewareDaemon.dbus_stop")
if self.bus_provider: if bus_filter is None:
self.bus_provider.stop() bus_filter = [
self.bus_provider.join(timeout=10.0) self.bp_middleware1,
if self.bus_provider.is_alive(): self.bp_ios1,
log.warning("dbus provider thread is still alive") ]
if self.bp_middleware1 and self.bp_middleware1 in bus_filter:
self.bp_middleware1.stop()
self.bp_middleware1.join(timeout=10.0)
if self.bp_middleware1.is_alive():
log.warning("dbus middleware1 provider thread is still alive")
if self.bp_ios1 and self.bp_ios1 in bus_filter:
self.bp_ios1.stop()
self.bp_ios1.join(timeout=10.0)
if self.bp_ios1.is_alive():
log.warning("dbus ios1 provider thread is still alive")
log.debug("leave MiddlewareDaemon.dbus_stop") log.debug("leave MiddlewareDaemon.dbus_stop")
@@ -97,6 +134,17 @@ class MiddlewareDaemon:
self._reconfigure = False self._reconfigure = False
pi.startup_complete() pi.startup_complete()
# Monitor bus providers for errors and restart them
restart = False
if not (self.bp_middleware1 and self.bp_middleware1.is_alive()):
log.warning("dbus middleware1 provider thread is not alive - restarting")
restart = True
if not (self.bp_ios1 and self.bp_ios1.is_alive()):
log.warning("dbus ios1 provider thread is not alive - restarting")
restart = True
if restart:
self.dbus_start()
# Cycle time calculation # Cycle time calculation
dm = divmod(ot - perf_counter(), self._cycle_time) dm = divmod(ot - perf_counter(), self._cycle_time)
# For float the result is (q, a % b), where q is usually math.floor(a / b) but may be 1 less than that. # For float the result is (q, a % b), where q is usually math.floor(a / b) but may be 1 less than that.

View File

@@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
# SPDX-FileCopyrightText: 2025 KUNBUS GmbH
# SPDX-License-Identifier: GPL-2.0-or-later
"""D-Bus ios version 1 of revpi_middleware."""
from .ios1_helper import REVPI_DBUS_BASE_PATH, REVPI_DBUS_NAME
from .bus_provider_ios1 import BusProviderIos1

View File

@@ -0,0 +1,122 @@
# -*- coding: utf-8 -*-
# SPDX-FileCopyrightText: 2025 KUNBUS GmbH
# SPDX-License-Identifier: GPL-2.0-or-later
"""D-Bus bus provider for revpi_middleware."""
from logging import getLogger
from threading import Thread, Event
import revpimodio2
from gi.repository import GLib
from pydbus import connect
from . import REVPI_DBUS_NAME
from .interface_devices import (
InterfaceDeviceManager,
InterfaceDevice,
)
from .interface_ios import (
InterfaceIoManager,
InterfaceInput,
InterfaceOutput,
)
log = getLogger(__name__)
class BusProviderIos1(Thread):
def __init__(
self,
dbus_address: str,
picontrol_device="/dev/piControl0",
config_rsc="/etc/revpi/config.rsc",
):
log.debug("enter BusProviderIos1.__init__")
super().__init__()
self._bus_address = dbus_address
self._loop = GLib.MainLoop()
self._lst_device_interfaces = []
self._lst_io_interfaces = []
self._modio = revpimodio2.RevPiModIO(
procimg=picontrol_device,
configrsc=config_rsc,
shared_procimg=True,
)
self.picontrol_device = picontrol_device
self.published = Event()
self.config_rsc = config_rsc
def run(self):
log.debug("enter BusProviderIos1.run")
bus = connect(self._bus_address)
self._lst_device_interfaces.clear()
self._lst_io_interfaces.clear()
for device in self._modio.device:
self._lst_device_interfaces.append(
InterfaceDevice(bus, device),
)
for io in self._modio.io:
interface = None
try:
if io.type == revpimodio2.INP:
interface = InterfaceInput(bus, io)
elif io.type == revpimodio2.OUT:
interface = InterfaceOutput(bus, io)
elif io.type == revpimodio2.MEM:
# todo: Implement memory
pass
except Exception as e:
log.warning(f"can not create dbus interface for {io.name}: {e}")
if interface is not None:
self._lst_io_interfaces.append(interface)
lst_interfaces = []
lst_interfaces += [
(interface.object_path, interface) for interface in self._lst_device_interfaces
]
lst_interfaces += [
(interface.object_path, interface) for interface in self._lst_io_interfaces
]
try:
bus.publish(
REVPI_DBUS_NAME,
InterfaceDeviceManager(self._lst_device_interfaces),
InterfaceIoManager(self._lst_io_interfaces, self._modio),
*lst_interfaces,
)
self.published.set()
except Exception as e:
log.error(f"can not publish dbus {REVPI_DBUS_NAME}: {e}")
# Subscribe to NotifyDriverReset on middleware1 dbus
iface_pi_control = bus.get(
"com.revolutionpi.middleware1",
"/com/revolutionpi/middleware1",
)["com.revolutionpi.middleware1.PiControl"]
iface_pi_control.onNotifyDriverReset = self.stop
try:
self._loop.run()
except Exception as e:
log.error(f"can not run dbus mainloop: {e}")
bus.con.close()
self._modio.cleanup()
log.debug("leave BusProviderIos1.run")
def stop(self):
log.debug("enter BusProviderIos1.stop")
self._loop.quit()
log.debug("leave BusProviderIos1.stop")
@property
def running(self):
return self._loop.is_running()

View File

@@ -0,0 +1,133 @@
# -*- coding: utf-8 -*-
# SPDX-FileCopyrightText: 2025 KUNBUS GmbH
# SPDX-License-Identifier: GPL-2.0-or-later
"""D-Bus interfaces for IOs."""
from pydbus.bus import Bus
from pydbus.generic import signal
from revpimodio2.device import Device
from .ios1_helper import get_io_object_path, get_device_object_path
class InterfaceDevice:
"""
<node>
<interface name="com.revolutionpi.ios1.Device">
<method name="GetDeviceInputs">
<arg name="object-path-list" type="ao" direction="out"/>
</method>
<method name="GetDeviceOutputs">
<arg name="object-path-list" type="ao" direction="out"/>
</method>
<property name="bmk" type="s" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
</property>
<property name="catalognr" type="s" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
</property>
<property name="comment" type="s" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
</property>
<property name="id" type="s" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
</property>
<property name="name" type="s" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
</property>
<property name="position" type="n" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
</property>
<property name="type" type="s" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
</property>
</interface>
</node>
"""
interface_name = "com.revolutionpi.ios1.Device"
PropertiesChanged = signal()
def __init__(self, dbus: Bus, device: Device):
self.dbus = dbus
self.device = device
self.object_path = get_device_object_path(device)
def GetDeviceInputs(self) -> list[str]:
return [get_io_object_path(io) for io in self.device.get_inputs()]
def GetDeviceOutputs(self) -> list[str]:
return [get_io_object_path(io) for io in self.device.get_outputs()]
@property
def bmk(self) -> str:
return self.device.bmk
@property
def catalognr(self):
return self.device.catalognr
@property
def comment(self):
return self.device.comment
@property
def id(self):
return self.device.id
@property
def name(self) -> str:
return self.device.name
@property
def position(self) -> int:
return self.device.position
@property
def type(self):
return self.device.type
class InterfaceDeviceManager:
"""
<node>
<interface name="com.revolutionpi.ios1.DeviceManager">
<method name="GetAllDevices">
<arg type="ao" direction="out"/>
</method>
<method name="GetByName">
<arg name="device-name" type="s" direction="in"/>
<arg name="object-path" type="o" direction="out"/>
</method>
<method name="GetByPosition">
<arg name="device-position" type="n" direction="in"/>
<arg name="object-path" type="o" direction="out"/>
</method>
</interface>
</node>
"""
interface_name = "com.revolutionpi.ios1.DeviceManager"
def __init__(
self,
device_interfaces: list[InterfaceDevice],
):
self._lst_device_interfaces = device_interfaces
def GetAllDevices(self) -> list[str]:
return [interface.object_path for interface in self._lst_device_interfaces]
def GetByName(self, device_name) -> str:
for interface in self._lst_device_interfaces:
if interface.device.name == device_name:
return interface.object_path
raise KeyError(f"No device with name '{device_name}' found.")
def GetByPosition(self, device_position) -> str:
for interface in self._lst_device_interfaces:
if interface.device.position == device_position:
return interface.object_path
raise KeyError(f"No device on position '{device_position}' found.")

View File

@@ -0,0 +1,306 @@
# -*- coding: utf-8 -*-
# SPDX-FileCopyrightText: 2025 KUNBUS GmbH
# SPDX-License-Identifier: GPL-2.0-or-later
"""D-Bus interfaces for IOs."""
from typing import Union, List
from pydbus import Variant
from pydbus.bus import Bus
from pydbus.generic import signal
from revpimodio2 import RevPiModIO, Cycletools, INP, OUT
from revpimodio2.io import IOBase
from .ios1_helper import get_io_object_path, get_variant_type
class InterfaceInput:
"""
<node>
<interface name="com.revolutionpi.ios1.Input">
<method name="SetByteorder">
<arg name="order" type="s" direction="in"/>
</method>
<method name="SetSigned">
<arg name="signed" type="b" direction="in"/>
</method>
<property name="address" type="n" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
</property>
<property name="bmk" type="s" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
</property>
<property name="bitaddress" type="n" access="readwrite">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
</property>
<property name="byteorder" type="s" access="readwrite">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/>
</property>
<property name="defaultvalue" type="v" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
</property>
<property name="length" type="q" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
</property>
<property name="name" type="s" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
</property>
<property name="signed" type="b" access="readwrite">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/>
</property>
<property name="value" type="v" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
</property>
</interface>
</node>
"""
interface_name = "com.revolutionpi.ios1.Input"
PropertiesChanged = signal()
def __init__(self, dbus: Bus, io: IOBase):
self._raw = False
self.dbus = dbus
self.io = io
self.object_path = get_io_object_path(io)
try:
self.variant_type = get_variant_type(self.io)
except ValueError:
# Fallback to bytes if the integer is too large
self._raw = True
self.variant_type = "ay"
def emit_io_change(self):
self.PropertiesChanged(
self.interface_name,
{
"value": Variant(
self.variant_type,
self.io.get_value() if self._raw else self.io.value,
),
},
[],
)
def SetByteorder(self, order: str) -> None:
self.byteorder = order
def SetSigned(self, signed: bool) -> None:
self.signed = signed
@property
def address(self) -> int:
return self.io.address
@property
def bmk(self) -> str:
return self.io.bmk
@property
def bitaddress(self) -> int:
return self.io._bitaddress
@property
def byteorder(self) -> str:
return self.io.byteorder
@byteorder.setter
def byteorder(self, value: str) -> None:
if hasattr(self.io, "_set_byteorder"):
self.io._set_byteorder(value)
self.variant_type = get_variant_type(self.io)
# Changing the byteorder can change the value, but we do NOT send a signal for that
# because the real value of the process image was not changed. But we inform the client
# about the changed byteorder property.
self.PropertiesChanged(
self.interface_name,
{},
["byteorder"],
)
@property
def defaultvalue(self) -> Variant:
return Variant(
self.variant_type,
self.io.get_value() if self._raw else self.io.defaultvalue,
)
@property
def length(self) -> int:
# 0 length for boolean
return 0 if self.variant_type == "b" else self.io.length
@property
def name(self) -> str:
return self.io.name
@property
def signed(self) -> bool:
if hasattr(self.io, "signed"):
return self.io.signed
return False
@signed.setter
def signed(self, value: bool) -> None:
if hasattr(self.io, "_set_signed"):
self.io._set_signed(value)
self.variant_type = get_variant_type(self.io)
# Changing the signedness can change the value, but we do NOT send a signal for that
# because the real value of the process image was not changed. But we inform the client
# about the changed signedness property.
self.PropertiesChanged(
self.interface_name,
{},
["signed"],
)
@property
def value(self) -> Variant:
if not self.io._parentdevice._selfupdate:
self.io._parentdevice.readprocimg()
return Variant(
self.variant_type,
self.io.get_value() if self._raw else self.io.value,
)
class InterfaceOutput(InterfaceInput):
"""
<node>
<interface name="com.revolutionpi.ios1.Output">
<method name="SetByteorder">
<arg name="order" type="s" direction="in"/>
</method>
<method name="SetSigned">
<arg name="signed" type="b" direction="in"/>
</method>
<method name="SetValue">
<arg name="value" type="v" direction="in"/>
</method>
<property name="address" type="n" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
</property>
<property name="bmk" type="s" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
</property>
<property name="bitaddress" type="n" access="readwrite">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
</property>
<property name="byteorder" type="s" access="readwrite">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/>
</property>
<property name="defaultvalue" type="v" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
</property>
<property name="length" type="q" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
</property>
<property name="name" type="s" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
</property>
<property name="signed" type="b" access="readwrite">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/>
</property>
<property name="value" type="v" access="readwrite">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
</property>
</interface>
</node>
"""
interface_name = "com.revolutionpi.ios1.Output"
def SetValue(self, value: Variant) -> None:
self.value = value
@property
def value(self) -> Variant:
return super().value
@value.setter
def value(self, value: Variant) -> None:
if self._raw:
self.io.set_value(value)
else:
self.io.value = value
if not self.io._parentdevice._selfupdate:
self.io._parentdevice.writeprocimg()
class InterfaceIoManager:
"""
<node>
<interface name="com.revolutionpi.ios1.IoManager">
<method name="GetAllInputs">
<arg name="object-path-list" type="ao" direction="out"/>
</method>
<method name="GetAllOutputs">
<arg name="object-path-list" type="ao" direction="out"/>
</method>
<method name="GetByName">
<arg name="name" type="s" direction="in"/>
<arg name="object-path" type="o" direction="out"/>
</method>
<method name="ActivateIoSignals">
</method>
<method name="DeactivateIoSignals">
</method>
<signal name="IoChanged">
<arg name="name" type="s" direction="out"/>
<arg name="value" type="v" direction="out"/>
</signal>
</interface>
</node>
"""
interface_name = "com.revolutionpi.ios1.IoManager"
IoChanged = signal()
def __init__(
self,
io_interfaces: List[Union[InterfaceInput, InterfaceOutput]],
modio: RevPiModIO,
):
self._dc_io_interfaces = {interface.name: interface for interface in io_interfaces}
self.modio = modio
self.lst_inp_object_path = []
self.lst_out_object_path = []
for interface in io_interfaces:
if interface.io.type == INP:
self.lst_inp_object_path.append(interface.object_path)
elif interface.io.type == OUT:
self.lst_out_object_path.append(interface.object_path)
def _modio_cycle(self, ct: Cycletools) -> None:
for io_name in self._dc_io_interfaces:
interface = self._dc_io_interfaces[io_name]
if ct.changed(interface.io):
interface.emit_io_change()
self.IoChanged(
interface.io.name,
Variant(interface.variant_type, interface.io.value),
)
def GetAllInputs(self) -> list[str]:
return self.lst_inp_object_path
def GetAllOutputs(self) -> list[str]:
return self.lst_out_object_path
def GetByName(self, io_name) -> str:
if io_name in self._dc_io_interfaces:
return self._dc_io_interfaces[io_name].object_path
raise KeyError(f"No IO with name '{io_name}' found.")
def ActivateIoSignals(self) -> None:
if not self.modio._looprunning:
self.modio.autorefresh_all()
self.modio.cycleloop(self._modio_cycle, cycletime=50, blocking=False)
def DeactivateIoSignals(self) -> None:
self.modio.exit(False)

View File

@@ -0,0 +1,51 @@
# -*- coding: utf-8 -*-
# SPDX-FileCopyrightText: 2025 KUNBUS GmbH
# SPDX-License-Identifier: GPL-2.0-or-later
"""Helper for io read and write."""
from logging import getLogger
from revpimodio2.device import Device
from revpimodio2.io import IOBase
log = getLogger(__name__)
REVPI_DBUS_NAME = "com.revolutionpi.ios1"
REVPI_DBUS_BASE_PATH = "/com/revolutionpi/ios1"
def get_io_object_path(io: IOBase) -> str:
return f"{REVPI_DBUS_BASE_PATH}/io/{io.name}"
def get_device_object_path(device: Device) -> str:
return f"{REVPI_DBUS_BASE_PATH}/device/{device.position}"
def get_variant_type(io: IOBase) -> str:
value_type = type(io.value)
byte_length = io.length
signed = io._signed
if value_type is bool:
return "b"
if value_type is float:
return "d"
if value_type is int:
if byte_length <= 2:
return "n" if signed else "q"
if byte_length <= 4:
return "i" if signed else "u"
if byte_length <= 8:
return "x" if signed else "t"
raise ValueError(f"Unsupported byte length: {byte_length}")
if value_type is str:
return "s"
if value_type is bytes:
return "ay"
raise TypeError(f"Unsupported type: {value_type}")

View File

@@ -2,7 +2,8 @@
# SPDX-FileCopyrightText: 2025 KUNBUS GmbH # SPDX-FileCopyrightText: 2025 KUNBUS GmbH
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
"""D-Bus middleware version 1 of revpi_middleware.""" """D-Bus middleware version 1 of revpi_middleware."""
from .dbus_helper import REVPI_DBUS_BASE_PATH, REVPI_DBUS_NAME from .dbus_helper import REVPI_DBUS_BASE_PATH, REVPI_DBUS_NAME
from .dbus_helper import extend_interface from .dbus_helper import extend_interface
from .bus_provider import BusProvider from .bus_provider_middleware1 import BusProviderMiddleware1

View File

@@ -2,11 +2,12 @@
# SPDX-FileCopyrightText: 2025 KUNBUS GmbH # SPDX-FileCopyrightText: 2025 KUNBUS GmbH
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
"""D-Bus bus provider for revpi_middleware.""" """D-Bus bus provider for revpi_middleware."""
from logging import getLogger from logging import getLogger
from threading import Thread from threading import Thread, Event
from gi.repository import GLib from gi.repository import GLib
from pydbus import SessionBus, SystemBus from pydbus import connect
from . import REVPI_DBUS_NAME from . import REVPI_DBUS_NAME
from .process_image import InterfacePiControl from .process_image import InterfacePiControl
@@ -15,25 +16,27 @@ from .system_config import InterfaceRevpiConfig, InterfaceSoftwareServices
log = getLogger(__name__) log = getLogger(__name__)
class BusProvider(Thread): class BusProviderMiddleware1(Thread):
def __init__( def __init__(
self, self,
dbus_address: str,
picontrol_device="/dev/piControl0", picontrol_device="/dev/piControl0",
config_rsc="/etc/revpi/config.rsc", config_rsc="/etc/revpi/config.rsc",
use_system_bus=True,
): ):
log.debug("enter BusProvider.__init__") log.debug("enter BusProviderMiddleware1.__init__")
super().__init__() super().__init__()
self._bus = SystemBus() if use_system_bus else SessionBus() self._bus_address = dbus_address
self._loop = GLib.MainLoop() self._loop = GLib.MainLoop()
self.picontrol_device = picontrol_device self.picontrol_device = picontrol_device
self.published = Event()
self.config_rsc = config_rsc self.config_rsc = config_rsc
def run(self): def run(self):
log.debug("enter BusProvider.run") log.debug("enter BusProviderMiddleware1.run")
bus = connect(self._bus_address)
# The 2nd, 3rd, ... arguments can be objects or tuples of a path and an object # The 2nd, 3rd, ... arguments can be objects or tuples of a path and an object
# Example(), # Example(),
@@ -41,16 +44,17 @@ class BusProvider(Thread):
# ("Subdir2", Example()), # ("Subdir2", Example()),
# ("Subdir2/Whatever", Example()) # ("Subdir2/Whatever", Example())
lst_interfaces = [ lst_interfaces = [
InterfacePiControl(self._bus, self.picontrol_device, self.config_rsc), InterfacePiControl(bus, self.picontrol_device, self.config_rsc),
InterfaceRevpiConfig(self._bus), InterfaceRevpiConfig(bus),
InterfaceSoftwareServices(self._bus), InterfaceSoftwareServices(bus),
] ]
try: try:
self._bus.publish( bus.publish(
REVPI_DBUS_NAME, REVPI_DBUS_NAME,
*lst_interfaces, *lst_interfaces,
) )
self.published.set()
except Exception as e: except Exception as e:
log.error(f"can not publish dbus {REVPI_DBUS_NAME}: {e}") log.error(f"can not publish dbus {REVPI_DBUS_NAME}: {e}")
@@ -59,18 +63,20 @@ class BusProvider(Thread):
except Exception as e: except Exception as e:
log.error(f"can not run dbus mainloop: {e}") log.error(f"can not run dbus mainloop: {e}")
bus.con.close()
# Clean up all interfaces # Clean up all interfaces
for interface in lst_interfaces: for interface in lst_interfaces:
if type(interface) is tuple: if type(interface) is tuple:
_, interface = interface _, interface = interface
interface.cleanup() interface.cleanup()
log.debug("leave BusProvider.run") log.debug("leave BusProviderMiddleware1.run")
def stop(self): def stop(self):
log.debug("enter BusProvider.stop") log.debug("enter BusProviderMiddleware1.stop")
self._loop.quit() self._loop.quit()
log.debug("leave BusProvider.stop") log.debug("leave BusProviderMiddleware1.stop")
@property @property
def running(self): def running(self):

View File

@@ -2,10 +2,10 @@
# SPDX-FileCopyrightText: 2025 KUNBUS GmbH # SPDX-FileCopyrightText: 2025 KUNBUS GmbH
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
"""Helper for dbus.""" """Helper for dbus."""
from logging import getLogger
from typing import Union
from pydbus import SessionBus, SystemBus from logging import getLogger
from pydbus.bus import Bus
log = getLogger(__name__) log = getLogger(__name__)
@@ -15,7 +15,7 @@ REVPI_DBUS_BASE_PATH = "/com/revolutionpi/middleware1"
class DbusInterface: class DbusInterface:
def __init__(self, bus: Union[SessionBus, SystemBus]): def __init__(self, bus: Bus):
self.bus = bus self.bus = bus
def cleanup(self): def cleanup(self):

View File

@@ -2,4 +2,5 @@
# SPDX-FileCopyrightText: 2025 KUNBUS GmbH # SPDX-FileCopyrightText: 2025 KUNBUS GmbH
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
"""D-Bus interfaces for piControl driver.""" """D-Bus interfaces for piControl driver."""
from .interface_picontrol import InterfacePiControl from .interface_picontrol import InterfacePiControl

View File

@@ -2,8 +2,10 @@
# SPDX-FileCopyrightText: 2025 KUNBUS GmbH # SPDX-FileCopyrightText: 2025 KUNBUS GmbH
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
"""D-Bus interfaces for piControl.""" """D-Bus interfaces for piControl."""
from logging import getLogger from logging import getLogger
from pydbus.bus import Bus
from pydbus.generic import signal from pydbus.generic import signal
from .process_image_helper import PiControlIoctl, ResetDriverWatchdog from .process_image_helper import PiControlIoctl, ResetDriverWatchdog
@@ -26,7 +28,7 @@ class InterfacePiControl(DbusInterface):
NotifyDriverReset = signal() NotifyDriverReset = signal()
def __init__(self, bus, picontrol_device: str, config_rsc: str): def __init__(self, bus: Bus, picontrol_device: str, config_rsc: str):
super().__init__(bus) super().__init__(bus)
self.picontrol_device = picontrol_device self.picontrol_device = picontrol_device

View File

@@ -7,6 +7,7 @@ Helper for the process image.
The ResetDriverWatchdog class is a copy of revpipyload project module "watchdogs" The ResetDriverWatchdog class is a copy of revpipyload project module "watchdogs"
https://github.com/naruxde/revpipyload/blob/b51c2b617a57cc7d96fd67e1da9f090a0624eacb/src/revpipyload/watchdogs.py https://github.com/naruxde/revpipyload/blob/b51c2b617a57cc7d96fd67e1da9f090a0624eacb/src/revpipyload/watchdogs.py
""" """
import os import os
from ctypes import c_int from ctypes import c_int
from fcntl import ioctl from fcntl import ioctl

View File

@@ -2,5 +2,6 @@
# SPDX-FileCopyrightText: 2025 KUNBUS GmbH # SPDX-FileCopyrightText: 2025 KUNBUS GmbH
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
"""D-Bus interfaces for system configuration.""" """D-Bus interfaces for system configuration."""
from .interface_config import InterfaceRevpiConfig from .interface_config import InterfaceRevpiConfig
from .interface_services import InterfaceSoftwareServices from .interface_services import InterfaceSoftwareServices

View File

@@ -2,6 +2,7 @@
# SPDX-FileCopyrightText: 2025 KUNBUS GmbH # SPDX-FileCopyrightText: 2025 KUNBUS GmbH
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
"""D-Bus interfaces for hardware configuration.""" """D-Bus interfaces for hardware configuration."""
from collections import namedtuple from collections import namedtuple
from logging import getLogger from logging import getLogger

View File

@@ -2,9 +2,11 @@
# SPDX-FileCopyrightText: 2025 KUNBUS GmbH # SPDX-FileCopyrightText: 2025 KUNBUS GmbH
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
"""D-Bus interfaces for software services.""" """D-Bus interfaces for software services."""
from logging import getLogger from logging import getLogger
from typing import List from typing import List
from pydbus.bus import Bus
from pydbus.generic import signal from pydbus.generic import signal
from ..dbus_helper import DbusInterface from ..dbus_helper import DbusInterface
@@ -47,7 +49,7 @@ class InterfaceSoftwareServices(DbusInterface):
AvailabilityChanged = signal() AvailabilityChanged = signal()
StatusChanged = signal() StatusChanged = signal()
def __init__(self, bus): def __init__(self, bus: Bus):
super().__init__(bus) super().__init__(bus)
self.mrk_available = {} self.mrk_available = {}

View File

@@ -2,6 +2,7 @@
# SPDX-FileCopyrightText: 2025 KUNBUS GmbH # SPDX-FileCopyrightText: 2025 KUNBUS GmbH
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
"""Main application of revpi-middleware daemon.""" """Main application of revpi-middleware daemon."""
from logging import getLogger from logging import getLogger
from .daemon import MiddlewareDaemon from .daemon import MiddlewareDaemon

View File

@@ -2,6 +2,7 @@
# SPDX-FileCopyrightText: 2018-2023 Sven Sager # SPDX-FileCopyrightText: 2018-2023 Sven Sager
# SPDX-License-Identifier: LGPL-2.0-or-later # SPDX-License-Identifier: LGPL-2.0-or-later
"""Global program initialization.""" """Global program initialization."""
__author__ = "Sven Sager" __author__ = "Sven Sager"
__copyright__ = "Copyright (C) 2018-2023 Sven Sager" __copyright__ = "Copyright (C) 2018-2023 Sven Sager"
__license__ = "LGPL-2.0-or-later" __license__ = "LGPL-2.0-or-later"

View File

@@ -3,6 +3,8 @@
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
from time import sleep from time import sleep
from gi.repository.Gio import dbus_address_get_for_bus_sync, BusType
from tests.dbus_middleware1.fake_devices import PiControlDeviceMockup from tests.dbus_middleware1.fake_devices import PiControlDeviceMockup
@@ -12,12 +14,13 @@ class TestBusProvider(PiControlDeviceMockup):
super().setUp() super().setUp()
# Do not import things on top of the module. Some classes or functions need to be mocked up first. # Do not import things on top of the module. Some classes or functions need to be mocked up first.
from revpi_middleware.dbus_middleware1 import BusProvider from revpi_middleware.dbus_middleware1 import BusProviderMiddleware1
# Prepare the bus provider and start it # Prepare the bus provider and start it
self.bp = BusProvider( bus_address = dbus_address_get_for_bus_sync(BusType.SESSION)
self.picontrol.name, self.bp = BusProviderMiddleware1(
use_system_bus=False, bus_address,
picontrol_device=self.picontrol.name,
) )
self.bp.start() self.bp.start()