2017-10-18 1 views
1

프로그램을 Tornado에서 Asyncio로 변환하려고 시도하고 있으며 첫 번째 단계는 실제 asyncio 이벤트 루프를 described here으로 사용하는 것입니다.Python Asyncio를 사용하여 GPIO 인터럽트를 기다립니다.

이 응용 프로그램은 임베디드 리눅스 컴퓨터에서 실행되며 sysfs/gpio subsystem을 통해 GPIO를 사용하고 일부 GPIO에서는 인터럽트를 기다리고 있습니다. 내가 직접 수행하여 토네이도 IOLoop이 점을 통합 할 수 있었다 :

코드 조각에서
# Register with the queue 
self.io_loop.add_handler(
    self.gpio._value_file, self._handle_interrupt, self.io_loop._EPOLLPRI | self.io_loop.ERROR 
) 

, _value_file는 GPIO가 읽을 수있는 파일의 파일 핸들입니다. EPOLLPRI 이벤트는 해당 GPIO에서 인터럽트가 발생할 때마다 발생합니다. 토네이도에서는 아주 잘 작동합니다. 인터럽트가 발생한 직후에 _handle_interrupt 함수를 호출합니다.

내 문제는이 문제를 원시 asyncio 이벤트 루프로 변환 할 수 없다는 것입니다. the documentation for watching file descriptors에서는 독자와 작성자를 추가하는 기능 만 있지만 파일 설명자에서는 일반 이벤트 마스크를 감시 할 기능이 없습니다. 경우 그 그러나 C.로 전환하기 때문에 내가 이렇게 보이는 asyncio IOLoop에 토네이도 IOLoop에서 전화를 번역 토네이도 계층에서 찾고, 코드에 다이빙을 할 수 있습니다 :

def add_handler(self, fd, handler, events): 
    fd, fileobj = self.split_fd(fd) 
    if fd in self.handlers: 
     raise ValueError("fd %s added twice" % fd) 
    self.handlers[fd] = (fileobj, stack_context.wrap(handler)) 
    if events & IOLoop.READ: 
     self.asyncio_loop.add_reader(
      fd, self._handle_events, fd, IOLoop.READ) 
     self.readers.add(fd) 
    if events & IOLoop.WRITE: 
     self.asyncio_loop.add_writer(
      fd, self._handle_events, fd, IOLoop.WRITE) 
     self.writers.add(fd) 

읽기 전용 WRITE 플래그가 변환되고 다른 모든 플래그는 무시됩니다.

누군가는 현재 asyncio를 사용하여 READ 및 WRITE 이벤트를 제외한 파일 설명자의 이벤트를 볼 수 없다고 확인할 수 있습니까? 아니면 내가 뭔가 잘못하고 실제로 방법이 있습니까?

답변

2

나는 지금 이것을위한 해결책을 발견했다. 저의 주요 정보 출처는 this thread in the Python-tulip groupthis piece of code으로 약간 채택해야했습니다.

POLLPRI 이벤트를 감시하는 데 사용할 수있는 epoll은 그 자체로 파일 설명자입니다. epoll이보고하는 FD에서 이벤트가 발생할 때마다 epoll 파일 설명자는 add_reader으로 asyncio를 사용하여 볼 수있는 POLLIN 이벤트를 생성합니다. 그래서 그 대신 직접 등록, 우리는 수동으로는 epoll 구조를 만드는 등처럼 ioloop에 등록 :

self.epoll = select.epoll() 
self.io_loop.add_reader(self.epoll.fileno(), self._handle_interrupt) 

실제 인터럽트 이벤트

다음이 시점에서 epoll 파일 구조

self.epoll.register(self.gpio._value_file, select.POLLPRI) 

에 등록, 인터럽트 이벤트는 _handle_interrupt 함수에서 수신됩니다. 실제로 이벤트 처리기에서 epoll 파일 구조를 폴링해야합니다, 또는 지속적으로 그들이 유사한 작업을 수행하기 때문에 높은 수준의 selectors 대신 낮은 수준의 select 기능을 사용하는 것이 중요 읽기 이벤트

def _handle_interrupt(self): 
    self.epoll.poll(0) 
    ... 

를 생성합니다 asyncio과 같은 이벤트 플래그 필터링. 냈다 다음 코드는 selectors.EpollSelector에서입니다 :

def register(self, fileobj, events, data=None): 
    key = super().register(fileobj, events, data) 
    epoll_events = 0 
    if events & EVENT_READ: 
     epoll_events |= select.EPOLLIN 
    if events & EVENT_WRITE: 
     epoll_events |= select.EPOLLOUT 
    try: 
     self._epoll.register(key.fd, epoll_events) 
    except BaseException: 
     super().unregister(fileobj) 
     raise 
    return key 

그것은 볼 수있는, 읽기 및 쓰기를 제외한 모든 이벤트가 필터링됩니다. 따라서 상위 레벨 인터페이스를 사용하여 POLLPRI 이벤트를 감시 할 수 없습니다. 따라서 하위 인터페이스를 사용하십시오.

나는이 문제에 사람들이 걸림돌이되는 것을 돕기를 바랍니다.

관련 문제