+++ /dev/null
-#!/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.
-
-These tests assume that at least one dummy gpiochip is present in the
-system and that it's detected as gpiochip0.
-'''
-
-import gpiod
-import select
-
-test_cases = []
-
-def add_test(name, func):
- global test_cases
-
- test_cases.append((name, func))
-
-def fire_line_event(chip, offset, rising):
- path = '/sys/kernel/debug/gpio-mockup-event/{}/{}'.format(chip, offset)
- with open(path, 'w') as fd:
- fd.write('{}'.format(1 if rising else 0))
-
-def print_event(event):
- print('type: {}'.format('rising' if event.type == gpiod.LineEvent.RISING_EDGE else 'falling'))
- print('timestamp: {}.{}'.format(event.sec, event.nsec))
- print('source line offset: {}'.format(event.source.offset()))
-
-def chip_open_default_lookup():
- by_name = gpiod.Chip('gpiochip0')
- by_path = gpiod.Chip('/dev/gpiochip0')
- by_label = gpiod.Chip('gpio-mockup-A')
- by_number = gpiod.Chip('0')
- print('All good')
- by_name.close()
- by_path.close()
- by_label.close()
- by_number.close()
-
-add_test('Open a GPIO chip using different lookup modes', chip_open_default_lookup)
-
-def chip_open_different_modes():
- chip = gpiod.Chip('/dev/gpiochip0', gpiod.Chip.OPEN_BY_PATH)
- chip.close()
- chip = gpiod.Chip('gpiochip0', gpiod.Chip.OPEN_BY_NAME)
- chip.close()
- chip = gpiod.Chip('gpio-mockup-A', gpiod.Chip.OPEN_BY_LABEL)
- chip.close()
- chip = gpiod.Chip('0', gpiod.Chip.OPEN_BY_NUMBER)
- chip.close()
- print('All good')
-
-add_test('Open a GPIO chip using different modes', chip_open_different_modes)
-
-def chip_open_nonexistent():
- try:
- chip = gpiod.Chip('/nonexistent_gpiochip')
- except OSError as ex:
- print('Exception raised as expected: {}'.format(ex))
- return
-
- assert False, 'OSError expected'
-
-add_test('Try to open a nonexistent GPIO chip', chip_open_nonexistent)
-
-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_use_after_close():
- chip = gpiod.Chip('gpiochip0')
- line = chip.get_line(2)
- chip.close()
-
- try:
- chip.name()
- except ValueError as ex:
- print('Error as expected: {}'.format(ex))
-
- try:
- line = chip.get_line(3)
- except ValueError as ex:
- print('Error as expected: {}'.format(ex))
- return
-
- assert False, 'ValueError expected'
-
-add_test('Use a GPIO chip after closing it', chip_use_after_close)
-
-def chip_with_statement():
- with gpiod.Chip('gpiochip0') as chip:
- print('Chip name in controlled execution: {}'.format(chip.name()))
- line = chip.get_line(3)
- print('Got line from chip in controlled execution: {}'.format(line.name()))
-
-add_test('Use a GPIO chip in controlled execution', chip_with_statement)
-
-def chip_info():
- chip = gpiod.Chip('gpiochip0')
- print('name: {}'.format(chip.name()))
- print('label: {}'.format(chip.label()))
- print('lines: {}'.format(chip.num_lines()))
- chip.close()
-
-add_test('Print chip info', chip_info)
-
-def print_chip():
- chip = gpiod.Chip('/dev/gpiochip0')
- print(chip)
- chip.close()
-
-add_test('Print chip object', print_chip)
-
-def create_chip_without_arguments():
- try:
- chip = gpiod.Chip()
- except TypeError as ex:
- print('Exception raised as expected: {}'.format(ex))
- return
-
- assert False, 'TypeError expected'
-
-add_test('Create chip object without arguments', create_chip_without_arguments)
-
-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)
- chip.close()
-
-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()))
- line.owner().close()
-
-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')
-
- print('getting four lines from chip')
- lines = chip.get_lines([2, 4, 5, 7])
-
- print('Retrieved lines:')
- for line in lines:
- print(line)
-
- chip.close()
-
-add_test('Get lines from chip', get_lines)
-
-def get_all_lines():
- chip = gpiod.Chip('gpio-mockup-A')
-
- print('Retrieving all lines from chip')
- lines = chip.get_all_lines()
-
- print('Retrieved lines:')
- for line in lines:
- print(line)
-
- chip.close()
-
-add_test('Get all lines from chip', get_all_lines)
-
-def find_lines():
- chip = gpiod.Chip('gpiochip0')
-
- print('looking up lines by names')
- lines = chip.find_lines(['gpio-mockup-A-3', 'gpio-mockup-A-4', 'gpio-mockup-A-7'])
-
- print('Retrieved lines:')
- for line in lines:
- print(line)
-
- chip.close()
-
-add_test('Find multiple lines by name', find_lines)
-
-def find_lines_one_bad():
- chip = gpiod.Chip('gpiochip0')
-
- print('looking up lines by names')
- try:
- lines = chip.find_lines(['gpio-mockup-A-3', 'nonexistent', 'gpio-mockup-A-7'])
- except TypeError as ex:
- print('Error as expected')
- return
-
- assert False, 'TypeError expected'
-
-add_test('Find multiple lines but one line name is non-existent', find_lines_one_bad)
-
-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)
- chip.close()
-
-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())
- chip.close()
-
-add_test('Convert a LineBulk to a list', line_bulk_to_list)
-
-def line_flags():
- chip = gpiod.Chip('gpiochip0')
- line = chip.get_line(3)
-
- print('line is used: {}'.format(line.is_used()))
- print('line is requested: {}'.format(line.is_requested()))
-
- print('requesting line')
- line.request(consumer="gpiod_test.py", type=gpiod.LINE_REQ_DIR_OUT,
- flags=(gpiod.LINE_REQ_FLAG_OPEN_DRAIN | gpiod.LINE_REQ_FLAG_ACTIVE_LOW))
-
- print('line is used: {}'.format(line.is_used()))
- print('line is open drain: {}'.format(line.is_open_drain()))
- print('line is open source: {}'.format(line.is_open_source()))
- print('line is requested: {}'.format(line.is_requested()))
- print('line is active-low: {}'.format(
- "True" if line.active_state() == gpiod.Line.ACTIVE_LOW else "False"))
-
- chip.close()
-
-add_test('Check various line flags', line_flags)
-
-def get_value_single_line():
- chip = gpiod.Chip('gpio-mockup-A')
- line = chip.get_line(2)
- line.request(consumer="gpiod_test.py", type=gpiod.LINE_REQ_DIR_IN)
- print('line value: {}'.format(line.get_value()))
- chip.close()
-
-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="gpiod_test.py", type=gpiod.LINE_REQ_DIR_IN)
-
- print('line value before: {}'.format(line.get_value()))
- line.release()
- line.request(consumer="gpiod_test.py", type=gpiod.LINE_REQ_DIR_OUT)
- line.set_value(1)
- line.release()
- line.request(consumer="gpiod_test.py", type=gpiod.LINE_REQ_DIR_IN)
- print('line value after: {}'.format(line.get_value()))
-
- chip.close()
-
-add_test('Set value - single line', set_value_single_line)
-
-def request_line_with_default_values():
- chip = gpiod.Chip('gpiochip0')
- line = chip.get_line(3)
-
- print('requesting a single line with a default value')
- line.request(consumer='gpiod_test.py', type=gpiod.LINE_REQ_DIR_OUT, default_vals=[ 1 ])
-
- print('line value after request: {}'.format(line.get_value()))
-
- chip.close()
-
-add_test('Request line with default value', request_line_with_default_values)
-
-def request_multiple_lines_with_default_values():
- chip = gpiod.Chip('gpiochip0')
- lines = chip.get_lines(( 1, 2, 3, 4, 5 ))
-
- print('requesting lines with default values')
- lines.request(consumer='gpiod_test.py', type=gpiod.LINE_REQ_DIR_OUT, default_vals=( 1, 0, 1, 0, 1 ))
-
- print('line values after request: {}'.format(lines.get_values()))
-
- chip.close()
-
-add_test('Request multiple lines with default values', request_multiple_lines_with_default_values)
-
-def request_line_incorrect_number_of_def_vals():
- with gpiod.Chip('gpiochip0') as chip:
- lines = chip.get_lines(( 1, 2, 3, 4, 5 ))
-
- print('requesting lines with incorrect number of default values')
- try:
- lines.request(consumer='gpiod_test.py',
- type=gpiod.LINE_REQ_DIR_OUT,
- default_vals=( 1, 0, 1, 0 ))
- except TypeError:
- print('TypeError raised as expected')
- return
-
- assert False, 'TypeError expected'
-
-add_test('Request with incorrect number of default values', request_line_incorrect_number_of_def_vals)
-
-def line_event_single_line():
- chip = gpiod.Chip('gpiochip0')
- line = chip.get_line(1)
-
- print('requesting line for events')
- line.request(consumer="gpiod_test.py", type=gpiod.LINE_REQ_EV_BOTH_EDGES)
-
- print('generating a line event')
- fire_line_event('gpiochip0', 1, True)
- assert line.event_wait(sec=1), 'Expected a line event to occur'
-
- print('event received')
- event = line.event_read()
- print_event(event)
-
- chip.close()
-
-add_test('Monitor a single line for events', line_event_single_line)
-
-def line_event_multiple_lines():
- chip = gpiod.Chip('gpiochip0')
- lines = chip.get_lines((1, 2, 3, 4, 5))
-
- print('requesting lines for events')
- lines.request(consumer="gpiod_test.py", type=gpiod.LINE_REQ_EV_BOTH_EDGES)
-
- print('generating two line events')
- fire_line_event('gpiochip0', 1, True)
- fire_line_event('gpiochip0', 2, True)
-
- events = lines.event_wait(sec=1)
- assert events is not None and len(events) == 2, 'Expected to receive two line events'
-
- print('events received:')
- for line in events:
- event = line.event_read()
- print_event(event)
-
- chip.close()
-
-add_test('Monitor multiple lines for events', line_event_multiple_lines)
-
-def line_event_poll_fd():
- chip = gpiod.Chip('gpiochip0')
- lines = chip.get_lines((1, 2, 3, 4, 5, 6))
- print('requesting lines for events')
- lines.request(consumer="gpiod_test.py", type=gpiod.LINE_REQ_EV_BOTH_EDGES)
-
- print('generating three line events')
- fire_line_event('gpiochip0', 2, True)
- fire_line_event('gpiochip0', 3, False)
- fire_line_event('gpiochip0', 5, True)
-
- print('retrieving the file descriptors')
- inputs = []
- fd_mapping = {}
- for line in lines:
- inputs.append(line.event_get_fd())
- fd_mapping[line.event_get_fd()] = line
-
- readable, writable, exceptional = select.select(inputs, [], inputs, 1.0)
- assert len(readable) == 3, 'Expected to receive three line events'
-
- print('events received:')
- for fd in readable:
- line = fd_mapping[fd]
- event = line.event_read()
- print_event(event)
-
- chip.close()
-
-add_test('Monitor multiple lines using their file descriptors', line_event_poll_fd)
-
-def line_event_repr():
- with gpiod.Chip('gpiochip0') as chip:
- line = chip.get_line(1)
-
- print('requesting line for events')
- line.request(consumer="gpiod_test.py", type=gpiod.LINE_REQ_EV_BOTH_EDGES)
-
- print('generating a line event')
- fire_line_event('gpiochip0', 1, True)
- assert line.event_wait(sec=1), 'Expected a line event to occur'
-
- print('event received: {}'.format(line.event_read()))
-
-add_test('Line event string repr', line_event_repr)
-
-print('API version is {}'.format(gpiod.version_string()))
-
-for name, func in test_cases:
- print('==============================================')
- print('{}:'.format(name))
- print()
- func()
--- /dev/null
+#!/usr/bin/env python3
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+#
+# This file is part of libgpiod.
+#
+# Copyright (C) 2019 Bartosz Golaszewski <bgolaszewski@baylibre.com>
+#
+
+import errno
+import gpiod
+import gpiomockup
+import os
+import select
+import threading
+import unittest
+
+from packaging import version
+
+mockup = None
+default_consumer = 'gpiod-py-test'
+
+class MockupTestCase(unittest.TestCase):
+
+ chip_sizes = None
+ flags = 0
+
+ def setUp(self):
+ mockup.probe(self.chip_sizes, flags=self.flags)
+
+ def tearDown(self):
+ mockup.remove()
+
+class EventThread(threading.Thread):
+
+ def __init__(self, chip_idx, line_offset, freq):
+ threading.Thread.__init__(self)
+ self.chip_idx = chip_idx
+ self.line_offset = line_offset
+ self.freq = freq
+ self.lock = threading.Lock()
+ self.cond = threading.Condition(self.lock)
+ self.should_stop = False
+
+ def run(self):
+ i = 0;
+ while True:
+ with self.lock:
+ if self.should_stop:
+ break;
+
+ if not self.cond.wait(float(self.freq) / 1000):
+ mockup.chip_set_pull(self.chip_idx,
+ self.line_offset, i % 2)
+ i += 1
+
+ def stop(self):
+ with self.lock:
+ self.should_stop = True
+ self.cond.notify_all()
+
+ def __enter__(self):
+ self.start()
+ return self
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ self.stop()
+ self.join()
+
+def check_kernel(major, minor, release):
+ current = os.uname().release
+ required = '{}.{}.{}'.format(major, minor, release)
+ if version.parse(current) < version.parse(required):
+ raise NotImplementedError(
+ 'linux kernel version must be at least {} - got {}'.format(required, current))
+
+#
+# Chip test cases
+#
+
+class ChipOpen(MockupTestCase):
+
+ chip_sizes = ( 8, 8, 8 )
+
+ def test_open_chip_by_name(self):
+ with gpiod.Chip(mockup.chip_name(1), gpiod.Chip.OPEN_BY_NAME) as chip:
+ self.assertEqual(chip.name(), mockup.chip_name(1))
+
+ def test_open_chip_by_path(self):
+ with gpiod.Chip(mockup.chip_path(1), gpiod.Chip.OPEN_BY_PATH) as chip:
+ self.assertEqual(chip.name(), mockup.chip_name(1))
+
+ def test_open_chip_by_num(self):
+ with gpiod.Chip('{}'.format(mockup.chip_num(1)),
+ gpiod.Chip.OPEN_BY_NUMBER) as chip:
+ self.assertEqual(chip.name(), mockup.chip_name(1))
+
+ def test_open_chip_by_label(self):
+ with gpiod.Chip('gpio-mockup-B', gpiod.Chip.OPEN_BY_LABEL) as chip:
+ self.assertEqual(chip.name(), mockup.chip_name(1))
+
+ def test_lookup_chip_by_name(self):
+ with gpiod.Chip(mockup.chip_name(1)) as chip:
+ self.assertEqual(chip.name(), mockup.chip_name(1))
+
+ def test_lookup_chip_by_path(self):
+ with gpiod.Chip(mockup.chip_path(1)) as chip:
+ self.assertEqual(chip.name(), mockup.chip_name(1))
+
+ def test_lookup_chip_by_num(self):
+ with gpiod.Chip('{}'.format(mockup.chip_num(1))) as chip:
+ self.assertEqual(chip.name(), mockup.chip_name(1))
+
+ def test_lookup_chip_by_label(self):
+ with gpiod.Chip('gpio-mockup-B') as chip:
+ self.assertEqual(chip.name(), mockup.chip_name(1))
+
+ def test_nonexistent_chip(self):
+ with self.assertRaises(FileNotFoundError):
+ chip = gpiod.Chip('nonexistent-chip')
+
+ def test_open_chip_no_arguments(self):
+ with self.assertRaises(TypeError):
+ chip = gpiod.Chip()
+
+class ChipClose(MockupTestCase):
+
+ chip_sizes = ( 8, )
+
+ def test_use_chip_after_close(self):
+ chip = gpiod.Chip(mockup.chip_name(0))
+ self.assertEqual(chip.name(), mockup.chip_name(0))
+ chip.close()
+ with self.assertRaises(ValueError):
+ chip.name()
+
+class ChipInfo(MockupTestCase):
+
+ chip_sizes = ( 16, )
+
+ def test_chip_get_info(self):
+ chip = gpiod.Chip(mockup.chip_name(0))
+ self.assertEqual(chip.name(), mockup.chip_name(0))
+ self.assertEqual(chip.label(), 'gpio-mockup-A')
+ self.assertEqual(chip.num_lines(), 16)
+
+class ChipGetLines(MockupTestCase):
+
+ chip_sizes = ( 8, 8, 4 )
+ flags = gpiomockup.Mockup.FLAG_NAMED_LINES
+
+ def test_get_single_line_by_offset(self):
+ with gpiod.Chip(mockup.chip_name(1)) as chip:
+ line = chip.get_line(4)
+ self.assertEqual(line.name(), 'gpio-mockup-B-4')
+
+ def test_find_single_line_by_name(self):
+ with gpiod.Chip(mockup.chip_name(1)) as chip:
+ line = chip.find_line('gpio-mockup-B-4')
+ self.assertEqual(line.offset(), 4)
+
+ def test_get_single_line_invalid_offset(self):
+ with gpiod.Chip(mockup.chip_name(1)) as chip:
+ with self.assertRaises(OSError) as err_ctx:
+ line = chip.get_line(11)
+
+ self.assertEqual(err_ctx.exception.errno, errno.EINVAL)
+
+ def test_find_single_line_nonexistent(self):
+ with gpiod.Chip(mockup.chip_name(1)) as chip:
+ line = chip.find_line('nonexistent-line')
+ self.assertEqual(line, None)
+
+ def test_get_multiple_lines_by_offsets_in_tuple(self):
+ with gpiod.Chip(mockup.chip_name(1)) as chip:
+ lines = chip.get_lines(( 1, 3, 6, 7 )).to_list()
+ self.assertEqual(len(lines), 4)
+ self.assertEqual(lines[0].name(), 'gpio-mockup-B-1')
+ self.assertEqual(lines[1].name(), 'gpio-mockup-B-3')
+ self.assertEqual(lines[2].name(), 'gpio-mockup-B-6')
+ self.assertEqual(lines[3].name(), 'gpio-mockup-B-7')
+
+ def test_get_multiple_lines_by_offsets_in_list(self):
+ with gpiod.Chip(mockup.chip_name(1)) as chip:
+ lines = chip.get_lines([ 1, 3, 6, 7 ]).to_list()
+ self.assertEqual(len(lines), 4)
+ self.assertEqual(lines[0].name(), 'gpio-mockup-B-1')
+ self.assertEqual(lines[1].name(), 'gpio-mockup-B-3')
+ self.assertEqual(lines[2].name(), 'gpio-mockup-B-6')
+ self.assertEqual(lines[3].name(), 'gpio-mockup-B-7')
+
+ def test_find_multiple_lines_by_names_in_tuple(self):
+ with gpiod.Chip(mockup.chip_name(1)) as chip:
+ lines = chip.find_lines(( 'gpio-mockup-B-0',
+ 'gpio-mockup-B-3',
+ 'gpio-mockup-B-4',
+ 'gpio-mockup-B-6' )).to_list()
+ self.assertEqual(len(lines), 4)
+ self.assertEqual(lines[0].offset(), 0)
+ self.assertEqual(lines[1].offset(), 3)
+ self.assertEqual(lines[2].offset(), 4)
+ self.assertEqual(lines[3].offset(), 6)
+
+ def test_find_multiple_lines_by_names_in_list(self):
+ with gpiod.Chip(mockup.chip_name(1)) as chip:
+ lines = chip.find_lines([ 'gpio-mockup-B-0',
+ 'gpio-mockup-B-3',
+ 'gpio-mockup-B-4',
+ 'gpio-mockup-B-6' ]).to_list()
+ self.assertEqual(len(lines), 4)
+ self.assertEqual(lines[0].offset(), 0)
+ self.assertEqual(lines[1].offset(), 3)
+ self.assertEqual(lines[2].offset(), 4)
+ self.assertEqual(lines[3].offset(), 6)
+
+ def test_get_multiple_lines_invalid_offset(self):
+ with gpiod.Chip(mockup.chip_name(1)) as chip:
+ with self.assertRaises(OSError) as err_ctx:
+ line = chip.get_lines(( 1, 3, 11, 7 ))
+
+ self.assertEqual(err_ctx.exception.errno, errno.EINVAL)
+
+ def test_find_multiple_lines_nonexistent(self):
+ with gpiod.Chip(mockup.chip_name(1)) as chip:
+ with self.assertRaises(TypeError):
+ lines = chip.find_lines(( 'gpio-mockup-B-0',
+ 'nonexistent-line',
+ 'gpio-mockup-B-4',
+ 'gpio-mockup-B-6' )).to_list()
+
+ def test_get_all_lines(self):
+ with gpiod.Chip(mockup.chip_name(2)) as chip:
+ lines = chip.get_all_lines().to_list()
+ self.assertEqual(len(lines), 4)
+ self.assertEqual(lines[0].name(), 'gpio-mockup-C-0')
+ self.assertEqual(lines[1].name(), 'gpio-mockup-C-1')
+ self.assertEqual(lines[2].name(), 'gpio-mockup-C-2')
+ self.assertEqual(lines[3].name(), 'gpio-mockup-C-3')
+
+#
+# Line test cases
+#
+
+class LineGlobalFindLine(MockupTestCase):
+
+ chip_sizes = ( 4, 8, 16 )
+ flags = gpiomockup.Mockup.FLAG_NAMED_LINES
+
+ def test_global_find_line_function(self):
+ line = gpiod.find_line('gpio-mockup-B-4')
+ self.assertNotEqual(line, None)
+ try:
+ self.assertEqual(line.owner().label(), 'gpio-mockup-B')
+ self.assertEqual(line.offset(), 4)
+ finally:
+ line.owner().close()
+
+ def test_global_find_line_function_nonexistent(self):
+ line = gpiod.find_line('nonexistent-line')
+ self.assertEqual(line, None)
+
+class LineInfo(MockupTestCase):
+
+ chip_sizes = ( 8, )
+ flags = gpiomockup.Mockup.FLAG_NAMED_LINES
+
+ def test_unexported_line(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(4)
+ self.assertEqual(line.offset(), 4)
+ self.assertEqual(line.name(), 'gpio-mockup-A-4')
+ self.assertEqual(line.direction(), gpiod.Line.DIRECTION_INPUT)
+ self.assertEqual(line.active_state(), gpiod.Line.ACTIVE_HIGH)
+ self.assertEqual(line.consumer(), None)
+ self.assertFalse(line.is_used())
+ self.assertFalse(line.is_requested())
+
+ def test_exported_line(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(4)
+ line.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_DIR_OUT,
+ flags=gpiod.LINE_REQ_FLAG_ACTIVE_LOW)
+ self.assertEqual(line.offset(), 4)
+ self.assertEqual(line.name(), 'gpio-mockup-A-4')
+ self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
+ self.assertEqual(line.active_state(), gpiod.Line.ACTIVE_LOW)
+ self.assertEqual(line.consumer(), default_consumer)
+ self.assertTrue(line.is_used())
+ self.assertTrue(line.is_requested())
+
+ def test_exported_line_with_flags(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(4)
+ flags = (gpiod.LINE_REQ_FLAG_ACTIVE_LOW |
+ gpiod.LINE_REQ_FLAG_OPEN_DRAIN)
+ line.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_DIR_OUT,
+ flags=flags)
+ self.assertEqual(line.offset(), 4)
+ self.assertEqual(line.name(), 'gpio-mockup-A-4')
+ # FIXME Uncomment the line below once this issue is fixed in the kernel.
+ #self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
+ self.assertEqual(line.active_state(), gpiod.Line.ACTIVE_LOW)
+ self.assertEqual(line.consumer(), default_consumer)
+ self.assertTrue(line.is_used())
+ self.assertTrue(line.is_requested())
+ self.assertTrue(line.is_open_drain())
+ self.assertFalse(line.is_open_source())
+
+class LineValues(MockupTestCase):
+
+ chip_sizes = ( 8, )
+
+ def test_get_value_single_line(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(3)
+ line.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_DIR_IN)
+ self.assertEqual(line.get_value(), 0)
+ mockup.chip_set_pull(0, 3, 1)
+ self.assertEqual(line.get_value(), 1)
+
+ def test_set_value_single_line(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(3)
+ line.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_DIR_OUT)
+ line.set_value(1)
+ self.assertEqual(mockup.chip_get_value(0, 3), 1)
+ line.set_value(0)
+ self.assertEqual(mockup.chip_get_value(0, 3), 0)
+
+ def test_set_value_with_default_value_argument(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(3)
+ line.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_DIR_OUT,
+ default_val=1)
+ self.assertEqual(mockup.chip_get_value(0, 3), 1)
+
+ def test_get_value_multiple_lines(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ lines = chip.get_lines(( 0, 3, 4, 6 ))
+ lines.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_DIR_IN)
+ self.assertEqual(lines.get_values(), [ 0, 0, 0, 0 ])
+ mockup.chip_set_pull(0, 0, 1)
+ mockup.chip_set_pull(0, 4, 1)
+ mockup.chip_set_pull(0, 6, 1)
+ self.assertEqual(lines.get_values(), [ 1, 0, 1, 1 ])
+
+ def test_set_value_multiple_lines(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ lines = chip.get_lines(( 0, 3, 4, 6 ))
+ lines.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_DIR_OUT)
+ lines.set_values(( 1, 0, 1, 1 ))
+ self.assertEqual(mockup.chip_get_value(0, 0), 1)
+ self.assertEqual(mockup.chip_get_value(0, 3), 0)
+ self.assertEqual(mockup.chip_get_value(0, 4), 1)
+ self.assertEqual(mockup.chip_get_value(0, 6), 1)
+ lines.set_values(( 0, 0, 1, 0 ))
+ self.assertEqual(mockup.chip_get_value(0, 0), 0)
+ self.assertEqual(mockup.chip_get_value(0, 3), 0)
+ self.assertEqual(mockup.chip_get_value(0, 4), 1)
+ self.assertEqual(mockup.chip_get_value(0, 6), 0)
+
+ def test_set_multiple_values_with_default_vals_argument(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ lines = chip.get_lines(( 0, 3, 4, 6 ))
+ lines.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_DIR_OUT,
+ default_vals=( 1, 0, 1, 1 ))
+ self.assertEqual(mockup.chip_get_value(0, 0), 1)
+ self.assertEqual(mockup.chip_get_value(0, 3), 0)
+ self.assertEqual(mockup.chip_get_value(0, 4), 1)
+ self.assertEqual(mockup.chip_get_value(0, 6), 1)
+
+ def test_get_value_active_low(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(3)
+ line.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_DIR_IN,
+ flags=gpiod.LINE_REQ_FLAG_ACTIVE_LOW)
+ self.assertEqual(line.get_value(), 1)
+ mockup.chip_set_pull(0, 3, 1)
+ self.assertEqual(line.get_value(), 0)
+
+ def test_set_value_active_low(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(3)
+ line.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_DIR_OUT,
+ flags=gpiod.LINE_REQ_FLAG_ACTIVE_LOW)
+ line.set_value(1)
+ self.assertEqual(mockup.chip_get_value(0, 3), 0)
+ line.set_value(0)
+ self.assertEqual(mockup.chip_get_value(0, 3), 1)
+
+class LineRequestBehavior(MockupTestCase):
+
+ chip_sizes = ( 8, )
+
+ def test_line_export_release(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(3)
+ line.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_DIR_IN)
+ self.assertTrue(line.is_requested())
+ self.assertEqual(line.get_value(), 0)
+ line.release()
+ self.assertFalse(line.is_requested())
+
+ def test_line_request_twice_two_calls(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(3)
+ line.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_DIR_IN)
+ with self.assertRaises(OSError):
+ line.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_DIR_IN)
+
+ def test_line_request_twice_in_bulk(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ lines = chip.get_lines(( 2, 3, 6, 6 ))
+ with self.assertRaises(OSError):
+ lines.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_DIR_IN)
+
+ def test_use_value_unrequested(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(3)
+ with self.assertRaises(OSError):
+ line.get_value()
+
+#
+# Iterator test cases
+#
+
+class ChipIterator(MockupTestCase):
+
+ chip_sizes = ( 4, 8, 16 )
+
+ def test_iterate_over_chips(self):
+ gotA = False
+ gotB = False
+ gotC = False
+
+ for chip in gpiod.ChipIter():
+ if chip.label() == 'gpio-mockup-A':
+ gotA = True
+ elif chip.label() == 'gpio-mockup-B':
+ gotB = True
+ elif chip.label() == 'gpio-mockup-C':
+ gotC = True
+
+ self.assertTrue(gotA)
+ self.assertTrue(gotB)
+ self.assertTrue(gotC)
+
+class LineIterator(MockupTestCase):
+
+ chip_sizes = ( 4, )
+
+ def test_iterate_over_lines(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ count = 0
+
+ for line in gpiod.LineIter(chip):
+ self.assertEqual(line.offset(), count)
+ count += 1
+
+ self.assertEqual(count, chip.num_lines())
+
+class LineBulkIter(MockupTestCase):
+
+ chip_sizes = ( 4, )
+
+ def test_line_bulk_iterator(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ lines = chip.get_all_lines()
+ count = 0
+
+ for line in lines:
+ self.assertEqual(line.offset(), count)
+ count += 1
+
+ self.assertEqual(count, chip.num_lines())
+
+#
+# Event test cases
+#
+
+class EventSingleLine(MockupTestCase):
+
+ chip_sizes = ( 8, )
+
+ def test_single_line_rising_edge_event(self):
+ with EventThread(0, 4, 200):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(4)
+ line.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_EV_RISING_EDGE)
+ self.assertTrue(line.event_wait(sec=1))
+ event = line.event_read()
+ self.assertEqual(event.type, gpiod.LineEvent.RISING_EDGE)
+ self.assertEqual(event.source.offset(), 4)
+
+ def test_single_line_falling_edge_event(self):
+ with EventThread(0, 4, 200):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(4)
+ line.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_EV_FALLING_EDGE)
+ self.assertTrue(line.event_wait(sec=1))
+ event = line.event_read()
+ self.assertEqual(event.type, gpiod.LineEvent.FALLING_EDGE)
+ self.assertEqual(event.source.offset(), 4)
+
+ def test_single_line_both_edges_events(self):
+ with EventThread(0, 4, 200):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(4)
+ line.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_EV_BOTH_EDGES)
+ self.assertTrue(line.event_wait(sec=1))
+ event = line.event_read()
+ self.assertEqual(event.type, gpiod.LineEvent.RISING_EDGE)
+ self.assertEqual(event.source.offset(), 4)
+ self.assertTrue(line.event_wait(sec=1))
+ event = line.event_read()
+ self.assertEqual(event.type, gpiod.LineEvent.FALLING_EDGE)
+ self.assertEqual(event.source.offset(), 4)
+
+ def test_single_line_both_edges_events_active_low(self):
+ with EventThread(0, 4, 200):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(4)
+ line.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_EV_BOTH_EDGES,
+ flags=gpiod.LINE_REQ_FLAG_ACTIVE_LOW)
+ self.assertTrue(line.event_wait(sec=1))
+ event = line.event_read()
+ self.assertEqual(event.type, gpiod.LineEvent.FALLING_EDGE)
+ self.assertEqual(event.source.offset(), 4)
+ self.assertTrue(line.event_wait(sec=1))
+ event = line.event_read()
+ self.assertEqual(event.type, gpiod.LineEvent.RISING_EDGE)
+ self.assertEqual(event.source.offset(), 4)
+
+class EventBulk(MockupTestCase):
+
+ chip_sizes = ( 8, )
+
+ def test_watch_multiple_lines_for_events(self):
+ with EventThread(0, 2, 200):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ lines = chip.get_lines(( 0, 1, 2, 3, 4 ))
+ lines.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_EV_BOTH_EDGES)
+ event_lines = lines.event_wait(sec=1)
+ self.assertEqual(len(event_lines), 1)
+ line = event_lines[0]
+ event = line.event_read()
+ self.assertEqual(event.type, gpiod.LineEvent.RISING_EDGE)
+ self.assertEqual(event.source.offset(), 2)
+ event_lines = lines.event_wait(sec=1)
+ self.assertEqual(len(event_lines), 1)
+ line = event_lines[0]
+ event = line.event_read()
+ self.assertEqual(event.type, gpiod.LineEvent.FALLING_EDGE)
+ self.assertEqual(event.source.offset(), 2)
+
+class EventValues(MockupTestCase):
+
+ chip_sizes = ( 8, )
+
+ def test_request_for_events_get_value(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(3)
+ line.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_EV_BOTH_EDGES)
+ self.assertEqual(line.get_value(), 0)
+ mockup.chip_set_pull(0, 3, 1)
+ self.assertEqual(line.get_value(), 1)
+
+ def test_request_for_events_get_value_active_low(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(3)
+ line.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_EV_BOTH_EDGES,
+ flags=gpiod.LINE_REQ_FLAG_ACTIVE_LOW)
+ self.assertEqual(line.get_value(), 1)
+ mockup.chip_set_pull(0, 3, 1)
+ self.assertEqual(line.get_value(), 0)
+
+class EventFileDescriptor(MockupTestCase):
+
+ chip_sizes = ( 8, )
+
+ def test_event_get_fd(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(3)
+ line.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_EV_BOTH_EDGES)
+ fd = line.event_get_fd();
+ self.assertGreaterEqual(fd, 0)
+
+ def test_event_get_fd_not_requested(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(3)
+ with self.assertRaises(OSError):
+ fd = line.event_get_fd();
+
+ def test_event_get_fd_requested_for_values(self):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ line = chip.get_line(3)
+ line.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_DIR_IN)
+ with self.assertRaises(OSError):
+ fd = line.event_get_fd();
+
+ def test_event_fd_polling(self):
+ with EventThread(0, 2, 200):
+ with gpiod.Chip(mockup.chip_name(0)) as chip:
+ lines = chip.get_lines(( 0, 1, 2, 3, 4, 5, 6 ))
+ lines.request(consumer=default_consumer,
+ type=gpiod.LINE_REQ_EV_BOTH_EDGES)
+
+ inputs = []
+ for line in lines:
+ inputs.append(line.event_get_fd())
+
+ readable, writable, exceptional = select.select(inputs, [],
+ inputs, 1.0)
+
+ self.assertEqual(len(readable), 1)
+ event = lines.to_list()[2].event_read()
+ self.assertEqual(event.type, gpiod.LineEvent.RISING_EDGE)
+ self.assertEqual(event.source.offset(), 2)
+
+#
+# Main
+#
+
+if __name__ == '__main__':
+ check_kernel(5, 2, 7)
+ mockup = gpiomockup.Mockup()
+ unittest.main()
--- /dev/null
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*
+ * This file is part of libgpiod.
+ *
+ * Copyright (C) 2019 Bartosz Golaszewski <bgolaszewski@baylibre.com>
+ */
+
+#include <Python.h>
+#include <gpio-mockup.h>
+
+typedef struct {
+ PyObject_HEAD
+ struct gpio_mockup *mockup;
+} gpiomockup_MockupObject;
+
+enum {
+ gpiomockup_FLAG_NAMED_LINES = 1,
+};
+
+static int gpiomockup_Mockup_init(gpiomockup_MockupObject *self,
+ PyObject *Py_UNUSED(ignored0),
+ PyObject *Py_UNUSED(ignored1))
+{
+ Py_BEGIN_ALLOW_THREADS;
+ self->mockup = gpio_mockup_new();
+ Py_END_ALLOW_THREADS;
+ if (!self->mockup) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void gpiomockup_Mockup_dealloc(gpiomockup_MockupObject *self)
+{
+ if (self->mockup) {
+ Py_BEGIN_ALLOW_THREADS;
+ gpio_mockup_unref(self->mockup);
+ Py_END_ALLOW_THREADS;
+ }
+
+ PyObject_Del(self);
+}
+
+static PyObject *gpiomockup_Mockup_probe(gpiomockup_MockupObject *self,
+ PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = { "chip_sizes",
+ "flags",
+ NULL };
+
+ PyObject *chip_sizes_obj, *iter, *next;
+ unsigned int *chip_sizes;
+ int ret, flags = 0, i;
+ Py_ssize_t num_chips;
+
+ ret = PyArg_ParseTupleAndKeywords(args, kwds, "O|i", kwlist,
+ &chip_sizes_obj, &flags);
+ if (!ret)
+ return NULL;
+
+ num_chips = PyObject_Size(chip_sizes_obj);
+ if (num_chips < 0) {
+ return NULL;
+ } else if (num_chips == 0) {
+ PyErr_SetString(PyExc_TypeError,
+ "Number of chips must be greater thatn 0");
+ return NULL;
+ }
+
+ chip_sizes = PyMem_RawCalloc(num_chips, sizeof(unsigned int));
+ if (!chip_sizes)
+ return NULL;
+
+ iter = PyObject_GetIter(chip_sizes_obj);
+ if (!iter) {
+ PyMem_RawFree(chip_sizes);
+ return NULL;
+ }
+
+ for (i = 0;; i++) {
+ next = PyIter_Next(iter);
+ if (!next) {
+ Py_DECREF(iter);
+ break;
+ }
+
+ chip_sizes[i] = PyLong_AsUnsignedLong(next);
+ Py_DECREF(next);
+ if (PyErr_Occurred()) {
+ Py_DECREF(iter);
+ PyMem_RawFree(chip_sizes);
+ return NULL;
+ }
+ }
+
+ if (flags & gpiomockup_FLAG_NAMED_LINES)
+ flags |= GPIO_MOCKUP_FLAG_NAMED_LINES;
+
+ Py_BEGIN_ALLOW_THREADS;
+ ret = gpio_mockup_probe(self->mockup, num_chips, chip_sizes, flags);
+ Py_END_ALLOW_THREADS;
+ PyMem_RawFree(chip_sizes);
+ if (ret)
+ return NULL;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *gpiomockup_Mockup_remove(gpiomockup_MockupObject *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ int ret;
+
+ Py_BEGIN_ALLOW_THREADS;
+ ret = gpio_mockup_remove(self->mockup);
+ Py_END_ALLOW_THREADS;
+ if (ret) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *gpiomockup_Mockup_chip_name(gpiomockup_MockupObject *self,
+ PyObject *args)
+{
+ unsigned int idx;
+ const char *name;
+ int ret;
+
+ ret = PyArg_ParseTuple(args, "I", &idx);
+ if (!ret)
+ return NULL;
+
+ name = gpio_mockup_chip_name(self->mockup, idx);
+ if (!name) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ return NULL;
+ }
+
+ return PyUnicode_FromString(name);
+}
+
+static PyObject *gpiomockup_Mockup_chip_path(gpiomockup_MockupObject *self,
+ PyObject *args)
+{
+ unsigned int idx;
+ const char *path;
+ int ret;
+
+ ret = PyArg_ParseTuple(args, "I", &idx);
+ if (!ret)
+ return NULL;
+
+ path = gpio_mockup_chip_path(self->mockup, idx);
+ if (!path) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ return NULL;
+ }
+
+ return PyUnicode_FromString(path);
+}
+
+static PyObject *gpiomockup_Mockup_chip_num(gpiomockup_MockupObject *self,
+ PyObject *args)
+{
+ unsigned int idx;
+ int ret, num;
+
+ ret = PyArg_ParseTuple(args, "I", &idx);
+ if (!ret)
+ return NULL;
+
+ num = gpio_mockup_chip_num(self->mockup, idx);
+ if (num < 0) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ return NULL;
+ }
+
+ return PyLong_FromLong(num);
+}
+
+static PyObject *gpiomockup_Mockup_chip_get_value(gpiomockup_MockupObject *self,
+ PyObject *args)
+{
+ unsigned int chip_idx, line_offset;
+ int ret, val;
+
+ ret = PyArg_ParseTuple(args, "II", &chip_idx, &line_offset);
+ if (!ret)
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS;
+ val = gpio_mockup_get_value(self->mockup, chip_idx, line_offset);
+ Py_END_ALLOW_THREADS;
+ if (val < 0) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ return NULL;
+ }
+
+ return PyLong_FromUnsignedLong(val);
+}
+
+static PyObject *gpiomockup_Mockup_chip_set_pull(gpiomockup_MockupObject *self,
+ PyObject *args)
+{
+ unsigned int chip_idx, line_offset;
+ int ret, pull;
+
+ ret = PyArg_ParseTuple(args, "IIi", &chip_idx, &line_offset, &pull);
+ if (!ret)
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS;
+ ret = gpio_mockup_set_pull(self->mockup, chip_idx, line_offset, pull);
+ Py_END_ALLOW_THREADS;
+ if (ret) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef gpiomockup_Mockup_methods[] = {
+ {
+ .ml_name = "probe",
+ .ml_meth = (PyCFunction)(void (*)(void))gpiomockup_Mockup_probe,
+ .ml_flags = METH_VARARGS | METH_KEYWORDS,
+ },
+ {
+ .ml_name = "remove",
+ .ml_meth = (PyCFunction)gpiomockup_Mockup_remove,
+ .ml_flags = METH_NOARGS,
+ },
+ {
+ .ml_name = "chip_name",
+ .ml_meth = (PyCFunction)gpiomockup_Mockup_chip_name,
+ .ml_flags = METH_VARARGS,
+ },
+ {
+ .ml_name = "chip_path",
+ .ml_meth = (PyCFunction)gpiomockup_Mockup_chip_path,
+ .ml_flags = METH_VARARGS,
+ },
+ {
+ .ml_name = "chip_num",
+ .ml_meth = (PyCFunction)gpiomockup_Mockup_chip_num,
+ .ml_flags = METH_VARARGS,
+ },
+ {
+ .ml_name = "chip_get_value",
+ .ml_meth = (PyCFunction)gpiomockup_Mockup_chip_get_value,
+ .ml_flags = METH_VARARGS,
+ },
+ {
+ .ml_name = "chip_set_pull",
+ .ml_meth = (PyCFunction)gpiomockup_Mockup_chip_set_pull,
+ .ml_flags = METH_VARARGS,
+ },
+ { }
+};
+
+static PyTypeObject gpiomockup_MockupType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ .tp_name = "gpiomockup.Mockup",
+ .tp_basicsize = sizeof(gpiomockup_MockupObject),
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_new = PyType_GenericNew,
+ .tp_init = (initproc)gpiomockup_Mockup_init,
+ .tp_dealloc = (destructor)gpiomockup_Mockup_dealloc,
+ .tp_methods = gpiomockup_Mockup_methods,
+};
+
+static PyModuleDef gpiomockup_Module = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "gpiomockup",
+ .m_size = -1,
+};
+
+PyMODINIT_FUNC PyInit_gpiomockup(void)
+{
+ PyObject *module, *val;
+ int ret;
+
+ module = PyModule_Create(&gpiomockup_Module);
+ if (!module)
+ return NULL;
+
+ ret = PyType_Ready(&gpiomockup_MockupType);
+ if (ret)
+ return NULL;
+ Py_INCREF(&gpiomockup_MockupType);
+
+ ret = PyModule_AddObject(module, "Mockup",
+ (PyObject *)&gpiomockup_MockupType);
+ if (ret)
+ return NULL;
+
+ val = PyLong_FromLong(gpiomockup_FLAG_NAMED_LINES);
+ if (!val)
+ return NULL;
+
+ ret = PyDict_SetItemString(gpiomockup_MockupType.tp_dict,
+ "FLAG_NAMED_LINES", val);
+ if (ret)
+ return NULL;
+
+ return module;
+}