From ba4c5175ebaa0a942ba0294be1cc488a29915bc2 Mon Sep 17 00:00:00 2001 From: Stefan Kratochwil Date: Tue, 11 Feb 2025 22:31:56 +0100 Subject: [PATCH 1/5] WIP: First working example for an async background task --- software/boards/RPI_PICO_W/manifest.py | 3 +++ software/src/nfc/__init__.py | 1 + software/src/nfc/main.py | 12 +++++++++ software/src/nfc/nfc.py | 37 ++++++++++++++++++++++++++ 4 files changed, 53 insertions(+) create mode 100644 software/src/nfc/__init__.py create mode 100644 software/src/nfc/main.py create mode 100644 software/src/nfc/nfc.py diff --git a/software/boards/RPI_PICO_W/manifest.py b/software/boards/RPI_PICO_W/manifest.py index 8f5a63a..58eb9e0 100644 --- a/software/boards/RPI_PICO_W/manifest.py +++ b/software/boards/RPI_PICO_W/manifest.py @@ -9,7 +9,10 @@ module("rp2_neopixel.py", "../../src") require("sdcard") require("aiorepl") +# Third party modules module("mfrc522.py", "../../lib/micropython-mfrc522/") module("microdot.py", "../../lib/microdot/src/microdot/") +# TonberryPico modules module("audiocore.py", "../../src/audiocore") +package("nfc", base_path="../../src/") diff --git a/software/src/nfc/__init__.py b/software/src/nfc/__init__.py new file mode 100644 index 0000000..c182b02 --- /dev/null +++ b/software/src/nfc/__init__.py @@ -0,0 +1 @@ +from nfc.nfc import Nfc diff --git a/software/src/nfc/main.py b/software/src/nfc/main.py new file mode 100644 index 0000000..82834ae --- /dev/null +++ b/software/src/nfc/main.py @@ -0,0 +1,12 @@ +import asyncio + +from nfc import Nfc + +async def main(): + n = Nfc() + while True: + await asyncio.sleep_ms(500) + print(f'{n.get_last_uid()}') + + +asyncio.run(main()) diff --git a/software/src/nfc/nfc.py b/software/src/nfc/nfc.py new file mode 100644 index 0000000..406385e --- /dev/null +++ b/software/src/nfc/nfc.py @@ -0,0 +1,37 @@ +import asyncio +import time + +from mfrc522 import MFRC522 + +class Nfc: + def __init__(self): + self.reader = MFRC522(spi_id=1, sck=10, miso=12, mosi=11, cs=13, rst=9, tocard_retries=10) + self.last_uid = None + self.last_uid_timestamp = None + self.task = asyncio.create_task(self._reader_poll_task()) + + + @staticmethod + def uid_to_string(uid: list): + return '0x' + ''.join(f'{i:02x}' for i in uid) + + + async def _reader_poll_task(self, poll_interval_ms: int = 50) -> list: + print('reader_poll_task alive') + + while True: + self.reader.init() + + # For now we omit the tag type + (stat, _) = self.reader.request(self.reader.REQIDL) + if stat == self.reader.OK: + (stat, uid) = self.reader.SelectTagSN() + if stat == self.reader.OK: + self.last_uid = uid + self.last_uid_timestamp = time.ticks_us() + + await asyncio.sleep_ms(poll_interval_ms) + + + def get_last_uid(self): + return self.last_uid, self.last_uid_timestamp From 5cda9891f5c13b4f84921283cad8d21e2f78f026 Mon Sep 17 00:00:00 2001 From: Stefan Kratochwil Date: Tue, 18 Feb 2025 22:09:50 +0100 Subject: [PATCH 2/5] Added docstrings and license information. Moved main.py contents to documentation as a simple example. --- software/src/nfc/__init__.py | 4 ++++ software/src/nfc/main.py | 12 ------------ software/src/nfc/nfc.py | 37 +++++++++++++++++++++++++++++++----- 3 files changed, 36 insertions(+), 17 deletions(-) delete mode 100644 software/src/nfc/main.py diff --git a/software/src/nfc/__init__.py b/software/src/nfc/__init__.py index c182b02..516cdd9 100644 --- a/software/src/nfc/__init__.py +++ b/software/src/nfc/__init__.py @@ -1 +1,5 @@ +''' +SPDX-License-Identifier: MIT +Copyright (c) 2025 Stefan Kratochwil (Kratochwil-LA@gmx.de) +''' from nfc.nfc import Nfc diff --git a/software/src/nfc/main.py b/software/src/nfc/main.py deleted file mode 100644 index 82834ae..0000000 --- a/software/src/nfc/main.py +++ /dev/null @@ -1,12 +0,0 @@ -import asyncio - -from nfc import Nfc - -async def main(): - n = Nfc() - while True: - await asyncio.sleep_ms(500) - print(f'{n.get_last_uid()}') - - -asyncio.run(main()) diff --git a/software/src/nfc/nfc.py b/software/src/nfc/nfc.py index 406385e..ca52256 100644 --- a/software/src/nfc/nfc.py +++ b/software/src/nfc/nfc.py @@ -1,24 +1,49 @@ +''' +SPDX-License-Identifier: MIT +Copyright (c) 2025 Stefan Kratochwil (Kratochwil-LA@gmx.de) +''' + import asyncio import time from mfrc522 import MFRC522 class Nfc: + ''' + This class implements an asyncio task which continuously polls the mfrc522 nfc reader. If a new + nfc tag was detected, the uid of the tag is stored alongside with the current system time. This + information can be retrieved again. + + Usage example: + + import asyncio + from nfc import Nfc + + async def main(): + n = Nfc() + while True: + await asyncio.sleep_ms(500) + print(f'{n.get_last_uid()}') + + asyncio.run(main()) + ''' def __init__(self): self.reader = MFRC522(spi_id=1, sck=10, miso=12, mosi=11, cs=13, rst=9, tocard_retries=10) self.last_uid = None self.last_uid_timestamp = None self.task = asyncio.create_task(self._reader_poll_task()) - @staticmethod def uid_to_string(uid: list): + ''' + Helper function to convert a nfc tag uid to a readable string. + ''' return '0x' + ''.join(f'{i:02x}' for i in uid) - async def _reader_poll_task(self, poll_interval_ms: int = 50) -> list: - print('reader_poll_task alive') - + ''' + Periodically polls the nfc reader. Stores tag uid and timestamp if a new tag was found. + ''' while True: self.reader.init() @@ -32,6 +57,8 @@ class Nfc: await asyncio.sleep_ms(poll_interval_ms) - def get_last_uid(self): + ''' + Returns the last read nfc tag uid alongside with the timestamp it was stored at. + ''' return self.last_uid, self.last_uid_timestamp From 976bc4053c61512a9670dd2e5bdfa8df5880893e Mon Sep 17 00:00:00 2001 From: Stefan Kratochwil Date: Tue, 18 Mar 2025 21:02:25 +0100 Subject: [PATCH 3/5] Made nfc.py executable, increased tocard_retries to 20 due to increased CPU frequency. --- software/src/nfc/nfc.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/software/src/nfc/nfc.py b/software/src/nfc/nfc.py index ca52256..8ef597b 100644 --- a/software/src/nfc/nfc.py +++ b/software/src/nfc/nfc.py @@ -28,7 +28,7 @@ class Nfc: asyncio.run(main()) ''' def __init__(self): - self.reader = MFRC522(spi_id=1, sck=10, miso=12, mosi=11, cs=13, rst=9, tocard_retries=10) + self.reader = MFRC522(spi_id=1, sck=10, miso=12, mosi=11, cs=13, rst=9, tocard_retries=20) self.last_uid = None self.last_uid_timestamp = None self.task = asyncio.create_task(self._reader_poll_task()) @@ -62,3 +62,13 @@ class Nfc: Returns the last read nfc tag uid alongside with the timestamp it was stored at. ''' return self.last_uid, self.last_uid_timestamp + + +if __name__ == '__main__': + async def main(): + n = Nfc() + while True: + await asyncio.sleep_ms(500) + print(f'{n.get_last_uid()}') + + asyncio.run(main()) From a2a9c824710b5df337cfb25a9fa2e85fe221d85f Mon Sep 17 00:00:00 2001 From: Stefan Kratochwil Date: Tue, 25 Mar 2025 22:05:14 +0100 Subject: [PATCH 4/5] Nfc module now depends on initialized MFRC522, fixed incorrect return type hint. --- software/src/nfc/nfc.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/software/src/nfc/nfc.py b/software/src/nfc/nfc.py index 8ef597b..242cbf6 100644 --- a/software/src/nfc/nfc.py +++ b/software/src/nfc/nfc.py @@ -27,8 +27,8 @@ class Nfc: asyncio.run(main()) ''' - def __init__(self): - self.reader = MFRC522(spi_id=1, sck=10, miso=12, mosi=11, cs=13, rst=9, tocard_retries=20) + def __init__(self, reader: MFRC522): + self.reader = reader self.last_uid = None self.last_uid_timestamp = None self.task = asyncio.create_task(self._reader_poll_task()) @@ -40,7 +40,7 @@ class Nfc: ''' return '0x' + ''.join(f'{i:02x}' for i in uid) - async def _reader_poll_task(self, poll_interval_ms: int = 50) -> list: + async def _reader_poll_task(self, poll_interval_ms: int = 50): ''' Periodically polls the nfc reader. Stores tag uid and timestamp if a new tag was found. ''' @@ -66,7 +66,8 @@ class Nfc: if __name__ == '__main__': async def main(): - n = Nfc() + reader = MFRC522(spi_id=1, sck=10, miso=12, mosi=11, cs=13, rst=9, tocard_retries=20) + n = Nfc(reader=reader) while True: await asyncio.sleep_ms(500) print(f'{n.get_last_uid()}') From ee43ad816a9a3d15164ae0656f350597c99a0e4b Mon Sep 17 00:00:00 2001 From: Stefan Kratochwil Date: Tue, 25 Mar 2025 22:16:38 +0100 Subject: [PATCH 5/5] Providing public interface, fixed formatting. --- software/src/nfc/__init__.py | 2 ++ software/src/nfc/nfc.py | 1 + 2 files changed, 3 insertions(+) diff --git a/software/src/nfc/__init__.py b/software/src/nfc/__init__.py index 516cdd9..bb3810a 100644 --- a/software/src/nfc/__init__.py +++ b/software/src/nfc/__init__.py @@ -3,3 +3,5 @@ SPDX-License-Identifier: MIT Copyright (c) 2025 Stefan Kratochwil (Kratochwil-LA@gmx.de) ''' from nfc.nfc import Nfc + +__all__ = ['Nfc'] diff --git a/software/src/nfc/nfc.py b/software/src/nfc/nfc.py index 242cbf6..13f8e6d 100644 --- a/software/src/nfc/nfc.py +++ b/software/src/nfc/nfc.py @@ -8,6 +8,7 @@ import time from mfrc522 import MFRC522 + class Nfc: ''' This class implements an asyncio task which continuously polls the mfrc522 nfc reader. If a new