All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kent Gibson <warthog618@gmail.com>
To: Bartosz Golaszewski <brgl@bgdev.pl>
Cc: linux-gpio@vger.kernel.org
Subject: Re: [libgpiod][RFC] helper functions for basic use cases
Date: Wed, 15 May 2024 17:18:48 +0800	[thread overview]
Message-ID: <20240515091848.GA86661@rigel> (raw)
In-Reply-To: <CAMRc=MdyUmfGaJ_0edvhMYwC7x5HwYyFAdD5EY-13+5yoRUeiw@mail.gmail.com>

On Wed, May 15, 2024 at 01:26:32AM -0700, Bartosz Golaszewski wrote:
> On Tue, 14 May 2024 15:38:04 +0200, Kent Gibson <warthog618@gmail.com> said:
> > On Tue, May 14, 2024 at 06:31:39AM -0700, Bartosz Golaszewski wrote:
> >> On Mon, 13 May 2024 12:13:31 +0200, Kent Gibson <warthog618@gmail.com> said:
> >> >
> >> >> > /**
> >> >> >  * @brief Set the bias of requested input line.
> >> >> >  * @param olr The request to reconfigure.
> >> >> >  * @param bias The new bias to apply to requested input line.
> >> >> >  * @return 0 on success, -1 on failure.
> >> >> >  */
> >> >> > int gpiod_olr_set_bias(struct gpiod_line_request * olr,
> >> >> > 		       enum gpiod_line_bias bias);
> >> >>
> >> >> For this to work, you'd most likely need a new struct wrapping the request
> >> >> and also storing the line config. Otherwise - how'd you keep the state of all
> >> >> the other line settings?
> >> >>
> >> >
> >> > Yeah, I realised that when I went to implement it :(.
> >> >
> >> > What I implemented was to read the line info and build the config from that.
> >> > So no impact on core.
> >> > Not the most efficient, but for this use case I wan't fussed.
> >> >
> >>
> >> I think those simplified requests should wrap the config structures, otherwise
> >> we'd have to readback the config from the kernel which would become quite
> >> complex for anything including more than one line.
> >>
> >
> > The whole point of the simplified requests is that they only deal with
> > a single line.  And the config mutators only deal with a single input.
> >
>
> For now anyway. :)
>
> > Wouldn't wrapping break the ability to use all the other
> > gpiod_line_request_XXX functions, and so require adding more functions
> > to make use of the simplified requests?
> >
>
> Not sure why? You need a request for a single line anyway and you need to store
> the config for it somewhere as toggling a single property will require a full
> gpiod_line_request_reconfigure() anyway.

But I don't intend to store the config for it, so the existing
gpiod_line_request is fine.

>
> I don't think it'll be enough to re-use struct gpiod_line_request here, you
> need some new structure. Unless you know how to do it. In that case: show me
> the code. :)
>

Sure thing.  This is what I have at the moment (the declarations are as
per earlier, just renamed.  And I just noticed some variables I haven't
renamed.  I'll add it to the todo list.):

diff --git a/lib/line-request.c b/lib/line-request.c
index b76b3d7..5af23e0 100644
--- a/lib/line-request.c
+++ b/lib/line-request.c
@@ -305,3 +305,200 @@ gpiod_line_request_read_edge_events(struct gpiod_line_request *request,

 	return gpiod_edge_event_buffer_read_fd(request->fd, buffer, max_events);
 }
+
+static struct gpiod_line_request *
+ext_request(const char  *path, unsigned int offset,
+	    enum gpiod_line_direction direction,
+	    enum gpiod_line_value value)
+{
+	struct gpiod_line_request *request = NULL;
+	struct gpiod_line_settings *settings;
+	struct gpiod_line_config *line_cfg;
+	struct gpiod_chip *chip;
+	int ret;
+
+	chip = gpiod_chip_open(path);
+	if (!chip)
+		return NULL;
+
+	settings = gpiod_line_settings_new();
+	if (!settings)
+		goto close_chip;
+
+	gpiod_line_settings_set_direction(settings, direction);
+	if (direction == GPIOD_LINE_DIRECTION_OUTPUT)
+		gpiod_line_settings_set_output_value(settings, value);
+
+	line_cfg = gpiod_line_config_new();
+	if (!line_cfg)
+		goto free_settings;
+
+	ret = gpiod_line_config_add_line_settings(line_cfg, &offset, 1,
+						  settings);
+	if (ret)
+		goto free_line_cfg;
+
+	request = gpiod_chip_request_lines(chip, NULL, line_cfg);
+
+free_line_cfg:
+	gpiod_line_config_free(line_cfg);
+
+free_settings:
+	gpiod_line_settings_free(settings);
+
+close_chip:
+	gpiod_chip_close(chip);
+
+	return request;
+}
+
+GPIOD_API struct gpiod_line_request *
+gpiod_ext_request_input(const char  *path, unsigned int offset)
+{
+	return ext_request(path, offset, GPIOD_LINE_DIRECTION_INPUT, 0);
+}
+
+GPIOD_API struct gpiod_line_request *
+gpiod_ext_request_output(const char  *path, unsigned int offset,
+			 enum gpiod_line_value value)
+{
+	return ext_request(path, offset, GPIOD_LINE_DIRECTION_OUTPUT, value);
+}
+
+static struct gpiod_line_settings *
+ext_line_settings(struct gpiod_line_request * olr)
+{
+	struct gpiod_line_settings *settings = NULL;
+	struct gpiod_line_info *line_info;
+	struct gpiod_chip *chip;
+	char path[32];
+
+	assert(olr);
+
+	if (olr->num_lines != 1) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	/*
+	 * This is all decidedly non-optimal, as generally the user has the
+	 * config available from when they made the request, but here we need to
+	 * rebuild it from the line info...
+	 */
+	memcpy(path, "/dev/", 5);
+	strncpy(&path[5], olr->chip_name, 26);
+	chip = gpiod_chip_open(path);
+	if (!chip)
+		return NULL;
+
+	// get info
+	line_info = gpiod_chip_get_line_info(chip, olr->offsets[0]);
+	gpiod_chip_close(chip);
+	if (!line_info)
+		return NULL;
+
+	if (gpiod_line_info_get_direction(line_info) != GPIOD_LINE_DIRECTION_INPUT) {
+		errno = EINVAL;
+		goto free_info;
+	}
+
+	settings = gpiod_line_settings_new();
+	if (!settings)
+		goto free_info;
+
+	gpiod_line_settings_set_direction(settings, GPIOD_LINE_DIRECTION_INPUT);
+	gpiod_line_settings_set_bias(settings,
+		gpiod_line_info_get_bias(line_info));
+	gpiod_line_settings_set_edge_detection(settings,
+		gpiod_line_info_get_edge_detection(line_info));
+	gpiod_line_settings_set_debounce_period_us(settings,
+		gpiod_line_info_get_debounce_period_us(line_info));
+
+free_info:
+	gpiod_line_info_free(line_info);
+
+	return settings;
+}
+
+static int
+ext_reconfigure(struct gpiod_line_request *request, struct gpiod_line_settings *settings)
+{
+	struct gpiod_line_config *line_cfg;
+	int ret;
+
+	line_cfg = gpiod_line_config_new();
+	if (!line_cfg)
+		return -1;
+
+	ret = gpiod_line_config_add_line_settings(line_cfg, request->offsets, 1,
+						  settings);
+	if (ret)
+		goto free_line_cfg;
+
+	ret = gpiod_line_request_reconfigure_lines(request, line_cfg);
+
+free_line_cfg:
+	gpiod_line_config_free(line_cfg);
+
+	return ret;
+}
+
+GPIOD_API int
+gpiod_ext_set_bias(struct gpiod_line_request * olr,
+		   enum gpiod_line_bias bias)
+{
+	int ret;
+
+	struct gpiod_line_settings *settings;
+
+	settings = ext_line_settings(olr);
+	if (!settings)
+		return -1;
+
+	ret = gpiod_line_settings_set_bias(settings, bias);
+	if (!ret)
+		ret = ext_reconfigure(olr, settings);
+
+	gpiod_line_settings_free(settings);
+
+	return ret;
+}
+
+GPIOD_API int
+gpiod_ext_set_debounce_period_us(struct gpiod_line_request * olr,
+				 unsigned long period)
+{
+	struct gpiod_line_settings *settings;
+	int ret;
+
+	settings = ext_line_settings(olr);
+	if (!settings)
+		return -1;
+
+	gpiod_line_settings_set_debounce_period_us(settings, period);
+	ret = ext_reconfigure(olr, settings);
+
+	gpiod_line_settings_free(settings);
+
+	return ret;
+}
+
+GPIOD_API int
+gpiod_ext_set_edge_detection(struct gpiod_line_request * olr,
+			     enum gpiod_line_edge edge)
+{
+	struct gpiod_line_settings *settings;
+	int ret;
+
+	settings = ext_line_settings(olr);
+	if (!settings)
+		return -1;
+
+	ret = gpiod_line_settings_set_edge_detection(settings, edge);
+	if (!ret)
+		ret = ext_reconfigure(olr, settings);
+
+	gpiod_line_settings_free(settings);
+
+	return ret;
+}


Oh, I also added this:

+/**
+ * @brief The size required to contain a single edge event.
+ * @return The size in bytes.
+ */
+size_t gpiod_edge_event_size();
+

So users can perform the event read themselves without requiring any
knowledge of event buffers (at the moment they can't determine the size
required to perform the read).

I also intend to provide an updated set of examples that use the ext API.
They should go in examples/ext?

Cheers,
Kent.


  reply	other threads:[~2024-05-15  9:18 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-05-07  2:21 [libgpiod][RFC] helper functions for basic use cases Kent Gibson
2024-05-10 18:37 ` Bartosz Golaszewski
2024-05-11  1:11   ` Kent Gibson
2024-05-13  8:28     ` Bartosz Golaszewski
2024-05-13 10:13       ` Kent Gibson
2024-05-14 13:31         ` Bartosz Golaszewski
2024-05-14 13:38           ` Kent Gibson
2024-05-15  8:26             ` Bartosz Golaszewski
2024-05-15  9:18               ` Kent Gibson [this message]
2024-05-15 13:37                 ` Kent Gibson
2024-05-15 13:54                 ` Bartosz Golaszewski
2024-05-15 14:14                   ` Kent Gibson
2024-05-16  0:19                     ` Kent Gibson
2024-05-16 13:55                     ` Kent Gibson
2024-05-17 10:53                     ` Bartosz Golaszewski
2024-05-17 12:37                       ` Kent Gibson
2024-05-22 10:59                         ` Bartosz Golaszewski
2024-05-22 12:41                           ` Kent Gibson
2024-05-24 14:20                             ` Bartosz Golaszewski
2024-05-15  7:06       ` Martin Hundebøll
2024-05-15  9:32         ` Kent Gibson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240515091848.GA86661@rigel \
    --to=warthog618@gmail.com \
    --cc=brgl@bgdev.pl \
    --cc=linux-gpio@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.