Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement GPIO support via sysfs with agent interface #468

Merged
merged 4 commits into from
Jul 26, 2019

Conversation

leiflm
Copy link
Contributor

@leiflm leiflm commented Jul 8, 2019

Description
This is only complementary work for #407

Checklist

  • Documentation for the feature
  • Tests for the feature
  • The arguments and description in doc/configuration.rst have been updated
  • CHANGES.rst has been updated
  • PR has been tested
  • Man pages have been regenerated

Complements #407

@leiflm leiflm changed the title Implement libgpiod support with agent interface WIP: Implement libgpiod support with agent interface Jul 8, 2019
@leiflm
Copy link
Contributor Author

leiflm commented Jul 8, 2019

I've just noticed, that the output port is not switched as expected.

I'm investigating the issue and will comment as soon as the issue is resolved.

@leiflm
Copy link
Contributor Author

leiflm commented Jul 9, 2019

I've just noticed, that the output port is not switched as expected.

This was a false assumption. The output is indeed toggled. It just turns back to its initial state once the instance is destroyed/the line gets released. This happens really quickly with the current code appearing as if it was never toggled in the first place.

I'm investigating the issue and will comment as soon as the issue is resolved.

Okay, turns out that when lines are released they recover their former state.

I'll modify the code to work around eventual pin default state recovery.

labgrid/resource/remote.py Outdated Show resolved Hide resolved
labgrid/resource/udev.py Outdated Show resolved Hide resolved
@leiflm
Copy link
Contributor Author

leiflm commented Jul 9, 2019

Since I'm not firm with the Python ecosystem: Where would the distro-specific requirement declaration for libgpiod go? Should I just update the debian file?

@jluebbe
Copy link
Member

jluebbe commented Jul 9, 2019

I've just noticed, that the output port is not switched as expected.

This was a false assumption. The output is indeed toggled. It just turns back to its initial state once the instance is destroyed/the line gets released. This happens really quickly with the current code appearing as if it was never toggled in the first place.

I'm investigating the issue and will comment as soon as the issue is resolved.

Okay, turns out that when lines are released they recover their former state.

I'll modify the code to work around eventual pin default state recovery.

Hmm, it seems that this is a limitation of the /dev/gpiochip interface. The current assumption of the DigitalOutputProtocol is that any configured value is kept until overwritten. This is relevant for usage with labgrid-client io, as no process is around to keep the device node open.

https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/tree/TODO#n11 mentions the plan to write a dbus-based daemon to handle that case, adding even more complexity. Maybe using the sysfs interface is the better approach? ;)

@jluebbe
Copy link
Member

jluebbe commented Jul 9, 2019

Since I'm not firm with the Python ecosystem: Where would the distro-specific requirement declaration for libgpiod go? Should I just update the debian file?

The documentation section on the driver should mention the requirement. Updating the Debian file is also useful.

@leiflm
Copy link
Contributor Author

leiflm commented Jul 9, 2019

I've just noticed, that the output port is not switched as expected.

This was a false assumption. The output is indeed toggled. It just turns back to its initial state once the instance is destroyed/the line gets released. This happens really quickly with the current code appearing as if it was never toggled in the first place.

I'm investigating the issue and will comment as soon as the issue is resolved.

Okay, turns out that when lines are released they recover their former state.
I'll modify the code to work around eventual pin default state recovery.

Hmm, it seems that this is a limitation of the /dev/gpiochip interface. The current assumption of the DigitalOutputProtocol is that any configured value is kept until overwritten. This is relevant for usage with labgrid-client io, as no process is around to keep the device node open.

https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/tree/TODO#n11 mentions the plan to write a dbus-based daemon to handle that case, adding even more complexity. Maybe using the sysfs interface is the better approach? ;)

Yeah. I think that the effort of transforming the libgpiod implementation into an agent was futile. So maybe the state prior to agent implementation (8de1391) could be merged? Should I force-push a state that removes all the commits on top?

@jluebbe
Copy link
Member

jluebbe commented Jul 9, 2019

Yeah. I think that the effort of transforming the libgpiod implementation into an agent was futile. So maybe the state prior to agent implementation (8de1391) could be merged? Should I force-push a state that removes all the commits on top?

That would be premature. Compared to that state, you now have network support.
If you keep the libgpiod handle open in the agent (over multiple get/set calls), you would have the same behaviour as using libgpio directly in the driver (just with added remote support). But even that wouldn't be enough for keeping the output state after the process has exited.

Is there some way in libgpiod to make the state persistent?

@leiflm
Copy link
Contributor Author

leiflm commented Jul 9, 2019

Yeah. I think that the effort of transforming the libgpiod implementation into an agent was futile. So maybe the state prior to agent implementation (8de1391) could be merged? Should I force-push a state that removes all the commits on top?

That would be premature. Compared to that state, you now have network support.

Yes. But with libgpiod the remote system has to have the python bindings for libgpiod installed too.
Compared to simply having a SSHDriver, that seems overly complex, doesn't it?

Maybe I could implement the networked variant using sysfs and keep the local implementation using libgpiod?

If you keep the libgpiod handle open in the agent (over multiple get/set calls), you would have the same behaviour as using libgpio directly in the driver (just with added remote support). But even that wouldn't be enough for keeping the output state after the process has exited.

Yeah. That's true. Maybe instead of implementing the DigitalOutputProtocol it should only implement
the ResetProtocol for the time being?

Is there some way in libgpiod to make the state persistent?

Citing the libgpiod project author here:

A common complaint from users about gpioset is that the state of a line is not retained once the program exits.

His reasoning behind that design:

While this is precisely the way linux character devices work, it's understandable that most users will want some centralized way of controlling GPIOs - similar to how sysfs worked

As all character devices are supposed to behave like this, there must be some general implementation in the kernel? Skimming through the kernel source (drivers/gpio/gpiolib.c) does not show a state recovery besides unassigning various flags.

@jluebbe
Copy link
Member

jluebbe commented Jul 9, 2019

Yeah. I think that the effort of transforming the libgpiod implementation into an agent was futile. So maybe the state prior to agent implementation (8de1391) could be merged? Should I force-push a state that removes all the commits on top?

That would be premature. Compared to that state, you now have network support.

Yes. But with libgpiod the remote system has to have the python bindings for libgpiod installed too.
Compared to simply having a SSHDriver, that seems overly complex, doesn't it?

Maybe I could implement the networked variant using sysfs and keep the local implementation using libgpiod?

I think I'd perfer to just use the sysfs interface via the agent. This avoids the additional dependency and solves the problem of keeping the configured output even after a process exits.

If you keep the libgpiod handle open in the agent (over multiple get/set calls), you would have the same behaviour as using libgpio directly in the driver (just with added remote support). But even that wouldn't be enough for keeping the output state after the process has exited.

Yeah. That's true. Maybe instead of implementing the DigitalOutputProtocol it should only implement
the ResetProtocol for the time being?

That would be much less useful. :/

Is there some way in libgpiod to make the state persistent?

Citing the libgpiod project author here:

A common complaint from users about gpioset is that the state of a line is not retained once the program exits.

His reasoning behind that design:

While this is precisely the way linux character devices work, it's understandable that most users will want some centralized way of controlling GPIOs - similar to how sysfs worked

As all character devices are supposed to behave like this, there must be some general implementation in the kernel? Skimming through the kernel source (drivers/gpio/gpiolib.c) does not show a state recovery besides unassigning various flags.

Given that even gpiolib still has that missing daemon as a TODO, the pragmatic approach for labgrid seems to come down to using the sysfs interface via the agent, as that does everything we need and fits our current model better. If there is a daemon in the future (or we decide to build that ourselves), we can still add an additional driver for the same resource.

It should be possible to translate the gpiochip number + offset information the the global index also via sysfs. That would allow us to use the same resource for both alternative drivers.

@leiflm
Copy link
Contributor Author

leiflm commented Jul 9, 2019

Given that even gpiolib still has that missing daemon as a TODO, the pragmatic approach for labgrid seems to come down to using the sysfs interface via the agent, as that does everything we need and fits our current model better. If there is a daemon in the future (or we decide to build that ourselves), we can still add an additional driver for the same resource.

Alright. For the given reasons, I'll change the agent to use the (deprecated) sysfs instead of libgpiod then.

@codecov
Copy link

codecov bot commented Jul 9, 2019

Codecov Report

Merging #468 into master will increase coverage by 0.1%.
The diff coverage is 68.5%.

Impacted file tree graph

@@           Coverage Diff            @@
##           master    #468     +/-   ##
========================================
+ Coverage    57.5%   57.7%   +0.1%     
========================================
  Files         118     120      +2     
  Lines        7569    7693    +124     
========================================
+ Hits         4358    4443     +85     
- Misses       3211    3250     +39
Impacted Files Coverage Δ
labgrid/remote/client.py 40% <0%> (-0.4%) ⬇️
labgrid/driver/__init__.py 100% <100%> (ø) ⬆️
labgrid/resource/base.py 100% <100%> (ø) ⬆️
labgrid/remote/exporter.py 36.6% <41.6%> (+0.2%) ⬆️
labgrid/driver/gpiodriver.py 63.6% <63.6%> (ø)
labgrid/resource/remote.py 82.5% <75%> (-0.4%) ⬇️
labgrid/util/agents/sysfsgpio.py 84.2% <84.2%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update c9186d3...3401bca. Read the comment docs.

@leiflm leiflm changed the title WIP: Implement libgpiod support with agent interface WIP: Implement GPIO support via sysfs with agent interface Jul 10, 2019
Copy link
Member

@jluebbe jluebbe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you squash your own commits together? They seem to change code that is changed again in your rewrite.

labgrid/driver/gpiodriver.py Outdated Show resolved Hide resolved
labgrid/remote/client.py Outdated Show resolved Hide resolved
labgrid/remote/exporter.py Outdated Show resolved Hide resolved
labgrid/util/agents/sysfsgpio.py Outdated Show resolved Hide resolved
labgrid/util/agents/sysfsgpio.py Show resolved Hide resolved
doc/configuration.rst Outdated Show resolved Hide resolved
@leiflm
Copy link
Contributor Author

leiflm commented Jul 10, 2019

About squashing: Sure. Which range? All of my code? All of the libgpiod code? Feel free to do it in a way you like/see fit.

@leiflm leiflm force-pushed the gpio branch 2 times, most recently from c9d1f5c to d281b38 Compare July 15, 2019 13:25
@Emantor Emantor added enhancement needs jluebbe attention Needs attention from @jluebbe labels Jul 19, 2019
Emantor
Emantor previously approved these changes Jul 19, 2019
Copy link
Member

@Emantor Emantor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some small improvment requests, which could also be done after merge. Thanks!

labgrid/util/agents/sysfsgpio.py Outdated Show resolved Hide resolved
labgrid/util/agents/sysfsgpio.py Outdated Show resolved Hide resolved
@leiflm leiflm force-pushed the gpio branch 2 times, most recently from db91e47 to 4018c2a Compare July 19, 2019 07:57
Bastian Germann and others added 4 commits July 25, 2019 15:47
GpioDigitalOutputDriver uses libgpiod to write a digital signal to a GPIO line.

The minimum requirement to use libgpiod's kernel interface is Linux 4.8.
The python binding is neither commonly available in Linux distributions nor on
PyPI, so import it only on usage.

Signed-off-by: Bastian Germann <[email protected]>
This allows to export local GPIO resources for consumption by remote
clients.

It is implemented using the deprecated `sysfs` interface, because
the `libgpiod` interface does not retain its state once the process
exits. A behavior that is expected by labgrid.

Signed-off-by: Leif Middelschulte <[email protected]>
[Jan Luebbe: squashed additional fixes into this commit]
Signed-off-by: Jan Luebbe <[email protected]>
Adds simple tests for:
 - instantiating a `GpioDigitialOutput`
 - setting (and verifying set) values.

Signed-off-by: Leif Middelschulte <[email protected]>
@jluebbe
Copy link
Member

jluebbe commented Jul 26, 2019

I've squashed the incremental changes into one commit. The original commits by @bgermann from PR #407 are unchanged.

@jluebbe jluebbe changed the title WIP: Implement GPIO support via sysfs with agent interface Implement GPIO support via sysfs with agent interface Jul 26, 2019
@jluebbe jluebbe mentioned this pull request Jul 26, 2019
5 tasks
@jluebbe jluebbe merged commit 8e05a08 into labgrid-project:master Jul 26, 2019
@bgermann
Copy link
Contributor

Thanks!

@pmelange
Copy link

I've just noticed, that the output port is not switched as expected.

This was a false assumption. The output is indeed toggled. It just turns back to its initial state once the instance is destroyed/the line gets released. This happens really quickly with the current code appearing as if it was never toggled in the first place.

I'm investigating the issue and will comment as soon as the issue is resolved.

Okay, turns out that when lines are released they recover their former state.
I'll modify the code to work around eventual pin default state recovery.

Hmm, it seems that this is a limitation of the /dev/gpiochip interface. The current assumption of the DigitalOutputProtocol is that any configured value is kept until overwritten. This is relevant for usage with labgrid-client io, as no process is around to keep the device node open.

https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/tree/TODO#n11 mentions the plan to write a dbus-based daemon to handle that case, adding even more complexity. Maybe using the sysfs interface is the better approach? ;)

I am currently working on trying to implement libgpio into labgrid instead of using sysfs. And I believe I have found the solution to the problem of the configured value being kept uptil overwritten.

When creating a line request, do it with direction=Direction.AS_IS. This will keep the state of the line as is was before being requested, and therefore no longer causing the value of the line to be changed. Afterwards, it's possible to set the line to output mode without any changes in the line happening. In addition, it is possible to get the current value of the line in the case where a line value needs to be toggled. Here is a small code snippet based on the toggle-line-value example in the libgpiod code.

def toggle_line_value(chip_path, line_offset):
    value_str = {Value.ACTIVE: "Active", Value.INACTIVE: "Inactive"}
    value = Value.ACTIVE

    with gpiod.request_lines(
        chip_path,
        consumer="toggle-line-value",
        config={
            line_offset: gpiod.LineSettings(
                direction=Direction.AS_IS
            )
        },
    ) as request:
        print("requesting the value")
        old_value = request.get_value(line_offset)
        print("old value {}={}".format(line_offset, value_str[old_value]))
        time.sleep(1)
        print("changing to output mode")
        request.reconfigure_lines(config={ line_offset: gpiod.LineSettings(
            direction=Direction.OUTPUT, output_value=old_value) })
        time.sleep(1)
        value = toggle_value(old_value)
        print("setting a new value")
        request.set_value(line_offset, value)
        time.sleep(1)
        print("requestion the value")
        old_value = request.get_value(line_offset)
        print("confirming value {}={}".format(line_offset, value_str[value]))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement needs jluebbe attention Needs attention from @jluebbe
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants