/* SPDX-License-Identifier: LGPL-2.1-or-later */
/* SPDX-FileCopyrightText: 2017-2022 Bartosz Golaszewski <brgl@bgdev.pl> */

/**
 * @file gpiod.h
 */

#ifndef __LIBGPIOD_GPIOD_H__
#define __LIBGPIOD_GPIOD_H__

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @struct gpiod_chip
 * @{
 *
 * Refer to @ref chips for functions that operate on gpiod_chip.
 *
 * @}
*/
struct gpiod_chip;

/**
 * @struct gpiod_chip_info
 * @{
 *
 * Refer to @ref chip_info for functions that operate on gpiod_chip_info.
 *
 * @}
*/
struct gpiod_chip_info;

/**
 * @struct gpiod_line_info
 * @{
 *
 * Refer to @ref line_info for functions that operate on gpiod_line_info.
 *
 * @}
*/
struct gpiod_line_info;

/**
 * @struct gpiod_line_settings
 * @{
 *
 * Refer to @ref line_settings for functions that operate on
 * gpiod_line_settings.
 *
 * @}
*/
struct gpiod_line_settings;

/**
 * @struct gpiod_line_config
 * @{
 *
 * Refer to @ref line_config for functions that operate on gpiod_line_config.
 *
 * @}
*/
struct gpiod_line_config;

/**
 * @struct gpiod_request_config
 * @{
 *
 * Refer to @ref request_config for functions that operate on
 * gpiod_request_config.
 *
 * @}
*/
struct gpiod_request_config;

/**
 * @struct gpiod_line_request
 * @{
 *
 * Refer to @ref line_request for functions that operate on
 * gpiod_line_request.
 *
 * @}
*/
struct gpiod_line_request;

/**
 * @struct gpiod_info_event
 * @{
 *
 * Refer to @ref line_watch for functions that operate on gpiod_info_event.
 *
 * @}
*/
struct gpiod_info_event;

/**
 * @struct gpiod_edge_event
 * @{
 *
 * Refer to @ref edge_event for functions that operate on gpiod_edge_event.
 *
 * @}
*/
struct gpiod_edge_event;

/**
 * @struct gpiod_edge_event_buffer
 * @{
 *
 * Refer to @ref edge_event for functions that operate on
 * gpiod_edge_event_buffer.
 *
 * @}
*/
struct gpiod_edge_event_buffer;

/**
 * @defgroup chips GPIO chips
 * @{
 *
 * Functions and data structures for GPIO chip operations.
 *
 * A GPIO chip object is associated with an open file descriptor to the GPIO
 * character device. It exposes basic information about the chip and allows
 * callers to retrieve information about each line, watch lines for state
 * changes and make line requests.
 */

/**
 * @brief Open a chip by path.
 * @param path Path to the gpiochip device file.
 * @return GPIO chip object or NULL if an error occurred. The returned object
 *         must be closed by the caller using ::gpiod_chip_close.
 */
struct gpiod_chip *gpiod_chip_open(const char *path);

/**
 * @brief Close the chip and release all associated resources.
 * @param chip Chip to close.
 */
void gpiod_chip_close(struct gpiod_chip *chip);

/**
 * @brief Get information about the chip.
 * @param chip GPIO chip object.
 * @return New GPIO chip info object or NULL if an error occurred. The returned
 *         object must be freed by the caller using ::gpiod_chip_info_free.
 */
struct gpiod_chip_info *gpiod_chip_get_info(struct gpiod_chip *chip);

/**
 * @brief Get the path used to open the chip.
 * @param chip GPIO chip object.
 * @return Path to the file passed as argument to ::gpiod_chip_open. The
 *         returned pointer is valid for the lifetime of the chip object and
 *         must not be freed by the caller.
 */
const char *gpiod_chip_get_path(struct gpiod_chip *chip);

/**
 * @brief Get a snapshot of information about a line.
 * @param chip GPIO chip object.
 * @param offset The offset of the GPIO line.
 * @return New GPIO line info object or NULL if an error occurred. The returned
 *         object must be freed by the caller using ::gpiod_line_info_free.
 */
struct gpiod_line_info *gpiod_chip_get_line_info(struct gpiod_chip *chip,
						 unsigned int offset);

/**
 * @brief Get a snapshot of the status of a line and start watching it for
 *        future changes.
 * @param chip GPIO chip object.
 * @param offset The offset of the GPIO line.
 * @return New GPIO line info object or NULL if an error occurred. The returned
 *         object must be freed by the caller using ::gpiod_line_info_free.
 * @note Line status does not include the line value. To monitor the line
 *       value the line must be requested as an input with edge detection set.
 */
struct gpiod_line_info *gpiod_chip_watch_line_info(struct gpiod_chip *chip,
						   unsigned int offset);

/**
 * @brief Stop watching a line for status changes.
 * @param chip GPIO chip object.
 * @param offset The offset of the line to stop watching.
 * @return 0 on success, -1 on failure.
 */
int gpiod_chip_unwatch_line_info(struct gpiod_chip *chip, unsigned int offset);

/**
 * @brief Get the file descriptor associated with the chip.
 * @param chip GPIO chip object.
 * @return File descriptor number for the chip.
 *
 * This function never fails. The returned file descriptor must not be closed
 * by the caller. Call ::gpiod_chip_close to close the file descriptor by
 * closing the chip owning it.
 */
int gpiod_chip_get_fd(struct gpiod_chip *chip);

/**
 * @brief Wait for line status change events on any of the watched lines
 *        on the chip.
 * @param chip GPIO chip object.
 * @param timeout_ns Wait time limit in nanoseconds. If set to 0, the function
 *                   returns immediately. If set to a negative number, the
 *                   function blocks indefinitely until an event becomes
 *                   available.
 * @return 0 if wait timed out, -1 if an error occurred, 1 if an event is
 *         pending.
 */
int gpiod_chip_wait_info_event(struct gpiod_chip *chip, int64_t timeout_ns);

/**
 * @brief Read a single line status change event from the chip.
 * @param chip GPIO chip object.
 * @return Newly read watch event object or NULL on error. The event must be
 *         freed by the caller using ::gpiod_info_event_free.
 * @note If no events are pending, this function will block.
 */
struct gpiod_info_event *gpiod_chip_read_info_event(struct gpiod_chip *chip);

/**
 * @brief Map a line's name to its offset within the chip.
 * @param chip GPIO chip object.
 * @param name Name of the GPIO line to map.
 * @return Offset of the line within the chip or -1 on error.
 * @note If a line with given name is not exposed by the chip, the function
 *       sets errno to ENOENT.
 */
int gpiod_chip_get_line_offset_from_name(struct gpiod_chip *chip,
					 const char *name);

/**
 * @brief Request a set of lines for exclusive usage.
 * @param chip GPIO chip object.
 * @param req_cfg Request config object. Can be NULL for default settings.
 * @param line_cfg Line config object.
 * @return New line request object or NULL if an error occurred. The request
 *         must be released by the caller using ::gpiod_line_request_release.
 */
struct gpiod_line_request *
gpiod_chip_request_lines(struct gpiod_chip *chip,
			 struct gpiod_request_config *req_cfg,
			 struct gpiod_line_config *line_cfg);

/**
 * @}
 *
 * @defgroup chip_info Chip info
 * @{
 *
 * Functions for retrieving kernel information about chips.
 *
 * Line info object contains an immutable snapshot of a chip's status.
 *
 * The chip info contains all the publicly available information about a
 * chip.
 *
 * Some accessor methods return pointers. Those pointers refer to internal
 * fields. The lifetimes of those fields are tied to the lifetime of the
 * containing chip info object. Such pointers remain valid until
 * ::gpiod_chip_info_free is called on the containing chip info object. They
 * must not be freed by the caller.
 */

/**
 * @brief Free a chip info object and release all associated resources.
 * @param info GPIO chip info object to free.
 */
void gpiod_chip_info_free(struct gpiod_chip_info *info);

/**
 * @brief Get the name of the chip as represented in the kernel.
 * @param info GPIO chip info object.
 * @return Valid pointer to a human-readable string containing the chip name.
 *         The string lifetime is tied to the chip info object so the pointer
 *         must not be freed by the caller.
 */
const char *gpiod_chip_info_get_name(struct gpiod_chip_info *info);

/**
 * @brief Get the label of the chip as represented in the kernel.
 * @param info GPIO chip info object.
 * @return Valid pointer to a human-readable string containing the chip label.
 *         The string lifetime is tied to the chip info object so the pointer
 *         must not be freed by the caller.
 */
const char *gpiod_chip_info_get_label(struct gpiod_chip_info *info);

/**
 * @brief Get the number of lines exposed by the chip.
 * @param info GPIO chip info object.
 * @return Number of GPIO lines.
 */
size_t gpiod_chip_info_get_num_lines(struct gpiod_chip_info *info);

/**
 * @}
 *
 * @defgroup line_defs Line definitions
 * @{
 *
 * These defines are used across the API.
 */

/**
 * @brief Logical line state.
 */
enum gpiod_line_value {
	GPIOD_LINE_VALUE_ERROR = -1,
	/**< Returned to indicate an error when reading the value. */
	GPIOD_LINE_VALUE_INACTIVE = 0,
	/**< Line is logically inactive. */
	GPIOD_LINE_VALUE_ACTIVE = 1,
	/**< Line is logically active. */
};

/**
 * @brief Direction settings.
 */
enum gpiod_line_direction {
	GPIOD_LINE_DIRECTION_AS_IS = 1,
	/**< Request the line(s), but don't change direction. */
	GPIOD_LINE_DIRECTION_INPUT,
	/**< Direction is input - for reading the value of an externally driven
	 *   GPIO line. */
	GPIOD_LINE_DIRECTION_OUTPUT,
	/**< Direction is output - for driving the GPIO line. */
};

/**
 * @brief Edge detection settings.
 */
enum gpiod_line_edge {
	GPIOD_LINE_EDGE_NONE = 1,
	/**< Line edge detection is disabled. */
	GPIOD_LINE_EDGE_RISING,
	/**< Line detects rising edge events. */
	GPIOD_LINE_EDGE_FALLING,
	/**< Line detects falling edge events. */
	GPIOD_LINE_EDGE_BOTH,
	/**< Line detects both rising and falling edge events. */
};

/**
 * @brief Internal bias settings.
 */
enum gpiod_line_bias {
	GPIOD_LINE_BIAS_AS_IS = 1,
	/**< Don't change the bias setting when applying line config. */
	GPIOD_LINE_BIAS_UNKNOWN,
	/**< The internal bias state is unknown. */
	GPIOD_LINE_BIAS_DISABLED,
	/**< The internal bias is disabled. */
	GPIOD_LINE_BIAS_PULL_UP,
	/**< The internal pull-up bias is enabled. */
	GPIOD_LINE_BIAS_PULL_DOWN,
	/**< The internal pull-down bias is enabled. */
};

/**
 * @brief Drive settings.
 */
enum gpiod_line_drive {
	GPIOD_LINE_DRIVE_PUSH_PULL = 1,
	/**< Drive setting is push-pull. */
	GPIOD_LINE_DRIVE_OPEN_DRAIN,
	/**< Line output is open-drain. */
	GPIOD_LINE_DRIVE_OPEN_SOURCE,
	/**< Line output is open-source. */
};

/**
 * @brief Clock settings.
 */
enum gpiod_line_clock {
	GPIOD_LINE_CLOCK_MONOTONIC = 1,
	/**< Line uses the monotonic clock for edge event timestamps. */
	GPIOD_LINE_CLOCK_REALTIME,
	/**< Line uses the realtime clock for edge event timestamps. */
	GPIOD_LINE_CLOCK_HTE,
	/**< Line uses the hardware timestamp engine for event timestamps. */
};

/**
 * @}
 *
 * @defgroup line_info Line info
 * @{
 *
 * Functions for retrieving kernel information about both requested and free
 * lines.
 *
 * Line info object contains an immutable snapshot of a line's status.
 *
 * The line info contains all the publicly available information about a
 * line, which does not include the line value. The line must be requested
 * to access the line value.
 *
 * Some accessor methods return pointers. Those pointers refer to internal
 * fields. The lifetimes of those fields are tied to the lifetime of the
 * containing line info object. Such pointers remain valid until
 * ::gpiod_line_info_free is called on the containing line info object. They
 * must not be freed by the caller.
 */

/**
 * @brief Free a line info object and release all associated resources.
 * @param info GPIO line info object to free.
 */
void gpiod_line_info_free(struct gpiod_line_info *info);

/**
 * @brief Copy a line info object.
 * @param info Line info to copy.
 * @return Copy of the line info or NULL on error. The returned object must
 *         be freed by the caller using :gpiod_line_info_free.
 */
struct gpiod_line_info *gpiod_line_info_copy(struct gpiod_line_info *info);

/**
 * @brief Get the offset of the line.
 * @param info GPIO line info object.
 * @return Offset of the line within the parent chip.
 *
 * The offset uniquely identifies the line on the chip. The combination of the
 * chip and offset uniquely identifies the line within the system.
 */
unsigned int gpiod_line_info_get_offset(struct gpiod_line_info *info);

/**
 * @brief Get the name of the line.
 * @param info GPIO line info object.
 * @return Name of the GPIO line as it is represented in the kernel.
 *         This function returns a valid pointer to a null-terminated string
 *         or NULL if the line is unnamed. The string lifetime is tied to the
 *         line info object so the pointer must not be freed.
 */
const char *gpiod_line_info_get_name(struct gpiod_line_info *info);

/**
 * @brief Check if the line is in use.
 * @param info GPIO line object.
 * @return True if the line is in use, false otherwise.
 *
 * The exact reason a line is busy cannot be determined from user space.
 * It may have been requested by another process or hogged by the kernel.
 * It only matters that the line is used and can't be requested until
 * released by the existing consumer.
 */
bool gpiod_line_info_is_used(struct gpiod_line_info *info);

/**
 * @brief Get the name of the consumer of the line.
 * @param info GPIO line info object.
 * @return Name of the GPIO consumer as it is represented in the kernel.
 *         This function returns a valid pointer to a null-terminated string
 *         or NULL if the consumer name is not set.
 *         The string lifetime is tied to the line info object so the pointer
 *         must not be freed.
 */
const char *gpiod_line_info_get_consumer(struct gpiod_line_info *info);

/**
 * @brief Get the direction setting of the line.
 * @param info GPIO line info object.
 * @return Returns ::GPIOD_LINE_DIRECTION_INPUT or
 *         ::GPIOD_LINE_DIRECTION_OUTPUT.
 */
enum gpiod_line_direction
gpiod_line_info_get_direction(struct gpiod_line_info *info);

/**
 * @brief Get the edge detection setting of the line.
 * @param info GPIO line info object.
 * @return Returns ::GPIOD_LINE_EDGE_NONE, ::GPIOD_LINE_EDGE_RISING,
 *         ::GPIOD_LINE_EDGE_FALLING or ::GPIOD_LINE_EDGE_BOTH.
 */
enum gpiod_line_edge
gpiod_line_info_get_edge_detection(struct gpiod_line_info *info);

/**
 * @brief Get the bias setting of the line.
 * @param info GPIO line object.
 * @return Returns ::GPIOD_LINE_BIAS_PULL_UP, ::GPIOD_LINE_BIAS_PULL_DOWN,
 *         ::GPIOD_LINE_BIAS_DISABLED or ::GPIOD_LINE_BIAS_UNKNOWN.
 */
enum gpiod_line_bias
gpiod_line_info_get_bias(struct gpiod_line_info *info);

/**
 * @brief Get the drive setting of the line.
 * @param info GPIO line info object.
 * @return Returns ::GPIOD_LINE_DRIVE_PUSH_PULL, ::GPIOD_LINE_DRIVE_OPEN_DRAIN
 *         or ::GPIOD_LINE_DRIVE_OPEN_SOURCE.
 */
enum gpiod_line_drive
gpiod_line_info_get_drive(struct gpiod_line_info *info);

/**
 * @brief Check if the logical value of the line is inverted compared to the
 *        physical.
 * @param info GPIO line object.
 * @return True if the line is "active-low", false otherwise.
 */
bool gpiod_line_info_is_active_low(struct gpiod_line_info *info);

/**
 * @brief Check if the line is debounced (either by hardware or by the kernel
 *        software debouncer).
 * @param info GPIO line info object.
 * @return True if the line is debounced, false otherwise.
 */
bool gpiod_line_info_is_debounced(struct gpiod_line_info *info);

/**
 * @brief Get the debounce period of the line, in microseconds.
 * @param info GPIO line info object.
 * @return Debounce period in microseconds.
 *         0 if the line is not debounced.
 */
unsigned long
gpiod_line_info_get_debounce_period_us(struct gpiod_line_info *info);

/**
 * @brief Get the event clock setting used for edge event timestamps for the
 *        line.
 * @param info GPIO line info object.
 * @return Returns ::GPIOD_LINE_CLOCK_MONOTONIC, ::GPIOD_LINE_CLOCK_HTE or
 *         ::GPIOD_LINE_CLOCK_REALTIME.
 */
enum gpiod_line_clock
gpiod_line_info_get_event_clock(struct gpiod_line_info *info);

/**
 * @}
 *
 * @defgroup line_watch Line status watch events
 * @{
 *
 * Accessors for the info event objects allowing to monitor changes in GPIO
 * line status.
 *
 * Callers are notified about changes in a line's status due to GPIO uAPI
 * calls. Each info event contains information about the event itself
 * (timestamp, type) as well as a snapshot of line's status in the form
 * of a line-info object.
 */

/**
 * @brief Line status change event types.
 */
enum gpiod_info_event_type {
	GPIOD_INFO_EVENT_LINE_REQUESTED = 1,
	/**< Line has been requested. */
	GPIOD_INFO_EVENT_LINE_RELEASED,
	/**< Previously requested line has been released. */
	GPIOD_INFO_EVENT_LINE_CONFIG_CHANGED,
	/**< Line configuration has changed. */
};

/**
 * @brief Free the info event object and release all associated resources.
 * @param event Info event to free.
 */
void gpiod_info_event_free(struct gpiod_info_event *event);

/**
 * @brief Get the event type of the status change event.
 * @param event Line status watch event.
 * @return One of ::GPIOD_INFO_EVENT_LINE_REQUESTED,
 *         ::GPIOD_INFO_EVENT_LINE_RELEASED or
 *         ::GPIOD_INFO_EVENT_LINE_CONFIG_CHANGED.
 */
enum gpiod_info_event_type
gpiod_info_event_get_event_type(struct gpiod_info_event *event);

/**
 * @brief Get the timestamp of the event.
 * @param event Line status watch event.
 * @return Timestamp in nanoseconds, read from the monotonic clock.
 */
uint64_t gpiod_info_event_get_timestamp_ns(struct gpiod_info_event *event);

/**
 * @brief Get the snapshot of line-info associated with the event.
 * @param event Line info event object.
 * @return Returns a pointer to the line-info object associated with the event.
 *         The object lifetime is tied to the event object, so the pointer must
 *         be not be freed by the caller.
 * @warning Thread-safety:
 *          Since the line-info object is tied to the event, different threads
 *          may not operate on the event and line-info at the same time. The
 *          line-info can be copied using ::gpiod_line_info_copy in order to
 *          create a standalone object - which then may safely be used from a
 *          different thread concurrently.
 */
struct gpiod_line_info *
gpiod_info_event_get_line_info(struct gpiod_info_event *event);

/**
 * @}
 *
 * @defgroup line_settings Line settings objects
 * @{
 *
 * Functions for manipulating line settings objects.
 *
 * Line settings object contains a set of line properties that can be used
 * when requesting lines or reconfiguring an existing request.
 *
 * Mutators in general can only fail if the new property value is invalid. The
 * return values can be safely ignored - the object remains valid even after
 * a mutator fails and simply uses the sane default appropriate for given
 * property.
 */

/**
 * @brief Create a new line settings object.
 * @return New line settings object or NULL on error. The returned object must
 *         be freed by the caller using ::gpiod_line_settings_free.
 */
struct gpiod_line_settings *gpiod_line_settings_new(void);

/**
 * @brief Free the line settings object and release all associated resources.
 * @param settings Line settings object.
 */
void gpiod_line_settings_free(struct gpiod_line_settings *settings);

/**
 * @brief Reset the line settings object to its default values.
 * @param settings Line settings object.
 */
void gpiod_line_settings_reset(struct gpiod_line_settings *settings);

/**
 * @brief Copy the line settings object.
 * @param settings Line settings object to copy.
 * @return New line settings object that must be freed using
 *         ::gpiod_line_settings_free or NULL on failure.
 */
struct gpiod_line_settings *
gpiod_line_settings_copy(struct gpiod_line_settings *settings);

/**
 * @brief Set direction.
 * @param settings Line settings object.
 * @param direction New direction.
 * @return 0 on success, -1 on error.
 */
int gpiod_line_settings_set_direction(struct gpiod_line_settings *settings,
				      enum gpiod_line_direction direction);

/**
 * @brief Get direction.
 * @param settings Line settings object.
 * @return Current direction.
 */
enum gpiod_line_direction
gpiod_line_settings_get_direction(struct gpiod_line_settings *settings);

/**
 * @brief Set edge detection.
 * @param settings Line settings object.
 * @param edge New edge detection setting.
 * @return 0 on success, -1 on failure.
 */
int gpiod_line_settings_set_edge_detection(struct gpiod_line_settings *settings,
					   enum gpiod_line_edge edge);

/**
 * @brief Get edge detection.
 * @param settings Line settings object.
 * @return Current edge detection setting.
 */
enum gpiod_line_edge
gpiod_line_settings_get_edge_detection(struct gpiod_line_settings *settings);

/**
 * @brief Set bias.
 * @param settings Line settings object.
 * @param bias New bias.
 * @return 0 on success, -1 on failure.
 */
int gpiod_line_settings_set_bias(struct gpiod_line_settings *settings,
				 enum gpiod_line_bias bias);

/**
 * @brief Get bias.
 * @param settings Line settings object.
 * @return Current bias setting.
 */
enum gpiod_line_bias
gpiod_line_settings_get_bias(struct gpiod_line_settings *settings);

/**
 * @brief Set drive.
 * @param settings Line settings object.
 * @param drive New drive setting.
 * @return 0 on success, -1 on failure.
 */
int gpiod_line_settings_set_drive(struct gpiod_line_settings *settings,
				  enum gpiod_line_drive drive);

/**
 * @brief Get drive.
 * @param settings Line settings object.
 * @return Current drive setting.
 */
enum gpiod_line_drive
gpiod_line_settings_get_drive(struct gpiod_line_settings *settings);

/**
 * @brief Set active-low setting.
 * @param settings Line settings object.
 * @param active_low New active-low setting.
 */
void gpiod_line_settings_set_active_low(struct gpiod_line_settings *settings,
					bool active_low);

/**
 * @brief Get active-low setting.
 * @param settings Line settings object.
 * @return True if active-low is enabled, false otherwise.
 */
bool gpiod_line_settings_get_active_low(struct gpiod_line_settings *settings);

/**
 * @brief Set debounce period.
 * @param settings Line settings object.
 * @param period New debounce period in microseconds.
 */
void
gpiod_line_settings_set_debounce_period_us(struct gpiod_line_settings *settings,
					   unsigned long period);

/**
 * @brief Get debounce period.
 * @param settings Line settings object.
 * @return Current debounce period in microseconds.
 */
unsigned long
gpiod_line_settings_get_debounce_period_us(
		struct gpiod_line_settings *settings);

/**
 * @brief Set event clock.
 * @param settings Line settings object.
 * @param event_clock New event clock.
 * @return 0 on success, -1 on failure.
 */
int gpiod_line_settings_set_event_clock(struct gpiod_line_settings *settings,
					enum gpiod_line_clock event_clock);

/**
 * @brief Get event clock setting.
 * @param settings Line settings object.
 * @return Current event clock setting.
 */
enum gpiod_line_clock
gpiod_line_settings_get_event_clock(struct gpiod_line_settings *settings);

/**
 * @brief Set the output value.
 * @param settings Line settings object.
 * @param value New output value.
 * @return 0 on success, -1 on failure.
 */
int gpiod_line_settings_set_output_value(struct gpiod_line_settings *settings,
					 enum gpiod_line_value value);

/**
 * @brief Get the output value.
 * @param settings Line settings object.
 * @return Current output value.
 */
enum gpiod_line_value
gpiod_line_settings_get_output_value(struct gpiod_line_settings *settings);

/**
 * @}
 *
 * @defgroup line_config Line configuration objects
 * @{
 *
 * Functions for manipulating line configuration objects.
 *
 * The line-config object contains the configuration for lines that can be
 * used in two cases:
 *  - when making a line request
 *  - when reconfiguring a set of already requested lines.
 *
 * A new line-config object is empty. Using it in a request will lead to an
 * error. In order to a line-config to become useful, it needs to be assigned
 * at least one offset-to-settings mapping by calling
 * ::gpiod_line_config_add_line_settings.
 *
 * When calling ::gpiod_chip_request_lines, the library will request all
 * offsets that were assigned settings in the order that they were assigned.
 * If any of the offsets was duplicated, the last one will take precedence.
 */

/**
 * @brief Create a new line config object.
 * @return New line config object or NULL on error. The returned object must
 *         be freed by the caller using ::gpiod_line_config_free.
 */
struct gpiod_line_config *gpiod_line_config_new(void);

/**
 * @brief Free the line config object and release all associated resources.
 * @param config Line config object to free.
 */
void gpiod_line_config_free(struct gpiod_line_config *config);

/**
 * @brief Reset the line config object.
 * @param config Line config object to free.
 *
 * Resets the entire configuration stored in the object. This is useful if
 * the user wants to reuse the object without reallocating it.
 */
void gpiod_line_config_reset(struct gpiod_line_config *config);

/**
 * @brief Add line settings for a set of offsets.
 * @param config Line config object.
 * @param offsets Array of offsets for which to apply the settings.
 * @param num_offsets Number of offsets stored in the offsets array.
 * @param settings Line settings to apply.
 * @return 0 on success, -1 on failure.
 */
int gpiod_line_config_add_line_settings(struct gpiod_line_config *config,
					const unsigned int *offsets,
					size_t num_offsets,
					struct gpiod_line_settings *settings);

/**
 * @brief Get line settings for offset.
 * @param config Line config object.
 * @param offset Offset for which to get line settings.
 * @return New line settings object (must be freed by the caller) or NULL on
 *         error.
 */
struct gpiod_line_settings *
gpiod_line_config_get_line_settings(struct gpiod_line_config *config,
				    unsigned int offset);

/**
 * @brief Set output values for a number of lines.
 * @param config Line config object.
 * @param values Buffer containing the output values.
 * @param num_values Number of values in the buffer.
 * @return 0 on success, -1 on error.
 *
 * This is a helper that allows users to set multiple (potentially different)
 * output values at once while using the same line settings object. Instead of
 * modifying the output value in the settings object and calling
 * ::gpiod_line_config_add_line_settings multiple times, we can specify the
 * settings, add them for a set of offsets and then call this function to
 * set the output values.
 *
 * Values set by this function override whatever values were specified in the
 * regular line settings.
 *
 * Each value must be associated with the line identified by the corresponding
 * entry in the offset array filled by
 * ::gpiod_line_request_get_requested_offsets.
 */
int gpiod_line_config_set_output_values(struct gpiod_line_config *config,
					const enum gpiod_line_value *values,
					size_t num_values);

/**
 * @brief Get the number of configured line offsets.
 * @param config Line config object.
 * @return Number of offsets for which line settings have been added.
 */
size_t
gpiod_line_config_get_num_configured_offsets(struct gpiod_line_config *config);

/**
 * @brief Get configured offsets.
 * @param config Line config object.
 * @param offsets Array to store offsets.
 * @param max_offsets Number of offsets that can be stored in the offsets array.
 * @return Number of offsets stored in the offsets array.
 *
 * If max_offsets is lower than the number of lines actually requested (this
 * value can be retrieved using ::gpiod_line_config_get_num_configured_offsets),
 * then only up to max_lines offsets will be stored in offsets.
 */
size_t
gpiod_line_config_get_configured_offsets(struct gpiod_line_config *config,
					 unsigned int *offsets,
					 size_t max_offsets);

/**
 * @}
 *
 * @defgroup request_config Request configuration objects
 * @{
 *
 * Functions for manipulating request configuration objects.
 *
 * Request config objects are used to pass a set of options to the kernel at
 * the time of the line request. The mutators don't return error values. If the
 * values are invalid, in general they are silently adjusted to acceptable
 * ranges.
 */

/**
 * @brief Create a new request config object.
 * @return New request config object or NULL on error. The returned object must
 *         be freed by the caller using ::gpiod_request_config_free.
 */
struct gpiod_request_config *gpiod_request_config_new(void);

/**
 * @brief Free the request config object and release all associated resources.
 * @param config Line config object.
 */
void gpiod_request_config_free(struct gpiod_request_config *config);

/**
 * @brief Set the consumer name for the request.
 * @param config Request config object.
 * @param consumer Consumer name.
 * @note If the consumer string is too long, it will be truncated to the max
 *       accepted length.
 */
void gpiod_request_config_set_consumer(struct gpiod_request_config *config,
				       const char *consumer);

/**
 * @brief Get the consumer name configured in the request config.
 * @param config Request config object.
 * @return Consumer name stored in the request config.
 */
const char *
gpiod_request_config_get_consumer(struct gpiod_request_config *config);

/**
 * @brief Set the size of the kernel event buffer for the request.
 * @param config Request config object.
 * @param event_buffer_size New event buffer size.
 * @note The kernel may adjust the value if it's too high. If set to 0, the
 *       default value will be used.
 * @note The kernel buffer is distinct from and independent of the user space
 *       buffer (::gpiod_edge_event_buffer_new).
 */
void
gpiod_request_config_set_event_buffer_size(struct gpiod_request_config *config,
					   size_t event_buffer_size);

/**
 * @brief Get the edge event buffer size for the request config.
 * @param config Request config object.
 * @return Edge event buffer size setting from the request config.
 */
size_t
gpiod_request_config_get_event_buffer_size(struct gpiod_request_config *config);

/**
 * @}
 *
 * @defgroup line_request Line request operations
 * @{
 *
 * Functions allowing interactions with requested lines.
 */

/**
 * @brief Release the requested lines and free all associated resources.
 * @param request Line request object to release.
 */
void gpiod_line_request_release(struct gpiod_line_request *request);

/**
 * @brief Get the name of the chip this request was made on.
 * @param request Line request object.
 * @return Name the GPIO chip device. The returned pointer is valid for the
 * lifetime of the request object and must not be freed by the caller.
 */
const char *
gpiod_line_request_get_chip_name(struct gpiod_line_request *request);

/**
 * @brief Get the number of lines in the request.
 * @param request Line request object.
 * @return Number of requested lines.
 */
size_t
gpiod_line_request_get_num_requested_lines(struct gpiod_line_request *request);

/**
 * @brief Get the offsets of the lines in the request.
 * @param request Line request object.
 * @param offsets Array to store offsets.
 * @param max_offsets Number of offsets that can be stored in the offsets array.
 * @return Number of offsets stored in the offsets array.
 *
 * If max_offsets is lower than the number of lines actually requested (this
 * value can be retrieved using ::gpiod_line_request_get_num_requested_lines),
 * then only up to max_lines offsets will be stored in offsets.
 */
size_t
gpiod_line_request_get_requested_offsets(struct gpiod_line_request *request,
					 unsigned int *offsets,
					 size_t max_offsets);

/**
 * @brief Get the value of a single requested line.
 * @param request Line request object.
 * @param offset The offset of the line of which the value should be read.
 * @return Returns 1 or 0 on success and -1 on error.
 */
enum gpiod_line_value
gpiod_line_request_get_value(struct gpiod_line_request *request,
			     unsigned int offset);

/**
 * @brief Get the values of a subset of requested lines.
 * @param request GPIO line request.
 * @param num_values Number of lines for which to read values.
 * @param offsets Array of offsets identifying the subset of requested lines
 *                from which to read values.
 * @param values Array in which the values will be stored. Must be sized
 *               to hold \p num_values entries. Each value is associated with
 *               the line identified by the corresponding entry in \p offsets.
 * @return 0 on success, -1 on failure.
 */
int gpiod_line_request_get_values_subset(struct gpiod_line_request *request,
					 size_t num_values,
					 const unsigned int *offsets,
					 enum gpiod_line_value *values);

/**
 * @brief Get the values of all requested lines.
 * @param request GPIO line request.
 * @param values Array in which the values will be stored. Must be sized to
 *               hold the number of lines filled by
 *               ::gpiod_line_request_get_num_requested_lines.
 *               Each value is associated with the line identified by the
 *               corresponding entry in the offset array filled by
 *               ::gpiod_line_request_get_requested_offsets.
 * @return 0 on success, -1 on failure.
 */
int gpiod_line_request_get_values(struct gpiod_line_request *request,
				  enum gpiod_line_value *values);

/**
 * @brief Set the value of a single requested line.
 * @param request Line request object.
 * @param offset The offset of the line for which the value should be set.
 * @param value Value to set.
 * @return 0 on success, -1 on failure.
 */
int gpiod_line_request_set_value(struct gpiod_line_request *request,
				 unsigned int offset,
				 enum gpiod_line_value value);

/**
 * @brief Set the values of a subset of requested lines.
 * @param request GPIO line request.
 * @param num_values Number of lines for which to set values.
 * @param offsets Array of offsets, containing the number of entries specified
 *                by \p num_values, identifying the requested lines for
 *                which to set values.
 * @param values Array of values to set, containing the number of entries
 *               specified by \p num_values. Each value is associated with the
 *               line identified by the corresponding entry in \p offsets.
 * @return 0 on success, -1 on failure.
 */
int gpiod_line_request_set_values_subset(struct gpiod_line_request *request,
					 size_t num_values,
					 const unsigned int *offsets,
					 const enum gpiod_line_value *values);

/**
 * @brief Set the values of all lines associated with a request.
 * @param request GPIO line request.
 * @param values Array containing the values to set. Must be sized to
 *               contain the number of lines filled by
 *               ::gpiod_line_request_get_num_requested_lines.
 *               Each value is associated with the line identified by the
 *               corresponding entry in the offset array filled by
 *               ::gpiod_line_request_get_requested_offsets.
 * @return 0 on success, -1 on failure.
 */
int gpiod_line_request_set_values(struct gpiod_line_request *request,
				  const enum gpiod_line_value *values);

/**
 * @brief Update the configuration of lines associated with a line request.
 * @param request GPIO line request.
 * @param config New line config to apply.
 * @return 0 on success, -1 on failure.
 * @note The new line configuration completely replaces the old.
 * @note Any requested lines without overrides are configured to the requested
 *       defaults.
 * @note Any configured overrides for lines that have not been requested
 *       are silently ignored.
 */
int gpiod_line_request_reconfigure_lines(struct gpiod_line_request *request,
					 struct gpiod_line_config *config);

/**
 * @brief Get the file descriptor associated with a line request.
 * @param request GPIO line request.
 * @return The file descriptor associated with the request.
 *         This function never fails.
 *         The returned file descriptor must not be closed by the caller.
 *         Call ::gpiod_line_request_release to close the file.
 */
int gpiod_line_request_get_fd(struct gpiod_line_request *request);

/**
 * @brief Wait for edge events on any of the requested lines.
 * @param request GPIO line request.
 * @param timeout_ns Wait time limit in nanoseconds. If set to 0, the function
 *                   returns immediately. If set to a negative number, the
 *                   function blocks indefinitely until an event becomes
 *                   available.
 * @return 0 if wait timed out, -1 if an error occurred, 1 if an event is
 *         pending.
 *
 * Lines must have edge detection set for edge events to be emitted.
 * By default edge detection is disabled.
 */
int gpiod_line_request_wait_edge_events(struct gpiod_line_request *request,
					int64_t timeout_ns);

/**
 * @brief Read a number of edge events from a line request.
 * @param request GPIO line request.
 * @param buffer Edge event buffer, sized to hold at least \p max_events.
 * @param max_events Maximum number of events to read.
 * @return On success returns the number of events read from the file
 *         descriptor, on failure return -1.
 * @note This function will block if no event was queued for the line request.
 * @note Any exising events in the buffer are overwritten. This is not an
 *       append operation.
 */
int gpiod_line_request_read_edge_events(struct gpiod_line_request *request,
					struct gpiod_edge_event_buffer *buffer,
					size_t max_events);

/**
 * @}
 *
 * @defgroup edge_event Line edge events handling
 * @{
 *
 * Functions and data types for handling edge events.
 *
 * An edge event object contains information about a single line edge event.
 * It contains the event type, timestamp and the offset of the line on which
 * the event occurred as well as two sequence numbers (global for all lines
 * in the associated request and local for this line only).
 *
 * Edge events are stored into an edge-event buffer object to improve
 * performance and to limit the number of memory allocations when a large
 * number of events are being read.
 */

/**
 * @brief Event types.
 */
enum gpiod_edge_event_type {
	GPIOD_EDGE_EVENT_RISING_EDGE = 1,
	/**< Rising edge event. */
	GPIOD_EDGE_EVENT_FALLING_EDGE,
	/**< Falling edge event. */
};

/**
 * @brief Free the edge event object.
 * @param event Edge event object to free.
 */
void gpiod_edge_event_free(struct gpiod_edge_event *event);

/**
 * @brief Copy the edge event object.
 * @param event Edge event to copy.
 * @return Copy of the edge event or NULL on error. The returned object must
 *         be freed by the caller using ::gpiod_edge_event_free.
 */
struct gpiod_edge_event *gpiod_edge_event_copy(struct gpiod_edge_event *event);

/**
 * @brief Get the event type.
 * @param event GPIO edge event.
 * @return The event type (::GPIOD_EDGE_EVENT_RISING_EDGE or
 *         ::GPIOD_EDGE_EVENT_FALLING_EDGE).
 */
enum gpiod_edge_event_type
gpiod_edge_event_get_event_type(struct gpiod_edge_event *event);

/**
 * @brief Get the timestamp of the event.
 * @param event GPIO edge event.
 * @return Timestamp in nanoseconds.
 * @note The source clock for the timestamp depends on the event_clock
 *       setting for the line.
 */
uint64_t gpiod_edge_event_get_timestamp_ns(struct gpiod_edge_event *event);

/**
 * @brief Get the offset of the line which triggered the event.
 * @param event GPIO edge event.
 * @return Line offset.
 */
unsigned int gpiod_edge_event_get_line_offset(struct gpiod_edge_event *event);

/**
 * @brief Get the global sequence number of the event.
 * @param event GPIO edge event.
 * @return Sequence number of the event in the series of events for all lines
 *         in the associated line request.
 */
unsigned long gpiod_edge_event_get_global_seqno(struct gpiod_edge_event *event);

/**
 * @brief Get the event sequence number specific to the line.
 * @param event GPIO edge event.
 * @return Sequence number of the event in the series of events only for this
 *         line within the lifetime of the associated line request.
 */
unsigned long gpiod_edge_event_get_line_seqno(struct gpiod_edge_event *event);

/**
 * @brief Create a new edge event buffer.
 * @param capacity Number of events the buffer can store (min = 1, max = 1024).
 * @return New edge event buffer or NULL on error.
 * @note If capacity equals 0, it will be set to a default value of 64. If
 *       capacity is larger than 1024, it will be limited to 1024.
 * @note The user space buffer is independent of the kernel buffer
 *       (::gpiod_request_config_set_event_buffer_size). As the user space
 *       buffer is filled from the kernel buffer, there is no benefit making
 *       the user space buffer larger than the kernel buffer.
 *       The default kernel buffer size for each request is (16 * num_lines).
 */
struct gpiod_edge_event_buffer *
gpiod_edge_event_buffer_new(size_t capacity);

/**
 * @brief Get the capacity (the max number of events that can be stored) of
 *        the event buffer.
 * @param buffer Edge event buffer.
 * @return The capacity of the buffer.
 */
size_t
gpiod_edge_event_buffer_get_capacity(struct gpiod_edge_event_buffer *buffer);

/**
 * @brief Free the edge event buffer and release all associated resources.
 * @param buffer Edge event buffer to free.
 */
void gpiod_edge_event_buffer_free(struct gpiod_edge_event_buffer *buffer);

/**
 * @brief Get an event stored in the buffer.
 * @param buffer Edge event buffer.
 * @param index Index of the event in the buffer.
 * @return Pointer to an event stored in the buffer. The lifetime of the
 *         event is tied to the buffer object. Users must not free the event
 *         returned by this function.
 * @warning Thread-safety:
 *          Since events are tied to the buffer instance, different threads
 *          may not operate on the buffer and any associated events at the same
 *          time. Events can be copied using ::gpiod_edge_event_copy in order
 *          to create a standalone objects - which each may safely be used from
 *          a different thread concurrently.
 */
struct gpiod_edge_event *
gpiod_edge_event_buffer_get_event(struct gpiod_edge_event_buffer *buffer,
				  unsigned long index);

/**
 * @brief Get the number of events a buffer has stored.
 * @param buffer Edge event buffer.
 * @return Number of events stored in the buffer.
 */
size_t
gpiod_edge_event_buffer_get_num_events(struct gpiod_edge_event_buffer *buffer);

/**
 * @}
 *
 * @defgroup misc Stuff that didn't fit anywhere else
 * @{
 *
 * Various libgpiod-related functions.
 */

/**
 * @brief Check if the file pointed to by path is a GPIO chip character device.
 * @param path Path to check.
 * @return True if the file exists and is either a GPIO chip character device
 *         or a symbolic link to one.
 */
bool gpiod_is_gpiochip_device(const char *path);

/**
 * @brief Get the API version of the library as a human-readable string.
 * @return A valid pointer to a human-readable string containing the library
 *         version. The pointer is valid for the lifetime of the program and
 *         must not be freed by the caller.
 */
const char *gpiod_api_version(void);

/**
 * @}
 */

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* __LIBGPIOD_GPIOD_H__ */
