Skip to content

Repository files navigation

NiusWireless

A unified, cross-platform Arduino driver for the wireless and RF modules you actually wire up to a microcontroller — RFID/NFC, LoRa, sub-GHz radios, BLE/Serial Bluetooth, 2.4 GHz packets — under one consistent API.

License: MITCIArduino LibraryVersion 0.4.0Architectures: AVR • SAMD • ESP • nRF52 • STM32 • RP2040 • RAMaintained by NiusRobotLabRepo


Why NiusWireless?

Most Arduino wireless libraries solve one module — RC522 or LoRa or NRF24, never all three with the same coding style, the same error model, or the same naming. NiusWireless consolidates eight popular RF modules behind a single header (NiusWireless.h) and a shared base class (NiusBase), so the sketch you write for an RC522 over SPI on an UNO R4 looks the same as the one you write for an SX1262 over SPI on a Pico W.

Highlights:

  • One API surface, eight modules. RFID-RC522, PN532 NFC, RFM95/96/98, SX1261/62/68, RA-01/02, NRF24L01(+), HC-12, HC-05/06.
  • RC522 done right. Hardware SPI, software (bit-bang) SPI and I2C; full card-type coverage (Classic 1K / 4K / Mini, Ultralight, NTAG213/215/216, Plus SL1); built-in CUID / UFUID / FUID magic-tag handling with a safe dry-run preview before any write hits block 0.
  • Honest typing.getCardType() / getCardTypeName() tell you whether the tag you're holding is actually a Classic 1K or an Ultralight — and the driver picks the right read path (dumpClassic vs dumpUltralight).
  • Cross-platform. AVR, SAMD, ESP32, ESP8266, nRF52 (ArduinoNRF), STM32, RP2040 / RP2350, Renesas RA — the same source builds on all of them.
  • Single header for sketches.#include <NiusWireless.h> pulls in whichever module classes you reference.

Table of contents

  1. Supported modules
  2. Quick start
  3. Wiring reference
  4. RC522 — card & tag coverage
  5. Examples
  6. Supported boards
  7. Installation
  8. Documentation
  9. Contributing
  10. License

Supported modules

ModuleClass(es)StatusBus
RFID-RC522 / MFRC522NiusRC522FullSPI (hw + sw), I2C
PN532 NFC/RFIDNiusPN532FullI2C, SPI
RFM95W / RFM96W / RFM98WNiusRFM95 / NiusRFM96 / NiusRFM98FullSPI
RA-01 / RA-02 (SX1278)NiusRA01 / NiusRA02FullSPI
SX1261 / SX1262 / SX1268NiusSX1261 / NiusSX1262 / NiusSX1268FullSPI
NRF24L01 / NRF24L01+NiusNRF24L01FullSPI (hw + sw)
HC-12 long-range serialNiusHC12ImplementedUART
HC-06 / HC-05 BluetoothNiusHC06ImplementedUART

All classes derive from NiusBase, so begin() / isReady() / reset() / getVersion() are always present.


Quick start

1. Software SPI (any 5 GPIOs)

The reference wiring for an Arduino UNO R4 WiFi uses SDA / SCL as software-SPI pins because they're conveniently broken out next to the analog header. Any five GPIO pins work on any board.

#include<NiusWireless.h>// SDA(CS)=D18/A4 SCK=D19/A5 MOSI=D11 MISO=D12 RST=D10
NiusRC522 rfid(SDA, 10, SCL, 11, 12);
voidsetup() {
Serial.begin(9600);
delay(1500); // USB-CDC enumerate on UNO R4
rfid.begin();
}
voidloop() {
if (!rfid.cardPresent()) return; // single-shot per physical tap
rfid.printInfo(); // UID / ATQA / SAK / type
rfid.halt(); // tag returns to HALT statedelay(1000); // debounce
}

2. Hardware SPI (board's default SPI bus)

#include<NiusWireless.h>// csPin = 10, rstPin = 9 on a classic Arduino UNO
NiusRC522 rfid(10, 9);
voidsetup() {
Serial.begin(9600);
rfid.begin(); // uses SPI.h defaults
}
voidloop() {
if (rfid.cardPresent()) {
Serial.println(rfid.getUID());
rfid.halt();
}
}

3. I2C

#include<NiusWireless.h>
#defineRC522_I2C_ADDR0x28// 0x29 if I2C_ADD0 is tied HIGH on the board
#defineRC522_RST_PIN10
NiusRC522 rfid(Wire, RC522_I2C_ADDR, RC522_RST_PIN);
voidsetup() {
Serial.begin(9600);
rfid.begin();
}
voidloop() {
if (!rfid.cardPresent()) return;
rfid.printInfo();
rfid.halt();
}

RC522 I2C is supported natively — the chip must be wired for I2C mode (I2C / SPI select pin tied appropriately) and use the chip's I2C_SDA / I2C_SCL pins.


Wiring reference

RC522 — software SPI (default)

RC522 pinUNO R4 WiFiNotes
SDA (CS)D18 / A4Any GPIO works
SCKD19 / A5Any GPIO works
MOSID11Any GPIO works
MISOD12Any GPIO works
IRQD13Optional — see setIRQPin()
RSTD10Any GPIO works
3.3V3.3VDo not power from 5V
GNDGND

RC522 — I2C

RC522 pinBoard pinNotes
I2C_SDAboard SDAdefault address 0x28 (0x29 with I2C_ADD0 HIGH)
I2C_SCLboard SCL
RSTany GPIO
3.3V3.3V
GNDGND

RFM9x / SX127x (LoRa)

Standard SPI wiring — see your board's SPI defaults. RFM95 / RFM96 / RFM98 and the RA-01 / RA-02 clones all share the same pinout and command set.

SX1261 / SX1262 / SX1268

Standard SPI plus BUSY, DIO1, and optional DIO2 (RF switch) / DIO3 (TCXO). See examples/sx1262_basic for a working configuration.

NRF24L01(+)

SPI: SCK / MOSI / MISO / CSN / CE. Power from 3.3V, not 5V. Add a 10 µF cap across VCC / GND if you see brownouts on TX.

Auto-acknowledge and auto-retransmit are enabled by default, so writeRadio() returns true only when the receiver acknowledged the packet. Dynamic payload length is used automatically on NRF24L01+ silicon. availablePayloadSize() and the three-argument readRadio() preserve packet atomicity: an undersized caller buffer does not silently truncate or consume the pending frame.

For interrupt-driven and low-energy applications, call setIRQPin() before begin(), attach the application's own FALLING-edge ISR, and inspect interruptFlags() or irqAsserted() outside the ISR. powerDown() enters the register-retaining radio power-down state; powerUp() performs the required oscillator wait and returns in standby. The driver owns no global ISR and does not allocate.

A board with two SPI peripherals can drive two radios by passing the bus explicitly — NiusNRF24L01 radio(ce, csn, SPI1). The nrf24_dual_link example runs a full bidirectional link, wired-IRQ check, and power-down/wake cycle on one Raspberry Pi Pico this way, which is a quick way to prove wiring and modules before deploying a real two-board link.

HC-12 / HC-05 / HC-06

Plain UART — TX / RX cross-connected at 3.3V levels. Use a divider if your board is 5V.

Both backends use caller-owned UART objects and allocate nothing in their bounded write() / read() data paths. HC-12 handles SET-controlled AT mode, channel, power, baud, and FU mode. HC-05/06 auto-detects the command dialect and supports name, baud, PIN, connection-state, and transparent SPP data. Pass a caller-owned SoftwareSerial object on AVR or a hardware UART such as Serial1 elsewhere.

PN532 — I2C (all supported boards)

PN532 pinM0-MiniESP32 / othersNotes
SDAD20board default SDAWire
SCLD21board default SCLWire
IRQD9 (required)optionalsee below
VCC3V33V3
GNDGNDGND

IRQ wiring by MCU:

MCUIRQ required?Default in examples
SAMD21 (M0-Mini, Zero)YesWire has no clock-stretch timeoutD9
ESP32, RP2040, UNO R4, AVR…No — driver polls I2C status when PN532_IRQ is 0xFFunwired OK

Examples pick the default automatically. Override before compile if needed:

#definePN532_IRQ4// your GPIO, any board
#include ... // or edit the #if block in the sketch

Test flow: pn532_i2c_scanpn532_i2c_basicpn532_i2c_adv. Do not generic-scan address 0x24.

Elechouse I2C DIP: SW1=ON, SW2=OFF. To switch I2C / SPI / HSU: cut power first, set the DIP, then repower so I0/I1 re-latch (USB unplug/replug, or RESET if RSTO → board RESET).

NiusPN532 mirrors the RC522 card/error surface: getCardType() / getCardTypeName(), lastError + errorName(), cardPresentWake(), dumpToSerial(), protected writeBlock(..., force=false), setUid(..., commit=false) dry-run (BCC recomputed; manufacturer bytes preserved), and Ultralight readPage() returning 16 bytes.

PN532 — SPI (RobotDyn SAMD21 M0-Mini)

Per SAMD21-M0-Mini.pdf:

PN532 pinM0-MiniNotes
SCK / MOSI / MISOICSPZero core pins 24 / 23 / 22 — hardware SPI by default
SS / NSSD8Chip select
IRQD9Optional; required in pn532_spi_adv (setIRQPin before begin)
RSTOboard RESETNot driven as a sketch GPIO (rstPin = 0xFF)
VCC3V3
GNDGND

Set DIP switches to SPI (Elechouse: SW1=OFF, SW2=ON).

To switch I2C / SPI / HSU: cut power first, set the DIP, then repower so I0/I1 re-latch (USB unplug/replug, or RESET if RSTO → board RESET).

Host SPI: SPI.begin() + SPISettings (default 2 MHz, setSpiClock(); clamped 100 kHz–4 MHz). Soft SPI on ICSP pins is a fallback if hardware SPI fails GetFirmwareVersion (or #define NIUS_PN532_FORCE_SOFT_SPI).

Test flow: pn532_spi_scanpn532_spi_basicpn532_spi_adv.

  • pn532_spi_scan — begin + firmware only, then optional wake/printInfo.
  • pn532_spi_basic — status-byte ready (no IRQ); setSpiClock(2000000).
  • pn532_spi_advsetIRQPin(D9)beforebegin(); dump / setUid / block 4.

RC522 — card & tag coverage

The NiusRC522 driver detects the card family from the ATQA + SAK bytes that anti-collision returns. For Ultralight-family cards it additionally sends GET_VERSION (0x60) to distinguish the specific product.

Detected typeSAKATQABlock / pageOperated by NiusRC522
MIFARE Mini0x090x040016 B / 16 BYes
MIFARE Classic 1K0x080x040016 B / 16 BYes
MIFARE Classic 4K0x180x020016 B / 16 BYes
MIFARE Ultralight0x000x44004 B / 16 BYes (readPage / writePage)
NTAG213 / 215 / 2160x000x44004 B / 16 BYes (distinguished by GET_VERSION)
MIFARE Plus0x10 / 0x110x420016 B / 16 BPartial — SL1 only (no SL2/SL3)
MIFARE DESFire EV10x20 / 0x280x4400n/aNo — needs APDU (use PN532)
ISO 14443-4 generic0x20+variesn/aNo
ISO 18092 (NFC-IP1)0x40+variesn/aNo (peer-to-peer)
TNP3xxx (SmartMX)0x30+variesn/aNo
FeliCa (Type F)n/an/an/aNo — RC522 cannot read FeliCa

Chinese "UID card" / "magic card" variants

The driver recognises every Chinese UID-changeable card variant as NIUS_CARD_MIFARE_1K — that's the protocol level. The differences live in how the UID is rewritten:

VariantSAKUID change mechanismOperated by NiusRC522
Gen 1a / Gen 1b ("UID card")0x08Special backdoor command (HALT + 0x40)Detected as Classic 1K; UID change needs raw transceive — use a Proxmark3
Gen 2 / CUID / DirectWrite0x08Standard WRITE 0xA0 to block 0Yes — rc522_spi_tag step 0
FUID (Write-Once)0x08Standard WRITE 0xA0 to block 0, onceYes — rc522_spi_tag step 0 (one-shot)
UFUID (Unfused FUID)0x08Standard WRITE 0xA0 to block 0Yes — rc522_spi_tag step 0
Gen 3 / "Magic Gen3"0x08 / 0x18Special gen3 backdoor (UID-only or full-block write)Detected as Classic 1K / 4K; needs Proxmark3 or PN532
Gen 4 / "Ultimate Magic"configConfigurable — emulates any of the aboveYes — depending on emulated type
Magic DesFire0x20APDU-levelNo — needs PN532

The default factory key for all of these is FF FF FF FF FF FF on a fresh card; later variants keep the factory key on sector 0 but switch the rest to a custom key.

Safe UID rewriting (CUID / FUID / UFUID)

Block 0 is special — a single bad write bricks the tag. The driver enforces two safety rails:

  • writeBlock(block, data) refuses block 0 and sector trailers (blocks 3, 7, 11, 15, …) by default. Pass force = true to opt in.
  • setUid(newUid, uidSize) is a dry-run preview by default — it prints the old UID, the new UID, the old / new BCC and which manufacturer bytes it preserves, then returns without writing. Pass commit = true to actually rewrite block 0; the call then backs up, writes, halts, re-detects and verifies the UID matches, and returns NIUS_ERR_UNKNOWN if the card reports a different UID.
uint8_t newUid[4] = {0xDE, 0xAD, 0xBE, 0xEF};
rfid.setUid(newUid, 4); // preview — no write
rfid.setUid(newUid, 4, /*commit=*/true); // backup, write, verify

Examples

Every sketch is a self-contained .ino under examples/. Open it from the Arduino IDE via File → Examples → NiusWireless → ….

SketchModuleWhat it does
rc522_spi_basicRC522 (software SPI)Minimal UID / type dump — 30 lines, the smallest sketch that exercises the driver
rc522_spi_advRC522 (software SPI)IRQ, raw register access, gain control
rc522_spi_s50RC522 (software SPI)Read and write MIFARE Classic 1K blocks
rc522_spi_tagRC522 (software SPI)Auto-adapts to detected type — Classic dump / write / value / key change / CUID, Ultralight page flow, or "use a different tool"
rc522_i2c_basicRC522 (I2C)Minimal UID / type dump over I2C
rc522_i2c_advRC522 (I2C)IRQ, raw register access, gain control over I2C
rfm95_basicRFM95WSend / receive LoRa packets
rfm95_advRFM95WCAD, interrupt RX, full config
sx1262_basicSX1262Send / receive with SX1262 / SX1268
sx1262_advSX1262DCDC, TCXO, DIO2 RF switch, CAD
nrf24_basicNRF24L01Transmit counter packets
nrf24_dual_linkNRF24L01Two radios on one board; bidirectional link test
hc12_basicHC-12Wireless Serial Monitor bridge
hc06_basicHC-06Bluetooth SPP terminal
pn532_i2c_scanPN532 (I2C)Step 1: confirm chip at 0x24; then UID / Type via wake
pn532_i2c_basicPN532 (I2C)Minimal UID / ATQA / SAK / Type (cardPresentWake)
pn532_i2c_advPN532 (I2C)dumpToSerial, setUid dry-run, block 4 R/W, optional Key A demo
pn532_spi_scanPN532 (SPI)Step 1: begin + FW; then UID / Type via wake
pn532_spi_basicPN532 (SPI)Minimal UID / Type — hw SPI, status poll, no IRQ
pn532_spi_advPN532 (SPI)IRQ + same advanced flow as pn532_i2c_adv

Supported boards

The library is architectures=* in library.properties and builds cleanly on every Arduino core we have tested:

FamilyExamples
AVRUNO, Mega, Nano, Pro Mini
SAMDZero, MKR family, Nano 33 IoT
ESP32DevKitC, ESP32-S3, ESP32-C3
ESP8266NodeMCU, Wemos D1 mini
nRF52ArduinoNRF core — ProMicro, nice!nano, SuperMini, XIAO nRF52
STM32STM32duino — Blue Pill, Black Pill, Nucleo
RP2040 / RP2350Pico, Pico W, Pico 2
Renesas RAArduino UNO R4 WiFi, UNO R4 Minima

Installation

Arduino IDE (recommended)

  1. Download the latest release .zip from Releases.
  2. In the IDE: Sketch → Include Library → Add .ZIP Library… and pick the downloaded file.
  3. Restart the IDE. The examples appear under File → Examples → NiusWireless.

Arduino CLI

arduino-cli lib install "NiusWireless"

PlatformIO

lib_deps =
https://github.com/dunknowcoding/NiusWireless.git

Manual / Git checkout

Drop the NiusWireless/ folder into your Arduino libraries/ directory and restart the IDE.


Documentation

  • docs/API.md — full API reference, with wiring tables, constructor variants, error-code catalogue and per-method notes.
  • Header doc-comments — every public method in NiusRC522.h, NiusRFM9x.h, etc. is documented inline. Most IDEs surface those tooltips automatically.

Contributing

Issues and pull requests are welcome. A few guidelines:

  • One module per PR. RC522 changes go in one PR, LoRa in another — keeps the review focused.
  • Run the examples on real hardware before submitting. Hardware-SPI, software-SPI and I2C each have their own regressions.
  • Match the existing style.clang-format config is at the repo root; public API follows the NiusBase interface — derive from it, don't fork it.

For security-relevant issues (e.g. an unintended write path on block 0), please open a private advisory rather than a public issue.


Maintainer

NiusRobotLab — Arduino and embedded firmware, mostly around RFID, LoRa and 2.4 GHz radios. Maintained by dunknowcoding.


License

This library is released under the MIT License. See LICENSE for the full text.

MIT License
Copyright (c) 2024-2026 dunknowcoding / NiusRobotLab
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.

About

Wireless Arduino library all-in-one

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages