1
0
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:
Bartosz Golaszewski
2018-02-19 12:52:38 +01:00
parent d3ea4f4148
commit 96c524c495
13 changed files with 2146 additions and 1 deletions

1
.gitignore vendored
View File

@@ -17,6 +17,7 @@ gpiomoncxx
gpiosetcxx
*.o
*.lo
*.la
doc
libgpiod.pc
libgpiodcxx.pc

View File

@@ -13,3 +13,9 @@ if WITH_BINDINGS_CXX
SUBDIRS += cxx
endif
if WITH_BINDINGS_PYTHON
SUBDIRS += python
endif

View 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

View 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

View 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()

View 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()))

View 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()))

View 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()

View 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'))

View 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)

View 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)

File diff suppressed because it is too large Load Diff

View File

@@ -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