Currently we're not checking if the object returned from
gpiod.fine_line() is None which results in an attribute error being
raised when we try to call line methods on a non-line object.
Add an if and bail-out with an error code if the line with given name
was not found.
Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
Currently if we call gpiod_Chip_find_lines() with some names that
cannot be looked up, we end up getting an exception from the LineBulk
object's constructor (because None is not a Line and LineBulk can only
hold Line objects).
Fix the behavior of gpiod_Chip_find_lines() for nonexistent lines by
raising an explicit exception if the underlying gpiod_Chip_find_line()
call returns None. Also: add a relevant test case.
Fixes: 96c524c495 ("bindings: implement python bindings")
Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
Unlike the C++ bindings: we can't expect the python runtime to call
the Chip object's destructor when all references are dropped. We need
to close each chip explicitly. Either call the close() method directly
or use controlled execution in all examples.
Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
We have a significant memory leak in the current implementation as we
don't call PyObject_Del() as the last action in tp_dealloc callbacks.
From tp_dealloc's documentation:
---
The destructor function should free all references which the instance
owns, free all memory buffers owned by the instance (using the freeing
function corresponding to the allocation function used to allocate the
buffer), and finally (as its last action) call the type’s tp_free
function.
---
PyObject_Del() will internally call the tp_free callback of the type.
Add a call to it as the last action in every destructor.
Fixes: 96c524c495 ("bindings: implement python bindings")
Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
When allocating raw memory let python decide which allocator to use.
Convert all calls to PyMem_Raw*() to PyMem_*().
Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
We can instantiate an object of a type by "calling" it's type structure
using PyObject_CallObject(). It will internally call the constructor so
use it to shrink the code.
Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
Add two new tests verifying the default_vals argument in line requests
for single and multiple lines.
Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
We're assigning the wrong local variable in PyArg_ParseTupleAndKeywords()
which results in not honoring the default_vals argument. Fix the
LineBulk.request() implementation.
Fixes: 96c524c495 ("bindings: implement python bindings")
Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
Unlike the other two helpers that are still declared at the top of the
source file - this routine doesn't need to know any gpiod-specific type
so move it up and remove the prototype.
Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
Strings with slashes trigger a warning in the kernel in
fs/proc/generic.c. Use a hardcoded consumer string.
Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
Using the .tp_init callback is more complicated and unnecessary. Call
gpiod_LineBulk_init() directly from gpiod_ListToLineBulk().
Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
Wrap the calls to PyObject_GetAttrString() and PyObject_Call() in
a single helper that allows to call a python method and pass it the
args and kwds tuples directly as received from the interpreter.
Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
PyList_GetItem() returns a borrowed reference so we need to increase
the reference count on the returned object before DECREF'ing the list
object itself
This fixes random 'free(): invalid pointer' errors.
Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
We need to decref the iter object in Line.set_values() if the
conversion from python to C unsigned integer fails.
Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
On some architectures we get a 'comparison between signed and unsigned
integer' warning when building python bindings. Fix it by changing the
type of the variable used for offset to unsigned int.
Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
Where it's impossible to use PyObject_CallMethod() (e.g. when we want
to pass args and kwargs unchanged to the method being called), use
a combination of PyObject_GetAttrString() and PyObject_Call().
Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
Avoid directly calling method callbacks. Use the routine provided by
Python API instead where possible.
Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
Provide __enter__ and __exit__ callbacks for Chip so that it can be
used with the 'with' statement.
Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
So far we rely on cpython's reference counting for closing the GPIO
chips and freeing the underlying resources. This is however wrong.
Python doesn't guarantee anything regarding the lifetime of an object.
Provide a method for closing the underlying chip handle and add
relevant checks to all methods using the resources associated with
a GPIO chip, so that we raise an error should the user use a chip
after closing it.
Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
Add more test cases/examples, implement some helper functions, tweak
the output messages, mention the need for a dummy chip in the system
in the module's pydoc string.
Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
gpiod_Line_event_wait() works differently than its LineBulk
counterpart. While the latter returns either a list of lines or False,
the former returns True if an event occurred on this line or False
otherwise.
False is not a good counterpart for an actual object, so instead return
None if no events occurred on any of the monitored lines.
Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
We don't return the object returned from gpiod_LineBulk_event_wait()
back to the interpreter. We need to collect it before returning True.
Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
We're not collecting the bulk object we're creating in this method. Add
Py_DECREF() where needed.
Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
For both find_line() variants (Chip's method and global function)
return None if the internal call to the C find_line function fails
with ENOENT. This is not an error so don't raise an exception.
Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
When returning back to the interpreter from gpiod_Module_find_line(),
there's only one chip object reference holder, but we set the refcount
to 2 (as if the chip object existed separately in the interpreter).
Fix it by decreasing the chip's refcount by one before returning the
line object.
Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
We should release the python global interpreter lock when performing
blocking operations and reacquire it again when we're done. Use the
relevant APIs provided by libpython.
Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
AX_PYTHON_DEVEL macro from the autoconf-archive collection doesn't work
when we're trying to cross-compile python bindings in environments such
as buildroot or yocto. It can't properly detect the location of python
headers.
Let's use AM_PATH_PYTHON to detect the python3 interpreter and then
either take the PYTHON_CPPFLAGS and PYTHON_LIBS variables from the
environment (so that cross-compiling build systems can pass their
custom locations to autotools) or try to detect them ourselves using
the python3-config tool.
Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
Create a C extension module wrapping the functionality of libgpiod
in a set of Python classes.
Add code examples including simplified reimplementations of gpio-tools
in Python.
Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>