Search code examples
pythonpython-3.xeventsembedded-linuxgpio

Python how to read an anonymous linux file for a GPIO event


Working on a python 3 implementation of the new linux gpio implementation. The initial setup works great:

class gpioevent_request(ctypes.Structure):
    _pack_ = 1
    _fields_ = [
                ('lineoffset', ctypes.c_ulong),
                ('handleflags', ctypes.c_ulong),
                ('eventflags', ctypes.c_ulong),
                ('consumer_label', ctypes.c_char * 32),
                ('fd', ctypes.c_int),
                ]

class gpioevent_data(ctypes.Structure):
    _pack_ = 1
    _fields_ = [
                ('timestamp', ctypes.c_ulonglong),
                ('id', ctypes.c_ulong),
                ]

self.event = gpioevent_request()
self.eventData = gpioevent_data()
...
# Open /dev/gpiochipx with os.open and set up the event structure
...
fcntl.ioctl(self._fd, GPIO_GET_LINEEVENT_IOCTL, self.event)

My challenge comes when I try to read the event information that is stored in the anonymous linux file created by the GPIO_GET_LINEEVENT_IOCTL call.

If I try os.read I get an invalid argument response:

os.read(self.event.fd, bytesToRead)

If I try libc read then it will read the file but I get all zeros for my data (timestamp and id):

import ctypes.util
libc = ctypes.CDLL(ctypes.util.find_library('c'))
self.f_read = libc.read
self.f_read(self.event.fd, ctypes.byref(self.eventData), ctypes.sizeof(self.eventData))

using epoll does seem to trigger the file on the rising or falling edge on my input pin but it works intermittently:

p = select.epoll()
p.register(self.event.fd, select.EPOLLIN | select.EPOLLET | select.EPOLLPRI)

Any insight is appreciated greatly.


Solution

  • My suspicion is that you don't want to _pack_ your ctypes.Structures at all. The docs say

    By default, Structure and Union fields are aligned in the same way the C compiler does it. It is possible to override this behavior be specifying a pack class attribute in the subclass definition.

    Since these are structures you're sharing with libc calls, you'll want them in the same default layout that it's used to seeing them.