Skip to content

Commit

Permalink
PM16D17: Use user-land driver
Browse files Browse the repository at this point in the history
The current PM16D17 kernel sensor driver is not using the existing
kernel API, but self-invented device tree bindings, which is rejected
while upstreaming, see [1].

This patch replaces the kernel driver with a user-land driver.

1. https://lore.kernel.org/linux-iio/[email protected]/

Signed-off-by: Baocheng Su <[email protected]>
  • Loading branch information
BaochengSu committed Feb 6, 2025
1 parent a989461 commit dfcee0c
Show file tree
Hide file tree
Showing 38 changed files with 679 additions and 568 deletions.
55 changes: 37 additions & 18 deletions recipes-app/iot2050-event-record/files/iot2050-event-record.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from datetime import datetime
from systemd import journal
from enum import Enum
from pystemd.dbuslib import DBus, DbusMessage
import grpc
from gRPC.EventInterface.iot2050_event_pb2 import (
WriteRequest,
Expand Down Expand Up @@ -127,33 +128,51 @@ def record_eio_events():
time.sleep(5)


class ProximitySensorDBus():
def __init__(self, critical_value: int):
self.critical_value = critical_value

def is_uncovered(self) -> bool:
with DBus() as bus:
res: DbusMessage = bus.call_method(
b"com.siemens.iot2050.pxmt",
b"/com/siemens/iot2050/pxmt",
b"com.siemens.iot2050.pxmt",
b"Retrieve",
[])
lux = int(res.body)
return lux < self.critical_value

return False

def __enter__(self):
return self

def __exit__(self, exc_type, exc_val, exc_tb):
pass


IIO_IMU_PATH = "/sys/devices/platform/bus@100000/2030000.i2c/i2c-5/5-006a/"
IIO_PRO_PATH = "/sys/devices/platform/bus@100000/2030000.i2c/i2c-5/5-0044/"
def record_sensor_events():
accel_x_raw = "{}/in_accel_x_raw"
accel_y_raw = "{}/in_accel_y_raw"
accel_z_raw = "{}/in_accel_z_raw"
pro_raw = "{}/in_proximity0_raw"
imu_w = os.walk(IIO_IMU_PATH)
pro_w = os.walk(IIO_PRO_PATH)
for (dirpath, dirnames, filenames) in imu_w:
if "in_accel_x_raw" in filenames:
accel_x_raw = accel_x_raw.format(dirpath)
accel_y_raw = accel_y_raw.format(dirpath)
accel_z_raw = accel_z_raw.format(dirpath)
break
for (dirpath, dirnames, filenames) in pro_w:
if "in_proximity0_raw" in filenames:
pro_raw = pro_raw.format(dirpath)
break

lux_critical_value = int(os.getenv('LUX_CRITICAL_VALUE', '100'))
pxmt_sensor = ProximitySensorDBus(critical_value=lux_critical_value)
with open(accel_x_raw, 'r') as x, \
open(accel_y_raw, 'r') as y, \
open(accel_z_raw, 'r') as z, \
open(pro_raw, 'r') as l:
pxmt_sensor as l:
is_uncovered = False
accel_critical_value = int(os.getenv('ACCEL_CRITICAL_VALUE'))
lux_critical_value = int(os.getenv('LUX_CRITICAL_VALUE'))
while True:
# Detect tilt sensor event
x.seek(0)
Expand All @@ -176,15 +195,15 @@ def record_sensor_events():
write_event(EVENT_TYPES["tilt"], tilted_event)

# Detect tamper sensor event
l.seek(0)
lux = int(l.read())
if lux < lux_critical_value and not is_uncovered:
is_uncovered = True
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
uncover_event = EVENT_STRINGS["uncover"].format(now)
write_event(EVENT_TYPES["uncover"], uncover_event)
elif lux > lux_critical_value and is_uncovered:
is_uncovered = False
if is_uncovered:
is_uncovered = l.is_uncovered()
else:
is_uncovered = l.is_uncovered()
if is_uncovered:
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
uncover_event = EVENT_STRINGS["uncover"].format(now)
write_event(EVENT_TYPES["uncover"], uncover_event)


def event_record():
if not is_grpc_servers_ready():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ SRC_URI = " \

S = "${WORKDIR}/src"

DEBIAN_DEPENDS = "python3, python3-grpcio, python3-psutil, python3-systemd"
DEBIAN_DEPENDS = "python3, python3-grpcio, python3-psutil, python3-systemd, python3-pystemd"

do_install() {
install -v -d ${D}/usr/lib/iot2050/event/
Expand Down
1 change: 1 addition & 0 deletions recipes-core/images/iot2050-image-example.bb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ IMAGE_INSTALL += " \
tee-supplicant \
iot2050-event-record \
linux-headers-${KERNEL_NAME} \
iot2050-proximity-driver \
"

IOT2050_NODE_RED_SUPPORT ?= "1"
Expand Down
39 changes: 39 additions & 0 deletions recipes-core/iot2050-proximity-driver/files/src/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# SPDX-License-Identifier: MIT
# SPDX-FileCopyrightText: Copyright (c) Siemens AG, 2025
# SPDX-FileContributor: Authored by Su Bao Cheng <[email protected]>

CROSS_COMPILE ?= aarch64-linux-gnu-

CC = $(CROSS_COMPILE)gcc

LDFLAGS = -lsystemd

TARGET = iot2050-pxmtd

INSTALL ?= install

DESTDIR ?= /

SRC = main.c \
dbus-service.c \
sensor.c

.PHONY: all clean install

all: $(TARGET)

$(TARGET): $(SRC)
$(CC) $(CFLAGS) -o $(TARGET) $(SRC) $(LDFLAGS)

clean:
rm -f $(TARGET)

install:
$(INSTALL) -v -d $(DESTDIR)/usr/bin
$(INSTALL) -v -d $(DESTDIR)/etc/dbus-1/system.d
$(INSTALL) -v -m 0755 $(TARGET) $(DESTDIR)/usr/bin
$(INSTALL) -v -m 0644 com.siemens.iot2050.pxmt.conf \
$(DESTDIR)/etc/dbus-1/system.d
$(INSTALL) -v -d ${DESTDIR}/lib/systemd/system/
$(INSTALL) -v -m 0644 iot2050-proximity-driver.service\
${DESTDIR}/lib/systemd/system/
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!DOCTYPE busconfig PUBLIC
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<policy user="root">
<allow own="com.siemens.iot2050.pxmt"/>
<allow send_interface="com.siemens.iot2050.pxmt"/>
</policy>
</busconfig>
96 changes: 96 additions & 0 deletions recipes-core/iot2050-proximity-driver/files/src/dbus-service.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: Copyright (c) Siemens AG, 2025
* SPDX-FileContributor: Authored by Su Bao Cheng <[email protected]>
*/

#include <systemd/sd-bus.h>
#include <errno.h>
#include <sys/capability.h>
#include "dbus-service.h"

typedef int (*retrieve_callback_t)(uint16_t *);

static retrieve_callback_t iot2050_pxmtd_retrieve_cb = NULL;

static int iot2050_pxmtd_retrieve(sd_bus_message *m,
void *userdata,
sd_bus_error *ret_error)
{
if (!iot2050_pxmtd_retrieve_cb)
return -ENXIO;

uint16_t ps_val;
int ret = iot2050_pxmtd_retrieve_cb(&ps_val);
if (ret < 0)
return ret;

return sd_bus_reply_method_return(m, "q", ps_val);
}

static const sd_bus_vtable iot2050_pxmtd_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_METHOD("Retrieve",
SD_BUS_NO_ARGS,
"q",
iot2050_pxmtd_retrieve,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END
};

int dbus_serve(retrieve_callback_t cb)
{
sd_bus_slot *slot = NULL;
sd_bus *bus = NULL;
int ret;

ret = sd_bus_open_system(&bus);
if (ret < 0) {
fprintf(stderr, "Failed to connect to system bus: %s\n",
strerror(-ret));
goto out;
}

iot2050_pxmtd_retrieve_cb = cb;

ret = sd_bus_add_object_vtable(bus, &slot,
"/com/siemens/iot2050/pxmt",
"com.siemens.iot2050.pxmt",
iot2050_pxmtd_vtable, NULL);
if (ret < 0) {
fprintf(stderr, "Failed to set dbus service property: %s\n",
strerror(-ret));
goto out;
}

ret = sd_bus_request_name(bus, "com.siemens.iot2050.pxmt", 0);
if (ret < 0) {
fprintf(stderr, "Failed to acquire service name: %s\n",
strerror(-ret));
goto out;
}

for (;;) {
ret = sd_bus_process(bus, NULL);
if (ret < 0) {
fprintf(stderr, "Failed to process bus: %s\n",
strerror(-ret));
goto out;
}
if (ret > 0)
continue;

ret = sd_bus_wait(bus, (uint64_t) -1);
if (ret < 0) {
fprintf(stderr, "Failed to wait on bus: %s\n",
strerror(-ret));
goto out;
}
}

ret = 0;
out:
sd_bus_slot_unref(slot);
sd_bus_unref(bus);

return ret;
}
15 changes: 15 additions & 0 deletions recipes-core/iot2050-proximity-driver/files/src/dbus-service.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: Copyright (c) Siemens AG, 2025
* SPDX-FileContributor: Authored by Su Bao Cheng <[email protected]>
*/

#ifndef IOT2050_PXMTD_DBUS_SERVICE_H
#define IOT2050_PXMTD_DBUS_SERVICE_H

#include <stdint.h>

typedef int (*retrieve_callback_t)(uint16_t *);

int dbus_serve(retrieve_callback_t cb);

#endif /* IOT2050_PXMTD_DBUS_SERVICE_H */
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# SPDX-License-Identifier: MIT
# SPDX-FileCopyrightText: Copyright (c) Siemens AG, 2025
# SPDX-FileContributor: Authored by Su Bao Cheng <[email protected]>

[Unit]
Description=Userspace driver for the proximity sensor of IOT2050
# Only run on IOT2050-SM variant
ConditionFirmware=device-tree-compatible(siemens,iot2050-advanced-sm)
ConditionVirtualization=!container

[Service]
Type=dbus
BusName=com.siemens.iot2050.pxmt
ExecStart=/usr/bin/iot2050-pxmtd
Restart=always
RestartSec=5
ProtectSystem=strict
ProtectHome=true
NoNewPrivileges=true
User=root

[Install]
WantedBy=multi-user.target
Alias=dbus-com.siemens.iot2050.pxmt.service
24 changes: 24 additions & 0 deletions recipes-core/iot2050-proximity-driver/files/src/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: Copyright (c) Siemens AG, 2025
* SPDX-FileContributor: Authored by Su Bao Cheng <[email protected]>
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "sensor.h"
#include "dbus-service.h"

int main()
{
setbuf(stdout, NULL);

int ret = init_sensor();
if (ret < 0) {
fprintf(stderr, "Failed to initialize the sensor: %s\n",
strerror(-ret));
exit(EXIT_FAILURE);
}

return dbus_serve(retrieve_sensor_data) == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
Loading

0 comments on commit dfcee0c

Please sign in to comment.