From 865d2ca7a94101e082a59fd33f259a592ac16949 Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Sun, 20 Apr 2025 12:19:41 +0200 Subject: [PATCH 01/23] refactor: Update interface name from 'picontrol' to 'PiControl' Renamed all occurrences of 'picontrol' to 'PiControl' in the D-Bus interface definitions, method calls, and test cases for consistency and adherence to naming conventions. This ensures uniformity across the codebase and resolves potential naming-related issues. --- src/revpi_middleware/cli_commands/cli_picontrol.py | 4 ++-- .../dbus_middleware1/process_image/interface_picontrol.py | 2 +- .../process_image/test_interface_picontrol.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/revpi_middleware/cli_commands/cli_picontrol.py b/src/revpi_middleware/cli_commands/cli_picontrol.py index 6eb355f..becac3e 100644 --- a/src/revpi_middleware/cli_commands/cli_picontrol.py +++ b/src/revpi_middleware/cli_commands/cli_picontrol.py @@ -38,7 +38,7 @@ def method_reset(): log.debug("D-Bus call of method ResetDriver") simple_call( "ResetDriver", - interface=extend_interface("picontrol"), + interface=extend_interface("PiControl"), bus_type=BusType.SESSION if pi.pargs.use_session_bus else BusType.SYSTEM, ) log.info("ResetDriver called via D-Bus") @@ -48,7 +48,7 @@ def method_await_reset(timeout: int = 0): detected_signal = await_signal( "NotifyDriverReset", timeout, - extend_interface("picontrol"), + extend_interface("PiControl"), bus_type=BusType.SESSION if pi.pargs.use_session_bus else BusType.SYSTEM, ) if detected_signal: diff --git a/src/revpi_middleware/dbus_middleware1/process_image/interface_picontrol.py b/src/revpi_middleware/dbus_middleware1/process_image/interface_picontrol.py index f62a972..0e8ccb0 100644 --- a/src/revpi_middleware/dbus_middleware1/process_image/interface_picontrol.py +++ b/src/revpi_middleware/dbus_middleware1/process_image/interface_picontrol.py @@ -15,7 +15,7 @@ log = getLogger(__name__) class InterfacePiControl(DbusInterface): """ - + diff --git a/tests/dbus_middleware1/process_image/test_interface_picontrol.py b/tests/dbus_middleware1/process_image/test_interface_picontrol.py index cd11a6e..ec26c9d 100644 --- a/tests/dbus_middleware1/process_image/test_interface_picontrol.py +++ b/tests/dbus_middleware1/process_image/test_interface_picontrol.py @@ -18,7 +18,7 @@ class TestObjectPicontrol(TestBusProvider): def test_reset_driver(self): simple_call( "ResetDriver", - interface=extend_interface("picontrol"), + interface=extend_interface("PiControl"), bus_type=BusType.SESSION, ) ioctl_call = IOCTL_QUEUE.get(timeout=2.0) @@ -37,7 +37,7 @@ class TestObjectPicontrol(TestBusProvider): result = await_signal( "NotifyDriverReset", timeout, - extend_interface("picontrol"), + extend_interface("PiControl"), bus_type=BusType.SESSION, ) self.assertTrue(result) From 3cc64f514fbd671111b5c90bf2e025aa21042b86 Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Sun, 20 Apr 2025 15:04:11 +0200 Subject: [PATCH 02/23] feat(dbus): Add `grep` function to search for patterns in a file The new `grep` function reads a specified file and returns lines containing a given pattern. It handles file not found errors and logs unexpected exceptions, improving resilience in file operations. --- .../dbus_middleware1/dbus_helper.py | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/revpi_middleware/dbus_middleware1/dbus_helper.py b/src/revpi_middleware/dbus_middleware1/dbus_helper.py index 23bcd2e..62dd766 100644 --- a/src/revpi_middleware/dbus_middleware1/dbus_helper.py +++ b/src/revpi_middleware/dbus_middleware1/dbus_helper.py @@ -41,3 +41,38 @@ def extend_interface(*args) -> str: the provided segments. """ return ".".join([REVPI_DBUS_NAME, *args]) + + +def grep(pattern, filename): + """ + Searches for lines in a file that contain a given pattern and returns them as a list. + + The function reads lines from the specified file and checks whether each line + contains the provided pattern. It returns a list of lines that match the + pattern. If the file is not found, an empty list is returned. Any other + exceptions during the file reading process are caught and logged. + + Args: + pattern (str): The substring to search for within the file's lines. + filename (str): The path to the file that will be searched. + + Returns: + list[str]: A list containing lines that include the provided pattern, with + leading and trailing spaces removed. + + Raises: + FileNotFoundError: This error is caught if the file specified is not + found. + Exception: Any unforeseen exception during file operations is caught and + logged. + """ + try: + with open(filename, "r") as file: + # Gibt alle Zeilen zurück, die das Muster enthalten + matching_lines = [line.strip() for line in file if pattern in line] + return matching_lines + except FileNotFoundError: + return [] + except Exception as e: + log.error(f"Error reading file: {e}") + return [] From c24c78761fb47c9529da12859e5f70412f3750de Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Sun, 20 Apr 2025 15:10:18 +0200 Subject: [PATCH 03/23] fix(cli): Change absolute imports to relative imports --- src/revpi_middleware/cli_commands/cli_base.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/revpi_middleware/cli_commands/cli_base.py b/src/revpi_middleware/cli_commands/cli_base.py index c57f277..19def6a 100644 --- a/src/revpi_middleware/cli_commands/cli_base.py +++ b/src/revpi_middleware/cli_commands/cli_base.py @@ -5,12 +5,11 @@ This module provides the foundation for the RevPi middleware CLI commands and argument parsing setup. """ -from argparse import ArgumentParser from logging import getLogger -from revpi_middleware.cli_commands import cli_picontrol -from revpi_middleware.proginit import StdLogOutput +from . import cli_config, cli_picontrol from .. import proginit as pi +from ..proginit import StdLogOutput log = getLogger(__name__) From 9ce36c78e73badd2ce74fa506298cdec444b9733 Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Sun, 20 Apr 2025 14:53:57 +0200 Subject: [PATCH 04/23] feat(dbus): Add D-Bus interface for system configuration in middleware Introduced `InterfaceRevpiConfig` to manage feature actions like enable/disable, status, and availability using D-Bus. Includes support for predefined features with systemd integration and exception handling for unsupported features. --- .../system_config/__init__.py | 5 + .../system_config/interface_config.py | 137 ++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 src/revpi_middleware/dbus_middleware1/system_config/__init__.py create mode 100644 src/revpi_middleware/dbus_middleware1/system_config/interface_config.py diff --git a/src/revpi_middleware/dbus_middleware1/system_config/__init__.py b/src/revpi_middleware/dbus_middleware1/system_config/__init__.py new file mode 100644 index 0000000..8f6ef5d --- /dev/null +++ b/src/revpi_middleware/dbus_middleware1/system_config/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# SPDX-FileCopyrightText: 2025 KUNBUS GmbH +# SPDX-License-Identifier: GPL-2.0-or-later +"""D-Bus interfaces for system configuration.""" +from .interface_config import InterfaceRevpiConfig diff --git a/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py b/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py new file mode 100644 index 0000000..03aaca2 --- /dev/null +++ b/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py @@ -0,0 +1,137 @@ +# -*- coding: utf-8 -*- +# SPDX-FileCopyrightText: 2025 KUNBUS GmbH +# SPDX-License-Identifier: GPL-2.0-or-later +"""D-Bus interfaces for hardware configuration.""" +from collections import namedtuple +from enum import Enum +from logging import getLogger + +from pydbus import SystemBus + +from ..dbus_helper import DbusInterface + +log = getLogger(__name__) + +FeatureFunction = namedtuple("FeatureFunction", ["function", "args"]) + + +class ConfigActions(Enum): + ENABLE = "enable" + DISABLE = "disable" + STATUS = "status" + AVAILABLE = "available" + + +class InterfaceRevpiConfig(DbusInterface): + """ + + + + + + + + + + + + + + + + + + + + """ + + def Disable(self, feature: str) -> None: + """Disable the feature.""" + feature_function = get_feature(feature) + feature_function.function(ConfigActions.DISABLE, *feature_function.args) + + def Enable(self, feature: str) -> None: + """Enable the feature.""" + feature_function = get_feature(feature) + feature_function.function(ConfigActions.ENABLE, *feature_function.args) + + def GetStatus(self, feature: str) -> bool: + """Get feature status.""" + feature_function = get_feature(feature) + return feature_function.function(ConfigActions.STATUS, *feature_function.args) + + def GetAvailability(self, feature: str) -> bool: + """Get feature availability on the RevPi.""" + feature_function = get_feature(feature) + return feature_function.function(ConfigActions.AVAILABLE, *feature_function.args) + + @property + def available_features(self) -> list[str]: + return list(AVAILABLE_FEATURES.keys()) + + +def get_feature(feature: str) -> FeatureFunction: + if feature not in AVAILABLE_FEATURES: + raise ValueError(f"feature {feature} does not exist") + feature_function = AVAILABLE_FEATURES[feature] + if not feature_function: + raise NotImplementedError(f"feature {feature} is not implemented") + return feature_function + + +def simple_systemd(action: ConfigActions, unit: str): + bus = SystemBus() + systemd_manager = bus.get(".systemd1") + + if action is ConfigActions.ENABLE: + systemd_manager.UnmaskUnitFiles([unit], False) + systemd_manager.EnableUnitFiles([unit], False, False) + systemd_manager.StartUnit(unit, "replace") + + elif action is ConfigActions.DISABLE: + systemd_manager.StopUnit(unit, "replace") + systemd_manager.DisableUnitFiles([unit], False) + + elif action is ConfigActions.STATUS: + try: + unit_path = systemd_manager.LoadUnit(unit) + properties = bus.get(".systemd1", unit_path) + except Exception: + log.warning(f"could not get systemd unit {unit}") + return False + + return properties.UnitFileState == "enabled" and properties.ActiveState == "active" + + elif action is ConfigActions.AVAILABLE: + try: + unit_path = systemd_manager.LoadUnit(unit) + properties = bus.get(".systemd1", unit_path) + except Exception: + log.warning(f"could not get systemd unit {unit}") + return False + + return properties.LoadState != "not-found" + + else: + raise ValueError(f"action {action} not supported") + + +AVAILABLE_FEATURES = { + "gui": False, + "revpi-con-can": False, + "var-log.mount": False, + "dphys-swapfile": False, + "pimodbus-master": FeatureFunction(simple_systemd, ["pimodbus-master.service"]), + "pimodbus-slave": FeatureFunction(simple_systemd, ["pimodbus-slave.service"]), + "systemd-timesyncd": FeatureFunction(simple_systemd, ["systemd-timesyncd.service"]), + "ssh": FeatureFunction(simple_systemd, ["ssh.service"]), + "nodered": FeatureFunction(simple_systemd, ["nodered.service"]), + "noderedrevpinodes-server": FeatureFunction( + simple_systemd, ["noderedrevpinodes-server.service"] + ), + "revpipyload": FeatureFunction(simple_systemd, ["revpipyload.service"]), + "bluetooth": False, + "ieee80211": False, + "avahi": False, + "external-antenna": False, +} From 3909fab37906e0e30ffdf191ddbdf41ff6d7c727 Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Sun, 20 Apr 2025 15:34:16 +0200 Subject: [PATCH 05/23] feat(dbus): Add GUI configuration handling to interface_config.py Introduced the `configure_gui` function to manage GUI enabling, disabling, availability, and status retrieval. Updated the `AVAILABLE_FEATURES` dictionary to include GUI management functionality, leveraging systemd and os module operations. --- .../system_config/interface_config.py | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py b/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py index 03aaca2..76c7933 100644 --- a/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py +++ b/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py @@ -5,6 +5,7 @@ from collections import namedtuple from enum import Enum from logging import getLogger +from os import X_OK, access from pydbus import SystemBus @@ -70,6 +71,28 @@ class InterfaceRevpiConfig(DbusInterface): return list(AVAILABLE_FEATURES.keys()) +def configure_gui(action: ConfigActions): + gui_available = access("/usr/bin/startx", X_OK) + + if action is ConfigActions.AVAILABLE: + return gui_available + + bus = SystemBus() + systemd_manager = bus.get(".systemd1") + + if action is ConfigActions.ENABLE: + systemd_manager.SetDefaultTarget("graphical.target", True) + + elif action is ConfigActions.DISABLE: + systemd_manager.SetDefaultTarget("multi-user.target", True) + + elif action is ConfigActions.STATUS: + return systemd_manager.GetDefaultTarget() == "graphical.target" + + else: + raise ValueError(f"action {action} not supported") + + def get_feature(feature: str) -> FeatureFunction: if feature not in AVAILABLE_FEATURES: raise ValueError(f"feature {feature} does not exist") @@ -117,7 +140,7 @@ def simple_systemd(action: ConfigActions, unit: str): AVAILABLE_FEATURES = { - "gui": False, + "gui": FeatureFunction(configure_gui, []), "revpi-con-can": False, "var-log.mount": False, "dphys-swapfile": False, From 7525c9f653d3f860e4dfd107651c4e5a6b174047 Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Sun, 20 Apr 2025 15:37:26 +0200 Subject: [PATCH 06/23] feat(revpiconfig): Add RevPiConfig class for device information handling This commit introduces a new `RevPiConfig` class to manage RevPi device configuration details, such as model, serial, compute module type, WiFi, and ConBridge detection. It parses CPU info from `/proc/cpuinfo` and leverages helper methods for hardware-specific checks, enhancing the middleware's ability to identify and manage hardware features. --- .../system_config/revpi_config.py | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py diff --git a/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py b/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py new file mode 100644 index 0000000..12ef5ee --- /dev/null +++ b/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- +# SPDX-FileCopyrightText: 2025 KUNBUS GmbH +# SPDX-License-Identifier: GPL-2.0-or-later +from enum import IntEnum +from logging import getLogger + +from ..dbus_helper import grep + +log = getLogger(__name__) + + +class ComputeModuleTypes(IntEnum): + UNKNOWN = 0 + CM1 = 6 + CM3 = 10 + CM4 = 20 + CM4S = 21 + CM5 = 24 + + +class RevPiConfig: + + def __init__(self): + self._cm_type = ComputeModuleTypes.UNKNOWN + self._cm_with_wifi = False + + self._revpi_with_con_bridge = False + + self.serial = "" + self.model = "" + + self._init_device_info() + + def _init_device_info(self): + dc_cpuinfo = {} + + # Extract CPU information + with open("/proc/cpuinfo", "r") as f: + line = "\n" + while line: + line = f.readline() + if line.startswith(("Revision", "Serial", "Model")): + key, value = line.split(":", 1) + key = key.strip().lower() + value = value.strip() + dc_cpuinfo[key] = value + + self.model = dc_cpuinfo.get("model", "") + self.serial = dc_cpuinfo.get("serial", "") + + # Detect Compute Module type + revision = dc_cpuinfo.get("revision", "") + if revision: + revision = int(revision, 16) + mask = 4080 # 0xFF0 in dezimal + try: + self._cm_type = ComputeModuleTypes((revision & mask) >> 4) + except ValueError: + pass + + # Detect WiFi + could_have_wifi = self._cm_type in (ComputeModuleTypes.CM4, ComputeModuleTypes.CM5) + if could_have_wifi: + lst_grep = grep("DRIVER=brcmfmac", "/sys/class/ieee80211/phy0/device/uevent") + self._cm_with_wifi = len(lst_grep) > 0 and self._cm_type in (ComputeModuleTypes) + + # Detect ConBridge + could_have_con_bridge = self._cm_type in (ComputeModuleTypes.CM3, ComputeModuleTypes.CM4S) + if could_have_con_bridge: + lst_grep = grep("kunbus,revpi-connect", "/proc/device-tree/compatible") + self._revpi_with_con_bridge = len(lst_grep) > 0 + + @property + def cm_type(self) -> ComputeModuleTypes: + return self._cm_type + + @property + def with_con_bridge(self) -> bool: + return self._revpi_with_con_bridge + + @property + def with_wifi(self) -> bool: + return self._cm_with_wifi + + +if __name__ == "__main__": + rc = RevPiConfig() + print("Model:", rc.model) + print("Serial: ", rc.serial) + print("CM Type: ", rc.cm_type.name) + print("With wifi: ", rc.with_wifi) + print("With con-bridge:", rc.with_con_bridge) From 66735a9ebadd0c24bf67fef57d19c5bad0683b62 Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Sun, 20 Apr 2025 15:42:05 +0200 Subject: [PATCH 07/23] refactor(dbus): Move system configuration methods to revpi_config.py Centralized `ConfigActions`, `configure_gui`, and `simple_systemd` into `revpi_config.py` to eliminate duplication and improve maintainability. Updated `interface_config.py` to import these methods, ensuring consistent functionality across modules. --- .../system_config/interface_config.py | 71 +------------------ .../system_config/revpi_config.py | 71 ++++++++++++++++++- 2 files changed, 71 insertions(+), 71 deletions(-) diff --git a/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py b/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py index 76c7933..b1aa68c 100644 --- a/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py +++ b/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py @@ -3,12 +3,9 @@ # SPDX-License-Identifier: GPL-2.0-or-later """D-Bus interfaces for hardware configuration.""" from collections import namedtuple -from enum import Enum from logging import getLogger -from os import X_OK, access - -from pydbus import SystemBus +from .revpi_config import ConfigActions, configure_gui, simple_systemd from ..dbus_helper import DbusInterface log = getLogger(__name__) @@ -16,13 +13,6 @@ log = getLogger(__name__) FeatureFunction = namedtuple("FeatureFunction", ["function", "args"]) -class ConfigActions(Enum): - ENABLE = "enable" - DISABLE = "disable" - STATUS = "status" - AVAILABLE = "available" - - class InterfaceRevpiConfig(DbusInterface): """ @@ -71,28 +61,6 @@ class InterfaceRevpiConfig(DbusInterface): return list(AVAILABLE_FEATURES.keys()) -def configure_gui(action: ConfigActions): - gui_available = access("/usr/bin/startx", X_OK) - - if action is ConfigActions.AVAILABLE: - return gui_available - - bus = SystemBus() - systemd_manager = bus.get(".systemd1") - - if action is ConfigActions.ENABLE: - systemd_manager.SetDefaultTarget("graphical.target", True) - - elif action is ConfigActions.DISABLE: - systemd_manager.SetDefaultTarget("multi-user.target", True) - - elif action is ConfigActions.STATUS: - return systemd_manager.GetDefaultTarget() == "graphical.target" - - else: - raise ValueError(f"action {action} not supported") - - def get_feature(feature: str) -> FeatureFunction: if feature not in AVAILABLE_FEATURES: raise ValueError(f"feature {feature} does not exist") @@ -102,43 +70,6 @@ def get_feature(feature: str) -> FeatureFunction: return feature_function -def simple_systemd(action: ConfigActions, unit: str): - bus = SystemBus() - systemd_manager = bus.get(".systemd1") - - if action is ConfigActions.ENABLE: - systemd_manager.UnmaskUnitFiles([unit], False) - systemd_manager.EnableUnitFiles([unit], False, False) - systemd_manager.StartUnit(unit, "replace") - - elif action is ConfigActions.DISABLE: - systemd_manager.StopUnit(unit, "replace") - systemd_manager.DisableUnitFiles([unit], False) - - elif action is ConfigActions.STATUS: - try: - unit_path = systemd_manager.LoadUnit(unit) - properties = bus.get(".systemd1", unit_path) - except Exception: - log.warning(f"could not get systemd unit {unit}") - return False - - return properties.UnitFileState == "enabled" and properties.ActiveState == "active" - - elif action is ConfigActions.AVAILABLE: - try: - unit_path = systemd_manager.LoadUnit(unit) - properties = bus.get(".systemd1", unit_path) - except Exception: - log.warning(f"could not get systemd unit {unit}") - return False - - return properties.LoadState != "not-found" - - else: - raise ValueError(f"action {action} not supported") - - AVAILABLE_FEATURES = { "gui": FeatureFunction(configure_gui, []), "revpi-con-can": False, diff --git a/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py b/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py index 12ef5ee..40b57a7 100644 --- a/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py +++ b/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py @@ -1,8 +1,11 @@ # -*- coding: utf-8 -*- # SPDX-FileCopyrightText: 2025 KUNBUS GmbH # SPDX-License-Identifier: GPL-2.0-or-later -from enum import IntEnum +from enum import Enum, IntEnum from logging import getLogger +from os import X_OK, access + +from pydbus import SystemBus from ..dbus_helper import grep @@ -18,6 +21,13 @@ class ComputeModuleTypes(IntEnum): CM5 = 24 +class ConfigActions(Enum): + ENABLE = "enable" + DISABLE = "disable" + STATUS = "status" + AVAILABLE = "available" + + class RevPiConfig: def __init__(self): @@ -83,6 +93,65 @@ class RevPiConfig: return self._cm_with_wifi +def configure_gui(action: ConfigActions): + gui_available = access("/usr/bin/startx", X_OK) + + if action is ConfigActions.AVAILABLE: + return gui_available + + bus = SystemBus() + systemd_manager = bus.get(".systemd1") + + if action is ConfigActions.ENABLE: + systemd_manager.SetDefaultTarget("graphical.target", True) + + elif action is ConfigActions.DISABLE: + systemd_manager.SetDefaultTarget("multi-user.target", True) + + elif action is ConfigActions.STATUS: + return systemd_manager.GetDefaultTarget() == "graphical.target" + + else: + raise ValueError(f"action {action} not supported") + + +def simple_systemd(action: ConfigActions, unit: str): + bus = SystemBus() + systemd_manager = bus.get(".systemd1") + + if action is ConfigActions.ENABLE: + systemd_manager.UnmaskUnitFiles([unit], False) + systemd_manager.EnableUnitFiles([unit], False, False) + systemd_manager.StartUnit(unit, "replace") + + elif action is ConfigActions.DISABLE: + systemd_manager.StopUnit(unit, "replace") + systemd_manager.DisableUnitFiles([unit], False) + + elif action is ConfigActions.STATUS: + try: + unit_path = systemd_manager.LoadUnit(unit) + properties = bus.get(".systemd1", unit_path) + except Exception: + log.warning(f"could not get systemd unit {unit}") + return False + + return properties.UnitFileState == "enabled" and properties.ActiveState == "active" + + elif action is ConfigActions.AVAILABLE: + try: + unit_path = systemd_manager.LoadUnit(unit) + properties = bus.get(".systemd1", unit_path) + except Exception: + log.warning(f"could not get systemd unit {unit}") + return False + + return properties.LoadState != "not-found" + + else: + raise ValueError(f"action {action} not supported") + + if __name__ == "__main__": rc = RevPiConfig() print("Model:", rc.model) From 0d601f623c300f7dd795e46d656357455361be25 Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Sun, 20 Apr 2025 16:02:39 +0200 Subject: [PATCH 08/23] feat(dbus): Remove 'var-log.mount' feature The 'var-log.mount' feature was dropped and has been removed from the AVAILABLE_FEATURES dictionary. --- .../dbus_middleware1/system_config/interface_config.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py b/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py index b1aa68c..f3aec0f 100644 --- a/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py +++ b/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py @@ -73,7 +73,6 @@ def get_feature(feature: str) -> FeatureFunction: AVAILABLE_FEATURES = { "gui": FeatureFunction(configure_gui, []), "revpi-con-can": False, - "var-log.mount": False, "dphys-swapfile": False, "pimodbus-master": FeatureFunction(simple_systemd, ["pimodbus-master.service"]), "pimodbus-slave": FeatureFunction(simple_systemd, ["pimodbus-slave.service"]), From e8eba43647a37d95154e32fcf9791ca60286e3b3 Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Sun, 20 Apr 2025 16:16:51 +0200 Subject: [PATCH 09/23] feat(dbus): Add avahi-daemon configuration to system services Introduce a `configure_avahi_daemon` function to manage the avahi-daemon service and socket with proper post actions. Update the interface configuration to enable avahi management using the new function. --- .../system_config/interface_config.py | 4 ++-- .../dbus_middleware1/system_config/revpi_config.py | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py b/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py index f3aec0f..fd53d14 100644 --- a/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py +++ b/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py @@ -5,7 +5,7 @@ from collections import namedtuple from logging import getLogger -from .revpi_config import ConfigActions, configure_gui, simple_systemd +from .revpi_config import ConfigActions, configure_avahi_daemon, configure_gui, simple_systemd from ..dbus_helper import DbusInterface log = getLogger(__name__) @@ -85,6 +85,6 @@ AVAILABLE_FEATURES = { "revpipyload": FeatureFunction(simple_systemd, ["revpipyload.service"]), "bluetooth": False, "ieee80211": False, - "avahi": False, + "avahi": FeatureFunction(configure_avahi_daemon, []), "external-antenna": False, } diff --git a/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py b/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py index 40b57a7..95741dd 100644 --- a/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py +++ b/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py @@ -93,6 +93,18 @@ class RevPiConfig: return self._cm_with_wifi +def configure_avahi_daemon(action: ConfigActions): + return_value = simple_systemd(action, "avahi-daemon.service") + + # Post actions for avahi-daemon + if action in (ConfigActions.ENABLE, ConfigActions.DISABLE): + # Apply the enable/disable action to the avahi socket AFTER the service + # unit, because a connected socket could interrupt stop + simple_systemd(action, "avahi-daemon.socket") + + return return_value + + def configure_gui(action: ConfigActions): gui_available = access("/usr/bin/startx", X_OK) From d0f641f2b56d9aa6d9e6c73756312bab880da30b Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Sun, 20 Apr 2025 16:32:57 +0200 Subject: [PATCH 10/23] feat(dbus): Add dphys-swapfile configuration functionality Implemented `configure_dphys_swapfile` to manage the dphys-swapfile service, including automatic swapfile removal when the service is disabled. Updated feature registry to support dphys-swapfile configuration. --- .../system_config/interface_config.py | 10 ++++++++-- .../system_config/revpi_config.py | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py b/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py index fd53d14..a4dee25 100644 --- a/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py +++ b/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py @@ -5,7 +5,13 @@ from collections import namedtuple from logging import getLogger -from .revpi_config import ConfigActions, configure_avahi_daemon, configure_gui, simple_systemd +from .revpi_config import ( + ConfigActions, + configure_avahi_daemon, + configure_dphys_swapfile, + configure_gui, + simple_systemd, +) from ..dbus_helper import DbusInterface log = getLogger(__name__) @@ -73,7 +79,7 @@ def get_feature(feature: str) -> FeatureFunction: AVAILABLE_FEATURES = { "gui": FeatureFunction(configure_gui, []), "revpi-con-can": False, - "dphys-swapfile": False, + "dphys-swapfile": FeatureFunction(configure_dphys_swapfile, []), "pimodbus-master": FeatureFunction(simple_systemd, ["pimodbus-master.service"]), "pimodbus-slave": FeatureFunction(simple_systemd, ["pimodbus-slave.service"]), "systemd-timesyncd": FeatureFunction(simple_systemd, ["systemd-timesyncd.service"]), diff --git a/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py b/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py index 95741dd..f3b7a91 100644 --- a/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py +++ b/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # SPDX-FileCopyrightText: 2025 KUNBUS GmbH # SPDX-License-Identifier: GPL-2.0-or-later +import subprocess from enum import Enum, IntEnum from logging import getLogger from os import X_OK, access @@ -105,6 +106,21 @@ def configure_avahi_daemon(action: ConfigActions): return return_value +def configure_dphys_swapfile(action: ConfigActions): + return_value = simple_systemd(action, "dphys-swapfile.service") + + # Post actions for dphys-swapfile + if action is ConfigActions.DISABLE: + # Remove swapfile afer disabling the service unit + subprocess.call( + ["/sbin/dphys-swapfile", "uninstall"], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + + return return_value + + def configure_gui(action: ConfigActions): gui_available = access("/usr/bin/startx", X_OK) From 2848fdcf547756ef18f4c831a976df5965ae9f8a Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Sun, 20 Apr 2025 19:17:41 +0200 Subject: [PATCH 11/23] feat(revpiconfig): Add ConfigTxt class for managing config.txt file Introduced the ConfigTxt class to handle parsing, editing, and saving of config.txt files. This includes methods for adding, clearing, and retrieving configuration values, as well as handling dtoverlays and dtparams. Enhanced system configuration capabilities by providing structured support for config file operations. --- .../system_config/revpi_config.py | 97 ++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py b/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py index f3b7a91..fa4c490 100644 --- a/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py +++ b/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py @@ -1,10 +1,15 @@ # -*- coding: utf-8 -*- # SPDX-FileCopyrightText: 2025 KUNBUS GmbH # SPDX-License-Identifier: GPL-2.0-or-later +import re +import shutil import subprocess +from collections import namedtuple from enum import Enum, IntEnum from logging import getLogger from os import X_OK, access +from os.path import exists +from typing import List from pydbus import SystemBus @@ -12,6 +17,10 @@ from ..dbus_helper import grep log = getLogger(__name__) +ConfigVariable = namedtuple("ConfigVariable", ["name", "value", "line_index"]) + +CONFIG_TXT_LOCATIONS = ("/boot/firmware/config.txt", "/boot/config.txt") + class ComputeModuleTypes(IntEnum): UNKNOWN = 0 @@ -69,7 +78,7 @@ class RevPiConfig: except ValueError: pass - # Detect WiFi + # Detect WiFi on CM module could_have_wifi = self._cm_type in (ComputeModuleTypes.CM4, ComputeModuleTypes.CM5) if could_have_wifi: lst_grep = grep("DRIVER=brcmfmac", "/sys/class/ieee80211/phy0/device/uevent") @@ -94,6 +103,89 @@ class RevPiConfig: return self._cm_with_wifi +class ConfigTxt: + re_name_value = re.compile(r"^\s*(?!#)(?P[^=\s].+?)\s*=\s*(?P\S+)\s*$") + + def __init__(self): + self._config_txt_path = "" + for path in CONFIG_TXT_LOCATIONS: + if exists(path): + self._config_txt_path = path + break + + if not self._config_txt_path: + raise FileNotFoundError("no config.txt found") + + self._config_txt_lines = [] + + def _clear_name_values(self, name: str, values: str or list) -> int: + counter = 0 + if type(values) is str: + values = [values] + + for config_var in self._get_all_name_values(): + if config_var.name == name and config_var.value in values: + self._config_txt_lines.pop(config_var.line_index) + counter += 1 + + return counter + + def _get_all_name_values(self) -> List[ConfigVariable]: + if not self._config_txt_lines: + self.reload_config() + + lst_return = [] + + for i in range(len(self._config_txt_lines)): + match = self.re_name_value.match(self._config_txt_lines[i]) + if match: + lst_return.append(ConfigVariable(match.group("name"), match.group("value"), i)) + + return lst_return + + def reload_config(self): + with open(self._config_txt_path, "r") as f: + self._config_txt_lines = f.readlines() + + def save_config(self): + if not self._config_txt_lines: + return + + tmp_path = f"{self._config_txt_path}.tmp" + with open(tmp_path, "w") as f: + f.writelines(self._config_txt_lines) + shutil.move(tmp_path, self._config_txt_path) + + self._config_txt_lines.clear() + + def add_name_value(self, name: str, value: str): + # Check weather name and value already exists + for config_var in self._get_all_name_values(): + if config_var.name == name and config_var.value == value: + return + + self._config_txt_lines.append(f"{name}={value}\n") + + def clear_dtoverlays(self, dtoverlays: str or list) -> int: + return self._clear_name_values("dtoverlay", dtoverlays) + + def clear_dtparams(self, dtparams: str or list) -> int: + return self._clear_name_values("dtparam", dtparams) + + def get_values(self, var_name: str) -> list: + var_values = [] + + for config_var in self._get_all_name_values(): + if config_var.name == var_name: + var_values.append(config_var.value) + + return var_values + + @property + def config_txt_path(self) -> str: + return self._config_txt_path + + def configure_avahi_daemon(action: ConfigActions): return_value = simple_systemd(action, "avahi-daemon.service") @@ -187,3 +279,6 @@ if __name__ == "__main__": print("CM Type: ", rc.cm_type.name) print("With wifi: ", rc.with_wifi) print("With con-bridge:", rc.with_con_bridge) + + config_txt = ConfigTxt() + print("Config file: ", config_txt.config_txt_path) From 870a55042e5212e489c492c518ce22cdd97a83d3 Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Sun, 20 Apr 2025 19:18:41 +0200 Subject: [PATCH 12/23] feat(dbus): Add support for configuring the external antenna Introduce the `configure_external_antenna` function to manage external antenna settings, including enable, disable, and status checks. Update the feature configuration in `interface_config` to include this functionality. This enhances WiFi-related configuration options. --- .../system_config/interface_config.py | 3 ++- .../system_config/revpi_config.py | 25 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py b/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py index a4dee25..f16a754 100644 --- a/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py +++ b/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py @@ -9,6 +9,7 @@ from .revpi_config import ( ConfigActions, configure_avahi_daemon, configure_dphys_swapfile, + configure_external_antenna, configure_gui, simple_systemd, ) @@ -92,5 +93,5 @@ AVAILABLE_FEATURES = { "bluetooth": False, "ieee80211": False, "avahi": FeatureFunction(configure_avahi_daemon, []), - "external-antenna": False, + "external-antenna": FeatureFunction(configure_external_antenna, []), } diff --git a/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py b/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py index fa4c490..33bb0b9 100644 --- a/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py +++ b/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py @@ -213,6 +213,31 @@ def configure_dphys_swapfile(action: ConfigActions): return return_value +def configure_external_antenna(action: ConfigActions): + revpi = RevPiConfig() + if action is ConfigActions.AVAILABLE: + return revpi.with_wifi + + config_txt = ConfigTxt() + + if action is ConfigActions.ENABLE and revpi.with_wifi: + config_txt.clear_dtparams(["ant1", "ant2"]) + config_txt.add_name_value("dtparam", "ant2") + config_txt.save_config() + + elif action is ConfigActions.DISABLE and revpi.with_wifi: + config_txt.clear_dtparams(["ant1", "ant2"]) + config_txt.save_config() + + elif action is ConfigActions.STATUS: + return revpi.with_wifi and "ant2" in config_txt.get_values("dtparam") + + else: + raise ValueError(f"action {action} not supported") + + return None + + def configure_gui(action: ConfigActions): gui_available = access("/usr/bin/startx", X_OK) From fe614d026ac90ac9a148daa5c0caef1af62ef02f Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Sun, 20 Apr 2025 19:19:13 +0200 Subject: [PATCH 13/23] feat(dbus): Add support for configuring 'revpi-con-can' feature Introduce the `configure_con_can` function to manage enabling, disabling, status checking, and availability of the 'revpi-con-can' feature. Update the `AVAILABLE_FEATURES` dictionary to integrate 'revpi-con-can' as a configurable feature. --- .../system_config/interface_config.py | 3 +- .../system_config/revpi_config.py | 28 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py b/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py index f16a754..e3fe7d3 100644 --- a/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py +++ b/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py @@ -8,6 +8,7 @@ from logging import getLogger from .revpi_config import ( ConfigActions, configure_avahi_daemon, + configure_con_can, configure_dphys_swapfile, configure_external_antenna, configure_gui, @@ -79,7 +80,7 @@ def get_feature(feature: str) -> FeatureFunction: AVAILABLE_FEATURES = { "gui": FeatureFunction(configure_gui, []), - "revpi-con-can": False, + "revpi-con-can": FeatureFunction(configure_con_can, []), "dphys-swapfile": FeatureFunction(configure_dphys_swapfile, []), "pimodbus-master": FeatureFunction(simple_systemd, ["pimodbus-master.service"]), "pimodbus-slave": FeatureFunction(simple_systemd, ["pimodbus-slave.service"]), diff --git a/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py b/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py index 33bb0b9..bb8a702 100644 --- a/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py +++ b/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py @@ -198,6 +198,34 @@ def configure_avahi_daemon(action: ConfigActions): return return_value +def configure_con_can(action: ConfigActions): + revpi = RevPiConfig() + if action is ConfigActions.AVAILABLE: + return revpi.with_con_bridge + + dt_overlay = "revpi-con-can" + config_txt = ConfigTxt() + + if action is ConfigActions.ENABLE and revpi.with_con_bridge: + config_txt.clear_dtoverlays([dt_overlay]) + config_txt.add_name_value("dtoverlay", dt_overlay) + config_txt.save_config() + subprocess.call(["/usr/bin/dtoverlay", dt_overlay]) + + elif action is ConfigActions.DISABLE and revpi.with_con_bridge: + config_txt.clear_dtoverlays([dt_overlay]) + config_txt.save_config() + subprocess.call(["/usr/bin/dtoverlay", "-r", dt_overlay]) + + elif action is ConfigActions.STATUS: + return revpi.with_con_bridge and dt_overlay in config_txt.get_values("dtparam") + + else: + raise ValueError(f"action {action} not supported") + + return None + + def configure_dphys_swapfile(action: ConfigActions): return_value = simple_systemd(action, "dphys-swapfile.service") From 18e6fb3d14fc7694b28b15df39da27b6cd0f7ccc Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Mon, 21 Apr 2025 09:04:10 +0200 Subject: [PATCH 14/23] feat(revpiconfig): Enhance Wi-Fi detection and add rfkill index support Improved logic to detect built-in and third-party Wi-Fi interfaces, including integration of `rfkill` index retrieval for Wi-Fi devices. This enhances support for various hardware setups and allows better control over Wi-Fi functionality. --- .../system_config/revpi_config.py | 36 ++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py b/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py index bb8a702..7cfe715 100644 --- a/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py +++ b/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py @@ -6,10 +6,11 @@ import shutil import subprocess from collections import namedtuple from enum import Enum, IntEnum +from glob import glob from logging import getLogger from os import X_OK, access -from os.path import exists -from typing import List +from os.path import exists, join +from typing import List, Optional from pydbus import SystemBus @@ -19,6 +20,7 @@ log = getLogger(__name__) ConfigVariable = namedtuple("ConfigVariable", ["name", "value", "line_index"]) +LINUX_WIFI_CLASS_PATH = "/sys/class/ieee80211" CONFIG_TXT_LOCATIONS = ("/boot/firmware/config.txt", "/boot/config.txt") @@ -45,6 +47,8 @@ class RevPiConfig: self._cm_with_wifi = False self._revpi_with_con_bridge = False + self._wlan_class_path = "" + self._wlan_rfkill_index = None self.serial = "" self.model = "" @@ -81,8 +85,26 @@ class RevPiConfig: # Detect WiFi on CM module could_have_wifi = self._cm_type in (ComputeModuleTypes.CM4, ComputeModuleTypes.CM5) if could_have_wifi: - lst_grep = grep("DRIVER=brcmfmac", "/sys/class/ieee80211/phy0/device/uevent") - self._cm_with_wifi = len(lst_grep) > 0 and self._cm_type in (ComputeModuleTypes) + wifi_interface = join(LINUX_WIFI_CLASS_PATH, "phy0") + lst_grep = grep("DRIVER=brcmfmac", join(wifi_interface, "device", "uevent")) + self._cm_with_wifi = len(lst_grep) > 0 + self._wlan_class_path = wifi_interface + + # If no build in Wi-Fi on the CM, detect third party Wi-Fi on RevPi Flat + if not self._cm_with_wifi and grep("revpi-flat", "/proc/device-tree/compatible"): + lst_wifi_interfaces = glob("/sys/class/ieee80211/*") + for wifi_interface in lst_wifi_interfaces: + if grep("DRIVER=mwifiex_sdio", join(wifi_interface, "device", "uevent")): + self._cm_with_wifi = True + self._wlan_class_path = wifi_interface + + # Detect rfkill index of the integrated Wi-Fi device + if self._wlan_class_path: + for rfkill_path in glob(join(self._wlan_class_path, "rfkill*")): + match_index = re.match(r"^/.+/rfkill(?P\d+)$", rfkill_path) + if match_index: + self._wlan_rfkill_index = int(match_index.group("index")) + break # Detect ConBridge could_have_con_bridge = self._cm_type in (ComputeModuleTypes.CM3, ComputeModuleTypes.CM4S) @@ -94,6 +116,10 @@ class RevPiConfig: def cm_type(self) -> ComputeModuleTypes: return self._cm_type + @property + def rfkill_index(self) -> Optional[int]: + return self._wlan_rfkill_index + @property def with_con_bridge(self) -> bool: return self._revpi_with_con_bridge @@ -331,6 +357,8 @@ if __name__ == "__main__": print("Serial: ", rc.serial) print("CM Type: ", rc.cm_type.name) print("With wifi: ", rc.with_wifi) + if rc.with_wifi: + print(" rfkill index: ", rc.rfkill_index) print("With con-bridge:", rc.with_con_bridge) config_txt = ConfigTxt() From 6eb7eeea403f241f0b72f27ae21d8ec31b1fc960 Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Mon, 21 Apr 2025 09:22:30 +0200 Subject: [PATCH 15/23] feat(dbus): Add Wi-Fi configuration support to the system config Introduces the `configure_wifi` function to handle Wi-Fi actions such as enabling, disabling, and checking status. Updates the `ieee80211` feature to use the new function, integrating Wi-Fi management into the existing configuration framework. --- .../system_config/interface_config.py | 3 +- .../system_config/revpi_config.py | 28 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py b/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py index e3fe7d3..0e96390 100644 --- a/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py +++ b/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py @@ -12,6 +12,7 @@ from .revpi_config import ( configure_dphys_swapfile, configure_external_antenna, configure_gui, + configure_wifi, simple_systemd, ) from ..dbus_helper import DbusInterface @@ -92,7 +93,7 @@ AVAILABLE_FEATURES = { ), "revpipyload": FeatureFunction(simple_systemd, ["revpipyload.service"]), "bluetooth": False, - "ieee80211": False, + "ieee80211": FeatureFunction(configure_wifi, []), "avahi": FeatureFunction(configure_avahi_daemon, []), "external-antenna": FeatureFunction(configure_external_antenna, []), } diff --git a/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py b/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py index 7cfe715..fdd25a3 100644 --- a/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py +++ b/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py @@ -314,6 +314,34 @@ def configure_gui(action: ConfigActions): raise ValueError(f"action {action} not supported") +def configure_wifi(action: ConfigActions): + revpi = RevPiConfig() + + if action is ConfigActions.ENABLE: + if revpi.rfkill_index is not None: + subprocess.call(["rfkill", "unblock", str(revpi.rfkill_index)]) + + elif action is ConfigActions.DISABLE: + if revpi.rfkill_index is not None: + subprocess.call(["rfkill", "block", str(revpi.rfkill_index)]) + + elif action is ConfigActions.AVAILABLE: + return revpi.with_wifi and revpi.rfkill_index is not None + + elif action is ConfigActions.STATUS: + if revpi.rfkill_index is None: + return False + + with open(f"/sys/class/rfkill/rfkill{revpi.rfkill_index}/soft", "r") as f: + buffer = f.read().strip() + return buffer == "0" + + else: + raise ValueError(f"action {action} not supported") + + return None + + def simple_systemd(action: ConfigActions, unit: str): bus = SystemBus() systemd_manager = bus.get(".systemd1") From 69e370f964dcf34dced72920f718e61841f2c994 Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Mon, 21 Apr 2025 10:04:39 +0200 Subject: [PATCH 16/23] refactor(revpiconfig: Change Wi-Fi detection and rfkill index logic Replaced inline rfkill index detection with a standalone `get_rfkill_index` function for improved modularity. Removed `_cm_with_wifi` and `_wlan_rfkill_index` attributes, utilizing `_wlan_class_path` for Wi-Fi presence checks. Adjusted property and output logic to incorporate the new function. --- .../system_config/revpi_config.py | 58 ++++++++++--------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py b/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py index fdd25a3..da1832c 100644 --- a/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py +++ b/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py @@ -44,11 +44,9 @@ class RevPiConfig: def __init__(self): self._cm_type = ComputeModuleTypes.UNKNOWN - self._cm_with_wifi = False self._revpi_with_con_bridge = False self._wlan_class_path = "" - self._wlan_rfkill_index = None self.serial = "" self.model = "" @@ -86,26 +84,16 @@ class RevPiConfig: could_have_wifi = self._cm_type in (ComputeModuleTypes.CM4, ComputeModuleTypes.CM5) if could_have_wifi: wifi_interface = join(LINUX_WIFI_CLASS_PATH, "phy0") - lst_grep = grep("DRIVER=brcmfmac", join(wifi_interface, "device", "uevent")) - self._cm_with_wifi = len(lst_grep) > 0 - self._wlan_class_path = wifi_interface + if grep("DRIVER=brcmfmac", join(wifi_interface, "device", "uevent")): + self._wlan_class_path = wifi_interface # If no build in Wi-Fi on the CM, detect third party Wi-Fi on RevPi Flat - if not self._cm_with_wifi and grep("revpi-flat", "/proc/device-tree/compatible"): + if not self._wlan_class_path and grep("revpi-flat", "/proc/device-tree/compatible"): lst_wifi_interfaces = glob("/sys/class/ieee80211/*") for wifi_interface in lst_wifi_interfaces: if grep("DRIVER=mwifiex_sdio", join(wifi_interface, "device", "uevent")): - self._cm_with_wifi = True self._wlan_class_path = wifi_interface - # Detect rfkill index of the integrated Wi-Fi device - if self._wlan_class_path: - for rfkill_path in glob(join(self._wlan_class_path, "rfkill*")): - match_index = re.match(r"^/.+/rfkill(?P\d+)$", rfkill_path) - if match_index: - self._wlan_rfkill_index = int(match_index.group("index")) - break - # Detect ConBridge could_have_con_bridge = self._cm_type in (ComputeModuleTypes.CM3, ComputeModuleTypes.CM4S) if could_have_con_bridge: @@ -113,12 +101,12 @@ class RevPiConfig: self._revpi_with_con_bridge = len(lst_grep) > 0 @property - def cm_type(self) -> ComputeModuleTypes: - return self._cm_type + def class_path_wifi(self) -> str: + return self._wlan_class_path @property - def rfkill_index(self) -> Optional[int]: - return self._wlan_rfkill_index + def cm_type(self) -> ComputeModuleTypes: + return self._cm_type @property def with_con_bridge(self) -> bool: @@ -126,7 +114,7 @@ class RevPiConfig: @property def with_wifi(self) -> bool: - return self._cm_with_wifi + return bool(self._wlan_class_path) class ConfigTxt: @@ -318,21 +306,24 @@ def configure_wifi(action: ConfigActions): revpi = RevPiConfig() if action is ConfigActions.ENABLE: - if revpi.rfkill_index is not None: - subprocess.call(["rfkill", "unblock", str(revpi.rfkill_index)]) + if revpi.with_wifi: + wifi_rfkill_index = get_rfkill_index(revpi.class_path_wifi) + subprocess.call(["rfkill", "unblock", str(wifi_rfkill_index)]) elif action is ConfigActions.DISABLE: - if revpi.rfkill_index is not None: - subprocess.call(["rfkill", "block", str(revpi.rfkill_index)]) + if revpi.with_wifi: + wifi_rfkill_index = get_rfkill_index(revpi.class_path_wifi) + subprocess.call(["rfkill", "block", str(wifi_rfkill_index)]) elif action is ConfigActions.AVAILABLE: - return revpi.with_wifi and revpi.rfkill_index is not None + return revpi.with_wifi elif action is ConfigActions.STATUS: - if revpi.rfkill_index is None: + if not revpi.with_wifi: return False - with open(f"/sys/class/rfkill/rfkill{revpi.rfkill_index}/soft", "r") as f: + wifi_rfkill_index = get_rfkill_index(revpi.class_path_wifi) + with open(f"/sys/class/rfkill/rfkill{wifi_rfkill_index}/soft", "r") as f: buffer = f.read().strip() return buffer == "0" @@ -342,6 +333,16 @@ def configure_wifi(action: ConfigActions): return None +def get_rfkill_index(device_class_path: str) -> Optional[int]: + re_rfkill_index = re.compile(r"^/.+/rfkill(?P\d+)$") + for rfkill_path in glob(join(device_class_path, "rfkill*")): + match_index = re_rfkill_index.match(rfkill_path) + if match_index: + return int(match_index.group("index")) + + return None + + def simple_systemd(action: ConfigActions, unit: str): bus = SystemBus() systemd_manager = bus.get(".systemd1") @@ -386,7 +387,8 @@ if __name__ == "__main__": print("CM Type: ", rc.cm_type.name) print("With wifi: ", rc.with_wifi) if rc.with_wifi: - print(" rfkill index: ", rc.rfkill_index) + print(" class path: ", rc.class_path_wifi) + print(" rfkill index: ", get_rfkill_index(rc.class_path_wifi)) print("With con-bridge:", rc.with_con_bridge) config_txt = ConfigTxt() From 604cb61870649669817bf4c0d5843c0b29a8cca3 Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Mon, 21 Apr 2025 10:17:56 +0200 Subject: [PATCH 17/23] feat(dbus): Add Bluetooth configuration functionality Introduce functionality to enable, disable, and check the status and availability of Bluetooth devices using the `configure_bluetooth` method. Integrate Bluetooth configuration into the feature management system by mapping it in `interface_config.py`. --- .../system_config/interface_config.py | 3 +- .../system_config/revpi_config.py | 35 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py b/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py index 0e96390..0356ba8 100644 --- a/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py +++ b/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py @@ -8,6 +8,7 @@ from logging import getLogger from .revpi_config import ( ConfigActions, configure_avahi_daemon, + configure_bluetooth, configure_con_can, configure_dphys_swapfile, configure_external_antenna, @@ -92,7 +93,7 @@ AVAILABLE_FEATURES = { simple_systemd, ["noderedrevpinodes-server.service"] ), "revpipyload": FeatureFunction(simple_systemd, ["revpipyload.service"]), - "bluetooth": False, + "bluetooth": FeatureFunction(configure_bluetooth, []), "ieee80211": FeatureFunction(configure_wifi, []), "avahi": FeatureFunction(configure_avahi_daemon, []), "external-antenna": FeatureFunction(configure_external_antenna, []), diff --git a/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py b/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py index da1832c..5b99432 100644 --- a/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py +++ b/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py @@ -20,6 +20,7 @@ log = getLogger(__name__) ConfigVariable = namedtuple("ConfigVariable", ["name", "value", "line_index"]) +LINUX_BT_CLASS_PATH = "/sys/class/bluetooth" LINUX_WIFI_CLASS_PATH = "/sys/class/ieee80211" CONFIG_TXT_LOCATIONS = ("/boot/firmware/config.txt", "/boot/config.txt") @@ -212,6 +213,40 @@ def configure_avahi_daemon(action: ConfigActions): return return_value +def configure_bluetooth(action: ConfigActions): + hci_device = join(LINUX_BT_CLASS_PATH, "hci0") + bt_rfkill_index = get_rfkill_index(hci_device) + + # If the bluetooth device is not present, the device should have been + # brought up by revpi-bluetooth's udev rules or vendor magic (devices + # based on CM4 and newer). Nothing we can do here, so treat the interface + # as disabled. + + if action is ConfigActions.ENABLE: + if bt_rfkill_index is not None: + subprocess.call(["rfkill", "unblock", str(bt_rfkill_index)]) + + elif action is ConfigActions.DISABLE: + if bt_rfkill_index is not None: + subprocess.call(["rfkill", "block", str(bt_rfkill_index)]) + + elif action is ConfigActions.STATUS: + if bt_rfkill_index is None: + return False + + with open(f"/sys/class/rfkill/rfkill{bt_rfkill_index}/soft", "r") as f: + buffer = f.read().strip() + return buffer == "0" + + elif action is ConfigActions.AVAILABLE: + return bt_rfkill_index is not None + + else: + raise ValueError(f"action {action} not supported") + + return None + + def configure_con_can(action: ConfigActions): revpi = RevPiConfig() if action is ConfigActions.AVAILABLE: From 555c781aed3dbac05f2ec255e77e6323be1bd96f Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Mon, 21 Apr 2025 10:21:36 +0200 Subject: [PATCH 18/23] feat(dbus): Add InterfaceRevpiConfig to DBus interfaces list Added the InterfaceRevpiConfig class to the list of DBus interfaces in `bus_provider.py`. This ensures the new system configuration interface is properly registered and accessible. --- src/revpi_middleware/dbus_middleware1/bus_provider.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/revpi_middleware/dbus_middleware1/bus_provider.py b/src/revpi_middleware/dbus_middleware1/bus_provider.py index 6f91bce..dd504f1 100644 --- a/src/revpi_middleware/dbus_middleware1/bus_provider.py +++ b/src/revpi_middleware/dbus_middleware1/bus_provider.py @@ -10,6 +10,7 @@ from pydbus import SessionBus, SystemBus from . import REVPI_DBUS_NAME from .process_image import InterfacePiControl +from .system_config import InterfaceRevpiConfig log = getLogger(__name__) @@ -41,6 +42,7 @@ class BusProvider(Thread): # ("Subdir2/Whatever", Example()) lst_interfaces = [ InterfacePiControl(self.picontrol_device, self.config_rsc), + InterfaceRevpiConfig(), ] try: From 0ecd86bd64edabef9615e2d0ce4bb980b19cf615 Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Mon, 21 Apr 2025 10:54:47 +0200 Subject: [PATCH 19/23] feat(cli): Add `get_properties` helper function for DBus interactions This function facilitates retrieving specific properties from a DBus interface, improving code modularity and reusability. It supports both system and session bus types, streamlining access to DBus resources. --- src/revpi_middleware/cli_commands/cli_base.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/revpi_middleware/cli_commands/cli_base.py b/src/revpi_middleware/cli_commands/cli_base.py index 19def6a..e0ff36f 100644 --- a/src/revpi_middleware/cli_commands/cli_base.py +++ b/src/revpi_middleware/cli_commands/cli_base.py @@ -29,6 +29,11 @@ def setup_command_line_arguments(): help="RevPi PiControl object", ) cli_picontrol.add_subparsers(obj_picontrol) + obj_config = rpictl_obj.add_parser( + "config", + help="RevPi configuration object (revpi-config)", + ) + cli_config.add_subparsers(obj_config) def main() -> int: @@ -39,6 +44,9 @@ def main() -> int: if obj == "picontrol": rc = cli_picontrol.main() + elif obj == "config": + rc = cli_config.main() + else: log.error(f"Unknown object: {obj}") rc = 1 From 8c145ef2ffbe95c57b23198522486d79e55a309a Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Mon, 21 Apr 2025 10:55:11 +0200 Subject: [PATCH 20/23] feat(cli): Add CLI command for configuring Revpi features Introduced a new CLI command to enable, disable, check the status, and list available features for Revpi using D-Bus calls. This implementation provides a structured interface for managing Revpi configurations via command-line actions. --- .../cli_commands/cli_config.py | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 src/revpi_middleware/cli_commands/cli_config.py diff --git a/src/revpi_middleware/cli_commands/cli_config.py b/src/revpi_middleware/cli_commands/cli_config.py new file mode 100644 index 0000000..d91b39c --- /dev/null +++ b/src/revpi_middleware/cli_commands/cli_config.py @@ -0,0 +1,93 @@ +# SPDX-FileCopyrightText: 2025 KUNBUS GmbH +# SPDX-License-Identifier: GPL-2.0-or-later +"""Command-Line for the picontrol object of CLI.""" +from argparse import ArgumentParser +from logging import getLogger + +from .dbus_helper import BusType, get_properties, simple_call +from .. import proginit as pi +from ..dbus_middleware1 import extend_interface + +log = getLogger(__name__) + + +def add_subparsers(parent_parser: ArgumentParser): + parent_parser.add_argument( + "action", + choices=["enable", "disable", "status", "available", "list-features"], + help="Action to be executed: enable, disable, status or available. " + "To get all available features, use 'list-features'.", + ) + parent_parser.add_argument( + "feature", + nargs="?", + default="", + help="Name of the feature to configer. To list all features use 'list-features' as action.", + ) + + +def main() -> int: + action = pi.pargs.action + dbus_value = False + try: + + if action == "list-features": + dbus_value = get_properties( + "available_features", + interface=extend_interface("RevpiConfig"), + bus_type=BusType.SESSION if pi.pargs.use_session_bus else BusType.SYSTEM, + ) + for feature in dbus_value: + print(feature) + + return 0 + + # For the following actions, a feature name is required + if pi.pargs.feature == "": + raise Exception("Feature name is required") + + if action == "enable": + simple_call( + "Enable", + pi.pargs.feature, + interface=extend_interface("RevpiConfig"), + bus_type=BusType.SESSION if pi.pargs.use_session_bus else BusType.SYSTEM, + ) + + elif action == "disable": + simple_call( + "Disable", + pi.pargs.feature, + interface=extend_interface("RevpiConfig"), + bus_type=BusType.SESSION if pi.pargs.use_session_bus else BusType.SYSTEM, + ) + + elif action == "status": + dbus_value = simple_call( + "GetStatus", + pi.pargs.feature, + interface=extend_interface("RevpiConfig"), + bus_type=BusType.SESSION if pi.pargs.use_session_bus else BusType.SYSTEM, + ) + + elif action == "available": + dbus_value = simple_call( + "GetAvailability", + pi.pargs.feature, + interface=extend_interface("RevpiConfig"), + bus_type=BusType.SESSION if pi.pargs.use_session_bus else BusType.SYSTEM, + ) + + else: + raise Exception(f"Unknown action: {action}") + + except Exception as e: + log.error(f"Error: {e}") + return 1 + + log.debug( + f"D-Bus call of method {action} for feature {pi.pargs.feature} returned: {dbus_value}" + ) + print(int(dbus_value)) + + return 0 From de1774f60ea5cf8d30231019c9bed8c3e56023a0 Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Mon, 21 Apr 2025 10:55:32 +0200 Subject: [PATCH 21/23] feat(cli): Add CLI support for RevPi configuration object (revpi-config) This implements a new command "config" in the CLI to handle RevPi configuration. It includes parsing and subparser setup for configuration-related operations. The change improves usability by extending CLI functionality to manage RevPi configuration objects. --- src/revpi_middleware/cli_commands/dbus_helper.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/revpi_middleware/cli_commands/dbus_helper.py b/src/revpi_middleware/cli_commands/dbus_helper.py index e14f072..45d6690 100644 --- a/src/revpi_middleware/cli_commands/dbus_helper.py +++ b/src/revpi_middleware/cli_commands/dbus_helper.py @@ -17,6 +17,18 @@ class BusType(Enum): SYSTEM = "system" +def get_properties( + property_name: str, + interface: str, + object_path=REVPI_DBUS_BASE_PATH, + bus_type=BusType.SYSTEM, +): + bus = SessionBus() if bus_type is BusType.SESSION else SystemBus() + revpi = bus.get(REVPI_DBUS_NAME, object_path) + iface = revpi[interface] + return getattr(iface, property_name) + + def simple_call( method: str, *args, From fc82ec0eb9571c1392f89732378ed7e861e86ad4 Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Mon, 21 Apr 2025 13:25:56 +0200 Subject: [PATCH 22/23] feat(revpiconfig): Replace rfkill subprocess calls with sysfs writes Updated Bluetooth and WiFi rfkill handling by replacing subprocess calls to "rfkill" with direct writes to sysfs files. This change simplifies the implementation and improves performance by avoiding external command execution. --- .../dbus_middleware1/system_config/revpi_config.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py b/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py index 5b99432..657038b 100644 --- a/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py +++ b/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py @@ -224,11 +224,13 @@ def configure_bluetooth(action: ConfigActions): if action is ConfigActions.ENABLE: if bt_rfkill_index is not None: - subprocess.call(["rfkill", "unblock", str(bt_rfkill_index)]) + with open(f"/sys/class/rfkill/rfkill{bt_rfkill_index}/soft", "w") as f: + f.write("0") elif action is ConfigActions.DISABLE: if bt_rfkill_index is not None: - subprocess.call(["rfkill", "block", str(bt_rfkill_index)]) + with open(f"/sys/class/rfkill/rfkill{bt_rfkill_index}/soft", "w") as f: + f.write("1") elif action is ConfigActions.STATUS: if bt_rfkill_index is None: @@ -343,12 +345,14 @@ def configure_wifi(action: ConfigActions): if action is ConfigActions.ENABLE: if revpi.with_wifi: wifi_rfkill_index = get_rfkill_index(revpi.class_path_wifi) - subprocess.call(["rfkill", "unblock", str(wifi_rfkill_index)]) + with open(f"/sys/class/rfkill/rfkill{wifi_rfkill_index}/soft", "w") as f: + f.write("0") elif action is ConfigActions.DISABLE: if revpi.with_wifi: wifi_rfkill_index = get_rfkill_index(revpi.class_path_wifi) - subprocess.call(["rfkill", "block", str(wifi_rfkill_index)]) + with open(f"/sys/class/rfkill/rfkill{wifi_rfkill_index}/soft", "w") as f: + f.write("1") elif action is ConfigActions.AVAILABLE: return revpi.with_wifi From 1fab228272ab0db06e3727c940a8b7230638fc65 Mon Sep 17 00:00:00 2001 From: Sven Sager Date: Mon, 21 Apr 2025 13:33:42 +0200 Subject: [PATCH 23/23] refactor: Rename WiFi to WLAN for consistent terminology Updated variable names, function names, and comments to replace "WiFi" with "WLAN" throughout the codebase. This ensures alignment with standardized terminology and improves clarity in functionality and configuration handling. Adjusted related configurations and interface mappings accordingly. --- .../system_config/interface_config.py | 4 +- .../system_config/revpi_config.py | 66 +++++++++---------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py b/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py index 0356ba8..380c913 100644 --- a/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py +++ b/src/revpi_middleware/dbus_middleware1/system_config/interface_config.py @@ -13,7 +13,7 @@ from .revpi_config import ( configure_dphys_swapfile, configure_external_antenna, configure_gui, - configure_wifi, + configure_wlan, simple_systemd, ) from ..dbus_helper import DbusInterface @@ -94,7 +94,7 @@ AVAILABLE_FEATURES = { ), "revpipyload": FeatureFunction(simple_systemd, ["revpipyload.service"]), "bluetooth": FeatureFunction(configure_bluetooth, []), - "ieee80211": FeatureFunction(configure_wifi, []), + "wlan": FeatureFunction(configure_wlan, []), "avahi": FeatureFunction(configure_avahi_daemon, []), "external-antenna": FeatureFunction(configure_external_antenna, []), } diff --git a/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py b/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py index 657038b..23d6378 100644 --- a/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py +++ b/src/revpi_middleware/dbus_middleware1/system_config/revpi_config.py @@ -21,7 +21,7 @@ log = getLogger(__name__) ConfigVariable = namedtuple("ConfigVariable", ["name", "value", "line_index"]) LINUX_BT_CLASS_PATH = "/sys/class/bluetooth" -LINUX_WIFI_CLASS_PATH = "/sys/class/ieee80211" +LINUX_WLAN_CLASS_PATH = "/sys/class/ieee80211" CONFIG_TXT_LOCATIONS = ("/boot/firmware/config.txt", "/boot/config.txt") @@ -81,19 +81,19 @@ class RevPiConfig: except ValueError: pass - # Detect WiFi on CM module - could_have_wifi = self._cm_type in (ComputeModuleTypes.CM4, ComputeModuleTypes.CM5) - if could_have_wifi: - wifi_interface = join(LINUX_WIFI_CLASS_PATH, "phy0") - if grep("DRIVER=brcmfmac", join(wifi_interface, "device", "uevent")): - self._wlan_class_path = wifi_interface + # Detect WLAN on CM module + could_have_wlan = self._cm_type in (ComputeModuleTypes.CM4, ComputeModuleTypes.CM5) + if could_have_wlan: + wlan_interface = join(LINUX_WLAN_CLASS_PATH, "phy0") + if grep("DRIVER=brcmfmac", join(wlan_interface, "device", "uevent")): + self._wlan_class_path = wlan_interface - # If no build in Wi-Fi on the CM, detect third party Wi-Fi on RevPi Flat + # If no build in WLAN on the CM, detect third party WLAN on RevPi Flat if not self._wlan_class_path and grep("revpi-flat", "/proc/device-tree/compatible"): - lst_wifi_interfaces = glob("/sys/class/ieee80211/*") - for wifi_interface in lst_wifi_interfaces: - if grep("DRIVER=mwifiex_sdio", join(wifi_interface, "device", "uevent")): - self._wlan_class_path = wifi_interface + lst_wlan_interfaces = glob("/sys/class/ieee80211/*") + for wlan_interface in lst_wlan_interfaces: + if grep("DRIVER=mwifiex_sdio", join(wlan_interface, "device", "uevent")): + self._wlan_class_path = wlan_interface # Detect ConBridge could_have_con_bridge = self._cm_type in (ComputeModuleTypes.CM3, ComputeModuleTypes.CM4S) @@ -102,7 +102,7 @@ class RevPiConfig: self._revpi_with_con_bridge = len(lst_grep) > 0 @property - def class_path_wifi(self) -> str: + def class_path_wlan(self) -> str: return self._wlan_class_path @property @@ -114,7 +114,7 @@ class RevPiConfig: return self._revpi_with_con_bridge @property - def with_wifi(self) -> bool: + def with_wlan(self) -> bool: return bool(self._wlan_class_path) @@ -295,21 +295,21 @@ def configure_dphys_swapfile(action: ConfigActions): def configure_external_antenna(action: ConfigActions): revpi = RevPiConfig() if action is ConfigActions.AVAILABLE: - return revpi.with_wifi + return revpi.with_wlan config_txt = ConfigTxt() - if action is ConfigActions.ENABLE and revpi.with_wifi: + if action is ConfigActions.ENABLE and revpi.with_wlan: config_txt.clear_dtparams(["ant1", "ant2"]) config_txt.add_name_value("dtparam", "ant2") config_txt.save_config() - elif action is ConfigActions.DISABLE and revpi.with_wifi: + elif action is ConfigActions.DISABLE and revpi.with_wlan: config_txt.clear_dtparams(["ant1", "ant2"]) config_txt.save_config() elif action is ConfigActions.STATUS: - return revpi.with_wifi and "ant2" in config_txt.get_values("dtparam") + return revpi.with_wlan and "ant2" in config_txt.get_values("dtparam") else: raise ValueError(f"action {action} not supported") @@ -339,30 +339,30 @@ def configure_gui(action: ConfigActions): raise ValueError(f"action {action} not supported") -def configure_wifi(action: ConfigActions): +def configure_wlan(action: ConfigActions): revpi = RevPiConfig() if action is ConfigActions.ENABLE: - if revpi.with_wifi: - wifi_rfkill_index = get_rfkill_index(revpi.class_path_wifi) - with open(f"/sys/class/rfkill/rfkill{wifi_rfkill_index}/soft", "w") as f: + if revpi.with_wlan: + wlan_rfkill_index = get_rfkill_index(revpi.class_path_wlan) + with open(f"/sys/class/rfkill/rfkill{wlan_rfkill_index}/soft", "w") as f: f.write("0") elif action is ConfigActions.DISABLE: - if revpi.with_wifi: - wifi_rfkill_index = get_rfkill_index(revpi.class_path_wifi) - with open(f"/sys/class/rfkill/rfkill{wifi_rfkill_index}/soft", "w") as f: + if revpi.with_wlan: + wlan_rfkill_index = get_rfkill_index(revpi.class_path_wlan) + with open(f"/sys/class/rfkill/rfkill{wlan_rfkill_index}/soft", "w") as f: f.write("1") elif action is ConfigActions.AVAILABLE: - return revpi.with_wifi + return revpi.with_wlan elif action is ConfigActions.STATUS: - if not revpi.with_wifi: + if not revpi.with_wlan: return False - wifi_rfkill_index = get_rfkill_index(revpi.class_path_wifi) - with open(f"/sys/class/rfkill/rfkill{wifi_rfkill_index}/soft", "r") as f: + wlan_rfkill_index = get_rfkill_index(revpi.class_path_wlan) + with open(f"/sys/class/rfkill/rfkill{wlan_rfkill_index}/soft", "r") as f: buffer = f.read().strip() return buffer == "0" @@ -424,10 +424,10 @@ if __name__ == "__main__": print("Model:", rc.model) print("Serial: ", rc.serial) print("CM Type: ", rc.cm_type.name) - print("With wifi: ", rc.with_wifi) - if rc.with_wifi: - print(" class path: ", rc.class_path_wifi) - print(" rfkill index: ", get_rfkill_index(rc.class_path_wifi)) + print("With WLAN: ", rc.with_wlan) + if rc.with_wlan: + print(" class path: ", rc.class_path_wlan) + print(" rfkill index: ", get_rfkill_index(rc.class_path_wlan)) print("With con-bridge:", rc.with_con_bridge) config_txt = ConfigTxt()