mirror of
https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git
synced 2026-10-25 12:39:18 +03:00
Add a new optional argument to Chip.request_lines() called output_values. It accepts a dictionary of mappings between line names or offsets to the output values the requested lines should be set to at request-time. Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
198 lines
4.0 KiB
C
198 lines
4.0 KiB
C
// SPDX-License-Identifier: LGPL-2.1-or-later
|
|
// SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
|
|
|
|
#include "internal.h"
|
|
|
|
typedef struct {
|
|
PyObject_HEAD;
|
|
struct gpiod_line_config *cfg;
|
|
} line_config_object;
|
|
|
|
static int line_config_init(line_config_object *self,
|
|
PyObject *Py_UNUSED(args), PyObject *Py_UNUSED(ignored))
|
|
{
|
|
self->cfg = gpiod_line_config_new();
|
|
if (!self->cfg) {
|
|
Py_gpiod_SetErrFromErrno();
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void line_config_finalize(line_config_object *self)
|
|
{
|
|
if (self->cfg)
|
|
gpiod_line_config_free(self->cfg);
|
|
}
|
|
|
|
static unsigned int *make_offsets(PyObject *obj, Py_ssize_t len)
|
|
{
|
|
unsigned int *offsets;
|
|
PyObject *offset;
|
|
Py_ssize_t i;
|
|
|
|
offsets = PyMem_Calloc(len, sizeof(unsigned int));
|
|
if (!offsets)
|
|
return (unsigned int *)PyErr_NoMemory();
|
|
|
|
for (i = 0; i < len; i++) {
|
|
offset = PyList_GetItem(obj, i);
|
|
if (!offset) {
|
|
PyMem_Free(offsets);
|
|
return NULL;
|
|
}
|
|
|
|
offsets[i] = Py_gpiod_PyLongAsUnsignedInt(offset);
|
|
if (PyErr_Occurred()) {
|
|
PyMem_Free(offsets);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return offsets;
|
|
}
|
|
|
|
static PyObject *
|
|
line_config_add_line_settings(line_config_object *self, PyObject *args)
|
|
{
|
|
PyObject *offsets_obj, *settings_obj;
|
|
struct gpiod_line_settings *settings;
|
|
unsigned int *offsets;
|
|
Py_ssize_t num_offsets;
|
|
int ret;
|
|
|
|
ret = PyArg_ParseTuple(args, "OO", &offsets_obj, &settings_obj);
|
|
if (!ret)
|
|
return NULL;
|
|
|
|
num_offsets = PyObject_Size(offsets_obj);
|
|
if (num_offsets < 0)
|
|
return NULL;
|
|
|
|
offsets = make_offsets(offsets_obj, num_offsets);
|
|
if (!offsets)
|
|
return NULL;
|
|
|
|
settings = Py_gpiod_LineSettingsGetData(settings_obj);
|
|
if (!settings) {
|
|
PyMem_Free(offsets);
|
|
return NULL;
|
|
}
|
|
|
|
ret = gpiod_line_config_add_line_settings(self->cfg, offsets,
|
|
num_offsets, settings);
|
|
PyMem_Free(offsets);
|
|
if (ret)
|
|
return Py_gpiod_SetErrFromErrno();
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
static PyObject *
|
|
line_config_set_output_values(line_config_object *self, PyObject *args)
|
|
{
|
|
PyObject *values, *iter, *next, *val_stripped;
|
|
enum gpiod_line_value *valbuf;
|
|
Py_ssize_t num_values, pos;
|
|
int ret;
|
|
|
|
values = PyTuple_GetItem(args, 0);
|
|
if (!values)
|
|
return NULL;
|
|
|
|
num_values = PyObject_Size(values);
|
|
if (num_values < 0)
|
|
return NULL;
|
|
|
|
valbuf = PyMem_Calloc(num_values, sizeof(*valbuf));
|
|
if (!valbuf)
|
|
return PyErr_NoMemory();
|
|
|
|
iter = PyObject_GetIter(values);
|
|
if (!iter) {
|
|
PyMem_Free(valbuf);
|
|
return NULL;
|
|
}
|
|
|
|
for (pos = 0;; pos++) {
|
|
next = PyIter_Next(iter);
|
|
if (!next) {
|
|
Py_DECREF(iter);
|
|
break;
|
|
}
|
|
|
|
val_stripped = PyObject_GetAttrString(next, "value");
|
|
Py_DECREF(next);
|
|
if (!val_stripped) {
|
|
PyMem_Free(valbuf);
|
|
Py_DECREF(iter);
|
|
return NULL;
|
|
}
|
|
|
|
valbuf[pos] = PyLong_AsLong(val_stripped);
|
|
Py_DECREF(val_stripped);
|
|
if (PyErr_Occurred()) {
|
|
PyMem_Free(valbuf);
|
|
Py_DECREF(iter);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
ret = gpiod_line_config_set_output_values(self->cfg,
|
|
valbuf, num_values);
|
|
PyMem_Free(valbuf);
|
|
if (ret)
|
|
return Py_gpiod_SetErrFromErrno();
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
static PyMethodDef line_config_methods[] = {
|
|
{
|
|
.ml_name = "add_line_settings",
|
|
.ml_meth = (PyCFunction)line_config_add_line_settings,
|
|
.ml_flags = METH_VARARGS,
|
|
},
|
|
{
|
|
.ml_name = "set_output_values",
|
|
.ml_meth = (PyCFunction)line_config_set_output_values,
|
|
.ml_flags = METH_VARARGS,
|
|
},
|
|
{ }
|
|
};
|
|
|
|
PyTypeObject line_config_type = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
.tp_name = "gpiod._ext.LineConfig",
|
|
.tp_basicsize = sizeof(line_config_object),
|
|
.tp_flags = Py_TPFLAGS_DEFAULT,
|
|
.tp_new = PyType_GenericNew,
|
|
.tp_init = (initproc)line_config_init,
|
|
.tp_finalize = (destructor)line_config_finalize,
|
|
.tp_dealloc = (destructor)Py_gpiod_dealloc,
|
|
.tp_methods = line_config_methods,
|
|
};
|
|
|
|
struct gpiod_line_config *Py_gpiod_LineConfigGetData(PyObject *obj)
|
|
{
|
|
line_config_object *line_cfg;
|
|
PyObject *type;
|
|
|
|
type = PyObject_Type(obj);
|
|
if (!type)
|
|
return NULL;
|
|
|
|
if ((PyTypeObject *)type != &line_config_type) {
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"not a gpiod._ext.LineConfig object");
|
|
Py_DECREF(type);
|
|
return NULL;
|
|
}
|
|
Py_DECREF(type);
|
|
|
|
line_cfg = (line_config_object *)obj;
|
|
|
|
return line_cfg->cfg;
|
|
}
|