{"id":13836332,"url":"https://github.com/josevcm/nfc-laboratory","last_synced_at":"2026-03-02T09:02:51.463Z","repository":{"id":38776148,"uuid":"231837379","full_name":"josevcm/nfc-laboratory","owner":"josevcm","description":" NFC signal and protocol analyzer using SDR receiver","archived":false,"fork":false,"pushed_at":"2026-02-14T07:46:50.000Z","size":97158,"stargazers_count":531,"open_issues_count":2,"forks_count":57,"subscribers_count":13,"default_branch":"master","last_synced_at":"2026-02-14T16:05:19.416Z","etag":null,"topics":["airspy","ask","bpsk","correlation","correlation-analysis","demodulation","dsp","felica-card","iso14443a","iso14443b","iso15963","nfc","nfc-a","nfc-b","nfc-forum","nfc-tag","nfc-v","radio","radio-frequency","sdr"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/josevcm.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"josevcm"}},"created_at":"2020-01-04T22:27:55.000Z","updated_at":"2026-02-13T12:01:02.000Z","dependencies_parsed_at":"2025-05-29T18:19:24.000Z","dependency_job_id":"01f71ffb-cb3e-4201-a554-86fa3121b9b7","html_url":"https://github.com/josevcm/nfc-laboratory","commit_stats":null,"previous_names":[],"tags_count":37,"template":false,"template_full_name":null,"purl":"pkg:github/josevcm/nfc-laboratory","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/josevcm%2Fnfc-laboratory","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/josevcm%2Fnfc-laboratory/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/josevcm%2Fnfc-laboratory/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/josevcm%2Fnfc-laboratory/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/josevcm","download_url":"https://codeload.github.com/josevcm/nfc-laboratory/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/josevcm%2Fnfc-laboratory/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29996278,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-02T01:47:34.672Z","status":"online","status_checked_at":"2026-03-02T02:00:07.342Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["airspy","ask","bpsk","correlation","correlation-analysis","demodulation","dsp","felica-card","iso14443a","iso14443b","iso15963","nfc","nfc-a","nfc-b","nfc-forum","nfc-tag","nfc-v","radio","radio-frequency","sdr"],"created_at":"2024-08-04T15:00:41.950Z","updated_at":"2026-03-02T09:02:51.417Z","avatar_url":"https://github.com/josevcm.png","language":"C++","funding_links":["https://github.com/sponsors/josevcm"],"categories":["C++"],"sub_categories":[],"readme":"# SDR nfc-laboratory 3\n\n[![GitHub Release](https://img.shields.io/github/release/josevcm/nfc-laboratory.svg)](https://github.com/josevcm/nfc-laboratory/releases/latest) \n[![Windows](https://img.shields.io/badge/Windows-Installer-0078D6?logo=windows\u0026logoColor=white)](https://github.com/josevcm/nfc-laboratory/releases/download/3.4.2/nfc-lab-3.4.2-x86_64-installer.exe)\n[![Linux](https://img.shields.io/badge/Linux-Debian%20%2F%20Ubuntu-FCC624?logo=linux\u0026logoColor=black)](https://github.com/josevcm/nfc-laboratory/releases/download/3.4.2/nfc-lab_3.4.2_amd64.deb)\n\nNFC signal sniffer and protocol decoder using SDR receiver for demodulation and decoding NFC-A, NFC-B, NFC-F and NFC-V\nsignals in real-time up to 424 Kbps. Logic analyzer for contact smart cards with protocol ISO7816.\n\n## Features\n\n- NFC Real-time signal capture and demodulation.\n- ISO7816 Real-time signal capture and decode.\n- Radio decoder for contactless ISO14443-A, ISO14443-B, ISO15693 and ISO18092.\n- Logic decoder for contact smart cards with protocol ISO7816.\n- Signal analysis and protocol timing.\n- Signal spectrum and wave view.\n- Signal frame and protocol detail view.\n- Signal export captures to compressed TRZ format.\n- Signal import from WAV and compressed TRZ format.\n- Support for AirSpy and RTL-SDR receivers.\n- Support for DreamSourceLab DSLogic Plus, Pro16 and Pro32 logic analyzer.\n\n## Installation\n\n### Windows\n\nYou can install NFC Laboratory using precompiled Windows installer from [releases](https://github.com/josevcm/nfc-laboratory/releases/latest/).\n\nOr download the portable installer from [releases](https://github.com/josevcm/nfc-laboratory/releases/latest/).\n\n### Linux\n\n#### Debian/Ubuntu\n\nDownload the `.deb` package from [releases](https://github.com/josevcm/nfc-laboratory/releases/latest/) and install:\n\n```bash\nsudo dpkg -i nfc-lab_*_amd64.deb\n```\n\n## Description\n\nBy using an SDR receiver it is possible to capture, demodulate and decode the NFC signal between the card and the\nreader.\n\nCurrently, detection and decoding is implemented for:\n\n- NFC-A (ISO14443A): 106kbps, 212kbps and 424kbps with ASK / BPSK modulation.\n- NFC-B (ISO14443B): 106kbps, 212kbps and 424kbps with ASK / BPSK modulation.\n- NFC-V (ISO15693): 26kbps and 53kbps, 1 of 4 code and 1 of 256 code PPM / BPSK modulation (pending FSK).\n- NFC-F (ISO18092): Preliminary support to 212kbps and 424kbps with manchester modulation.\n\nFor contact smart cards, the ISO7816 protocol is implemented with the help of a logic analyzer from DreamSourceLab.\n\n## Application screenshots\n\nMain signal view.\n\n![APP](doc/img/nfc-lab-screenshot0.png \"Main Signal view\")\n\n![APP](doc/img/nfc-lab-screenshot1.png \"Main Signal view\")\n\nNFC wave detail view.\n\n![APP](doc/img/nfc-lab-screenshot2.png \"Contactless card wave view\")\n\nISO7816 wave detail view.\n\n![APP](doc/img/nfc-lab-screenshot3.png \"Contact card wave view\")\n\nRadio spectrum view.\n\n![APP](doc/img/nfc-lab-screenshot4.png \"Radio spectrum\")\n\nProtocol detail view and filtering capabilities.\n\n![APP](doc/img/nfc-lab-screenshot5.png \"Protocol detail example\")\n\n![APP](doc/img/nfc-lab-screenshot6.png \"Protocol detail example\")\n\n![APP](doc/img/nfc-lab-screenshot7.png \"Protocol detail example\")\n\nAs can be seen, the application split functionalities in different tabs:\n\n- At the top left:\n  - **Frames**: Graphic view for decoded frames captured in contact interface and contactless interface.\n  - **Signal**: Shows the raw signal captured with logic analyzer and the radio interface with protocol markers.\n  - **Receiver**: During acquire shows the spectrum of the signal captured in the radio interface.\n\n- At the bottom:\n  - **Frames**: Table view for decoded frames captured in contact interface and contactless interface.\n\n## Application settings\n\nSettings are stored in user home directory, inside Roaming folder for windows %USERPROFILE%\\AppData\\Roaming\\josevcm\\nfc-lab.ini.\nThe file is created the first time the application is run and can contain the following sections:\n\nWindow state, updated every application close.\n\n```\n[window]\ntimeFormat=false\nfollowEnabled=true\nfilterEnabled=true\nwindowWidth=1024\nwindowHeight=700\n```\n\nLogic decoder and ISO7816 status, controlled from the toolbar option **Logic Acquire**, **Logic Decoder** under **Features** and **Protocol** menu. \nCurrently, channel signal mappings **channelIO**, **channelCLK**, **channelRST**, **channelVCC** are fixed, change this values has no effect.\n\n```\n[decoder.logic]\nenabled=true\n\n[decoder.logic.protocol.iso7816]\nenabled=true\nchannelIO=0\nchannelCLK=1\nchannelRST=2\nchannelVCC=3\n```\n\nRadio decoder and NFC-A, NFC-B, NFC-F, NFC-V status, controlled from the toolbar option **Radio Acquire**, **Radio Decoder** under **Features** and **Protocol** menu.\n\n```\n[decoder.radio]\nenabled=true\n\n[decoder.radio.protocol.nfca]\nenabled=true\n\n[decoder.radio.protocol.nfcb]\nenabled=true\n\n[decoder.radio.protocol.nfcf]\nenabled=true\n\n[decoder.radio.protocol.nfcv]\nenabled=true\n```\n\nConfiguration parameters for the Airspy receiver, the best performance is obtained by tuning in 3rd harmonic\nat 40.68Mhz.\n\n```\n[device.radio.airspy]\ncenterFreq=40680000\nsampleRate=10000000\ngainMode=1\ngainValue=4\nmixerAgc=0\ntunerAgc=0\nbiasTee=0\ndirectSampling=0\nenabled=true\n```\n\n\nConfiguration parameters for the HydraSDR RFOne receiver, the best performance is obtained by tuning in 2rd harmonic\nat 27.12Mhz.\n\n```\n[device.radio.hydrasdr]\ncenterFreq=27120000\nsampleRate=10000000\ngainMode=1\ngainValue=3\nmixerAgc=0\ntunerAgc=0\nbiasTee=0\ndirectSampling=0\nenabled=true\n```\n\nFor some readers as Renesas NFC Readers, tunning on the 2nd harmonic will not be able to decode the signal, \nso we suggest to set center frequency on the 3rd harmonic, 40,68MHz.\n\n```\n[device.radio.hydrasdr]\ncenterFreq=40680000\nsampleRate=10000000\ngainMode=1\ngainValue=3\nmixerAgc=0\ntunerAgc=0\nbiasTee=0\ndirectSampling=0\nenabled=true\n```\n\nConfiguration parameters for the RTL-SDR receiver, the best performance is obtained by tuning to the 2nd harmonic\nat 27.12Mhz. Decoding with this device is quite limited due to its low sampling frequency and 8-bit resolution,\nit will not offer the necessary quality, is supported only as a reference to experiment with it.\n\n```\n[device.radio.rtlsdr]\ncenterFreq=27120000\nsampleRate=3200000\ngainMode=1\ngainValue=125\nbiasTee=0\ndirectSampling=0\nmixerAgc=0\ntunerAgc=0\n```\n\nLogging control to see what happened.\n\n```\n[logger]\nroot=WARN\napp.main=INFO\napp.qt=INFO\ndecoder.IsoDecoder=WARN\ndecoder.Iso7816=WARN\ndecoder.NfcDecoder=WARN\ndecoder.NfcA=WARN\ndecoder.NfcB=WARN\ndecoder.NfcF=WARN\ndecoder.NfcV=WARN\nworker.FourierProcess=WARN\nworker.LogicDecoder=INFO\nworker.LogicDevice=INFO\nworker.RadioDecoder=INFO\nworker.RadioDevice=INFO\nworker.SignalResampling=WARN\nworker.SignalStorage=WARN\nworker.TraceStorage=WARN\nhw.AirspyDevice=WARN\nhw.MiriDevice=WARN\nhw.RealtekDevice=WARN\nhw.RecordDevice=WARN\nhw.DSLogicDevice=WARN\nhw.DeviceFactory=WARN\nhw.UsbContext=WARN\nhw.UsbDevice=WARN\nrt.Executor=INFO\nrt.Worker=INFO\n```\n\nAll default values are fixed and can be enough for most of the cases.\n\n## SDR Receivers tested\n\nI have tried several receivers obtaining the best results with AirSpy Mini, I do not have more devices, but surely it\nworks with others.\n\n- HydraSDR RFOne: New SDR receiver with very good results, tuning the second harmonic at 27.12Mhz or third harmonic at 40.68Mhz, \n  with a sampling frequency of 10 Mbps, with these parameters it is possible to capture the communication up to 424 Kbps. \n  This is the recommended device to use with this tool. Many thanks to Benjamin Vernoux for his support with this new receiver, \n  see [HydraSDR RFOne](https://github.com/hydrasdr).\n\n- AirSpy Mini or R2: Very good results, tuning the third harmonic at 40.68Mhz, with a sampling frequency of 10 Mbps, \n  with these parameters it is possible to capture the communication up to 424 Kbps. This is the recommended device \n  to use with this tool, see [AirSpy](https://github.com/airspy).\n\n- RTL SDR: It works by tuning the second harmonic at 27.12Mhz, due to the limitation in the maximum sampling frequency \n  of 3Mbps and its 8 bits of resolution only allows you to capture the commands up to 106Kbps and some responses in \n  very clean signals with good antenna. This device is supported only as a reference to experiment with it, I not \n  recommend using it if you want to obtain good results.\n\n- RTL SDR BLOG V4: This device is capable if tunning directly at 13.56Mhz, but keeps limitations of legacy RTLSDR in the maximum \n  sampling frequency of 3Mbps and its 8 bits of resolution only allows you to capture the commands up to 106Kbps and some responses in\n  very clean signals with good antenna. This device is supported only as a reference to experiment with it, I not\n  recommend using it if you want to obtain good results.\n\nReceivers tested, from left to right:\n\n![Devices](doc/img/nfc-lab-devices1.png \"Devices\")\n\nNooelec RTL-SDR with HydraNFC calibration coil:\n\n![Devices](doc/img/nfc-lab-devices2.png \"Devices\")\n\nAirSpy with custom antenna and ARC122U reader:\n\n![Devices](doc/img/nfc-lab-devices3.png \"Devices\")\n\nHydraSDR RFOne with custom antenna made from RC522 reader PCB:\n\n![Devices](doc/img/nfc-lab-devices8.png \"Devices\")\n\n### Driver Setup for RTL-SDR\n\nYou can found instructions under https://www.rtl-sdr.com/rtl-sdr-quick-start-guide/\n\n### Upconverters \u0026 Bias-tee\n\nTo avoid tuning harmonics it is possible to use an up-converter and thus tune directly to the carrier \nfrequency of 13.56Mhz. Currently, biasTee is supported for AirSpy and HydraSDR RFOne in combination with SpyVerter thanks to [Benjamin DELPY](https://github.com/gentilkiwi). \n\nThe configuration required is:\n\n```\n[device.radio.airspy]\ncenterFreq=133560000\nsampleRate=10000000\ngainMode=0\ngainValue=3\ntunerAgc=false\nmixerAgc=false\nbiasTee=1\n```\n\n```\n[device.radio.hydrasdr]\ncenterFreq=133560000\nsampleRate=10000000\ngainMode=0\ngainValue=3\ntunerAgc=false\nmixerAgc=false\nbiasTee=1\n```\n### Direct Sampling mode\n\nAnother way to avoid using harmonics is activate direct sampling mode and tune to the carrier frequency of 13.56Mhz in those devices that allow it. \nCurrently it is only available for RTLSDR thanks to the contribution of [Vincent Långström](https://github.com/vinicentus). You can use direct \nsampling on either the Q- or I-branch. The Q-branch is preferred due to better results, set the Q-branch with directSampling=2 and the I-branch \nwith directSampling=1, directSampling=0 turns off direct sampling.\n\nNote: No all RTLSDR devices support this feature.\n\nThe configuration required is:\n\n```\n[device.rtlsdr]\n...\ncenterFreq=13560000\ndirectSampling=1\n...\n```\n\n## Logic Analyzer tested\n\nThe only tested LA is DreamSourceLab DSLogic Plus, it works perfectly with the app, Pro16 and Pro32 are also supported but not tested (I don't have one).\nFirmware files for this LA are included in the repository, you can find them in the **dat/firmware** folder, this files must\nbe located inside firmware folder along nfc-lab.exe application. Thanks to [DreamSourceLab](https://www.dreamsourcelab.com/product/dslogic-series/).\n\n![Devices](doc/img/nfc-lab-devices4.png \"Devices\")\n\nThe channel connections required to decode ISO7816 protocol are:\n\n- Channel 0: IO\n- Channel 1: CLK\n- Channel 2: RST\n- Channel 3: VCC\n\n![Devices](doc/img/nfc-lab-devices5.png \"Devices\")\n\nI use a simple adapter to connect the smart card to the logic analyzer from aliexpress, like [this](https://aliexpress.com/item/4000967188424.html) and [this](https://aliexpress.com/item/1005007077428556.html):\n\n![Devices](doc/img/nfc-lab-devices6.png \"Devices\")\n\n![Devices](doc/img/nfc-lab-devices7.png \"Devices\")\n\n## Hardware requirements and performance\n\nThe demodulator is designed to run in real time, so it requires a recent computer with a lot of processing capacity.\n\nI have opted for a mixed approach where some optimizations are sacrificed in favor of maintaining \nclarity in the code and facilitating its monitoring and debugging.\n\nFor this reason it is possible that certain parts can be improved in performance, but I have done it as a didactic \nexercise rather than a production application.\n\n## Input / Output formats\n\nThe application allows you to read and write files in two different formats:\n\n- WAV: Reading signals in 16 bits per sample WAV format with 1 or 2 channels for NFC signals and 4 channels for logic analyzer \n  signals. \n\n  - Radio signal with 1 channel should contain samples in absolute real values. If 2 channels are used they should contain the sampling of the I / Q components.\n  - Logic signal with 4 channels should contain the sampling of the IO, CLK, RST and VCC signals in that order.\n\n- TRZ: The analyzed signal can be stored and read from a compressed format based on TGZ with contains:\n\n  - Signal data in custom binary format.\n  - Signal metadata in JSON format.\n\nJSON contents are in entry named **frame.json** inside TRZ file:\n\n```\n{\n   \"frames\": [\n      {\n          \"dateTime\": 1731144155.0108738,\n          \"frameData\": \"05:00:08:39:73\",\n          \"frameFlags\": 0,\n          \"framePhase\": 257,\n          \"frameRate\": 105938,\n          \"frameType\": 258,\n          \"sampleEnd\": 115545,\n          \"sampleRate\": 10000000,\n          \"sampleStart\": 108739,\n          \"techType\": 258,\n          \"timeEnd\": 0.0115545,\n          \"timeStart\": 0.0108739\n      },\n...\n}\n```\n\n- datetime: Date and time of the frame in seconds since epoch\n- frameData: Data of the frame in hexadecimal format.\n- frameFlags: Flags of the frame, a combination of the following values:\n  - ShortFrame = 0x01\n  - Encrypted = 0x02\n  - Truncated = 0x08\n  - ParityError = 0x10\n  - CrcError = 0x20\n  - SyncError = 0x40\n- framePhase: Phase of the frame, one of the following values:\n  - NfcAnyPhase = 0x0100\n  - NfcCarrierPhase = 0x0101\n  - NfcSelectionPhase = 0x0102\n  - NfcApplicationPhase = 0x0103\n  - IsoAnyPhase = 0x0200\n- frameRate: Rate of the frame, in bits per second, one of the following values\n- frameType: Type of the frame, one of the following values:\n  - NfcCarrierOff = 0x0100\n  - NfcCarrierOn = 0x0101\n  - NfcPollFrame = 0x0102\n  - NfcListenFrame = 0x0103\n  - IsoVccLow = 0x200\n  - IsoVccHigh = 0x201\n  - IsoRstLow = 0x202\n  - IsoRstHigh = 0x203\n  - IsoATRFrame = 0x0210\n  - IsoRequestFrame = 0x0211\n  - IsoResponseFrame = 0x0212\n  - IsoExchangeFrame = 0x0213\n- sampleStart: Start of the frame in samples.\n- sampleEnd: End of the frame in samples.\n- techType: Type of technology, one of the following values:\n  - NoneTech = 0x0000\n  - NfcAnyTech = 0x0100\n  - NfcATech = 0x0101\n  - NfcBTech = 0x0102\n  - NfcFTech = 0x0103\n  - NfcVTech = 0x0104\n  - IsoAnyTech = 0x0200\n  - Iso7816Tech = 0x0201\n- timeEnd: End of the frame in seconds.\n- timeStart: Start of the frame in seconds.\n\n## Live console output\n\nWith -j option the application is able to export the decoded frames to JSON format in console output. Thanks to [Steffen-W](https://github.com/Steffen-W) for this feature.\n\nEach JSON frame contains this fields:\n\n| Field                | Type   | Description                                                           |\n|----------------------|--------|-----------------------------------------------------------------------|\n| `timestamp`          | int    | Frame sample time                                                     |\n| `tech`               | string | NfcA, NfcB, NfcF, NfcV, UNKNOWN                                       |\n| `type`               | string | CarrierOff, CarrierOn, Poll, Listen                                   |\n| `tech_type`          | int    | Tech: 0x0101=NfcA, 0x0102=NfcB, 0x0103=NfcF, 0x0104=NfcV              |\n| `frame_type`         | int    | Type: 0x0100=CarrierOff, 0x0101=CarrierOn, 0x0102=Poll, 0x0103=Listen |\n| `sample_rate`        | int    | Sample rate in Hz (e.g., 3200000)                                     |\n| `sample_start/end`   | int    | Frame sample start / end (relative)                                   |\n| `time_start/end`     | float  | Time in seconds (relative)                                            |\n| `date_time`          | float  | Absolute Unix timestamp                                               |\n| `rate`               | int    | Bitrate in bps                                                        |\n| `flags`              | array  | Errors: crc-error, parity-error, truncated, sync-error                |\n| `data`               | string | Hex payload: `\"AA:BB:CC\"` (optional for carrier events)               |\n| `length`             | int    | Number of bytes in frameData                                          |\n\nExample:\n\n```\n$./nfc-lab -j\n{\"date_time\":1737800643,\"frame_type\":256,\"sample_end\":0,\"sample_rate\":10000000,\"sample_start\":0,\"tech\":\"UNKNOWN\",\"tech_type\":256,\"time_end\":0,\"time_start\":0,\"timestamp\":0,\"type\":\"CarrierOff\"}\n{\"date_time\":1737800643,\"frame_type\":256,\"sample_end\":1,\"sample_rate\":10000000,\"sample_start\":1,\"tech\":\"UNKNOWN\",\"tech_type\":256,\"time_end\":1e-07,\"time_start\":1e-07,\"timestamp\":1,\"type\":\"CarrierOff\"}\n{\"date_time\":1737800643.0000038,\"frame_type\":257,\"sample_end\":38,\"sample_rate\":10000000,\"sample_start\":38,\"tech\":\"UNKNOWN\",\"tech_type\":256,\"time_end\":3.8e-06,\"time_start\":3.8e-06,\"timestamp\":38,\"type\":\"CarrierOn\"}\n{\"data\":\"e0:80:31:73\",\"date_time\":1737800643.0031676,\"flags\":[\"request\"],\"frame_type\":258,\"length\":4,\"rate\":105938,\"sample_end\":35216,\"sample_rate\":10000000,\"sample_start\":31677,\"tech\":\"NfcA\",\"tech_type\":257,\"time_end\":0.0035216,\"time_start\":0.0031677,\"timestamp\":31677,\"type\":\"Poll\"}\n{\"data\":\"06:75:77:81:02:80:02:f0\",\"date_time\":1737800643.0036075,\"flags\":[\"response\"],\"frame_type\":259,\"length\":8,\"rate\":105938,\"sample_end\":42918,\"sample_rate\":10000000,\"sample_start\":36075,\"tech\":\"NfcA\",\"tech_type\":257,\"time_end\":0.0042918,\"time_start\":0.0036075,\"timestamp\":36075,\"type\":\"Listen\"}\n{\"data\":\"02:90:5a:00:00:03:ab:22:e5:00:eb:6b\",\"date_time\":1737800643.0061498,\"flags\":[\"request\"],\"frame_type\":258,\"length\":12,\"rate\":105938,\"sample_end\":71838,\"sample_rate\":10000000,\"sample_start\":61497,\"tech\":\"NfcA\",\"tech_type\":257,\"time_end\":0.0071838,\"time_start\":0.0061497,\"timestamp\":61497,\"type\":\"Poll\"}\n{\"data\":\"02:91:00:29:10\",\"date_time\":1737800643.0086663,\"flags\":[\"response\"],\"frame_type\":259,\"length\":5,\"rate\":105938,\"sample_end\":91003,\"sample_rate\":10000000,\"sample_start\":86662,\"tech\":\"NfcA\",\"tech_type\":257,\"time_end\":0.0091003,\"time_start\":0.0086662,\"timestamp\":86662,\"type\":\"Listen\"}\n{\"data\":\"03:90:6c:00:00:01:08:00:67:ce\",\"date_time\":1737800643.0235095,\"flags\":[\"request\"],\"frame_type\":258,\"length\":10,\"rate\":105938,\"sample_end\":243727,\"sample_rate\":10000000,\"sample_start\":235096,\"tech\":\"NfcA\",\"tech_type\":257,\"time_end\":0.0243727,\"time_start\":0.0235096,\"timestamp\":235096,\"type\":\"Poll\"}\n{\"data\":\"03:d4:17:00:00:91:00:3f:fe\",\"date_time\":1737800643.0254395,\"flags\":[\"response\"],\"frame_type\":259,\"length\":9,\"rate\":105938,\"sample_end\":262136,\"sample_rate\":10000000,\"sample_start\":254396,\"tech\":\"NfcA\",\"tech_type\":257,\"time_end\":0.0262136,\"time_start\":0.0254396,\"timestamp\":254396,\"type\":\"Listen\"}\n{\"data\":\"02:90:bd:00:00:07:01:00:00:00:80:00:00:00:1a:83\",\"date_time\":1737800643.0412457,\"flags\":[\"request\"],\"frame_type\":258,\"length\":16,\"rate\":105938,\"sample_end\":426181,\"sample_rate\":10000000,\"sample_start\":412458,\"tech\":\"NfcA\",\"tech_type\":257,\"time_end\":0.0426181,\"time_start\":0.0412458,\"timestamp\":412458,\"type\":\"Poll\"}\n{\"data\":\"02:04:3c:70:02:52:48:80:24:66:4d:fb:bb:a5:78:8d:00:00:45:67:10:10:20:11:00:70:29:d5:f7:1b:00:00:00:00:00:00:00:01:97:3e:07:d2:04:00:00:00:00:00:00:00:00:00:00:00:00:97:3e:00:00:00:91:af:a7:98\",\"date_time\":1737800643.0433269,\"flags\":[\"response\"],\"frame_type\":259,\"length\":64,\"rate\":105938,\"sample_end\":487734,\"sample_rate\":10000000,\"sample_start\":433268,\"tech\":\"NfcA\",\"tech_type\":257,\"time_end\":0.0487734,\"time_start\":0.0433268,\"timestamp\":433268,\"type\":\"Listen\"}\n```\n\n### Live console output with python parsing\n\nAdditionally, with the help of the **tools/py_nfclab** module, it is possible to parse and display the frames in a more friendly way. See [tools/py_nfclab/README.md](tools/py_nfclab/README.md) for more information about this module.\n\n```\n$ ./nfc-lab -j | python3 -m tools.py_nfclab\nNFC Frame Monitor\nLive mode - reading from stdin\n(Press Ctrl+C to stop)\n================================================================================\n[    0.000000]   NfcAnyTech        CarrierOff |                  |   0B | (no data)\n[    0.000000]   NfcAnyTech        CarrierOff |                  |   0B | (no data)\n[    0.000004]   NfcAnyTech         CarrierOn |                  |   0B | (no data)\n[    0.003168]         NfcA 105938       Poll | RATS             |   4B | Cmd:E0 Params:80 CRC:3173\n[    0.003608]         NfcA 105938     Listen | I-Block          |   8B | Payload:067577810280 CRC:02F0\n[    0.006150]         NfcA 105938       Poll | I-Block          |  12B | Cmd:02 Params:905A000003AB22E500 CRC:EB6B\n[    0.008666]         NfcA 105938     Listen | I-Block          |   5B | Payload:029100 CRC:2910\n[    0.023510]         NfcA 105938       Poll | I-Block          |  10B | Cmd:03 Params:906C0000010800 CRC:67CE\n[    0.025440]         NfcA 105938     Listen | I-Block          |   9B | Payload:03D41700009100 CRC:3FFE\n[    0.041246]         NfcA 105938       Poll | I-Block          |  16B | Cmd:02 Params:90BD0000070100000080000000 CRC:1A83\n[    0.043327]         NfcA 105938     Listen | I-Block          |  64B | Payload[62B]:02043C700252488024664DFBBBA5788D... CRC:A798\n```\n\n## Testing files\n\nIn the \"wav\" folder you can find a series of samples of different captures for the NFC-A, NFC-B, NFC-F and NFC-V \nmodulations with their corresponding analysis inside the \"json\" files.\n\nThese files can be opened directly from the NFC-LAB application through the toolbar to see their analysis, but the \nmain objective is to pass the unit tests and check the correct operation of the decoder.\n\nTo run the unit tests, the **test-sdr** artifact must be compiled and launched using the path to the \"wav\" folder \nas an argument, for example:\n\n```\ntest-sdr.exe ../wav/\nTEST FILE \"test_NFC-A_106kbps_001.wav\": PASS\nTEST FILE \"test_NFC-A_106kbps_002.wav\": PASS\nTEST FILE \"test_NFC-A_106kbps_003.wav\": PASS\nTEST FILE \"test_NFC-A_106kbps_004.wav\": PASS\nTEST FILE \"test_NFC-A_212kbps_001.wav\": PASS\nTEST FILE \"test_NFC-A_424kbps_001.wav\": PASS\nTEST FILE \"test_NFC-A_424kbps_002.wav\": PASS\nTEST FILE \"test_NFC-B_106kbps_001.wav\": PASS\nTEST FILE \"test_NFC-B_106kbps_002.wav\": PASS\nTEST FILE \"test_NFC-F_212kbps_001.wav\": PASS\nTEST FILE \"test_NFC-F_212kbps_002.wav\": PASS\nTEST FILE \"test_NFC-V_26kbps_001.wav\": PASS\nTEST FILE \"test_NFC-V_26kbps_002.wav\": PASS\nTEST FILE \"test_POLL_ABF_001.wav\": PASS\nTEST FILE \"test_POLL_AB_001.wav\": PASS\n```\n\n## Build instructions\n\nThis project is based on Qt6 and MinGW-W64, with minimal dependencies.\n\nContains the following components:\n\n- /src/nfc-app/app-qt: Application interface based on Qt Widgets\n- /src/nfc-app/app-rx: Command line decoder application.\n- /src/nfc-lib/lib-ext: External libraries and drivers for SDR and logic analyzer.\n- /src/nfc-lib/lib-hw: Hardware abstraction layer for SDR and logic analyzer.\n- /src/nfc-lib/lib-lab: Signal processing and protocol decoding.\n- /src/nfc-lib/lib-rt: Runtime utilities and thread management.\n\nAll can be compiled with mingw-g64, a minimum version is required to support C++17, recommended 11.0 or higher.\n\n### Prerequisites\n\n- CMake version 3.16 or higher\n  - `winget install -e --id=Kitware.CMake`\n  - alternative see http://www.cmake.org/cmake/resources/software.html\n- Git-bash or your preferred git client\n  - `winget install -e --id Git.Git`\n  - alternative see https://gitforwindows.org/\n- MSYS2 if you like to install everything with pacma\n  - `winget install -e --id MSYS2.MSYS2`\n  - add `C:\\msys64\\mingw64\\bin` to the environment variable `Path`\n- Qt6 framework 6.x\n  - inside MSYS2: `pacman -S mingw-w64-x86_64-qt6-base`\n  - alternative see https://www.qt.io/offline-installers\n- GCC / G++ for Linux build, version 11.0 or later\n  - inside MSYS2: `pacman -S mingw-w64-ucrt-x86_64-gcc`\n  - alternative mingw-w64 11 for windows build see https://www.mingw-w64.org/downloads\n- USB lib\n  - inside MSYS2: `pacman -S mingw-w64-x86_64-libusb`\n\n### Manual build for Windows\n\nOnce you have all pre-requisites ready, clone the repository:\n```\ngit clone https://github.com/josevcm/nfc-laboratory.git\n```\n\nCreate a **build** directory and configure the project (change `CMAKE_BUILD_TYPE=Debug` and `-B cmake-build-debug` for debug output)\n\n```\ncmake -DCMAKE_BUILD_TYPE=Release -G \"CodeBlocks - MinGW Makefiles\" -S nfc-laboratory -B build\n```\n\nCompile the project:\n```\ncmake --build build --target nfc-lab -- -j 6\n```\n\n```\ncmake\n[  1%] Building C object src/nfc-lib/lib-ext/microtar/CMakeFiles/microtar.dir/src/main/c/microtar.c.obj\n[  2%] Building C object src/nfc-lib/lib-ext/mufft/CMakeFiles/mufft-sse.dir/src/main/c/x86/kernel.sse.c.obj\n[  2%] Building C object src/nfc-lib/lib-ext/airspy/CMakeFiles/airspy.dir/src/main/c/airspy.c.obj\n....\n[ 98%] Linking CXX executable nfc-lab.exe\n[100%] Built target nfc-lab\n```\n\nCreate a coppy of the application for easier access:\n\n```\ncp .\\build\\src\\nfc-app\\app-qt\\nfc-lab.exe nfc-lab.exe\n```\n\nApplication is ready to use!\n\nIf you do not have an SDR receiver, I have included a small capture sample signal in file \"wav/capture-424kbps.wav\" that\nserves as an example to test demodulation.\n\n### Manual build for Linux\n\nInstall dependencies (ubuntu)\n\n```\nsudo apt install cmake g++ g++-11 qt6-base-dev libqt6svg6 libusb-1.0-0-dev zlib1g-dev libgl1-mesa-dev libairspy-dev librtlsdr-dev\n```\n\nClone the repository\n```\ngit clone https://github.com/josevcm/nfc-laboratory.git\n```\n\nCreate a **build** directory and configure the project (change `CMAKE_BUILD_TYPE=Debug` and `-B cmake-build-debug` for debug output)\n\n```\ncmake -DCMAKE_BUILD_TYPE=Release -S nfc-laboratory -B build\n```\n\nCompile the project:\n\n```\ncmake --build build --target nfc-lab -- -j$(nproc)\n```\n\nCopy the base configuration files to the build directory:\n\n```\ncp -r nfc-laboratory/dat/firmware build/src/nfc-app/app-qt/\n```\n\nCreate a symbolic link to the application for easier access:\n\n```\nln -s build/src/nfc-app/app-qt/nfc-lab nfc-lab\n```\n\nLaunch the application:\n\n```\n./nfc-lab\n```\n\n## Source code licensing\n\nIf you think it is an interesting job, or you plan to use it for something please email me and let me know, I\nwill be happy to exchange experiences, thank you very much.\n\nThis project is published under the terms of the GPLv3 license, however there are parts of it subject to other types of\nlicenses, please check if you are interested in this work.\n\n- AirSpy SDR driver at `src/nfc-lib/lib-ext/airspy` see https://github.com/airspy/airspyone_host\n- HydraSDR RFOne driver at `src/nfc-lib/lib-ext/hydrasdr` see https://github.com/hydrasdr/rfone_host\n- MiriSDR driver at `src/nfc-lib/lib-ext/mirisdr` see https://github.com/f4exb/libmirisdr-4\n- RTL SDR driver at `src/nfc-lib/lib-ext/rtlsdr` see https://osmocom.org/projects/rtl-sdr\n- mufft library at `src/nfc-lib/lib-ext/mufft` see https://github.com/Themaister/muFFT\n- nlohmann json at `src/nfc-lib/lib-ext/nlohmann` see https://github.com/nlohmann/json\n- microtar at `src/nfc-lib/lib-ext/microtar` see https://github.com/rxi/microtar\n- QCustomPlot at `src/nfc-app/app-qt/src/main/cpp/3party/customplot` see https://www.qcustomplot.com/\n- QDarkStyleSheet at `src/nfc-app/app-qt/src/main/assets/theme` see https://github.com/ColinDuquesnoy/QDarkStyleSheet\n- Crapto1 at `src/nfc-lib/lib-ext/crapto1`\n\n## Releases\n\nPrecompiled installer for x86_64 can be found in repository, you can download latest version from [releases](https://github.com/josevcm/nfc-laboratory/releases/latest/)\n\n# How it works?\n\n## Basic notions of the signals to be analyzed\n\nNormal NFC cards work on the 13.56 Mhz frequency, therefore the first step is receive this signal and demodulate to get\nthe baseband stream. For this purpose any SDR device capable of tuning this frequency can be used, i have the\nfantastic and cheap AirSpy Mini capable of tuning from 24Mhz to 1700Mhz. (https://airspy.com/airspy-mini/)\n\nHowever, it is not possible to tune 13.56Mhz with this receiver, instead I use the second harmonic at 27.12Mhz or third\nat 40.68Mhz with good results.\n\nThe received signal will be composed of the I and Q components as in the following image.\n\n![IQ](doc/img/nfc-baseband-iq.png \"IQ signal capture\")\n\nFrom these components the real magnitude is calculated using the classic formula sqrt (I ^ 2 + Q ^ 2). Let's see a capture\nof the signal received in baseband (after I/Q to magnitude transform) for the REQA command and its response:\n\n![REQA](doc/img/nfc-baseband-reqa.png \"REQA signal capture\")\n\nAs can be seen, it is a signal modulated in 100% ASK that corresponds to the NFC-A REQA 26h command of the NFC \nspecifications, the response of the card uses something called load modulation that manifests as a series of pulses on \nthe main signal after the command. This is the most basic modulation, but each of the NFC-A / B / F / V standards has \nits own characteristics.\n\n### NFC-A modulation\n\nThe standard corresponds to the ISO14443A specifications which describe the way it is modulated as well as the \napplicable timings.\n\nReader frames are encoded using 100% ASK with modified miller encoding.\n\n![NFCA ASK](doc/img/nfca-ask-miller.png \"NFC-A ASK reader frame signal\")\n\nWhen the speed is 106 Kbps card responses are encoded using manchester scheme with OOK load modulation over a \nsubcarrier at 848 KHz.\n\n![NFCA OOK](doc/img/nfca-ask-ook.png \"NFC-A OOK card response signal\")\n\nFor higher speeds, 212 kbps, 424 kbps and 848 kbps it uses a NRZ-L with binary phase change modulation, BPSK, over \nsame subcarrier.\n\n![NFCA BPSK](doc/img/nfca-bpsk.png \"NFC-A BPSK card response signal\")\n\n### NFC-B modulation\n\nThe standard corresponds to the ISO14443B specifications which describe the way it is modulated as well as the \napplicable timings.\n\nReader frames are encoded in 10% ASK using NRZ-L encoding.\n\n![NFCB ASK](doc/img/nfcb-ask-nrz.png \"NFC-B ASK reader frame signal\")\n\nResponses from the card are encoded with binary phase change modulation, BPSK, using NRZ-L encoding.\n\n![NFCB ASK](doc/img/nfcb-bpsk.png \"NFC-B BPSK card response signal\")\n\n### NFC-F modulation\n\nThe standard corresponds to the ISO18092 and JIS.X.6319 specifications which describe the way it is modulated as well \nas the applicable timings.\n\nSupport speeds from 212 kbps to 848 kbps, both reader and card frames are encoded using either observed or reversed \nmanchester as see below.\n\n![NFCF Manchester](doc/img/nfcf-manchester.png \"NFC-F manchester reader frame signal\")\n\nObserved manchester modulation.\n\n![NFCF OBSERVE](doc/img/nfcf-observe.png \"NFC-F manchester observed modulation\")\n\nReversed manchester modulation.\n\n![NFCF REVERSE](doc/img/nfcf-reverse.png \"NFC-B manchester reversed modulation\")\n\n### NFC-V modulation\n\nThe standard corresponds to the ISO15693 specifications which describe the way it is modulated as well as the \napplicable timings.\n\nThe coding is based on pulse position modulation (PPM) where the information is encoded by modifying the time when the \npulse is located within each time slot.\n\nThere are two modes, 1 of 4 and 1 of 256, where each symbol encodes 2 and 8 bits respectively, this is the example for \nthe first one.\n\n![NFCV PPM 2 bit](doc/img/nfcv-ppm2.png \"NFC-V PPM reader modulation\")\n\nCard responses can be encoded in two different ways depending on the value of bit 0 in the flags field of the request made by VCD. \n\nIf the flags bit 0 = 0, the card will respond using only one subcarrier at fc/32 (423,75 kHz), with OOK modulation, (as in NFC-A). \nIf the flags bit 0 = 1, the card will respond using two subcarriers at fc/32 (423,75 kHz) and fc/28 (484,28 kHz) with 2-FSK modulation. \n\nNOTE: Currently only the first mode is supported in this software (sorry).\n\nDepending on the encoding, the possible speeds are 26Kbps and 53Kbps, however these cards can be read from greater \ndistances.\n\n## Signal processing\n\nNow we are going to see how to decode this.\n\n### First step, prepare base signals\n\nBefore starting to decode each of these modulations, it is necessary to start with a series of basic signals that will\nhelp us in the rest of the process.\n\nThe concepts that I am going to explain next are very well described on Sam Koblenski's page \n(https://sam-koblenski.blogspot.com/2015/08/everyday-dsp-for-programmers-basic.html) which I recommend you read to \nfully understand all the processes related to the analysis that we are going to carry out.\n\nRemember that the sample received from the SDR receiver is made up of the I / Q values, therefore the first step is to \nobtain the real signal.\n\nOnce we have the real signal, it is necessary to eliminate the continuous component (DC) that will greatly facilitate \nthe subsequent analysis process. For this we will use a simple IIR filter.\n\nTo calculate the modulation depth we need to know the envelope of the signal as if it were not modulated by the pulses \nor sub-carrier, for this we will use a simple slow exponential average.\n\nFinally we will obtain the standard deviation or variance of the signal that will help us to calculate the appropriate detection thresholds\nbased on the background noise.\n\n![Signal processing](doc/img/signal-pre-process.png \"Signal pre-processing\")\n\nAn example of each component, x(t), w(t), v(t) and a(t).\n\n![Signal processing](doc/img/signal-pre-process-example.png \"Signal pre-processing\")\n\n### Next, identify the type of modulation needed\n\nAs we have seen in the description, the NFC-A / B / F / V standards will use different modulations but all are based on\ntwo basic techniques, amplitude modulation and phase modulation.\n\nFor the encoding of each symbol they use Miller, Manchester or NRZ-L. The first two can be detected by correlation\ntechniques and for NRZ-L it is enough to detect the level of the signal at each point of synchronization, let's see it\nin detail.\n\n### Basic notions of signal correlation\n\nThe correlation operation is a measure of how much one signal resembles another that serves as a reference. It is used\nintensively in digital signal analysis. With analog signals, the correlation of each sample x(t) requires N \nmultiplications, therefore a symbol needs N^2 multiplications, being a costly process.\n\nBut since the reference signal is digital, it only has two possible values 0 or 1, which greatly simplifies the\ncalculation by eliminating all the multiplications, allowing the correlation to be carried out by process a simple\nmoving average.\n\n![SYMBOLS S0 S1](doc/img/nfc-decoder-symbols.png  \"Basic Symbols\")\n\nThese would be the two basic symbols that we need to carry out the correlation, if you study a little the operations\nthat need to be carried out you will see that they are reduced to calculating the mean over the duration of the symbol\nand then obtaining the difference between the critical points, t = 0, t = N / 2 and t = N as seen in next diagram.\n\n![SYMBOLS Correlation](doc/img/nfc-symbol-correlation.png  \"Correlation Process\")\n\nWe will widely use this operation to extract the information within the NFC signals\n\n### Demodulation of ASK miller and manchester signals\n\nFor ASK modulated signals, it is enough to carry out the correlation described above on the baseband signal x(t). Below\nis the correlation functions for the two basic symbols S0, S1 used to calculate all the others. Last value is function\nSD and represent the absolute difference between S0 and S1 necessary to detect the timmings.\n\n![CORRELATION](doc/img/nfc-decoder-example.png \"Decoder request correlation\")\n\nWhen the speed is 106 kbps, the answer can be extracted by applying the same technique, but instead of using the signal\nx(t) we will do it with w(t) multiplying it by itself obtaining a measure of the power that we will then integrate\nover 1/4 of the symbol period, in such a way that we will obtain a fairly clear ASK signal to be able to apply the\ncorrelation described above, this is the diagram of the process.\n\n![NFC ASK request](doc/img/nfc-demodulator-ask-request.png \"Decoder response correlation\")\n\nCard is much weaker but enough to allow its detection using the same technique for patterns E, D, F,\nhere it is shown in better scale the process described. From top to bottom the signals are: x(t), w(t), w(t)^2 and y(t).\n\n![NFC ASK response](doc/img/nfc-demodulator-response.png \"Decoder response correlation\")\n\n### Demodulation of BPSK signals\n\nFor BPSK demodulation a reference signal is required to detect the phase changes (carrier recovery), since that is\ncomplex I have chosen to implement it by multiplying each symbol by the preceding one, so that it is possible to\ndetermine the value of symbols through the changes produced between then.\n\nIt is very important that the signal does not contain a DC shift, therefore the signal w(t) obtained previously\nis taken as input to the process.\n\n![BPSK1](doc/img/nfc-demodulator-bpsk-process.png \"414Kbps BPSK demodulation process\")\n\nBelow you can see the signal modulated in BPSK for a response frame at 424Kbps, followed by the demodulation y(t) and\nintegration process over a quarter of a symbol r(t).\n\n![BPSK2](doc/img/nfc-demodulator-bpsk-detector.png \"414Kbps BPSK response demodulation\")\n\nFinally, by checking if the result is positive or negative, the value of each symbol can be determined. It is somewhat\nmore complex since timing and synchronization must be considered but with this signal is straightforward detect symbol\nvalues.\n\n### Symbol detection\n\nFrom the correlation process we obtain a flow of symbols where it is already possible to apply the specific decoding\ndefined in each of the standards, NFC-A / B / F / V. Each symbol correlation is evaluated in the appropriate instants\naccording to the synchronization.\n\nThe correlation process begins with the calculation of the S0 and S1 values that represent the basic symbols\nsubsequently used to discriminate between the NFC patterns X, Y, Z, E, D, F, M, N etc. that are subsequently interpreted \nby a state machine in accordance with the specifications of ISO ISO14443A, ISO14443B, ISO15693 and Felica to obtain a \nbyte stream that can be easily processed.\n\n![DEC2](doc/img/nfc-demodulator-pattern-process.png \"Pattern and frame detection\")\n\n### Bitrate discrimination\n\nSo, we have seen how demodulation is performed, but how does this apply when there are different speeds? Well, since we\ndo not know in advance the transmission speed it is necessary to apply the same process for all possible speeds through\na bank of correlators. Really only is necessary to do it for the first symbol of each frame, once the bitrate is known\nthe rest are decoded using that speed.\n\n![DEC3](doc/img/nfc-demodulator-speed-detector.png \"Bitrate discrimination\")\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjosevcm%2Fnfc-laboratory","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjosevcm%2Fnfc-laboratory","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjosevcm%2Fnfc-laboratory/lists"}