mirror of
https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git
synced 2026-10-24 00:48:53 +03:00
bindings: implement python bindings
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>
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -17,6 +17,7 @@ gpiomoncxx
|
||||
gpiosetcxx
|
||||
*.o
|
||||
*.lo
|
||||
*.la
|
||||
doc
|
||||
libgpiod.pc
|
||||
libgpiodcxx.pc
|
||||
|
||||
@@ -13,3 +13,9 @@ if WITH_BINDINGS_CXX
|
||||
SUBDIRS += cxx
|
||||
|
||||
endif
|
||||
|
||||
if WITH_BINDINGS_PYTHON
|
||||
|
||||
SUBDIRS += python
|
||||
|
||||
endif
|
||||
|
||||
18
bindings/python/Makefile.am
Normal file
18
bindings/python/Makefile.am
Normal file
@@ -0,0 +1,18 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#
|
||||
# This file is part of libgpiod.
|
||||
#
|
||||
# Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
|
||||
#
|
||||
|
||||
SUBDIRS = . examples
|
||||
|
||||
pyexec_LTLIBRARIES = gpiod.la
|
||||
|
||||
gpiod_la_SOURCES = gpiodmodule.c
|
||||
|
||||
gpiod_la_CFLAGS = -I$(top_srcdir)/include/ -include $(top_builddir)/config.h
|
||||
gpiod_la_CFLAGS += $(PYTHON_CPPFLAGS) -Wall -Wextra -g
|
||||
gpiod_la_LDFLAGS = -module -avoid-version
|
||||
gpiod_la_LIBADD = $(top_builddir)/src/lib/libgpiod.la
|
||||
15
bindings/python/examples/Makefile.am
Normal file
15
bindings/python/examples/Makefile.am
Normal file
@@ -0,0 +1,15 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#
|
||||
# This file is part of libgpiod.
|
||||
#
|
||||
# Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
|
||||
#
|
||||
|
||||
EXTRA_DIST = gpiod_tests.py \
|
||||
gpiodetect.py \
|
||||
gpiofind.py \
|
||||
gpioget.py \
|
||||
gpioinfo.py \
|
||||
gpiomon.py \
|
||||
gpioset.py
|
||||
145
bindings/python/examples/gpiod_tests.py
Executable file
145
bindings/python/examples/gpiod_tests.py
Executable file
@@ -0,0 +1,145 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#
|
||||
# This file is part of libgpiod.
|
||||
#
|
||||
# Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
|
||||
#
|
||||
|
||||
'''Misc tests of libgpiod python bindings.'''
|
||||
|
||||
import gpiod
|
||||
import sys
|
||||
|
||||
test_cases = []
|
||||
|
||||
def add_test(name, func):
|
||||
global test_cases
|
||||
|
||||
test_cases.append((name, func))
|
||||
|
||||
def chip_open():
|
||||
chip = gpiod.Chip('gpiochip0')
|
||||
chip = gpiod.Chip('/dev/gpiochip0', gpiod.Chip.OPEN_BY_PATH)
|
||||
chip = gpiod.Chip('gpiochip0', gpiod.Chip.OPEN_BY_NAME)
|
||||
chip = gpiod.Chip('gpio-mockup-A', gpiod.Chip.OPEN_BY_LABEL)
|
||||
chip = gpiod.Chip('0', gpiod.Chip.OPEN_BY_NUMBER)
|
||||
chip = gpiod.Chip('gpio-mockup-A', gpiod.Chip.OPEN_LOOKUP)
|
||||
print('All good')
|
||||
|
||||
add_test('Open a GPIO chip using different modes', chip_open)
|
||||
|
||||
def chip_open_no_args():
|
||||
try:
|
||||
chip = gpiod.Chip()
|
||||
except TypeError:
|
||||
print('Error as expected')
|
||||
return
|
||||
|
||||
assert False, 'TypeError expected'
|
||||
|
||||
add_test('Open a GPIO chip without arguments', chip_open_no_args)
|
||||
|
||||
def chip_info():
|
||||
chip = gpiod.Chip('gpiochip0')
|
||||
print('name: {}'.format(chip.name()))
|
||||
print('label: {}'.format(chip.label()))
|
||||
print('lines: {}'.format(chip.num_lines()))
|
||||
|
||||
add_test('Print chip info', chip_info)
|
||||
|
||||
def print_chip():
|
||||
chip = gpiod.Chip('/dev/gpiochip0')
|
||||
print(chip)
|
||||
|
||||
add_test('Print chip object', print_chip)
|
||||
|
||||
def create_line_object():
|
||||
try:
|
||||
line = gpiod.Line()
|
||||
except NotImplementedError:
|
||||
print('Error as expected')
|
||||
return
|
||||
|
||||
assert False, 'NotImplementedError expected'
|
||||
|
||||
add_test('Create a line object - should fail', create_line_object)
|
||||
|
||||
def print_line():
|
||||
chip = gpiod.Chip('gpio-mockup-A')
|
||||
line = chip.get_line(3)
|
||||
print(line)
|
||||
|
||||
add_test('Print line object', print_line)
|
||||
|
||||
def find_line():
|
||||
line = gpiod.find_line('gpio-mockup-A-4')
|
||||
print('found line - offset: {}'.format(line.offset()))
|
||||
|
||||
add_test('Find line globally', find_line)
|
||||
|
||||
def create_empty_line_bulk():
|
||||
try:
|
||||
lines = gpiod.LineBulk()
|
||||
except TypeError:
|
||||
print('Error as expected')
|
||||
return
|
||||
|
||||
assert False, 'TypeError expected'
|
||||
|
||||
add_test('Create a line bulk object - should fail', create_empty_line_bulk)
|
||||
|
||||
def get_lines():
|
||||
chip = gpiod.Chip('gpio-mockup-A')
|
||||
lines = chip.get_lines([2, 4, 5, 7])
|
||||
print('Retrieved lines:')
|
||||
for line in lines:
|
||||
print(line)
|
||||
|
||||
add_test('Get lines from chip', get_lines)
|
||||
|
||||
def create_line_bulk_from_lines():
|
||||
chip = gpiod.Chip('gpio-mockup-A')
|
||||
line1 = chip.get_line(2)
|
||||
line2 = chip.get_line(4)
|
||||
line3 = chip.get_line(6)
|
||||
lines = gpiod.LineBulk([line1, line2, line3])
|
||||
print('Created LineBulk:')
|
||||
print(lines)
|
||||
|
||||
add_test('Create a LineBulk from a list of lines', create_line_bulk_from_lines)
|
||||
|
||||
def line_bulk_to_list():
|
||||
chip = gpiod.Chip('gpio-mockup-A')
|
||||
lines = chip.get_lines((1, 2, 3))
|
||||
print(lines.to_list())
|
||||
|
||||
add_test('Convert a LineBulk to a list', line_bulk_to_list)
|
||||
|
||||
def get_value_single_line():
|
||||
chip = gpiod.Chip('gpio-mockup-A')
|
||||
line = chip.get_line(2)
|
||||
line.request(consumer=sys.argv[0], type=gpiod.LINE_REQ_DIR_IN)
|
||||
print('line value: {}'.format(line.get_value()))
|
||||
|
||||
add_test('Get value - single line', get_value_single_line)
|
||||
|
||||
def set_value_single_line():
|
||||
chip = gpiod.Chip('gpiochip0')
|
||||
line = chip.get_line(3)
|
||||
line.request(consumer=sys.argv[0], type=gpiod.LINE_REQ_DIR_IN)
|
||||
print('line value before: {}'.format(line.get_value()))
|
||||
line.release()
|
||||
line.request(consumer=sys.argv[0], type=gpiod.LINE_REQ_DIR_OUT)
|
||||
line.set_value(1)
|
||||
line.release()
|
||||
line.request(consumer=sys.argv[0], type=gpiod.LINE_REQ_DIR_IN)
|
||||
print('line value after: {}'.format(line.get_value()))
|
||||
|
||||
add_test('Set value - single line', set_value_single_line)
|
||||
|
||||
for name, func in test_cases:
|
||||
print('==============================================')
|
||||
print('{}:'.format(name))
|
||||
func()
|
||||
17
bindings/python/examples/gpiodetect.py
Executable file
17
bindings/python/examples/gpiodetect.py
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#
|
||||
# This file is part of libgpiod.
|
||||
#
|
||||
# Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
|
||||
#
|
||||
|
||||
'''Reimplementation of the gpiodetect tool in Python.'''
|
||||
|
||||
import gpiod
|
||||
|
||||
for chip in gpiod.ChipIter():
|
||||
print('{} [{}] ({} lines)'.format(chip.name(),
|
||||
chip.label(),
|
||||
chip.num_lines()))
|
||||
16
bindings/python/examples/gpiofind.py
Executable file
16
bindings/python/examples/gpiofind.py
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#
|
||||
# This file is part of libgpiod.
|
||||
#
|
||||
# Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
|
||||
#
|
||||
|
||||
'''Reimplementation of the gpiofind tool in Python.'''
|
||||
|
||||
import gpiod
|
||||
import sys
|
||||
|
||||
line = gpiod.find_line(sys.argv[1])
|
||||
print('{} {}'.format(line.owner().name(), line.offset()))
|
||||
30
bindings/python/examples/gpioget.py
Executable file
30
bindings/python/examples/gpioget.py
Executable file
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#
|
||||
# This file is part of libgpiod.
|
||||
#
|
||||
# Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
|
||||
#
|
||||
|
||||
'''Simplified reimplementation of the gpioget tool in Python.'''
|
||||
|
||||
import gpiod
|
||||
import sys
|
||||
|
||||
if len(sys.argv) < 3:
|
||||
raise TypeError('usage: gpioget.py <gpiochip> <offset1> <offset2> ...')
|
||||
|
||||
chip = gpiod.Chip(sys.argv[1])
|
||||
|
||||
offsets = []
|
||||
for off in sys.argv[2:]:
|
||||
offsets.append(int(off))
|
||||
|
||||
lines = chip.get_lines(offsets)
|
||||
lines.request(consumer=sys.argv[0], type=gpiod.LINE_REQ_DIR_IN)
|
||||
vals = lines.get_values()
|
||||
|
||||
for val in vals:
|
||||
print(val, end=' ')
|
||||
print()
|
||||
29
bindings/python/examples/gpioinfo.py
Executable file
29
bindings/python/examples/gpioinfo.py
Executable file
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#
|
||||
# This file is part of libgpiod.
|
||||
#
|
||||
# Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
|
||||
#
|
||||
|
||||
'''Simplified reimplementation of the gpioinfo tool in Python.'''
|
||||
|
||||
import gpiod
|
||||
|
||||
for chip in gpiod.ChipIter():
|
||||
print('{} - {} lines:'.format(chip.name(), chip.num_lines()))
|
||||
|
||||
for line in gpiod.LineIter(chip):
|
||||
offset = line.offset()
|
||||
name = line.name()
|
||||
consumer = line.consumer()
|
||||
direction = line.direction()
|
||||
active_state = line.active_state()
|
||||
|
||||
print('\tline {:>3}: {:>18} {:>12} {:>8} {:>10}'.format(
|
||||
offset,
|
||||
'unnamed' if name is None else name,
|
||||
'unused' if consumer is None else consumer,
|
||||
'input' if direction == gpiod.Line.DIRECTION_INPUT else 'output',
|
||||
'active-low' if active_state == gpiod.Line.ACTIVE_LOW else 'active-high'))
|
||||
45
bindings/python/examples/gpiomon.py
Executable file
45
bindings/python/examples/gpiomon.py
Executable file
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#
|
||||
# This file is part of libgpiod.
|
||||
#
|
||||
# Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
|
||||
#
|
||||
|
||||
'''Simplified reimplementation of the gpiomon tool in Python.'''
|
||||
|
||||
import gpiod
|
||||
import sys
|
||||
|
||||
def print_event(event):
|
||||
if event.type == gpiod.LineEvent.RISING_EDGE:
|
||||
print(' RISING EDGE', end='')
|
||||
elif event.type == gpiod.LineEvent.FALLING_EDGE:
|
||||
print('FALLING EDGE', end='')
|
||||
else:
|
||||
raise TypeError('Invalid event type')
|
||||
|
||||
print(' {}.{} line: {}'.format(event.sec, event.nsec, event.source.offset()))
|
||||
|
||||
if len(sys.argv) < 3:
|
||||
raise TypeError('usage: gpiomon.py <gpiochip> <offset1> <offset2> ...')
|
||||
|
||||
chip = gpiod.Chip(sys.argv[1])
|
||||
|
||||
offsets = []
|
||||
for off in sys.argv[2:]:
|
||||
offsets.append(int(off))
|
||||
|
||||
lines = chip.get_lines(offsets)
|
||||
lines.request(consumer=sys.argv[0], type=gpiod.LINE_REQ_EV_BOTH_EDGES)
|
||||
|
||||
try:
|
||||
while True:
|
||||
ev_lines = lines.event_wait(sec=1)
|
||||
if ev_lines:
|
||||
for line in ev_lines:
|
||||
event = line.event_read()
|
||||
print_event(event)
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(130)
|
||||
29
bindings/python/examples/gpioset.py
Executable file
29
bindings/python/examples/gpioset.py
Executable file
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#
|
||||
# This file is part of libgpiod.
|
||||
#
|
||||
# Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
|
||||
#
|
||||
|
||||
'''Simplified reimplementation of the gpioset tool in Python.'''
|
||||
|
||||
import gpiod
|
||||
import sys
|
||||
|
||||
if len(sys.argv) < 3:
|
||||
raise TypeError('usage: gpioset.py <gpiochip> <offset1>=<value1> ...')
|
||||
|
||||
chip = gpiod.Chip(sys.argv[1])
|
||||
|
||||
offsets = []
|
||||
values = []
|
||||
for arg in sys.argv[2:]:
|
||||
arg = arg.split('=')
|
||||
offsets.append(int(arg[0]))
|
||||
values.append(int(arg[1]))
|
||||
|
||||
lines = chip.get_lines(offsets)
|
||||
lines.request(consumer=sys.argv[0], type=gpiod.LINE_REQ_DIR_OUT)
|
||||
vals = lines.set_values(values)
|
||||
1767
bindings/python/gpiodmodule.c
Normal file
1767
bindings/python/gpiodmodule.c
Normal file
File diff suppressed because it is too large
Load Diff
29
configure.ac
29
configure.ac
@@ -151,6 +151,31 @@ then
|
||||
AX_CXX_COMPILE_STDCXX_11([ext], [mandatory])
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE([bindings-python],
|
||||
[AC_HELP_STRING([--enable-bindings-python],
|
||||
[enable python3 bindings [default=no]])],
|
||||
[
|
||||
if test "x$enableval" = xyes
|
||||
then
|
||||
with_bindings_python=true
|
||||
else
|
||||
with_bindings_python=false
|
||||
fi
|
||||
],
|
||||
[with_bindings_python=false])
|
||||
AM_CONDITIONAL([WITH_BINDINGS_PYTHON], [test "x$with_bindings_python" = xtrue])
|
||||
|
||||
if test "x$with_bindings_python" = xtrue
|
||||
then
|
||||
AX_PYTHON_DEVEL([>= '3.0.0'])
|
||||
AM_PATH_PYTHON([3.0])
|
||||
AC_CHECK_PROG([has_python3], [python3], [true], [false])
|
||||
if test "X$has_python3" = xfalse
|
||||
then
|
||||
AC_MSG_ERROR([python3 not found - needed for python bindings], [1])
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_CHECK_PROG([has_doxygen], [doxygen], [true], [false])
|
||||
AM_CONDITIONAL([HAS_DOXYGEN], [test "x$has_doxygen" = xtrue])
|
||||
if test "x$has_doxygen" = xfalse
|
||||
@@ -168,6 +193,8 @@ AC_CONFIG_FILES([libgpiod.pc
|
||||
bindings/cxx/libgpiodcxx.pc
|
||||
bindings/Makefile
|
||||
bindings/cxx/Makefile
|
||||
bindings/cxx/examples/Makefile])
|
||||
bindings/cxx/examples/Makefile
|
||||
bindings/python/Makefile
|
||||
bindings/python/examples/Makefile])
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
Reference in New Issue
Block a user