Skip to content

Refactoring to save memory #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Sep 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ install:
- pip install circuitpython-build-tools Sphinx sphinx-rtd-theme
- pip install --force-reinstall pylint==1.9.2
script:
- pylint adafruit_pn532.py
- pylint adafruit_pn532/*.py
- ([[ ! -d "examples" ]] || pylint --disable=missing-docstring,invalid-name,bad-whitespace
examples/*.py)
- circuitpython-build-bundles --filename_prefix adafruit-circuitpython-pn532 --library_location .
Expand Down
Empty file added adafruit_pn532/__init__.py
Empty file.
186 changes: 1 addition & 185 deletions adafruit_pn532.py → adafruit_pn532/adafruit_pn532.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,8 @@
* Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
"""


import time
from digitalio import Direction
import adafruit_bus_device.i2c_device as i2c_device
import adafruit_bus_device.spi_device as spi_device

from micropython import const

Expand Down Expand Up @@ -105,13 +102,6 @@

_WAKEUP = const(0x55)

_SPI_STATREAD = const(0x02)
_SPI_DATAWRITE = const(0x01)
_SPI_DATAREAD = const(0x03)
_SPI_READY = const(0x01)

_I2C_ADDRESS = const(0x24)

_MIFARE_ISO14443A = const(0x00)

# Mifare Commands
Expand Down Expand Up @@ -186,22 +176,12 @@ def _reset(pin):
pin.value = True
time.sleep(0.1)

def reverse_bit(num):
"""Turn an LSB byte to an MSB byte, and vice versa. Used for SPI as
it is LSB for the PN532, but 99% of SPI implementations are MSB only!"""
result = 0
for _ in range(8):
result <<= 1
result += (num & 1)
num >>= 1
return result



class BusyError(Exception):
"""Base class for exceptions in this module."""
pass


class PN532:
"""PN532 driver base, must be extended for I2C/SPI/UART interfacing"""

Expand Down Expand Up @@ -464,167 +444,3 @@ def ntag2xx_read_block(self, block_number):
not read then None will be returned.
"""
return self.mifare_classic_read_block(block_number)[0:4] # only 4 bytes per page

class PN532_UART(PN532):
"""Driver for the PN532 connected over Serial UART"""
def __init__(self, uart, *, irq=None, reset=None, debug=False):
"""Create an instance of the PN532 class using Serial connection.
Optional IRQ pin (not used), reset pin and debugging output.
"""
self.debug = debug
self._irq = irq
self._uart = uart
super().__init__(debug=debug, reset=reset)

def _wakeup(self):
"""Send any special commands/data to wake up PN532"""
#self._write_frame([_HOSTTOPN532, _COMMAND_SAMCONFIGURATION, 0x01])
self.SAM_configuration()

def _wait_ready(self, timeout=1):
"""Wait `timeout` seconds"""
time.sleep(timeout)
return True

def _read_data(self, count):
"""Read a specified count of bytes from the PN532."""
frame = self._uart.read(count)
if not frame:
raise BusyError("No data read from PN532")
if self.debug:
print("Reading: ", [hex(i) for i in frame])
else:
time.sleep(0.1)
return frame

def _write_data(self, framebytes):
"""Write a specified count of bytes to the PN532"""
while self._uart.read(1): # this would be a lot nicer if we could query the # of bytes
pass
self._uart.write('\x55\x55\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') # wake up!
self._uart.write(framebytes)

class PN532_I2C(PN532):
"""Driver for the PN532 connected over I2C."""
def __init__(self, i2c, *, irq=None, reset=None, req=None, debug=False):
"""Create an instance of the PN532 class using I2C. Note that PN532
uses clock stretching. Optional IRQ pin (not used),
reset pin and debugging output.
"""
self.debug = debug
self._irq = irq
self._req = req
if reset:
_reset(reset)
self._i2c = i2c_device.I2CDevice(i2c, _I2C_ADDRESS)
super().__init__(debug=debug, reset=reset)

def _wakeup(self): # pylint: disable=no-self-use
"""Send any special commands/data to wake up PN532"""
if self._req:
self._req.direction = Direction.OUTPUT
self._req.value = True
time.sleep(0.1)
self._req.value = False
time.sleep(0.1)
self._req.value = True
time.sleep(0.5)

def _wait_ready(self, timeout=1):
"""Poll PN532 if status byte is ready, up to `timeout` seconds"""
status = bytearray(1)
timestamp = time.monotonic()
while (time.monotonic() - timestamp) < timeout:
try:
with self._i2c:
self._i2c.readinto(status)
except OSError:
self._wakeup()
continue
if status == b'\x01':
return True # No longer busy
else:
time.sleep(0.05) # lets ask again soon!
# Timed out!
return False

def _read_data(self, count):
"""Read a specified count of bytes from the PN532."""
# Build a read request frame.
frame = bytearray(count+1)
with self._i2c as i2c:
i2c.readinto(frame, end=1) # read status byte!
if frame[0] != 0x01: # not ready
raise BusyError
i2c.readinto(frame) # ok get the data, plus statusbyte
if self.debug:
print("Reading: ", [hex(i) for i in frame[1:]])
else:
time.sleep(0.1)
return frame[1:] # don't return the status byte

def _write_data(self, framebytes):
"""Write a specified count of bytes to the PN532"""
with self._i2c as i2c:
i2c.write(framebytes)

class PN532_SPI(PN532):
"""Driver for the PN532 connected over SPI. Pass in a hardware or bitbang
SPI device & chip select digitalInOut pin. Optional IRQ pin (not used),
reset pin and debugging output."""
def __init__(self, spi, cs_pin, *, irq=None, reset=None, debug=False):
"""Create an instance of the PN532 class using SPI"""
self.debug = debug
self._irq = irq
self._spi = spi_device.SPIDevice(spi, cs_pin)
super().__init__(debug=debug, reset=reset)

def _wakeup(self):
"""Send any special commands/data to wake up PN532"""
with self._spi as spi:
time.sleep(1)
spi.write(bytearray([0x00])) #pylint: disable=no-member
time.sleep(1)

def _wait_ready(self, timeout=1):
"""Poll PN532 if status byte is ready, up to `timeout` seconds"""
status = bytearray([reverse_bit(_SPI_STATREAD), 0])

timestamp = time.monotonic()
while (time.monotonic() - timestamp) < timeout:
with self._spi as spi:
time.sleep(0.02) # required
spi.write_readinto(status, status) #pylint: disable=no-member
if reverse_bit(status[1]) == 0x01: # LSB data is read in MSB
return True # Not busy anymore!
else:
time.sleep(0.01) # pause a bit till we ask again
# We timed out!
return False

def _read_data(self, count):
"""Read a specified count of bytes from the PN532."""
# Build a read request frame.
frame = bytearray(count+1)
# Add the SPI data read signal byte, but LSB'ify it
frame[0] = reverse_bit(_SPI_DATAREAD)

with self._spi as spi:
time.sleep(0.02) # required
spi.write_readinto(frame, frame) #pylint: disable=no-member
for i, val in enumerate(frame):
frame[i] = reverse_bit(val) # turn LSB data to MSB
if self.debug:
print("Reading: ", [hex(i) for i in frame[1:]])
return frame[1:]

def _write_data(self, framebytes):
"""Write a specified count of bytes to the PN532"""
# start by making a frame with data write in front,
# then rest of bytes, and LSBify it
rev_frame = [reverse_bit(x) for x in bytes([_SPI_DATAWRITE]) + framebytes]
if self.debug:
print("Writing: ", [hex(i) for i in rev_frame])
with self._spi as spi:
time.sleep(0.02) # required
spi.write(bytes(rev_frame)) #pylint: disable=no-member
111 changes: 111 additions & 0 deletions adafruit_pn532/i2c.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# Adafruit PN532 NFC/RFID control library.
# Author: Tony DiCola
#
# The MIT License (MIT)
#
# Copyright (c) 2015-2018 Adafruit Industries
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""
``adafruit_pn532.i2c``
====================================================

This module will let you communicate with a PN532 RFID/NFC shield or breakout
using I2C.

* Author(s): Original Raspberry Pi code by Tony DiCola, CircuitPython by ladyada,
refactor by Carter Nelson

"""

__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_PN532.git"

import time
import adafruit_bus_device.i2c_device as i2c_device
from digitalio import Direction
from micropython import const
from adafruit_pn532.adafruit_pn532 import PN532, BusyError, _reset

# pylint: disable=bad-whitespace
_I2C_ADDRESS = const(0x24)

class PN532_I2C(PN532):
"""Driver for the PN532 connected over I2C."""
def __init__(self, i2c, *, irq=None, reset=None, req=None, debug=False):
"""Create an instance of the PN532 class using I2C. Note that PN532
uses clock stretching. Optional IRQ pin (not used),
reset pin and debugging output.
"""
self.debug = debug
self._irq = irq
self._req = req
if reset:
_reset(reset)
self._i2c = i2c_device.I2CDevice(i2c, _I2C_ADDRESS)
super().__init__(debug=debug, reset=reset)

def _wakeup(self): # pylint: disable=no-self-use
"""Send any special commands/data to wake up PN532"""
if self._req:
self._req.direction = Direction.OUTPUT
self._req.value = True
time.sleep(0.1)
self._req.value = False
time.sleep(0.1)
self._req.value = True
time.sleep(0.5)

def _wait_ready(self, timeout=1):
"""Poll PN532 if status byte is ready, up to `timeout` seconds"""
status = bytearray(1)
timestamp = time.monotonic()
while (time.monotonic() - timestamp) < timeout:
try:
with self._i2c:
self._i2c.readinto(status)
except OSError:
self._wakeup()
continue
if status == b'\x01':
return True # No longer busy
else:
time.sleep(0.05) # lets ask again soon!
# Timed out!
return False

def _read_data(self, count):
"""Read a specified count of bytes from the PN532."""
# Build a read request frame.
frame = bytearray(count+1)
with self._i2c as i2c:
i2c.readinto(frame, end=1) # read status byte!
if frame[0] != 0x01: # not ready
raise BusyError
i2c.readinto(frame) # ok get the data, plus statusbyte
if self.debug:
print("Reading: ", [hex(i) for i in frame[1:]])
else:
time.sleep(0.1)
return frame[1:] # don't return the status byte

def _write_data(self, framebytes):
"""Write a specified count of bytes to the PN532"""
with self._i2c as i2c:
i2c.write(framebytes)
Loading