2017-04-10 1 views
0

私のプロジェクトでは、Adafruit PN532 nfc https://www.adafruit.com/product/364ブレークアウトカードを使用する予定です。Pythonノンブロッキングpn532タグの読み込み

このコードサンプルのようにループを避けるために、非ブロックコードをPythonで(割り込みを使用して)書く方法がありますか?

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

+0

@Aaronの回答に基づいて試してみたコードです。 Python 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

をあなたのスレッドはメインスレッドが終了するとすぐに削除されてしまう "デーモン"になります。間違った時刻にスレッドが終了した場合にファイルハンドルをオープンにしておくことができるため、ファイルの読み取り/書き込みのようなものはデーモンスレッドでは実行しないでください。 – 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 
関連する問題