2017-04-10 3 views
0

내 프로젝트에 Adafruit PN532 nfc https://www.adafruit.com/product/364 브레이크 아웃 카드를 사용할 계획입니다.Python 논 블로킹 pn532 태그 읽기

이 코드 샘플 에서처럼 루프를 피하기 위해 비 차단 코드를 파이썬 (인터럽트를 사용하여?)에 작성하는 방법이 있습니까?

https://github.com/adafruit/Adafruit_Python_PN532/blob/master/examples/readmifare.py

+0

@Aaron의 답변에 따라 해봤 코드입니다. 파이썬 3.x의 asyncio 모듈은 기본적인 이벤트 핸들러 클래스를 내장하고 있습니다. https://docs.python.org/3/library/asyncio-eventloop.html – Aaron

+1

궁극적으로 이벤트를 기다리기 위해서는 무엇인가가 블로킹되어야하며, 이벤트 핸들러 해당 이벤트를 올바른 콜백 함수로 보내 처리합니다. 콜백이 즉시 반환되는 한 아무런 문제가 없습니다. API에서 솔루션을 함께 패치해야하는 경우 변경할 수 없거나 변경하고 싶지 않습니다. 스레드 내에서 블로킹 호출을 넣고 스레드가 값을 업데이트하고 콜백이 해당 값을 폴링합니다 (잠금 장치와 원하는 안전성 요소 포함). – Aaron

+0

흥미롭게도 adafruit 라이브러리의 timeout 키워드는 무시됩니다. – Aaron

답변

1

(내 의견에 대하여 ..) asyncio 조금 가벼운 무게이지만, threading 또한 시스템을 호출하는 이벤트를 가지고 있으며, 현재 더 나은 (스레딩 asyncio보다 더 오래되고와있다 문서화 조금 조금 덜 추상적입니다.) 내가 이해할 때, 당신은 다른 작업을하면서 블로킹 리소스를 읽을 수 있기를 원합니다. 이 경우 텍스트 파일을 표준 출력으로 천천히 인쇄하면서 카드를 읽을 때까지 대기 할 스레드를 생성합니다. 이것은 그런 식으로하는 방법의 예일뿐입니다. 비슷한 결과를 얻는 방법은 여러 가지가 있습니다.

import binascii 
import time 
import threading 
from collections import deque #use as a fifo queue 

queue = deque() #queue to pass information from thread to main process 
queue_lock = threading.Lock() #prevent possible issues from 
txt_file = '50_shades_of_grey.txt' #don't ask ;) 
running = True 

def nfc_reader(): 
    #copied from adafruit example 
    import Adafruit_PN532 as PN532 
    CS = 18 
    MOSI = 23 
    MISO = 24 
    SCLK = 25 

    pn532 = PN532.PN532(cs=CS, sclk=SCLK, mosi=MOSI, miso=MISO) 
    pn532.begin() 
    ic, ver, rev, support = pn532.get_firmware_version() 
    print(f'Found PN532 with firmware version: {ver}.{rev}') 
    pn532.SAM_configuration() 

    # Main loop to detect cards and read a block. 
    print('Waiting for MiFare card...') 
    while True: 
     if not running: #cheap way to kill a thread nicely (cheap ain't pretty) 
      return 
     #don't bother specifying a timeout, they forgot to support it in the library 
     uid = pn532.read_passive_target() 
     # Try again if no card is available. 
     if uid is None: 
      continue 
     print('Found card with UID: 0x{0}'.format(binascii.hexlify(uid))) 
     # Authenticate block 4 for reading with default key (0xFFFFFFFFFFFF). 
     if not pn532.mifare_classic_authenticate_block(uid, 4, PN532.MIFARE_CMD_AUTH_B, 
                 [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]): 
      print('Failed to authenticate block 4!') 
      continue 
     # Read block 4 data. 
     data = pn532.mifare_classic_read_block(4) 
     if data is None: 
      print('Failed to read block 4!') 
      continue 
     # make sure our queue is free 
     with queue_lock: 
      # replaced print with deque.append 
      queue.append(f'Read block 4: 0x{binascii.hexlify(data[:4])}') 
     #optionally emit some sort of signal that data is ready. In our case the main loop will chech periodically on it's own 

# Main program 
nfc_thread = threading.Thread(target=nfc_reader) 
nfc_thread.start() 

with open(txt_file, 'r') as f: 
    while True: #also cheap, but easy 
     if queue: #bool(deque) works like bool(list) 
      with queue_lock: 
       print("we found a card!") 
       print(queue.popleft()) 
       continue 
     try: 
      print(next(f)) #otherwise go back to more interesting matters 
     except StopIteration: 
      running = False 
      nfc_thread.join() 
      break 
     time.sleep(.9) #notice loop time will be less than timeout on nfc read. 
         # you could put the printing of the *book* into another thread 
         # and use events to immediately call your return from your 
         # nfc reader
+1

코드없이 코드를 시도했습니다. 'book reading'base :) 당신의 답변에 감사드립니다. 이제 코어에서 무한 루프를 실행하지 않고 프로그램을 유지하는 방법을 스스로 묻습니다. –

+0

메인 스레드가 자식 스레드보다 먼저 종료되면 고아가 생깁니다. 이 오류는 오류가 발생하거나 (조용히) 또는 메모리가 부족할 때까지 계속 실행될 것입니다 (고아원에서 충분한 공간이 아님). 궁극적으로는 여분의 스레드가 완료 될 때까지 주 스레드를 계속 유지해야합니다. 주 스레드가 아직 살아 있어야하는 동안 CPU 또는 RAM의 상당한 양을 차지해야한다는 것을 의미하지는 않습니다 ... 이벤트 청취자는 0 % 근처로 CPU를 가져올 수 있으며 자동으로 – Aaron

+0

을 기다리는 동안 분류 할 수 있습니다 메인 스레드가 끝나자 마자 unceremoniously 삭제됩니다 "데몬"으로 스레드. 스레드가 잘못된 시간에 종료되면 파일 핸들을 열어 둘 수 있기 때문에 파일 읽기/쓰기와 같은 작업은 데몬 스레드에서 수행하지 않아야합니다. – Aaron

0

여기에 당신이 이벤트 루프와 이벤트 기반의 코딩 스타일을 볼 필요가

import binascii 
import time 
import threading 
from collections import deque #use as a fifo queue 
import RPi.GPIO as GPIO 
import Adafruit_PN532 as PN532 

queue = deque() #queue to pass information from thread to main process 
queue_lock = threading.Lock() #prevent possible issues from 
running = True 

def nfc_reader(): 
    CS = 18 
    MOSI = 23 
    MISO = 24 
    SCLK = 25 

    pn532 = PN532.PN532(cs=CS, sclk=SCLK, mosi=MOSI, miso=MISO) 
    pn532.begin() 
    ic, ver, rev, support = pn532.get_firmware_version() 
    print('Found PN532 with firmware version: {0}.{1}'.format(ver, rev)) 
    pn532.SAM_configuration() 

    while True: 
     if not running: #cheap way to kill a thread nicely (cheap ain't pretty) 
      return 

     uid = pn532.read_passive_target() 
     if uid is None: 
      continue 
     #print('card read') 
     message = 'Read card\n{0}'.format(binascii.hexlify(uid)) 

     # make sure our queue is free 
     with queue_lock: 
      # replaced print with deque.append 
      queue.append(message) 
      time.sleep(1) 
     #optionally emit some sort of signal that data is ready. In our case the main loop will chech periodically on it's own 

# Main program 
nfc_thread = threading.Thread(target=nfc_reader) 
nfc_thread.start() 


while True: #also cheap, but easy 
    if queue: #bool(deque) works like bool(list) 
     with queue_lock: 
      print("we found a card!") 
      print(queue.popleft()) 
      continue 
    time.sleep(.9) #notice loop time will be less than timeout on nfc read. 
        # you could put the printing of the *book* into another thread 
        # and use events to immediately call your return from your 
        # nfc reader