dotnet / iot

This repo includes .NET Core implementations for various IoT boards, chips, displays and PCBs.
MIT License
2.16k stars 580 forks source link

GPIOController (PinChangeEventHandler): Assigning a PinChangeEventHandler callback or Controller.OpenPin() causes "Segmentation Error" #2273

Closed PRIMETSS closed 7 months ago

PRIMETSS commented 8 months ago

Using Latest stable release v3.1.0 & 3.2.0-prerelease.24077.2 & current repo Main (29/Jan/2024) Creating a console App with

After moving from a working (older) to latest stable SDK & OpenWRT on RiPi Compute Module 4. 'Segmentation fault' happens when assign the ValueChanged callback. This project had been running fine with previous version(s) & GPIO buttons were working.

_gpioPinButtonUp.ValueChanged += GpioPinButtonUp_ValueChanged

Using:
Dotnet SDK v8.101 (Alpine: dotnet-sdk-8.0.101-linux-musl-arm64) [on RPi ComputeModule CM4]
OpenWRT v23.05.2 YES
    Prev: (GPIO event working [hw buttons])
        Dotnet v8.0.100-rc.2.23502.2
        OpenWRT SNAPSHOT r24111-66f6c20e45

To replicate I build a simple console app, add dependency System.Device.Gpio (v3.1.0, tried right back to 2.2 & above preview versions and current Repo's Main branch) and GPIOController and GPIOPin, assign a callback to Pins ValueChanged event.

Build & Run App on RPi CM4 and get "Segmentation fault" after trying to assign the call back. image

Have also tried the LibGpiodDriver when building the GPIO controller.

var LinuxLibGpioDriver = new LibGpiodDriver(gpioChip: 0, LibGpiodDriverVersion.V1);
var controller = new GpioController(PinNumberingScheme.Logical, LinuxLibGpioDriver);

Did a strace and get this which might shine some light?

Looks for Library OK: image

Fault: image

Code: image

Remark out the Event Callback assign, and runs as expected. //_Pin.ValueChanged += GpioPinButtonUp_ValueChanged; Has something change recently with assigning callbacks in dotnet or is it a kernal/linux lib issue?

PRIMETSS commented 8 months ago

Also get 'Segmentation Error' calling

Controller.OpenPin(pin);

Code:

using System;
using System.Device.Gpio;
using System.Threading;
using System.Device.Gpio.Drivers;

Console.WriteLine("Blinking LED. Press Ctrl+C to end.");

int pin = 5;

Console.WriteLine("======> Sleeping for remote Debugger connect."); // Didnt work
Thread.Sleep(30000);

Console.WriteLine("======> Creating Controller.");

var LinuxLibGpioDriver = new LibGpiodDriver(gpioChip: 0, LibGpiodDriverVersion.V1);
Console.WriteLine($"LinuxLibGpioDriver created {LinuxLibGpioDriver}");

var controller = new GpioController(PinNumberingScheme.Logical, LinuxLibGpioDriver);
Console.WriteLine($"GpioController created Sch:{controller.NumberingScheme} Pins:{controller.PinCount}");

Console.WriteLine($"About to open Pin {pin} PinMode.Input");
var _Pin = controller.OpenPin(pin, PinMode.Input);
Console.WriteLine($"======> PinCreated {_Pin.PinNumber}");

Console.WriteLine("======> Assigning event handler.");
//_Pin.ValueChanged += GpioPinButtonUp_ValueChanged;
Console.WriteLine("Assigned event handler.");

bool ledOn = true;
while (true)
{
    //controller.Write(pin, ((ledOn) ? PinValue.High : PinValue.Low));
    var v = controller.Read(pin);

    Thread.Sleep(1000);
    ledOn = !ledOn;
}

void GpioPinButtonUp_ValueChanged(object sender, PinValueChangedEventArgs pinValueChangedEventArgs)
{
}

image STRACE: image

PRIMETSS commented 8 months ago

Ahh I think its a broken libgpiod library or gpiod-tools? image

huesla commented 8 months ago

The "gpioinfo" command failing isn't a good sign, and it may correlate to your problem. To find the root cause, it's better to begin with a functioning state and make small changes gradually -> note versions of the working .NET Runtime / libgpiod combination -> upgrade to NET8 -> check whether it works -> upgrade libgpiod (see here) -> if all still works the issue probably comes with updating OpenWRT (some Linux driver maybe).

pgrawehr commented 8 months ago

What is the exact operating system you're running? I've been working with LibGpiod on a Raspberry Pi 4 for years now and never saw such a problem.

PRIMETSS commented 8 months ago

OpenWRT, (muscl-linux-arm64) which is a running on Raspberry Pi Compute Model CM4.

Thankyou! I have another RPi CM4 dev board (prev working GPIO OS & Dotnet) here that I will investigate LibGpiod functionally on. As GPIO through Dotnet was working on this board/version I assume it was using the old deprecated SYSFS file system GPIO functionality.

But if OK, guess I will wipe and load with all current stable and see if LibGpiod works.

WillThisRun commented 8 months ago

I have a similar problem when I call Controller.OpenPin() I also get a segmentation fault. This happens with System.Device.Gpio v3.1.0. However if I downgrade it to version 3.0.0 all is working as it should.

I'm running a .Net 8 application on a Variscite Dart-6UL module. Which has an NXP iMX6UL ARM Cortex-A7 processor. The OS is Debian 12 (Bookworm), custom build. Last updated on 23 January 2024.

Unfortunately I currently don't have the time to investigate it much further.

The "gpioinfo" console command does give the listing of all gpio lines. Libgpiod2 has version "1.6.3-1+b3"

huesla commented 8 months ago

However if I downgrade it to version 3.0.0 all is working as it should.

One diff between the versions is that dotnet iot explicitly uses libgpiod.so.2 (instead of libgpiod.so that points to whatever latest installed version) and maybe something is off with the libgpiod.so.2 file. I think the simplest way to tell whether the issue lies within libgpiod or something from the .NET world is to test it with some C code.

  1. Find installed libgpiod libraries: sudo find / -iname "*libgpiod.so*"
  2. Create small C program gpio-read-libgpiod2.c.txt or for libgpiod.so.3 gpio-read-libgpiod3.c.txt
  3. link and compile against libgpiod: gcc gpio-read-libgpiod2.c -l:libgpiod.so.2 -o gpio-read-libgpiod2
  4. execute: ./gpio-read-libgpiod2
PRIMETSS commented 8 months ago

Apologies!

I have traced this issue to a installed 'gpiod-tools' to help gather info on GPIO Controller This installs a dependency 'libgpiod' which causes the "Segmentation Fault" I did this on the 'old' previously working board (which was working) and it to had same issue! Removing gpiod-tools stopped this issue happening.

Need now to more forward and move on with migrating to the newer System.Device.GPIO library that uses the newer IOCTL LibGpiodDriver and see how go.

[I'll report back, as have a hunch I'm going to hit this issue again...]

PRIMETSS commented 8 months ago

[Update] Remove kernal module 'libgpiod' (v1.6.4-1) reverts back to using non IOCTL interface works no crash. Install 'libgpiod' (v1.6.4-1) and use constructor parms


var LinuxLibGpioDriver = new LibGpiodDriver(gpioChip: 1, LibGpiodDriverVersion.V1);
Console.WriteLine($"LinuxGPIO created {LinuxLibGpioDriver}");
this._gpioController = new GpioController(PinNumberingScheme.Logical, LinuxLibGpioDriver);

Segmentation Fault re-occurs.

So I'm assuming this is a problem in the implementation of BusyBox Linux libgpiod library.....?
I'll investigate more and raise and issue to OpenWRT

[I'm happy to close this issue (if other contributors agree)]
@WillThisRun : Ref notes above might help your issue?
@huesla : Thanks Will investigate more!

![image](https://github.com/dotnet/iot/assets/11331370/e299adc5-d834-404a-8193-3ccaf19997e2)

[Update2]
Believe issue is OpenWRT is still bundling libgpiod v1.6, but dotnet is targeting latest v2.1 assume? 

https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/
![image](https://github.com/dotnet/iot/assets/11331370/fe6c75a3-38ed-46b0-8a21-d54687ab51c8)
WillThisRun commented 8 months ago

I compiled that libgpio2 test, I did have to downgrade the Libgpiod2 from version "1.6.3-1+b3" to "1.6.2-1" in order to get libgpiod-dev installed to have the required header files.

The System.Device.Gpio v3.1.0 still failed with this other libgpio2 version. The test in native compiled C however does work:

root@DNR00ZZ00A0AA75:~/test# ./gpio-read-libgpiod2 GPIO 24 is 0

huesla commented 8 months ago

The System.Device.Gpio v3.1.0 still failed with this other libgpio2 version.

If the C program works and if it is really linked to ".so.2", it strongly suggests a bug in dotnet iot. It's weird though, because LibGpiodDriver gets used a lot. I myself use it on RPI OS that is also Debian 12 based. I just tested it with .NET7 and 8 with both libgpiod versions, 1.6 and 2.1, which worked fine. @WillThisRun What SDK / Runtime versions do you use?

huesla commented 8 months ago

[Update] Remove kernal module 'libgpiod' (v1.6.4-1) reverts back to using non IOCTL interface works no crash.

When libgpiod is not installed, dotnet iot falls back to the SysFsDriver, which avoids the use of the seemingly broken libgpiod , or whatever is behind it's curtain, on your system. You could try removing any libgpiod files and build it yourself see here

[Update2] Believe issue is OpenWRT is still bundling libgpiod v1.6, but dotnet is targeting latest v2.1 assume?

That depends on what dotnet iot version you are using. dotnet-iot 3.1 supports libgpiod v1.6, latest master of dotnet-iot supports libgpiod v2.1 and lower.

WillThisRun commented 8 months ago

Strange, the problem seems to be with the pinnumbers. I used to just keep numbering them and just use pin 135 for example. But it no longer supports that and gives me a Segmentation fault. I will have to change my code to actually use chip and pin. Because I used to have the lazy-mans init: GpioController gpioController = new();

So at least for me it seems to be a user error, which was allowed on other versions. Though I do feel that a segmentation fault on the part of the libgpiod is a bit harsh. Thank you all for helping me realize my mistake.

krwq commented 7 months ago

[Triage] @PRIMETSS @WillThisRun @huesla can you clarify the issue here a bit? Is this a single issue or more than one issue? Can you write what OS and libgpiod versions do you have installed? Are you using 64 or 32bit OS? What do we need to reproduce this? Can you share at minimum:

PRIMETSS commented 7 months ago

Apologies I should have supplied

root@RMS-HEAT-TRIAL:~# cat /etc/os-release NAME="OpenWrt" VERSION="23.05.2" ID="openwrt" ID_LIKE="lede openwrt" PRETTY_NAME="OpenWrt 23.05.2" VERSION_ID="23.05.2" HOME_URL="https://openwrt.org/" BUG_URL="https://bugs.openwrt.org/" SUPPORT_URL="https://forum.openwrt.org/" BUILD_ID="r23630-842932a63d" OPENWRT_BOARD="bcm27xx/bcm2711" OPENWRT_ARCH="aarch64_cortex-a72" OPENWRT_TAINTS="" OPENWRT_DEVICE_MANUFACTURER="OpenWrt" OPENWRT_DEVICE_MANUFACTURER_URL="https://openwrt.org/" OPENWRT_DEVICE_PRODUCT="Generic" OPENWRT_DEVICE_REVISION="v0" OPENWRT_RELEASE="OpenWrt 23.05.2 r23630-842932a63d"

` root@RMS-HEAT-TRIAL:~# cat /proc/cpuinfo processor : 0 BogoMIPS : 108.00 Features : fp asimd evtstrm crc32 cpuid CPU implementer : 0x41 CPU architecture: 8 CPU variant : 0x0 CPU part : 0xd08 CPU revision : 3

processor : 1 BogoMIPS : 108.00 Features : fp asimd evtstrm crc32 cpuid CPU implementer : 0x41 CPU architecture: 8 CPU variant : 0x0 CPU part : 0xd08 CPU revision : 3

processor : 2 BogoMIPS : 108.00 Features : fp asimd evtstrm crc32 cpuid CPU implementer : 0x41 CPU architecture: 8 CPU variant : 0x0 CPU part : 0xd08 CPU revision : 3

processor : 3 BogoMIPS : 108.00 Features : fp asimd evtstrm crc32 cpuid CPU implementer : 0x41 CPU architecture: 8 CPU variant : 0x0 CPU part : 0xd08 CPU revision : 3

Hardware : BCM2835 Revision : b03141 Serial : 10000000f958ecb0 Model : Raspberry Pi Compute Module 4 Rev 1.1 `

libgpiod - 1.6.4-1 - C library for interacting with the linux GPIO character device (gpiod stands for GPIO device).

root@RMS-HEAT-TRIAL:~# ls -las /usr/lib/libgpiod.* 0 lrwxrwxrwx 1 root root 17 Feb 9 08:54 /usr/lib/libgpiod.so.2 -> libgpiod.so.2.2.2 68 -rwxr-xr-x 1 root root 65539 Mar 11 2023 /usr/lib/libgpiod.so.2.2.2

WillThisRun commented 7 months ago

It is a 32bit cpu therefore it is also a 32bit OS And my problem was that I used to just keep counting the inputs and that worked. For example: Port 0 pin 0 is 0 Port 0 pin 31 is 31 Port 1 pin 0 is 32 Port 2 pin 4 is 68

But now I must use the port and pin numbers.

root@DNR00ZZ00A0AA75:~# cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
NAME="Debian GNU/Linux"
VERSION_ID="12"
VERSION="12 (bookworm)"
VERSION_CODENAME=bookworm
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
root@DNR00ZZ00A0AA75:~# cat /proc/cpuinfo
processor       : 0
model name      : ARMv7 Processor rev 5 (v7l)
BogoMIPS        : 109.09
Features        : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x0
CPU part        : 0xc07
CPU revision    : 5

Hardware        : Freescale i.MX6 Ultralite (Device Tree)
Revision        : 0000
Serial          : 0000000000000000
root@DNR00ZZ00A0AA75:~# apt list --installed | grep libgpiod

WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

libgpiod-dev/oldstable,now 1.6.2-1 armhf [installed]
libgpiod2/oldstable,now 1.6.2-1 armhf [installed]
python3-libgpiod/oldstable,now 1.6.2-1 armhf [installed]
root@DNR00ZZ00A0AA75:~# ls -las /lib/**/libgpiod.*
32 -rw-r--r-- 1 root root 30054 Dec 14  2020 /lib/arm-linux-gnueabihf/libgpiod.a
 0 lrwxrwxrwx 1 root root    17 Dec 14  2020 /lib/arm-linux-gnueabihf/libgpiod.so -> libgpiod.so.2.2.2
 0 lrwxrwxrwx 1 root root    17 Dec 14  2020 /lib/arm-linux-gnueabihf/libgpiod.so.2 -> libgpiod.so.2.2.2
24 -rw-r--r-- 1 root root 21952 Dec 14  2020 /lib/arm-linux-gnueabihf/libgpiod.so.2.2.2
root@DNR00ZZ00A0AA75:~#
PRIMETSS commented 7 months ago

[IMPORTANT]

Actually just hit the "Segmentation Error" again on a field unit we are testing. Its never had this issue. But this unit I JUST notice was opening a GPIO Port (#GPIO6) for an input that was also been forced into an Output at boot through the deprecated SYSFS method image

Our code Initializes the GPIOController at start up to enable some GPIO ports for physical PCB Button control. I believe this is when the Segment Fault occurred! Crashing the app running (as a service) So this dual use of same GPIO port using old SYSFS and the new LibGpiodDriver might be the issue image image

As this was the system I was using when got the issue above, I wonder if this was the cause of issues I have seen. So, Sorry!!! It's possible this is cause. Will have to investigate, but thought I'd leave comment just in case! I'll get back once re-confirmed the issue is still there now I have discovered this!

pgrawehr commented 7 months ago

@PRIMETSS Yes, this is a known issue, see #1992. When sysfs keeps a pin open, it cannot be accessed trough libgpiod. This shouldn't cause a segfault (but rather some defined exception), but maybe that behavior is OS-dependent or otherwise tied to that specific setup.

To avoid this problem, use echo "6" > /sys/class/gpio/unexport after you're done with sysfs.

Ellerbach commented 7 months ago

[Triage] As it seems that this is not a real issue we can directly fix and everyone found a workaround as problems were mainly related to the configuration, we will most likely close this issue if no new problem that can be fixed in this repository is open.

dotnet-policy-service[bot] commented 7 months ago

This issue has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for 4 days. It will be closed if no further activity occurs within 3 days of this comment.