KevinGisi.com Whatever is here is here

Near Field Communication

Great news — it looks like NFC stickers are going to be the right path forward. Received a bundle today, stuck a sticker on the inside of a cartridge, and my iPhone can pick it up a centimeter away from the outside of the cartridge. Next step is to try to verify with a reader chip.

Unfortunately, the chip I got doesn’t have a datasheet. Thankfully, it’s a common enough model, there’s a guide to its use with the Raspberry Pi already. Lucky me, I’ve learned a little bit about the I2C protocol (which the EEPROMs use), and now I’m learning a bit about the SPI protocol.

After hooking up the RC522 chip via the breadboard and lovingly plagiarizing some code from the tutorial, I got things working. Mostly. While I could pull a unique ID from the NFC stickers, the library did announce an AUTH FAILURE. It was reporting it on STDOUT, so I could have just tried to suppress the error, but it seems it’s related to the NFC stickers I have being an older standard. I came across this reported issue, and was able to cobble together a solution based around the workaround listed there (the relevant issue).

Remember: we don’t need to actually write any data to these stickers. We just need a unique serial number that the Raspberry Pi can use to drive its own behavior. Merging that with our existing app code, here’s where we’re at:

#!/usr/bin/env python3

import subprocess
import RPi.GPIO as GPIO
from mfrc522 import MFRC522
from time import sleep

ROM_DICT = {
    '04:6c:6a:8a:92:4c:68:80:36:48:00:00:e1:10:3e:00': 'Super Mario World (USA).sfc',
    '04:53:6c:b3:92:4c:68:81:37:48:00:00:e1:10:3e:00': 'Donkey Kong Country (U).smc'
}

def main():
    try:
        # Await power on
        cartridge_id = get_nfc_id()
        print("CARTRIDGE is %s"%cartridge_id)
        rom = ROM_DICT[cartridge_id]
        print("ROM is %s"%rom)
        game = run_game(rom)
        game.wait()
        # On power off, kill the subprocess
        # On reset, restart the subprocess
    finally:
        cleanup()

def run_game(rom):
    return subprocess.Popen([
        '/opt/retropie/emulators/retroarch/bin/retroarch',
        '-L', '/opt/retropie/libretrocores/lr-snes9x2010/snes9x2010_libretro.so',
        '--config', '/opt/retropie/configs/snes/retroarch.cfg',
        '/home/pi/RetroPie/roms/snes/%s'%(rom),
        '--appendconfig', '/dev/shm/retroarch.cfg'])

def get_nfc_id():
    reader = MFRC522()
    while True:
        status, _ = reader.MFRC522_Request(reader.PICC_REQIDL)
        if status != reader.MI_OK:
            sleep(0.1)
            continue
        status, backData = reader.MFRC522_Anticoll()
        buf = reader.MFRC522_Read(0)
        reader.MFRC522_Request(reader.PICC_HALT)
        if buf:
            return(':'.join(format(n, '02x') for n in buf))

def cleanup():
    GPIO.cleanup()

if __name__ == '__main__':
    main()

I opened up a second cartridge to attach a second sticker, and gave it a whirl. Thrilled to report that it works as-expected! Assuming that we can mount the reader within a centimeter of the back of the SNES cartridge, we’re good to go!

We’ll revisit the script at a later point when we’ve moved a bit further on with the housing. We’ll want to wire up the power and reset buttons — as well as the power indicator light — to some of the remaining GPIO pins, and then update our script to support the interrupts.

Next we have a big decision on our hands: are we modding an existing console, or building ourselves something new?