ExplorationSystems / opengpio

3 stars 1 forks source link

Feature Request: Support Pull-Up and Pull-Down settings #1

Open Tom-Hirschberger opened 3 months ago

Tom-Hirschberger commented 3 months ago

Hi, switched to your library recently as Kernel 6.6 broke one of my MagicMirror modules. Would be grate to be able to set pull-up or pull-down for pins while registering them.

kueckermann commented 2 months ago

Having some issues with this one. It seems that while libgpiod does have the functionality for pull up/down and debounce, it doesn't seem to be exposed in the development headers from libgpiod-dev. The headers for the core cpp library do clearly have these parameters available. You'll notice in this file that internal bias for pull up/down is there: https://github.com/brgl/libgpiod/blob/master/bindings/cxx/gpiodcxx/line.hpp

But the header file that comes from libgpiod-dev doesn't have any availability for this, as reference here the section from the header file for line:

class line
{
public:

    /**
     * @brief Default constructor. Creates an empty line object.
     */
    GPIOD_API line(void);

    /**
     * @brief Copy constructor.
     * @param other Other line object.
     */
    GPIOD_API line(const line& other) = default;

    /**
     * @brief Move constructor.
     * @param other Other line object.
     */
    GPIOD_API line(line&& other) = default;

    /**
     * @brief Assignment operator.
     * @param other Other line object.
     * @return Reference to this object.
     */
    GPIOD_API line& operator=(const line& other) = default;

    /**
     * @brief Move assignment operator.
     * @param other Other line object.
     * @return Reference to this object.
     */
    GPIOD_API line& operator=(line&& other) = default;

    /**
     * @brief Destructor.
     */
    GPIOD_API ~line(void) = default;

    /**
     * @brief Get the offset of this line.
     * @return Offet of this line.
     */
    GPIOD_API unsigned int offset(void) const;

    /**
     * @brief Get the name of this line (if any).
     * @return Name of this line or an empty string if it is unnamed.
     */
    GPIOD_API ::std::string name(void) const;

    /**
     * @brief Get the consumer of this line (if any).
     * @return Name of the consumer of this line or an empty string if it
     *         is unused.
     */
    GPIOD_API ::std::string consumer(void) const;

    /**
     * @brief Get current direction of this line.
     * @return Current direction setting.
     */
    GPIOD_API int direction(void) const noexcept;

    /**
     * @brief Get current active state of this line.
     * @return Current active state setting.
     */
    GPIOD_API int active_state(void) const noexcept;

    /**
     * @brief Check if this line is used by the kernel or other user space
     *        process.
     * @return True if this line is in use, false otherwise.
     */
    GPIOD_API bool is_used(void) const;

    /**
     * @brief Check if this line represents an open-drain GPIO.
     * @return True if the line is an open-drain GPIO, false otherwise.
     */
    GPIOD_API bool is_open_drain(void) const;

    /**
     * @brief Check if this line represents an open-source GPIO.
     * @return True if the line is an open-source GPIO, false otherwise.
     */
    GPIOD_API bool is_open_source(void) const;

    /**
     * @brief Request this line.
     * @param config Request config (see gpiod::line_request).
     * @param default_val Default value - only matters for OUTPUT direction.
     */
    GPIOD_API void request(const line_request& config, int default_val = 0) const;

    /**
     * @brief Release the line if it was previously requested.
     */
    GPIOD_API void release(void) const;

    /**
     * @brief Check if this user has ownership of this line.
     * @return True if the user has ownership of this line, false otherwise.
     */
    GPIOD_API bool is_requested(void) const;

    /**
     * @brief Read the line value.
     * @return Current value (0 or 1).
     */
    GPIOD_API int get_value(void) const;

    /**
     * @brief Set the value of this line.
     * @param val New value (0 or 1).
     */
    GPIOD_API void set_value(int val) const;

    /**
     * @brief Wait for an event on this line.
     * @param timeout Time to wait before returning if no event occurred.
     * @return True if an event occurred and can be read, false if the wait
     *         timed out.
     */
    GPIOD_API bool event_wait(const ::std::chrono::nanoseconds& timeout) const;

    /**
     * @brief Read a line event.
     * @return Line event object.
     */
    GPIOD_API line_event event_read(void) const;

    /**
     * @brief Get the event file descriptor associated with this line.
     * @return File descriptor number.
     */
    GPIOD_API int event_get_fd(void) const;

    /**
     * @brief Get the reference to the parent chip.
     * @return Reference to the parent chip object.
     */
    GPIOD_API const chip& get_chip(void) const;

    /**
     * @brief Reset the state of this object.
     *
     * This is useful when the user needs to e.g. keep the line_event object
     * but wants to drop the reference to the GPIO chip indirectly held by
     * the line being the source of the event.
     */
    GPIOD_API void reset(void);

    /**
     * @brief Check if two line objects reference the same GPIO line.
     * @param rhs Right-hand side of the equation.
     * @return True if both objects reference the same line, fale otherwise.
     */
    GPIOD_API bool operator==(const line& rhs) const noexcept;

    /**
     * @brief Check if two line objects reference different GPIO lines.
     * @param rhs Right-hand side of the equation.
     * @return False if both objects reference the same line, true otherwise.
     */
    GPIOD_API bool operator!=(const line& rhs) const noexcept;

    /**
     * @brief Check if this object holds a reference to any GPIO line.
     * @return True if this object references a GPIO line, false otherwise.
     */
    GPIOD_API explicit operator bool(void) const noexcept;

    /**
     * @brief Check if this object doesn't reference any GPIO line.
     * @return True if this object doesn't reference any GPIO line, true
     *         otherwise.
     */
    GPIOD_API bool operator!(void) const noexcept;

    /**
     * @brief Possible direction settings.
     */
    enum : int {
        DIRECTION_INPUT = 1,
        /**< Line's direction setting is input. */
        DIRECTION_OUTPUT,
        /**< Line's direction setting is output. */
    };

    /**
     * @brief Possible active state settings.
     */
    enum : int {
        ACTIVE_LOW = 1,
        /**< Line's active state is low. */
        ACTIVE_HIGH,
        /**< Line's active state is high. */
    };

Not sure why, but can only think that this is newer functionality that isn't exposed in libgpiod-dev yet. But that's just a guess. Will see if it's possible to directly reference the header files from the core library instead of from libgpiod-dev.

Tom-Hirschberger commented 2 months ago

Hi,

I do not have much knowledge of C++ but it looks like the last changes of the bindings are at least two years old.

https://github.com/brgl/libgpiod/blob/master/bindings/cxx/line.cpp

Thought it might be cause of the change to version 2 of the lib but the bias and pull settings are included into the 1.6.x branch, too.

kueckermann commented 2 months ago

I noticed found devs that seemed to be working on dev bindings for version 2, which is why I also suspected that the current dev bindings were for an older version. I'll try include version 2 as a git submodule and use the header files directly from there. I'm traveling for work this week, so I'll probably only get onto this again next week.

kueckermann commented 2 months ago

@Tom-Hirschberger I'm back from my work trip and I've had a look into this. I was able to add libgpiod as a submodule to the package. Thankfully it doesn't require any external dependancies so the project build pipeline works just fine. However, the version 2.1.x structure is not compatible with the headers exposed by libgpiod 1.6.x, so the compiler throws a bunch of errors.

Thankfully tho, version 2 seems relatively straight forward so I should be able to reuse the majority of the existing opengpio.cpp code with changes mostly around how c++ requests the chip and line objects. I was able to get a striped down version of the file to compile.

I'm working on this on the branch version/libgpiod_v2.1.x. It's probably going to take a bit of work still, but once done, we'll be able to make use of all the features within version 2 of libgpiod. I'll keep you updated.

Tom-Hirschberger commented 2 months ago

Thank you very much for your affort.

kueckermann commented 2 months ago

@Tom-Hirschberger I managed to get it working for input, output, and watching. Debounce and Bias appear to be working. I need to finish up PWM still. The only thing that I need to really work on setting up is to automate the download, build, and install of libgpiod v2.1.x. I can't find a prebuilt version of this that can be installed via apt install, so for now it seems that the easiest is that it builds and installs on the device from the source code. This seems fine because it doesn't require any dependancies, but that downside is it takes several minutes to install. In future, prebuilt binaries could be packaged with the library.

Once I've finished up the install side of things I'll send you details on how to try it out.

kueckermann commented 2 months ago

@Tom-Hirschberger I've completed the setup of the library. Would you mind to give it a try? You can install using npm install "https://github.com/ExplorationSystems/opengpio.git#version/libgpiod_v2.1.x"

Note that it will take a while to install since it's building from source code and you'll probably think the install has jammed, but just let it be. Even for like 15 minutes. If this works, I'll probably look at packaging the prebuild binaries atleast for ARM.

Tom-Hirschberger commented 2 months ago

Do not know when I have time to test. But I will do as fast as I can.

kueckermann commented 2 months ago

@Tom-Hirschberger no stress. Are you using an ARM based system?

kueckermann commented 2 months ago

@Tom-Hirschberger after much trial and error I opted to remove auto building of libgpiod version 2 from being embedded in the library. Rather, I added instructions on how to build the prerequisites into the readme. It's easy enough for people to do anyway.

I've pushed the latest version to: https://github.com/ExplorationSystems/opengpio/tree/version/libgpiod_v2.1.x You can follow the instructions in the README to install libgpiod v2.1.

After you've installed it successfully, you can run npm install "https://github.com/ExplorationSystems/opengpio.git#version/libgpiod_v2.1.x" to install the library.

Everything should work as before, expect there are new additions to use the built in debounce and bias. Here's an example:

import { NanoPi_NEO3, Edge, Bias } from 'opengpio';

const watch = NanoPi_NEO3.watch(NanoPi_NEO3.bcm.GPIO2_B7, Edge.Both, {
    debounce: 20,
    bias: Bias.PullDown
});

No rush, but once you've given this new version a try and can confirm that it works then I'll pull it into main and deploy it to npm as a new version.

kueckermann commented 2 months ago

I've also setup a script to automate the install process for libgpiod, you can execute the following to use it: curl https://raw.githubusercontent.com/ExplorationSystems/opengpio/version/libgpiod_v2.1.x/install-libgpiod.sh | bash

Tom-Hirschberger commented 2 months ago

Hi and thank you very much.

Maybe i will have time to test at the next weekend. Need to setup a example.

Edit: I use Raspberry Pis mostly. 32Bit and 64Bit OS.

Tom-Hirschberger commented 2 months ago

Hi, had some minutes and tried the installation. The script quits with an error during compilation of the library.

pi@mirror-dev:~ $ curl https://raw.githubusercontent.com/ExplorationSystems/opengpio/version/libgpiod_v2.1.x/install-libgpiod.sh | bash
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   522  100   522    0     0   1955      0 --:--:-- --:--:-- --:--:--  1962
Cleaning directory
Ensure build dependancies
Paketlisten werden gelesen… Fertig
Abhängigkeitsbaum wird aufgebaut… Fertig
Statusinformationen werden eingelesen… Fertig
tar ist schon die neueste Version (1.34+dfsg-1.2+deb12u1).
gzip ist schon die neueste Version (1.12-1).
build-essential ist schon die neueste Version (12.9).
autoconf ist schon die neueste Version (2.71-3).
curl ist schon die neueste Version (7.88.1-10+deb12u5).
Die folgenden Pakete wurden automatisch installiert und werden nicht mehr benötigt:
  libcamera0.1 libssl1.1 linux-headers-6.1.0-rpi7-common-rpi
Verwenden Sie »sudo apt autoremove«, um sie zu entfernen.
0 aktualisiert, 0 neu installiert, 0 zu entfernen und 104 nicht aktualisiert.
Fetching libgpiod v2.1
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  206k    0  206k    0     0   560k      0 --:--:-- --:--:-- --:--:--  562k
Build and install libgpiod
autoreconf: export WARNINGS=
autoreconf: Entering directory '.'
autoreconf: configure.ac: not using Gettext
autoreconf: running: aclocal --force -I m4
aclocal: warning: couldn't open directory 'm4': No such file or directory
autoreconf: configure.ac: tracing
autoreconf: configure.ac: creating directory autostuff
autoreconf: configure.ac: not using Libtool
autoreconf: configure.ac: not using Intltool
autoreconf: configure.ac: not using Gtkdoc
autoreconf: running: /usr/bin/autoconf --force
configure.ac:75: warning: The macro `AC_HEADER_STDC' is obsolete.
configure.ac:75: You should run autoupdate.
./lib/autoconf/headers.m4:704: AC_HEADER_STDC is expanded from...
configure.ac:75: the top level
configure.ac:203: error: Unexpanded AX_ macro found. Please install GNU autoconf-archive.
      If this token and others are legitimate, please use m4_pattern_allow.
      See the Autoconf documentation.
autoreconf: error: /usr/bin/autoconf failed with exit status: 1
make: *** Es wurden keine Ziele angegeben und keine „make“-Steuerdatei gefunden.  Schluss.
make: *** Keine Regel, um „install“ zu erstellen.  Schluss.
kueckermann commented 1 month ago

@Tom-Hirschberger thanks for checking. Seems like a build dependency is missing, I'll add it to the script.

kueckermann commented 1 month ago

@Tom-Hirschberger could you try two things:

  1. I've added an additional build lib that seems to be missing based on the logs you provided. Can you try run curl https://raw.githubusercontent.com/ExplorationSystems/opengpio/version/libgpiod_v2.1.x/install-libgpiod.sh | bash again and see what happens? I feel this approach might be a big of trial and error tho.

  2. If the above still fails can you try following the build script at the lib's readme? Easiest is to clone this repo locally git clone -b v2.1.x https://github.com/brgl/libgpiod.git and follow the readme. If you encounter any missing libs, try install them and let me know which ones were missing and I'll add them to the automated script. Also, from your logs it says you might need to run autoupdate. If installing fails after trying all the above, I'd recommend running the autoupdate command in the cloned repo's root directory. Send over any logs.

kueckermann commented 1 month ago

Last thing... What version of linux are you on?

Tom-Hirschberger commented 1 month ago

Hi, I had the plan to debug further to provide more information to you already but had not found any time yet. But I will try to in the next days.

I am running two systems at the moment. One is Debian Bullseye 32bit, one is Debian Bookworm 64bit.

kueckermann commented 1 month ago

No stress @Tom-Hirschberger. Also been very busy my side the last week. 👍

Tom-Hirschberger commented 1 month ago

Hi,

i had to modify your installer slightly:

# Clean directory
echo "Cleaning directory"
rm -rf libgpiod-2.1

#autoupdate package does not exist
#
echo "Update apt cache"
sudo apt -y update

# Ensure build dependancies
echo "Ensure build dependancies"
sudo apt -y install tar gzip build-essential autoconf curl autoconf-archive libtool

# Fetch libgpiod on branch 2.1.x
echo "Fetching libgpiod v2.1"
curl -o libgpiod-2.1.tar.gz 'https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/snapshot/libgpiod-2.1.tar.gz'
tar xf libgpiod-2.1.tar.gz
cd libgpiod-2.1

# Build and install libgpiod
echo "Build and install libgpiod"
./autogen.sh --enable-bindings-cxx
make
sudo make install

With the libtool dependency installed the lib gets compiled and is installed but although i removed my node_modules directory and the package-lock.json before re-run the npm install i get the following error if run my test script:

node index.js 
node: symbol lookup error: /home/pi/test/node_modules/opengpio/build/Release/opengpio.node: undefined symbol: _ZN5gpiod13line_settingsC1Ev

Tried to run sudo ldconfig after the compile to make sure the system recognized the new lib but it does not make any difference.

kueckermann commented 1 month ago

That's super helpful. Thanks a ton.

The linker issue is an odd one. I'll take a look into this. The only thing that initially comes to mind is if it's somehow utilising a file from the old version of libgpiod. I think I'll try install debian on my device and run this to see if I can reproduce the linker issue.

I might send a few questions but I think this sufficient information for me to dig further.