5 Commits

Author SHA1 Message Date
1fab228272 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.
2025-04-21 13:34:10 +02:00
fc82ec0eb9 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.
2025-04-21 13:25:56 +02:00
de1774f60e 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.
2025-04-21 10:55:32 +02:00
8c145ef2ff 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.
2025-04-21 10:55:11 +02:00
0ecd86bd64 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.
2025-04-21 10:54:47 +02:00
5 changed files with 154 additions and 37 deletions

View File

@@ -29,6 +29,11 @@ def setup_command_line_arguments():
help="RevPi PiControl object", help="RevPi PiControl object",
) )
cli_picontrol.add_subparsers(obj_picontrol) 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: def main() -> int:
@@ -39,6 +44,9 @@ def main() -> int:
if obj == "picontrol": if obj == "picontrol":
rc = cli_picontrol.main() rc = cli_picontrol.main()
elif obj == "config":
rc = cli_config.main()
else: else:
log.error(f"Unknown object: {obj}") log.error(f"Unknown object: {obj}")
rc = 1 rc = 1

View File

@@ -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

View File

@@ -17,6 +17,18 @@ class BusType(Enum):
SYSTEM = "system" 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( def simple_call(
method: str, method: str,
*args, *args,

View File

@@ -13,7 +13,7 @@ from .revpi_config import (
configure_dphys_swapfile, configure_dphys_swapfile,
configure_external_antenna, configure_external_antenna,
configure_gui, configure_gui,
configure_wifi, configure_wlan,
simple_systemd, simple_systemd,
) )
from ..dbus_helper import DbusInterface from ..dbus_helper import DbusInterface
@@ -94,7 +94,7 @@ AVAILABLE_FEATURES = {
), ),
"revpipyload": FeatureFunction(simple_systemd, ["revpipyload.service"]), "revpipyload": FeatureFunction(simple_systemd, ["revpipyload.service"]),
"bluetooth": FeatureFunction(configure_bluetooth, []), "bluetooth": FeatureFunction(configure_bluetooth, []),
"ieee80211": FeatureFunction(configure_wifi, []), "wlan": FeatureFunction(configure_wlan, []),
"avahi": FeatureFunction(configure_avahi_daemon, []), "avahi": FeatureFunction(configure_avahi_daemon, []),
"external-antenna": FeatureFunction(configure_external_antenna, []), "external-antenna": FeatureFunction(configure_external_antenna, []),
} }

View File

@@ -21,7 +21,7 @@ log = getLogger(__name__)
ConfigVariable = namedtuple("ConfigVariable", ["name", "value", "line_index"]) ConfigVariable = namedtuple("ConfigVariable", ["name", "value", "line_index"])
LINUX_BT_CLASS_PATH = "/sys/class/bluetooth" 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") CONFIG_TXT_LOCATIONS = ("/boot/firmware/config.txt", "/boot/config.txt")
@@ -81,19 +81,19 @@ class RevPiConfig:
except ValueError: except ValueError:
pass pass
# Detect WiFi on CM module # Detect WLAN on CM module
could_have_wifi = self._cm_type in (ComputeModuleTypes.CM4, ComputeModuleTypes.CM5) could_have_wlan = self._cm_type in (ComputeModuleTypes.CM4, ComputeModuleTypes.CM5)
if could_have_wifi: if could_have_wlan:
wifi_interface = join(LINUX_WIFI_CLASS_PATH, "phy0") wlan_interface = join(LINUX_WLAN_CLASS_PATH, "phy0")
if grep("DRIVER=brcmfmac", join(wifi_interface, "device", "uevent")): if grep("DRIVER=brcmfmac", join(wlan_interface, "device", "uevent")):
self._wlan_class_path = wifi_interface 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"): if not self._wlan_class_path and grep("revpi-flat", "/proc/device-tree/compatible"):
lst_wifi_interfaces = glob("/sys/class/ieee80211/*") lst_wlan_interfaces = glob("/sys/class/ieee80211/*")
for wifi_interface in lst_wifi_interfaces: for wlan_interface in lst_wlan_interfaces:
if grep("DRIVER=mwifiex_sdio", join(wifi_interface, "device", "uevent")): if grep("DRIVER=mwifiex_sdio", join(wlan_interface, "device", "uevent")):
self._wlan_class_path = wifi_interface self._wlan_class_path = wlan_interface
# Detect ConBridge # Detect ConBridge
could_have_con_bridge = self._cm_type in (ComputeModuleTypes.CM3, ComputeModuleTypes.CM4S) 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 self._revpi_with_con_bridge = len(lst_grep) > 0
@property @property
def class_path_wifi(self) -> str: def class_path_wlan(self) -> str:
return self._wlan_class_path return self._wlan_class_path
@property @property
@@ -114,7 +114,7 @@ class RevPiConfig:
return self._revpi_with_con_bridge return self._revpi_with_con_bridge
@property @property
def with_wifi(self) -> bool: def with_wlan(self) -> bool:
return bool(self._wlan_class_path) return bool(self._wlan_class_path)
@@ -224,11 +224,13 @@ def configure_bluetooth(action: ConfigActions):
if action is ConfigActions.ENABLE: if action is ConfigActions.ENABLE:
if bt_rfkill_index is not None: 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: elif action is ConfigActions.DISABLE:
if bt_rfkill_index is not None: 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: elif action is ConfigActions.STATUS:
if bt_rfkill_index is None: if bt_rfkill_index is None:
@@ -293,21 +295,21 @@ def configure_dphys_swapfile(action: ConfigActions):
def configure_external_antenna(action: ConfigActions): def configure_external_antenna(action: ConfigActions):
revpi = RevPiConfig() revpi = RevPiConfig()
if action is ConfigActions.AVAILABLE: if action is ConfigActions.AVAILABLE:
return revpi.with_wifi return revpi.with_wlan
config_txt = ConfigTxt() 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.clear_dtparams(["ant1", "ant2"])
config_txt.add_name_value("dtparam", "ant2") config_txt.add_name_value("dtparam", "ant2")
config_txt.save_config() 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.clear_dtparams(["ant1", "ant2"])
config_txt.save_config() config_txt.save_config()
elif action is ConfigActions.STATUS: 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: else:
raise ValueError(f"action {action} not supported") raise ValueError(f"action {action} not supported")
@@ -337,28 +339,30 @@ def configure_gui(action: ConfigActions):
raise ValueError(f"action {action} not supported") raise ValueError(f"action {action} not supported")
def configure_wifi(action: ConfigActions): def configure_wlan(action: ConfigActions):
revpi = RevPiConfig() revpi = RevPiConfig()
if action is ConfigActions.ENABLE: if action is ConfigActions.ENABLE:
if revpi.with_wifi: if revpi.with_wlan:
wifi_rfkill_index = get_rfkill_index(revpi.class_path_wifi) wlan_rfkill_index = get_rfkill_index(revpi.class_path_wlan)
subprocess.call(["rfkill", "unblock", str(wifi_rfkill_index)]) with open(f"/sys/class/rfkill/rfkill{wlan_rfkill_index}/soft", "w") as f:
f.write("0")
elif action is ConfigActions.DISABLE: elif action is ConfigActions.DISABLE:
if revpi.with_wifi: if revpi.with_wlan:
wifi_rfkill_index = get_rfkill_index(revpi.class_path_wifi) wlan_rfkill_index = get_rfkill_index(revpi.class_path_wlan)
subprocess.call(["rfkill", "block", str(wifi_rfkill_index)]) with open(f"/sys/class/rfkill/rfkill{wlan_rfkill_index}/soft", "w") as f:
f.write("1")
elif action is ConfigActions.AVAILABLE: elif action is ConfigActions.AVAILABLE:
return revpi.with_wifi return revpi.with_wlan
elif action is ConfigActions.STATUS: elif action is ConfigActions.STATUS:
if not revpi.with_wifi: if not revpi.with_wlan:
return False return False
wifi_rfkill_index = get_rfkill_index(revpi.class_path_wifi) wlan_rfkill_index = get_rfkill_index(revpi.class_path_wlan)
with open(f"/sys/class/rfkill/rfkill{wifi_rfkill_index}/soft", "r") as f: with open(f"/sys/class/rfkill/rfkill{wlan_rfkill_index}/soft", "r") as f:
buffer = f.read().strip() buffer = f.read().strip()
return buffer == "0" return buffer == "0"
@@ -420,10 +424,10 @@ if __name__ == "__main__":
print("Model:", rc.model) print("Model:", rc.model)
print("Serial: ", rc.serial) print("Serial: ", rc.serial)
print("CM Type: ", rc.cm_type.name) print("CM Type: ", rc.cm_type.name)
print("With wifi: ", rc.with_wifi) print("With WLAN: ", rc.with_wlan)
if rc.with_wifi: if rc.with_wlan:
print(" class path: ", rc.class_path_wifi) print(" class path: ", rc.class_path_wlan)
print(" rfkill index: ", get_rfkill_index(rc.class_path_wifi)) print(" rfkill index: ", get_rfkill_index(rc.class_path_wlan))
print("With con-bridge:", rc.with_con_bridge) print("With con-bridge:", rc.with_con_bridge)
config_txt = ConfigTxt() config_txt = ConfigTxt()