Krolyxon
Commit f34b1e2

Branches

Tags

Refs →

orion-rff34b1e2

Migrate to PlatformIO

Now since i have been able to make PSRAM working with platformio, i
don't have to use this shitty Arduino-IDE anymore which does not even
allow me to use subfolders like a normal programmer would do
Author
krolyxon
Date
2026-05-11 14:01 +0530
Parent
360d2d2
Commit
f34b1e2fbd94bcc8d0ee2e2e2e43e214d0b329a1

+6205 −111

44 files changed

  1. M .gitignore +72 −0
  2. D build.sh +0 −63
  3. A platformio.ini +25 −0
  4. R firmware/badusb.cpp → src/badusb.cpp +1 −1
  5. R firmware/badusb.h → src/badusb.h +0 −0
  6. R firmware/ble_mouse.cpp → src/ble_mouse.cpp +1 −1
  7. R firmware/ble_mouse.h → src/ble_mouse.h +0 −0
  8. R firmware/blescanner.cpp → src/blescanner.cpp +2 −2
  9. R firmware/blescanner.h → src/blescanner.h +0 −0
  10. R firmware/buttons.cpp → src/buttons.cpp +0 −0
  11. R firmware/buttons.h → src/buttons.h +0 −0
  12. R firmware/config.h → src/config.h +1 −1
  13. R firmware/device_check.cpp → src/device_check.cpp +21 −7
  14. R firmware/device_check.h → src/device_check.h +0 −0
  15. A src/libs/Adafruit_PN532.cpp +1820 −0
  16. A src/libs/Adafruit_PN532.h +223 −0
  17. R firmware/BleConnectionStatus.cpp → src/libs/BleConnectionStatus.cpp +0 −0
  18. R firmware/BleConnectionStatus.h → src/libs/BleConnectionStatus.h +0 −0
  19. R firmware/BleMouse.cpp → src/libs/BleMouse.cpp +2 −2
  20. R firmware/BleMouse.h → src/libs/BleMouse.h +0 −0
  21. R firmware/ELECHOUSE_CC1101_SRC_DRV.cpp → src/libs/ELECHOUSE_CC1101_SRC_DRV.cpp +0 −0
  22. R firmware/ELECHOUSE_CC1101_SRC_DRV.h → src/libs/ELECHOUSE_CC1101_SRC_DRV.h +0 −0
  23. R firmware/firmware.ino → src/main.cpp +19 −5
  24. A src/nfc.cpp +117 −0
  25. A src/nfc.h +4 −0
  26. R firmware/cc1101.cpp → src/rf/cc1101.cpp +73 −18
  27. R firmware/cc1101.h → src/rf/cc1101.h +0 −0
  28. R firmware/nrf24.cpp → src/rf/nrf24.cpp +2 −2
  29. R firmware/nrf24.h → src/rf/nrf24.h +0 −0
  30. R firmware/sysinfo.cpp → src/sysinfo.cpp +1 −1
  31. R firmware/sysinfo.h → src/sysinfo.h +0 −0
  32. R firmware/display.cpp → src/ui/display.cpp +0 −0
  33. R firmware/display.h → src/ui/display.h +0 −0
  34. R firmware/menu.cpp → src/ui/menu.cpp +4 −4
  35. R firmware/menu.h → src/ui/menu.h +0 −0
  36. R firmware/wifi_analyzer.cpp → src/wifi/wifi_analyzer.cpp +2 −2
  37. R firmware/wifi_analyzer.h → src/wifi/wifi_analyzer.h +0 −0
  38. R firmware/wifi_scan.cpp → src/wifi/wifi_scan.cpp +2 −2
  39. R firmware/wifi_scan.h → src/wifi/wifi_scan.h +0 −0
  40. A test/Adafruit_PN532.cpp +1820 −0
  41. A test/Adafruit_PN532.h +223 −0
  42. A test/ELECHOUSE_CC1101_SRC_DRV.cpp +1309 −0
  43. A test/ELECHOUSE_CC1101_SRC_DRV.h +194 −0
  44. A test/test.ino +267 −0
M .gitignore View
@@ -3,3 +3,75 @@ documentation
33
44 # Clangd cache
55 .cache
6+
7+
8+# Compiled object files
9+*.o
10+*.obj
11+
12+# Precompiled Headers
13+*.gch
14+*.pch
15+
16+# Libraries
17+*.a
18+*.lib
19+
20+# Shared objects
21+*.so
22+*.dylib
23+*.dll
24+
25+# Executables
26+*.exe
27+*.out
28+*.app
29+
30+# PlatformIO
31+.pio/
32+.piolibdeps/
33+.vscode/.browse.c_cpp.db*
34+.vscode/c_cpp_properties.json
35+.vscode/launch.json
36+.vscode/ipch
37+
38+# macOS
39+.DS_Store
40+
41+# Linux
42+*~
43+
44+# Windows
45+Thumbs.db
46+ehthumbs.db
47+Desktop.ini
48+
49+# Logs
50+*.log
51+
52+# Temporary files
53+*.tmp
54+*.temp
55+*.bak
56+*.swp
57+
58+# Environment files
59+.env
60+.env.*
61+
62+# Python cache (if using scripts/tools)
63+__pycache__/
64+*.pyc
65+
66+# Arduino IDE leftovers
67+*.ino.cpp
68+
69+# Build directories
70+build/
71+dist/
72+
73+# Coverage
74+coverage/
75+*.gcda
76+*.gcno
77+*.gcov
D build.sh View
@@ -1,63 +0,0 @@
1−#!/usr/bin/env bash
2−
3−set -e
4−
5−# ========= CONFIG =========
6−PORT="/dev/ttyACM0"
7−
8−FQBN="esp32:esp32:esp32s3:\
9−UploadSpeed=921600,\
10−USBMode=hwcdc,\
11−CDCOnBoot=default,\
12−MSCOnBoot=default,\
13−DFUOnBoot=default,\
14−UploadMode=default,\
15−CPUFreq=240,\
16−FlashMode=qio,\
17−FlashSize=16M,\
18−PartitionScheme=fatflash,\
19−DebugLevel=none,\
20−PSRAM=opi,\
21−LoopCore=1,\
22−EventsCore=1,\
23−EraseFlash=none,\
24−JTAGAdapter=default,\
25−ZigbeeMode=default"
26−
27−# ========= FLAGS =========
28−UPLOAD=false
29−SKETCH_PATH="./firmware"
30−
31−while [[ $# -gt 0 ]]; do
32− case "$1" in
33− -u|--upload)
34− UPLOAD=true
35− shift
36− ;;
37− *)
38− SKETCH_PATH="$1"
39− shift
40− ;;
41− esac
42−done
43−
44−# ========= BUILD =========
45−echo "Compiling sketch..."
46−
47−arduino-cli compile \
48− --fqbn "$FQBN" \
49− "$SKETCH_PATH"
50−
51−echo "Compile successful."
52−
53−# ========= UPLOAD =========
54−if [ "$UPLOAD" = true ]; then
55− echo "Uploading to $PORT..."
56−
57− arduino-cli upload \
58− -p "$PORT" \
59− --fqbn "$FQBN" \
60− "$SKETCH_PATH"
61−
62− echo "Upload complete."
63−fi
A platformio.ini View
@@ -0,0 +1,25 @@
1+[env:esp32-s3-n16r8]
2+platform = espressif32
3+board = esp32-s3-devkitc-1
4+framework = arduino
5+
6+monitor_speed = 115200
7+upload_speed = 921600
8+
9+board_build.flash_mode = qio
10+board_build.flash_size = 16MB
11+
12+board_build.psram = enabled
13+board_build.arduino.memory_type = qio_opi
14+
15+build_flags =
16+ -DBOARD_HAS_PSRAM
17+ -DARDUINO_USB_CDC_ON_BOOT=1
18+
19+lib_deps =
20+ olikraus/U8g2
21+ bblanchon/ArduinoJson
22+ nrf24/RF24
23+ adafruit/Adafruit NeoPixel
24+ t-vk/ESP32 BLE Mouse
25+ adafruit/Adafruit PN532
R firmware/badusb.cpp → src/badusb.cpp View
@@ -1,6 +1,6 @@
11 #include <Arduino.h>
22 #include <USBHIDKeyboard.h>
3−#include "display.h"
3+#include "ui/display.h"
44
55 extern USBHIDKeyboard Keyboard;
66
R firmware/badusb.h → src/badusb.h View

[No content changes]

R firmware/ble_mouse.cpp → src/ble_mouse.cpp View
@@ -4,7 +4,7 @@
44 #include "config.h"
55
66 #include "buttons.h"
7−#include "display.h"
7+#include "ui/display.h"
88
99 // ===== BLE MOUSE =====
1010 // BleMouse bleMouse("Orion-RF", "Orion-RF", 100);
R firmware/ble_mouse.h → src/ble_mouse.h View

[No content changes]

R firmware/blescanner.cpp → src/blescanner.cpp View
@@ -4,7 +4,7 @@
44 #include <BLEAdvertisedDevice.h>
55 #include <vector>
66
7−#include "display.h"
7+#include "ui/display.h"
88 #include "buttons.h"
99 #include "config.h"
1010
@@ -26,7 +26,7 @@ class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks {
2626 void onResult(BLEAdvertisedDevice advertisedDevice) override {
2727 BLEDeviceInfo dev;
2828
29− String tempName = advertisedDevice.getName();
29+ String tempName = advertisedDevice.getName().c_str();
3030
3131 if (tempName.length() == 0 && advertisedDevice.haveServiceData()) {
3232 tempName = advertisedDevice.getServiceData().c_str();
R firmware/blescanner.h → src/blescanner.h View

[No content changes]

R firmware/buttons.cpp → src/buttons.cpp View

[No content changes]

R firmware/buttons.h → src/buttons.h View

[No content changes]

R firmware/config.h → src/config.h View
@@ -19,7 +19,7 @@
1919 // CC1101 via FSPI
2020 #define cc1101_SCK 15
2121 #define cc1101_MISO 3
22−#define cc1101_MOSI 46
22+#define cc1101_MOSI 35
2323
2424 //////////////cc1101(1)//////////
2525 #define CC1101_CS 45
R firmware/device_check.cpp → src/device_check.cpp View
@@ -2,9 +2,9 @@
22 #include <SPI.h>
33 #include <Wire.h>
44 #include <RF24.h>
5−#include "ELECHOUSE_CC1101_SRC_DRV.h"
5+#include "libs/ELECHOUSE_CC1101_SRC_DRV.h"
66
7−#include "display.h"
7+#include "ui/display.h"
88 #include "buttons.h"
99 #include "config.h"
1010
@@ -25,13 +25,26 @@ struct DeviceStatus {
2525 };
2626
2727 // ===== NRF CHECK =====
28+//bool checkNRF(RF24 &radio)
29+//{
30+// // safer: only init if needed
31+// if (!radio.isChipConnected()) {
32+// if (!radio.begin(RADIO_SPI))
33+// return false;
34+// }
35+//
36+// return radio.isChipConnected();
37+//}
38+
2839 bool checkNRF(RF24 &radio)
2940 {
30− // safer: only init if needed
31− if (!radio.isChipConnected()) {
32− if (!radio.begin(RADIO_SPI))
33− return false;
34− }
41+ radio.powerDown();
42+ delay(5);
43+
44+ if (!radio.begin(RADIO_SPI))
45+ return false;
46+
47+ delay(5);
3548
3649 return radio.isChipConnected();
3750 }
@@ -156,6 +169,7 @@ void device_check_run()
156169 // CC1101
157170 status.cc1101_1 = checkCC1101(CC1101_CS);
158171 status.cc1101_2 = checkCC1101(CC1101_2_CS);
172+ //status.cc1101_1 = status.cc1101_2 = false;
159173
160174 // Buttons
161175 status.buttons = checkButtons();
R firmware/device_check.h → src/device_check.h View

[No content changes]

A src/libs/Adafruit_PN532.cpp View
@@ -0,0 +1,1820 @@
1+/**************************************************************************/
2+/*!
3+ @file Adafruit_PN532.cpp
4+
5+ @section intro_sec Introduction
6+
7+ Driver for NXP's PN532 NFC/13.56MHz RFID Transceiver
8+
9+ This is a library for the Adafruit PN532 NFC/RFID breakout boards
10+ This library works with the Adafruit NFC breakout
11+ ----> https://www.adafruit.com/products/364
12+
13+ Check out the links above for our tutorials and wiring diagrams
14+ These chips use SPI or I2C to communicate.
15+
16+ Adafruit invests time and resources providing this open source code,
17+ please support Adafruit and open-source hardware by purchasing
18+ products from Adafruit!
19+
20+ @section author Author
21+
22+ Adafruit Industries
23+
24+ @section license License
25+
26+ BSD (see license.txt)
27+
28+ @section HISTORY
29+
30+ v2.2 - Added startPassiveTargetIDDetection() to start card detection and
31+ readDetectedPassiveTargetID() to read it, useful when using the
32+ IRQ pin.
33+
34+ v2.1 - Added NTAG2xx helper functions
35+
36+ v2.0 - Refactored to add I2C support from Adafruit_NFCShield_I2C library.
37+
38+ v1.4 - Added setPassiveActivationRetries()
39+
40+ v1.2 - Added writeGPIO()
41+ - Added readGPIO()
42+
43+ v1.1 - Changed readPassiveTargetID() to handle multiple UID sizes
44+ - Added the following helper functions for text display
45+ static void PrintHex(const byte * data, const uint32_t numBytes)
46+ static void PrintHexChar(const byte * pbtData, const uint32_t
47+ numBytes)
48+ - Added the following Mifare Classic functions:
49+ bool mifareclassic_IsFirstBlock (uint32_t uiBlock)
50+ bool mifareclassic_IsTrailerBlock (uint32_t uiBlock)
51+ uint8_t mifareclassic_AuthenticateBlock (uint8_t * uid, uint8_t
52+ uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t * keyData) uint8_t
53+ mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t * data) uint8_t
54+ mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t * data)
55+ - Added the following Mifare Ultalight functions:
56+ uint8_t mifareultralight_ReadPage (uint8_t page, uint8_t * buffer)
57+*/
58+/**************************************************************************/
59+
60+#include "Adafruit_PN532.h"
61+
62+byte pn532ack[] = {0x00, 0x00, 0xFF,
63+ 0x00, 0xFF, 0x00}; ///< ACK message from PN532
64+byte pn532response_firmwarevers[] = {
65+ 0x00, 0x00, 0xFF,
66+ 0x06, 0xFA, 0xD5}; ///< Expected firmware version message from PN532
67+
68+// Uncomment these lines to enable debug output for PN532(SPI) and/or MIFARE
69+// related code
70+
71+// #define PN532DEBUG
72+// #define MIFAREDEBUG
73+
74+// If using Native Port on Arduino Zero or Due define as SerialUSB
75+#define PN532DEBUGPRINT Serial ///< Fixed name for debug Serial instance
76+// #define PN532DEBUGPRINT SerialUSB ///< Fixed name for debug Serial instance
77+
78+#define PN532_PACKBUFFSIZ 64 ///< Packet buffer size in bytes
79+byte pn532_packetbuffer[PN532_PACKBUFFSIZ]; ///< Packet buffer used in various
80+ ///< transactions
81+
82+/**************************************************************************/
83+/*!
84+ @brief Instantiates a new PN532 class using software SPI.
85+
86+ @param clk SPI clock pin (SCK)
87+ @param miso SPI MISO pin
88+ @param mosi SPI MOSI pin
89+ @param ss SPI chip select pin (CS/SSEL)
90+*/
91+/**************************************************************************/
92+Adafruit_PN532::Adafruit_PN532(uint8_t clk, uint8_t miso, uint8_t mosi,
93+ uint8_t ss) {
94+ _cs = ss;
95+ spi_dev = new Adafruit_SPIDevice(ss, clk, miso, mosi, 1000000,
96+ SPI_BITORDER_LSBFIRST, SPI_MODE0);
97+}
98+
99+/**************************************************************************/
100+/*!
101+ @brief Instantiates a new PN532 class using I2C.
102+
103+ @param irq Location of the IRQ pin
104+ @param reset Location of the RSTPD_N pin
105+ @param theWire pointer to I2C bus to use
106+*/
107+/**************************************************************************/
108+Adafruit_PN532::Adafruit_PN532(uint8_t irq, uint8_t reset, TwoWire *theWire)
109+ : _irq(irq), _reset(reset) {
110+ pinMode(_irq, INPUT);
111+ pinMode(_reset, OUTPUT);
112+ i2c_dev = new Adafruit_I2CDevice(PN532_I2C_ADDRESS, theWire);
113+}
114+
115+/**************************************************************************/
116+/*!
117+ @brief Instantiates a new PN532 class using hardware SPI.
118+
119+ @param ss SPI chip select pin (CS/SSEL)
120+ @param theSPI pointer to the SPI bus to use
121+*/
122+/**************************************************************************/
123+Adafruit_PN532::Adafruit_PN532(uint8_t ss, SPIClass *theSPI) {
124+ _cs = ss;
125+ spi_dev = new Adafruit_SPIDevice(ss, 1000000, SPI_BITORDER_LSBFIRST,
126+ SPI_MODE0, theSPI);
127+}
128+
129+/**************************************************************************/
130+/*!
131+ @brief Instantiates a new PN532 class using hardware UART (HSU).
132+
133+ @param reset Location of the RSTPD_N pin
134+ @param theSer pointer to HardWare Serial bus to use
135+*/
136+/**************************************************************************/
137+Adafruit_PN532::Adafruit_PN532(uint8_t reset, HardwareSerial *theSer)
138+ : _reset(reset) {
139+ pinMode(_reset, OUTPUT);
140+ ser_dev = theSer;
141+}
142+
143+/**************************************************************************/
144+/*!
145+ @brief Setups the HW
146+
147+ @returns true if successful, otherwise false
148+*/
149+/**************************************************************************/
150+bool Adafruit_PN532::begin() {
151+ if (spi_dev) {
152+ // SPI initialization
153+ if (!spi_dev->begin()) {
154+ return false;
155+ }
156+ } else if (i2c_dev) {
157+ // I2C initialization
158+ // PN532 will fail address check since its asleep, so suppress
159+ if (!i2c_dev->begin(false)) {
160+ return false;
161+ }
162+ } else if (ser_dev) {
163+ ser_dev->begin(115200);
164+ // clear out anything in read buffer
165+ while (ser_dev->available())
166+ ser_dev->read();
167+ } else {
168+ // no interface specified
169+ return false;
170+ }
171+ reset(); // HW reset - put in known state
172+ delay(10);
173+ wakeup(); // hey! wakeup!
174+ return true;
175+}
176+
177+/**************************************************************************/
178+/*!
179+ @brief Perform a hardware reset. Requires reset pin to have been provided.
180+*/
181+/**************************************************************************/
182+void Adafruit_PN532::reset(void) {
183+ // see Datasheet p.209, Fig.48 for timings
184+ if (_reset != -1) {
185+ digitalWrite(_reset, LOW);
186+ delay(1); // min 20ns
187+ digitalWrite(_reset, HIGH);
188+ delay(2); // max 2ms
189+ }
190+}
191+
192+/**************************************************************************/
193+/*!
194+ @brief Wakeup from LowVbat mode into Normal Mode.
195+*/
196+/**************************************************************************/
197+void Adafruit_PN532::wakeup(void) {
198+ // interface specific wakeups - each one is unique!
199+ if (spi_dev) {
200+ // hold CS low for 2ms
201+ digitalWrite(_cs, LOW);
202+ delay(2);
203+ } else if (ser_dev) {
204+ uint8_t w[3] = {0x55, 0x00, 0x00};
205+ ser_dev->write(w, 3);
206+ delay(2);
207+ }
208+
209+ // PN532 will clock stretch I2C during SAMConfig as a "wakeup"
210+
211+ // need to config SAM to stay in Normal Mode
212+ SAMConfig();
213+}
214+
215+/**************************************************************************/
216+/*!
217+ @brief Prints a hexadecimal value in plain characters
218+
219+ @param data Pointer to the byte data
220+ @param numBytes Data length in bytes
221+*/
222+/**************************************************************************/
223+void Adafruit_PN532::PrintHex(const byte *data, const uint32_t numBytes) {
224+ uint32_t szPos;
225+ for (szPos = 0; szPos < numBytes; szPos++) {
226+ PN532DEBUGPRINT.print(F("0x"));
227+ // Append leading 0 for small values
228+ if (data[szPos] <= 0xF)
229+ PN532DEBUGPRINT.print(F("0"));
230+ PN532DEBUGPRINT.print(data[szPos] & 0xff, HEX);
231+ if ((numBytes > 1) && (szPos != numBytes - 1)) {
232+ PN532DEBUGPRINT.print(F(" "));
233+ }
234+ }
235+ PN532DEBUGPRINT.println();
236+}
237+
238+/**************************************************************************/
239+/*!
240+ @brief Prints a hexadecimal value in plain characters, along with
241+ the char equivalents in the following format
242+
243+ 00 00 00 00 00 00 ......
244+
245+ @param data Pointer to the byte data
246+ @param numBytes Data length in bytes
247+*/
248+/**************************************************************************/
249+void Adafruit_PN532::PrintHexChar(const byte *data, const uint32_t numBytes) {
250+ uint32_t szPos;
251+ for (szPos = 0; szPos < numBytes; szPos++) {
252+ // Append leading 0 for small values
253+ if (data[szPos] <= 0xF)
254+ PN532DEBUGPRINT.print(F("0"));
255+ PN532DEBUGPRINT.print(data[szPos], HEX);
256+ if ((numBytes > 1) && (szPos != numBytes - 1)) {
257+ PN532DEBUGPRINT.print(F(" "));
258+ }
259+ }
260+ PN532DEBUGPRINT.print(F(" "));
261+ for (szPos = 0; szPos < numBytes; szPos++) {
262+ if (data[szPos] <= 0x1F)
263+ PN532DEBUGPRINT.print(F("."));
264+ else
265+ PN532DEBUGPRINT.print((char)data[szPos]);
266+ }
267+ PN532DEBUGPRINT.println();
268+}
269+
270+/**************************************************************************/
271+/*!
272+ @brief Checks the firmware version of the PN5xx chip
273+
274+ @returns The chip's firmware version and ID
275+*/
276+/**************************************************************************/
277+uint32_t Adafruit_PN532::getFirmwareVersion(void) {
278+ uint32_t response;
279+
280+ pn532_packetbuffer[0] = PN532_COMMAND_GETFIRMWAREVERSION;
281+
282+ if (!sendCommandCheckAck(pn532_packetbuffer, 1)) {
283+ return 0;
284+ }
285+
286+ // read data packet
287+ readdata(pn532_packetbuffer, 13);
288+
289+ // check some basic stuff
290+ if (0 != memcmp((char *)pn532_packetbuffer,
291+ (char *)pn532response_firmwarevers, 6)) {
292+#ifdef PN532DEBUG
293+ PN532DEBUGPRINT.println(F("Firmware doesn't match!"));
294+#endif
295+ return 0;
296+ }
297+
298+ int offset = 7;
299+ response = pn532_packetbuffer[offset++];
300+ response <<= 8;
301+ response |= pn532_packetbuffer[offset++];
302+ response <<= 8;
303+ response |= pn532_packetbuffer[offset++];
304+ response <<= 8;
305+ response |= pn532_packetbuffer[offset++];
306+
307+ return response;
308+}
309+
310+/**************************************************************************/
311+/*!
312+ @brief Sends a command and waits a specified period for the ACK
313+
314+ @param cmd Pointer to the command buffer
315+ @param cmdlen The size of the command in bytes
316+ @param timeout timeout before giving up
317+
318+ @returns 1 if everything is OK, 0 if timeout occured before an
319+ ACK was recieved
320+*/
321+/**************************************************************************/
322+// default timeout of one second
323+bool Adafruit_PN532::sendCommandCheckAck(uint8_t *cmd, uint8_t cmdlen,
324+ uint16_t timeout) {
325+
326+ // I2C works without using IRQ pin by polling for RDY byte
327+ // seems to work best with some delays between transactions
328+ uint8_t SLOWDOWN = 0;
329+ if (i2c_dev || spi_dev) // SPI and I2C need 1ms slow for page reads
330+ SLOWDOWN = 1;
331+
332+ // write the command
333+ writecommand(cmd, cmdlen);
334+
335+ // I2C TUNING
336+ delay(SLOWDOWN);
337+
338+ // Wait for chip to say its ready!
339+ if (!waitready(timeout)) {
340+ return false;
341+ }
342+
343+#ifdef PN532DEBUG
344+ if (spi_dev == NULL) {
345+ PN532DEBUGPRINT.println(F("IRQ received"));
346+ }
347+#endif
348+
349+ // read acknowledgement
350+ if (!readack()) {
351+#ifdef PN532DEBUG
352+ PN532DEBUGPRINT.println(F("No ACK frame received!"));
353+#endif
354+ return false;
355+ }
356+
357+ // I2C TUNING
358+ delay(SLOWDOWN);
359+
360+ // Wait for chip to say its ready!
361+ if (!waitready(timeout)) {
362+ return false;
363+ }
364+
365+ return true; // ack'd command
366+}
367+
368+/**************************************************************************/
369+/*!
370+ @brief Writes an 8-bit value that sets the state of the PN532's GPIO
371+ pins.
372+ @param pinstate P3 pins state.
373+
374+ @warning This function is provided exclusively for board testing and
375+ is dangerous since it will throw an error if any pin other
376+ than the ones marked "Can be used as GPIO" are modified! All
377+ pins that can not be used as GPIO should ALWAYS be left high
378+ (value = 1) or the system will become unstable and a HW reset
379+ will be required to recover the PN532.
380+
381+ pinState[0] = P30 Can be used as GPIO
382+ pinState[1] = P31 Can be used as GPIO
383+ pinState[2] = P32 *** RESERVED (Must be 1!) ***
384+ pinState[3] = P33 Can be used as GPIO
385+ pinState[4] = P34 *** RESERVED (Must be 1!) ***
386+ pinState[5] = P35 Can be used as GPIO
387+
388+ @return 1 if everything executed properly, 0 for an error
389+*/
390+/**************************************************************************/
391+bool Adafruit_PN532::writeGPIO(uint8_t pinstate) {
392+ // uint8_t errorbit;
393+
394+ // Make sure pinstate does not try to toggle P32 or P34
395+ pinstate |= (1 << PN532_GPIO_P32) | (1 << PN532_GPIO_P34);
396+
397+ // Fill command buffer
398+ pn532_packetbuffer[0] = PN532_COMMAND_WRITEGPIO;
399+ pn532_packetbuffer[1] = PN532_GPIO_VALIDATIONBIT | pinstate; // P3 Pins
400+ pn532_packetbuffer[2] = 0x00; // P7 GPIO Pins (not used ... taken by SPI)
401+
402+#ifdef PN532DEBUG
403+ PN532DEBUGPRINT.print(F("Writing P3 GPIO: "));
404+ PN532DEBUGPRINT.println(pn532_packetbuffer[1], HEX);
405+#endif
406+
407+ // Send the WRITEGPIO command (0x0E)
408+ if (!sendCommandCheckAck(pn532_packetbuffer, 3))
409+ return 0x0;
410+
411+ // Read response packet (00 FF PLEN PLENCHECKSUM D5 CMD+1(0x0F) DATACHECKSUM
412+ // 00)
413+ readdata(pn532_packetbuffer, 8);
414+
415+#ifdef PN532DEBUG
416+ PN532DEBUGPRINT.print(F("Received: "));
417+ PrintHex(pn532_packetbuffer, 8);
418+ PN532DEBUGPRINT.println();
419+#endif
420+
421+ int offset = 6;
422+ return (pn532_packetbuffer[offset] == 0x0F);
423+}
424+
425+/**************************************************************************/
426+/*!
427+ Reads the state of the PN532's GPIO pins
428+
429+ @returns An 8-bit value containing the pin state where:
430+
431+ pinState[0] = P30
432+ pinState[1] = P31
433+ pinState[2] = P32
434+ pinState[3] = P33
435+ pinState[4] = P34
436+ pinState[5] = P35
437+*/
438+/**************************************************************************/
439+uint8_t Adafruit_PN532::readGPIO(void) {
440+ pn532_packetbuffer[0] = PN532_COMMAND_READGPIO;
441+
442+ // Send the READGPIO command (0x0C)
443+ if (!sendCommandCheckAck(pn532_packetbuffer, 1))
444+ return 0x0;
445+
446+ // Read response packet (00 FF PLEN PLENCHECKSUM D5 CMD+1(0x0D) P3 P7 IO1
447+ // DATACHECKSUM 00)
448+ readdata(pn532_packetbuffer, 11);
449+
450+ /* READGPIO response should be in the following format:
451+
452+ byte Description
453+ ------------- ------------------------------------------
454+ b0..5 Frame header and preamble (with I2C there is an extra 0x00)
455+ b6 P3 GPIO Pins
456+ b7 P7 GPIO Pins (not used ... taken by SPI)
457+ b8 Interface Mode Pins (not used ... bus select pins)
458+ b9..10 checksum */
459+
460+ int p3offset = 7;
461+
462+#ifdef PN532DEBUG
463+ PN532DEBUGPRINT.print(F("Received: "));
464+ PrintHex(pn532_packetbuffer, 11);
465+ PN532DEBUGPRINT.println();
466+ PN532DEBUGPRINT.print(F("P3 GPIO: 0x"));
467+ PN532DEBUGPRINT.println(pn532_packetbuffer[p3offset], HEX);
468+ PN532DEBUGPRINT.print(F("P7 GPIO: 0x"));
469+ PN532DEBUGPRINT.println(pn532_packetbuffer[p3offset + 1], HEX);
470+ PN532DEBUGPRINT.print(F("IO GPIO: 0x"));
471+ PN532DEBUGPRINT.println(pn532_packetbuffer[p3offset + 2], HEX);
472+ // Note: You can use the IO GPIO value to detect the serial bus being used
473+ switch (pn532_packetbuffer[p3offset + 2]) {
474+ case 0x00: // Using UART
475+ PN532DEBUGPRINT.println(F("Using UART (IO = 0x00)"));
476+ break;
477+ case 0x01: // Using I2C
478+ PN532DEBUGPRINT.println(F("Using I2C (IO = 0x01)"));
479+ break;
480+ case 0x02: // Using SPI
481+ PN532DEBUGPRINT.println(F("Using SPI (IO = 0x02)"));
482+ break;
483+ }
484+#endif
485+
486+ return pn532_packetbuffer[p3offset];
487+}
488+
489+/**************************************************************************/
490+/*!
491+ @brief Configures the SAM (Secure Access Module)
492+ @return true on success, false otherwise.
493+*/
494+/**************************************************************************/
495+bool Adafruit_PN532::SAMConfig(void) {
496+ pn532_packetbuffer[0] = PN532_COMMAND_SAMCONFIGURATION;
497+ pn532_packetbuffer[1] = 0x01; // normal mode;
498+ pn532_packetbuffer[2] = 0x14; // timeout 50ms * 20 = 1 second
499+ pn532_packetbuffer[3] = 0x01; // use IRQ pin!
500+
501+ if (!sendCommandCheckAck(pn532_packetbuffer, 4))
502+ return false;
503+
504+ // read data packet
505+ readdata(pn532_packetbuffer, 9);
506+
507+ int offset = 6;
508+ return (pn532_packetbuffer[offset] == 0x15);
509+}
510+
511+/**************************************************************************/
512+/*!
513+ Sets the MxRtyPassiveActivation byte of the RFConfiguration register
514+
515+ @param maxRetries 0xFF to wait forever, 0x00..0xFE to timeout
516+ after mxRetries
517+
518+ @returns 1 if everything executed properly, 0 for an error
519+*/
520+/**************************************************************************/
521+bool Adafruit_PN532::setPassiveActivationRetries(uint8_t maxRetries) {
522+ pn532_packetbuffer[0] = PN532_COMMAND_RFCONFIGURATION;
523+ pn532_packetbuffer[1] = 5; // Config item 5 (MaxRetries)
524+ pn532_packetbuffer[2] = 0xFF; // MxRtyATR (default = 0xFF)
525+ pn532_packetbuffer[3] = 0x01; // MxRtyPSL (default = 0x01)
526+ pn532_packetbuffer[4] = maxRetries;
527+
528+#ifdef MIFAREDEBUG
529+ PN532DEBUGPRINT.print(F("Setting MxRtyPassiveActivation to "));
530+ PN532DEBUGPRINT.print(maxRetries, DEC);
531+ PN532DEBUGPRINT.println(F(" "));
532+#endif
533+
534+ if (!sendCommandCheckAck(pn532_packetbuffer, 5))
535+ return 0x0; // no ACK
536+
537+ return 1;
538+}
539+
540+/***** ISO14443A Commands ******/
541+
542+/**************************************************************************/
543+/*!
544+ @brief Waits for an ISO14443A target to enter the field and reads
545+ its ID.
546+
547+ @param cardbaudrate Baud rate of the card
548+ @param uid Pointer to the array that will be populated
549+ with the card's UID (up to 7 bytes)
550+ @param uidLength Pointer to the variable that will hold the
551+ length of the card's UID.
552+ @param timeout Timeout in milliseconds.
553+
554+ @return 1 if everything executed properly, 0 for an error
555+*/
556+/**************************************************************************/
557+bool Adafruit_PN532::readPassiveTargetID(uint8_t cardbaudrate, uint8_t *uid,
558+ uint8_t *uidLength, uint16_t timeout) {
559+ pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET;
560+ pn532_packetbuffer[1] = 1; // max 1 cards at once (we can set this to 2 later)
561+ pn532_packetbuffer[2] = cardbaudrate;
562+
563+ if (!sendCommandCheckAck(pn532_packetbuffer, 3, timeout)) {
564+#ifdef PN532DEBUG
565+ PN532DEBUGPRINT.println(F("No card(s) read"));
566+#endif
567+ return 0x0; // no cards read
568+ }
569+
570+ return readDetectedPassiveTargetID(uid, uidLength);
571+}
572+
573+/**************************************************************************/
574+/*!
575+ @brief Put the reader in detection mode, non blocking so interrupts
576+ must be enabled.
577+ @param cardbaudrate Baud rate of the card
578+ @return 1 if everything executed properly, 0 for an error
579+*/
580+/**************************************************************************/
581+bool Adafruit_PN532::startPassiveTargetIDDetection(uint8_t cardbaudrate) {
582+ pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET;
583+ pn532_packetbuffer[1] = 1; // max 1 cards at once (we can set this to 2 later)
584+ pn532_packetbuffer[2] = cardbaudrate;
585+
586+ return sendCommandCheckAck(pn532_packetbuffer, 3);
587+}
588+
589+/**************************************************************************/
590+/*!
591+ Reads the ID of the passive target the reader has deteceted.
592+
593+ @param uid Pointer to the array that will be populated
594+ with the card's UID (up to 7 bytes)
595+ @param uidLength Pointer to the variable that will hold the
596+ length of the card's UID.
597+
598+ @returns 1 if everything executed properly, 0 for an error
599+*/
600+/**************************************************************************/
601+bool Adafruit_PN532::readDetectedPassiveTargetID(uint8_t *uid,
602+ uint8_t *uidLength) {
603+ // read data packet
604+ readdata(pn532_packetbuffer, 20);
605+ // check some basic stuff
606+
607+ /* ISO14443A card response should be in the following format:
608+
609+ byte Description
610+ ------------- ------------------------------------------
611+ b0..6 Frame header and preamble
612+ b7 Tags Found
613+ b8 Tag Number (only one used in this example)
614+ b9..10 SENS_RES
615+ b11 SEL_RES
616+ b12 NFCID Length
617+ b13..NFCIDLen NFCID */
618+
619+#ifdef MIFAREDEBUG
620+ PN532DEBUGPRINT.print(F("Found "));
621+ PN532DEBUGPRINT.print(pn532_packetbuffer[7], DEC);
622+ PN532DEBUGPRINT.println(F(" tags"));
623+#endif
624+ if (pn532_packetbuffer[7] != 1)
625+ return 0;
626+
627+ uint16_t sens_res = pn532_packetbuffer[9];
628+ sens_res <<= 8;
629+ sens_res |= pn532_packetbuffer[10];
630+#ifdef MIFAREDEBUG
631+ PN532DEBUGPRINT.print(F("ATQA: 0x"));
632+ PN532DEBUGPRINT.println(sens_res, HEX);
633+ PN532DEBUGPRINT.print(F("SAK: 0x"));
634+ PN532DEBUGPRINT.println(pn532_packetbuffer[11], HEX);
635+#endif
636+
637+ /* Card appears to be Mifare Classic */
638+ *uidLength = pn532_packetbuffer[12];
639+#ifdef MIFAREDEBUG
640+ PN532DEBUGPRINT.print(F("UID:"));
641+#endif
642+ for (uint8_t i = 0; i < pn532_packetbuffer[12]; i++) {
643+ uid[i] = pn532_packetbuffer[13 + i];
644+#ifdef MIFAREDEBUG
645+ PN532DEBUGPRINT.print(F(" 0x"));
646+ PN532DEBUGPRINT.print(uid[i], HEX);
647+#endif
648+ }
649+#ifdef MIFAREDEBUG
650+ PN532DEBUGPRINT.println();
651+#endif
652+
653+ return 1;
654+}
655+
656+/**************************************************************************/
657+/*!
658+ @brief Exchanges an APDU with the currently inlisted peer
659+
660+ @param send Pointer to data to send
661+ @param sendLength Length of the data to send
662+ @param response Pointer to response data
663+ @param responseLength Pointer to the response data length
664+ @return true on success, false otherwise.
665+*/
666+/**************************************************************************/
667+bool Adafruit_PN532::inDataExchange(uint8_t *send, uint8_t sendLength,
668+ uint8_t *response,
669+ uint8_t *responseLength) {
670+ if (sendLength > PN532_PACKBUFFSIZ - 2) {
671+#ifdef PN532DEBUG
672+ PN532DEBUGPRINT.println(F("APDU length too long for packet buffer"));
673+#endif
674+ return false;
675+ }
676+ uint8_t i;
677+
678+ pn532_packetbuffer[0] = 0x40; // PN532_COMMAND_INDATAEXCHANGE;
679+ pn532_packetbuffer[1] = _inListedTag;
680+ for (i = 0; i < sendLength; ++i) {
681+ pn532_packetbuffer[i + 2] = send[i];
682+ }
683+
684+ if (!sendCommandCheckAck(pn532_packetbuffer, sendLength + 2, 1000)) {
685+#ifdef PN532DEBUG
686+ PN532DEBUGPRINT.println(F("Could not send APDU"));
687+#endif
688+ return false;
689+ }
690+
691+ if (!waitready(1000)) {
692+#ifdef PN532DEBUG
693+ PN532DEBUGPRINT.println(F("Response never received for APDU..."));
694+#endif
695+ return false;
696+ }
697+
698+ readdata(pn532_packetbuffer, sizeof(pn532_packetbuffer));
699+
700+ if (pn532_packetbuffer[0] == 0 && pn532_packetbuffer[1] == 0 &&
701+ pn532_packetbuffer[2] == 0xff) {
702+ uint8_t length = pn532_packetbuffer[3];
703+ if (pn532_packetbuffer[4] != (uint8_t)(~length + 1)) {
704+#ifdef PN532DEBUG
705+ PN532DEBUGPRINT.println(F("Length check invalid"));
706+ PN532DEBUGPRINT.println(length, HEX);
707+ PN532DEBUGPRINT.println((~length) + 1, HEX);
708+#endif
709+ return false;
710+ }
711+ if (pn532_packetbuffer[5] == PN532_PN532TOHOST &&
712+ pn532_packetbuffer[6] == PN532_RESPONSE_INDATAEXCHANGE) {
713+ if ((pn532_packetbuffer[7] & 0x3f) != 0) {
714+#ifdef PN532DEBUG
715+ PN532DEBUGPRINT.println(F("Status code indicates an error"));
716+#endif
717+ return false;
718+ }
719+
720+ length -= 3;
721+
722+ if (length > *responseLength) {
723+ length = *responseLength; // silent truncation...
724+ }
725+
726+ for (i = 0; i < length; ++i) {
727+ response[i] = pn532_packetbuffer[8 + i];
728+ }
729+ *responseLength = length;
730+
731+ return true;
732+ } else {
733+ PN532DEBUGPRINT.print(F("Don't know how to handle this command: "));
734+ PN532DEBUGPRINT.println(pn532_packetbuffer[6], HEX);
735+ return false;
736+ }
737+ } else {
738+ PN532DEBUGPRINT.println(F("Preamble missing"));
739+ return false;
740+ }
741+}
742+
743+/**************************************************************************/
744+/*!
745+ @brief 'InLists' a passive target. PN532 acting as reader/initiator,
746+ peer acting as card/responder.
747+ @return true on success, false otherwise.
748+*/
749+/**************************************************************************/
750+bool Adafruit_PN532::inListPassiveTarget() {
751+ pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET;
752+ pn532_packetbuffer[1] = 1;
753+ pn532_packetbuffer[2] = 0;
754+
755+#ifdef PN532DEBUG
756+ PN532DEBUGPRINT.print(F("About to inList passive target"));
757+#endif
758+
759+ if (!sendCommandCheckAck(pn532_packetbuffer, 3, 1000)) {
760+#ifdef PN532DEBUG
761+ PN532DEBUGPRINT.println(F("Could not send inlist message"));
762+#endif
763+ return false;
764+ }
765+
766+ if (!waitready(30000)) {
767+ return false;
768+ }
769+
770+ readdata(pn532_packetbuffer, sizeof(pn532_packetbuffer));
771+
772+ if (pn532_packetbuffer[0] == 0 && pn532_packetbuffer[1] == 0 &&
773+ pn532_packetbuffer[2] == 0xff) {
774+ uint8_t length = pn532_packetbuffer[3];
775+ if (pn532_packetbuffer[4] != (uint8_t)(~length + 1)) {
776+#ifdef PN532DEBUG
777+ PN532DEBUGPRINT.println(F("Length check invalid"));
778+ PN532DEBUGPRINT.println(length, HEX);
779+ PN532DEBUGPRINT.println((~length) + 1, HEX);
780+#endif
781+ return false;
782+ }
783+ if (pn532_packetbuffer[5] == PN532_PN532TOHOST &&
784+ pn532_packetbuffer[6] == PN532_RESPONSE_INLISTPASSIVETARGET) {
785+ if (pn532_packetbuffer[7] != 1) {
786+#ifdef PN532DEBUG
787+ PN532DEBUGPRINT.println(F("Unhandled number of targets inlisted"));
788+#endif
789+ PN532DEBUGPRINT.println(F("Number of tags inlisted:"));
790+ PN532DEBUGPRINT.println(pn532_packetbuffer[7]);
791+ return false;
792+ }
793+
794+ _inListedTag = pn532_packetbuffer[8];
795+ PN532DEBUGPRINT.print(F("Tag number: "));
796+ PN532DEBUGPRINT.println(_inListedTag);
797+
798+ return true;
799+ } else {
800+#ifdef PN532DEBUG
801+ PN532DEBUGPRINT.print(F("Unexpected response to inlist passive host"));
802+#endif
803+ return false;
804+ }
805+ } else {
806+#ifdef PN532DEBUG
807+ PN532DEBUGPRINT.println(F("Preamble missing"));
808+#endif
809+ return false;
810+ }
811+
812+ return true;
813+}
814+
815+/***** Mifare Classic Functions ******/
816+
817+/**************************************************************************/
818+/*!
819+ @brief Indicates whether the specified block number is the first block
820+ in the sector (block 0 relative to the current sector)
821+ @param uiBlock Block number to test.
822+ @return true if first block, false otherwise.
823+*/
824+/**************************************************************************/
825+bool Adafruit_PN532::mifareclassic_IsFirstBlock(uint32_t uiBlock) {
826+ // Test if we are in the small or big sectors
827+ if (uiBlock < 128)
828+ return ((uiBlock) % 4 == 0);
829+ else
830+ return ((uiBlock) % 16 == 0);
831+}
832+
833+/**************************************************************************/
834+/*!
835+ @brief Indicates whether the specified block number is the sector
836+ trailer.
837+ @param uiBlock Block number to test.
838+ @return true if sector trailer, false otherwise.
839+*/
840+/**************************************************************************/
841+bool Adafruit_PN532::mifareclassic_IsTrailerBlock(uint32_t uiBlock) {
842+ // Test if we are in the small or big sectors
843+ if (uiBlock < 128)
844+ return ((uiBlock + 1) % 4 == 0);
845+ else
846+ return ((uiBlock + 1) % 16 == 0);
847+}
848+
849+/**************************************************************************/
850+/*!
851+ Tries to authenticate a block of memory on a MIFARE card using the
852+ INDATAEXCHANGE command. See section 7.3.8 of the PN532 User Manual
853+ for more information on sending MIFARE and other commands.
854+
855+ @param uid Pointer to a byte array containing the card UID
856+ @param uidLen The length (in bytes) of the card's UID (Should
857+ be 4 for MIFARE Classic)
858+ @param blockNumber The block number to authenticate. (0..63 for
859+ 1KB cards, and 0..255 for 4KB cards).
860+ @param keyNumber Which key type to use during authentication
861+ (0 = MIFARE_CMD_AUTH_A, 1 = MIFARE_CMD_AUTH_B)
862+ @param keyData Pointer to a byte array containing the 6 byte
863+ key value
864+
865+ @returns 1 if everything executed properly, 0 for an error
866+*/
867+/**************************************************************************/
868+uint8_t Adafruit_PN532::mifareclassic_AuthenticateBlock(uint8_t *uid,
869+ uint8_t uidLen,
870+ uint32_t blockNumber,
871+ uint8_t keyNumber,
872+ uint8_t *keyData) {
873+ // uint8_t len;
874+ uint8_t i;
875+
876+ // Hang on to the key and uid data
877+ memcpy(_key, keyData, 6);
878+ memcpy(_uid, uid, uidLen);
879+ _uidLen = uidLen;
880+
881+#ifdef MIFAREDEBUG
882+ PN532DEBUGPRINT.print(F("Trying to authenticate card "));
883+ Adafruit_PN532::PrintHex(_uid, _uidLen);
884+ PN532DEBUGPRINT.print(F("Using authentication KEY "));
885+ PN532DEBUGPRINT.print(keyNumber ? 'B' : 'A');
886+ PN532DEBUGPRINT.print(F(": "));
887+ Adafruit_PN532::PrintHex(_key, 6);
888+#endif
889+
890+ // Prepare the authentication command //
891+ pn532_packetbuffer[0] =
892+ PN532_COMMAND_INDATAEXCHANGE; /* Data Exchange Header */
893+ pn532_packetbuffer[1] = 1; /* Max card numbers */
894+ pn532_packetbuffer[2] = (keyNumber) ? MIFARE_CMD_AUTH_B : MIFARE_CMD_AUTH_A;
895+ pn532_packetbuffer[3] =
896+ blockNumber; /* Block Number (1K = 0..63, 4K = 0..255 */
897+ memcpy(pn532_packetbuffer + 4, _key, 6);
898+ for (i = 0; i < _uidLen; i++) {
899+ pn532_packetbuffer[10 + i] = _uid[i]; /* 4 byte card ID */
900+ }
901+
902+ if (!sendCommandCheckAck(pn532_packetbuffer, 10 + _uidLen))
903+ return 0;
904+
905+ // Read the response packet
906+ readdata(pn532_packetbuffer, 12);
907+
908+ // check if the response is valid and we are authenticated???
909+ // for an auth success it should be bytes 5-7: 0xD5 0x41 0x00
910+ // Mifare auth error is technically byte 7: 0x14 but anything other and 0x00
911+ // is not good
912+ if (pn532_packetbuffer[7] != 0x00) {
913+#ifdef PN532DEBUG
914+ PN532DEBUGPRINT.print(F("Authentification failed: "));
915+ Adafruit_PN532::PrintHexChar(pn532_packetbuffer, 12);
916+#endif
917+ return 0;
918+ }
919+
920+ return 1;
921+}
922+
923+/**************************************************************************/
924+/*!
925+ Tries to read an entire 16-byte data block at the specified block
926+ address.
927+
928+ @param blockNumber The block number to authenticate. (0..63 for
929+ 1KB cards, and 0..255 for 4KB cards).
930+ @param data Pointer to the byte array that will hold the
931+ retrieved data (if any)
932+
933+ @returns 1 if everything executed properly, 0 for an error
934+*/
935+/**************************************************************************/
936+uint8_t Adafruit_PN532::mifareclassic_ReadDataBlock(uint8_t blockNumber,
937+ uint8_t *data) {
938+#ifdef MIFAREDEBUG
939+ PN532DEBUGPRINT.print(F("Trying to read 16 bytes from block "));
940+ PN532DEBUGPRINT.println(blockNumber);
941+#endif
942+
943+ /* Prepare the command */
944+ pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
945+ pn532_packetbuffer[1] = 1; /* Card number */
946+ pn532_packetbuffer[2] = MIFARE_CMD_READ; /* Mifare Read command = 0x30 */
947+ pn532_packetbuffer[3] =
948+ blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */
949+
950+ /* Send the command */
951+ if (!sendCommandCheckAck(pn532_packetbuffer, 4)) {
952+#ifdef MIFAREDEBUG
953+ PN532DEBUGPRINT.println(F("Failed to receive ACK for read command"));
954+#endif
955+ return 0;
956+ }
957+
958+ /* Read the response packet */
959+ readdata(pn532_packetbuffer, 26);
960+
961+ /* If byte 8 isn't 0x00 we probably have an error */
962+ if (pn532_packetbuffer[7] != 0x00) {
963+#ifdef MIFAREDEBUG
964+ PN532DEBUGPRINT.println(F("Unexpected response"));
965+ Adafruit_PN532::PrintHexChar(pn532_packetbuffer, 26);
966+#endif
967+ return 0;
968+ }
969+
970+ /* Copy the 16 data bytes to the output buffer */
971+ /* Block content starts at byte 9 of a valid response */
972+ memcpy(data, pn532_packetbuffer + 8, 16);
973+
974+/* Display data for debug if requested */
975+#ifdef MIFAREDEBUG
976+ PN532DEBUGPRINT.print(F("Block "));
977+ PN532DEBUGPRINT.println(blockNumber);
978+ Adafruit_PN532::PrintHexChar(data, 16);
979+#endif
980+
981+ return 1;
982+}
983+
984+/**************************************************************************/
985+/*!
986+ Tries to write an entire 16-byte data block at the specified block
987+ address.
988+
989+ @param blockNumber The block number to authenticate. (0..63 for
990+ 1KB cards, and 0..255 for 4KB cards).
991+ @param data The byte array that contains the data to write.
992+
993+ @returns 1 if everything executed properly, 0 for an error
994+*/
995+/**************************************************************************/
996+uint8_t Adafruit_PN532::mifareclassic_WriteDataBlock(uint8_t blockNumber,
997+ uint8_t *data) {
998+#ifdef MIFAREDEBUG
999+ PN532DEBUGPRINT.print(F("Trying to write 16 bytes to block "));
1000+ PN532DEBUGPRINT.println(blockNumber);
1001+#endif
1002+
1003+ /* Prepare the first command */
1004+ pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
1005+ pn532_packetbuffer[1] = 1; /* Card number */
1006+ pn532_packetbuffer[2] = MIFARE_CMD_WRITE; /* Mifare Write command = 0xA0 */
1007+ pn532_packetbuffer[3] =
1008+ blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */
1009+ memcpy(pn532_packetbuffer + 4, data, 16); /* Data Payload */
1010+
1011+ /* Send the command */
1012+ if (!sendCommandCheckAck(pn532_packetbuffer, 20)) {
1013+#ifdef MIFAREDEBUG
1014+ PN532DEBUGPRINT.println(F("Failed to receive ACK for write command"));
1015+#endif
1016+ return 0;
1017+ }
1018+ delay(10);
1019+
1020+ /* Read the response packet */
1021+ readdata(pn532_packetbuffer, 26);
1022+
1023+ return 1;
1024+}
1025+
1026+/**************************************************************************/
1027+/*!
1028+ Formats a Mifare Classic card to store NDEF Records
1029+
1030+ @returns 1 if everything executed properly, 0 for an error
1031+*/
1032+/**************************************************************************/
1033+uint8_t Adafruit_PN532::mifareclassic_FormatNDEF(void) {
1034+ uint8_t sectorbuffer1[16] = {0x14, 0x01, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1,
1035+ 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1};
1036+ uint8_t sectorbuffer2[16] = {0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1,
1037+ 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1};
1038+ uint8_t sectorbuffer3[16] = {0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0x78, 0x77,
1039+ 0x88, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
1040+
1041+ // Note 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 must be used for key A
1042+ // for the MAD sector in NDEF records (sector 0)
1043+
1044+ // Write block 1 and 2 to the card
1045+ if (!(mifareclassic_WriteDataBlock(1, sectorbuffer1)))
1046+ return 0;
1047+ if (!(mifareclassic_WriteDataBlock(2, sectorbuffer2)))
1048+ return 0;
1049+ // Write key A and access rights card
1050+ if (!(mifareclassic_WriteDataBlock(3, sectorbuffer3)))
1051+ return 0;
1052+
1053+ // Seems that everything was OK (?!)
1054+ return 1;
1055+}
1056+
1057+/**************************************************************************/
1058+/*!
1059+ Writes an NDEF URI Record to the specified sector (1..15)
1060+
1061+ Note that this function assumes that the Mifare Classic card is
1062+ already formatted to work as an "NFC Forum Tag" and uses a MAD1
1063+ file system. You can use the NXP TagWriter app on Android to
1064+ properly format cards for this.
1065+
1066+ @param sectorNumber The sector that the URI record should be written
1067+ to (can be 1..15 for a 1K card)
1068+ @param uriIdentifier The uri identifier code (0 = none, 0x01 =
1069+ "http://www.", etc.)
1070+ @param url The uri text to write (max 38 characters).
1071+
1072+ @returns 1 if everything executed properly, 0 for an error
1073+*/
1074+/**************************************************************************/
1075+uint8_t Adafruit_PN532::mifareclassic_WriteNDEFURI(uint8_t sectorNumber,
1076+ uint8_t uriIdentifier,
1077+ const char *url) {
1078+ // Figure out how long the string is
1079+ uint8_t len = strlen(url);
1080+
1081+ // Make sure we're within a 1K limit for the sector number
1082+ if ((sectorNumber < 1) || (sectorNumber > 15))
1083+ return 0;
1084+
1085+ // Make sure the URI payload is between 1 and 38 chars
1086+ if ((len < 1) || (len > 38))
1087+ return 0;
1088+
1089+ // Note 0xD3 0xF7 0xD3 0xF7 0xD3 0xF7 must be used for key A
1090+ // in NDEF records
1091+
1092+ // Setup the sector buffer (w/pre-formatted TLV wrapper and NDEF message)
1093+ uint8_t sectorbuffer1[16] = {0x00,
1094+ 0x00,
1095+ 0x03,
1096+ (uint8_t)(len + 5),
1097+ 0xD1,
1098+ 0x01,
1099+ (uint8_t)(len + 1),
1100+ 0x55,
1101+ uriIdentifier,
1102+ 0x00,
1103+ 0x00,
1104+ 0x00,
1105+ 0x00,
1106+ 0x00,
1107+ 0x00,
1108+ 0x00};
1109+ uint8_t sectorbuffer2[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1110+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1111+ uint8_t sectorbuffer3[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1112+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1113+ uint8_t sectorbuffer4[16] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0x7F, 0x07,
1114+ 0x88, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
1115+ if (len <= 6) {
1116+ // Unlikely we'll get a url this short, but why not ...
1117+ memcpy(sectorbuffer1 + 9, url, len);
1118+ sectorbuffer1[len + 9] = 0xFE;
1119+ } else if (len == 7) {
1120+ // 0xFE needs to be wrapped around to next block
1121+ memcpy(sectorbuffer1 + 9, url, len);
1122+ sectorbuffer2[0] = 0xFE;
1123+ } else if ((len > 7) && (len <= 22)) {
1124+ // Url fits in two blocks
1125+ memcpy(sectorbuffer1 + 9, url, 7);
1126+ memcpy(sectorbuffer2, url + 7, len - 7);
1127+ sectorbuffer2[len - 7] = 0xFE;
1128+ } else if (len == 23) {
1129+ // 0xFE needs to be wrapped around to final block
1130+ memcpy(sectorbuffer1 + 9, url, 7);
1131+ memcpy(sectorbuffer2, url + 7, len - 7);
1132+ sectorbuffer3[0] = 0xFE;
1133+ } else {
1134+ // Url fits in three blocks
1135+ memcpy(sectorbuffer1 + 9, url, 7);
1136+ memcpy(sectorbuffer2, url + 7, 16);
1137+ memcpy(sectorbuffer3, url + 23, len - 24);
1138+ sectorbuffer3[len - 22] = 0xFE;
1139+ }
1140+
1141+ // Now write all three blocks back to the card
1142+ if (!(mifareclassic_WriteDataBlock(sectorNumber * 4, sectorbuffer1)))
1143+ return 0;
1144+ if (!(mifareclassic_WriteDataBlock((sectorNumber * 4) + 1, sectorbuffer2)))
1145+ return 0;
1146+ if (!(mifareclassic_WriteDataBlock((sectorNumber * 4) + 2, sectorbuffer3)))
1147+ return 0;
1148+ if (!(mifareclassic_WriteDataBlock((sectorNumber * 4) + 3, sectorbuffer4)))
1149+ return 0;
1150+
1151+ // Seems that everything was OK (?!)
1152+ return 1;
1153+}
1154+
1155+/***** Mifare Ultralight Functions ******/
1156+
1157+/**************************************************************************/
1158+/*!
1159+ @brief Tries to read an entire 4-byte page at the specified address.
1160+
1161+ @param page The page number (0..63 in most cases)
1162+ @param buffer Pointer to the byte array that will hold the
1163+ retrieved data (if any)
1164+ @return 1 on success, 0 on error.
1165+*/
1166+/**************************************************************************/
1167+uint8_t Adafruit_PN532::mifareultralight_ReadPage(uint8_t page,
1168+ uint8_t *buffer) {
1169+ if (page >= 64) {
1170+#ifdef MIFAREDEBUG
1171+ PN532DEBUGPRINT.println(F("Page value out of range"));
1172+#endif
1173+ return 0;
1174+ }
1175+
1176+#ifdef MIFAREDEBUG
1177+ PN532DEBUGPRINT.print(F("Reading page "));
1178+ PN532DEBUGPRINT.println(page);
1179+#endif
1180+
1181+ /* Prepare the command */
1182+ pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
1183+ pn532_packetbuffer[1] = 1; /* Card number */
1184+ pn532_packetbuffer[2] = MIFARE_CMD_READ; /* Mifare Read command = 0x30 */
1185+ pn532_packetbuffer[3] = page; /* Page Number (0..63 in most cases) */
1186+
1187+ /* Send the command */
1188+ if (!sendCommandCheckAck(pn532_packetbuffer, 4)) {
1189+#ifdef MIFAREDEBUG
1190+ PN532DEBUGPRINT.println(F("Failed to receive ACK for write command"));
1191+#endif
1192+ return 0;
1193+ }
1194+
1195+ /* Read the response packet */
1196+ readdata(pn532_packetbuffer, 26);
1197+#ifdef MIFAREDEBUG
1198+ PN532DEBUGPRINT.println(F("Received: "));
1199+ Adafruit_PN532::PrintHexChar(pn532_packetbuffer, 26);
1200+#endif
1201+
1202+ /* If byte 8 isn't 0x00 we probably have an error */
1203+ if (pn532_packetbuffer[7] == 0x00) {
1204+ /* Copy the 4 data bytes to the output buffer */
1205+ /* Block content starts at byte 9 of a valid response */
1206+ /* Note that the command actually reads 16 byte or 4 */
1207+ /* pages at a time ... we simply discard the last 12 */
1208+ /* bytes */
1209+ memcpy(buffer, pn532_packetbuffer + 8, 4);
1210+ } else {
1211+#ifdef MIFAREDEBUG
1212+ PN532DEBUGPRINT.println(F("Unexpected response reading block: "));
1213+ Adafruit_PN532::PrintHexChar(pn532_packetbuffer, 26);
1214+#endif
1215+ return 0;
1216+ }
1217+
1218+/* Display data for debug if requested */
1219+#ifdef MIFAREDEBUG
1220+ PN532DEBUGPRINT.print(F("Page "));
1221+ PN532DEBUGPRINT.print(page);
1222+ PN532DEBUGPRINT.println(F(":"));
1223+ Adafruit_PN532::PrintHexChar(buffer, 4);
1224+#endif
1225+
1226+ // Return OK signal
1227+ return 1;
1228+}
1229+
1230+/**************************************************************************/
1231+/*!
1232+ Tries to write an entire 4-byte page at the specified block
1233+ address.
1234+
1235+ @param page The page number to write. (0..63 for most cases)
1236+ @param data The byte array that contains the data to write.
1237+ Should be exactly 4 bytes long.
1238+
1239+ @returns 1 if everything executed properly, 0 for an error
1240+*/
1241+/**************************************************************************/
1242+uint8_t Adafruit_PN532::mifareultralight_WritePage(uint8_t page,
1243+ uint8_t *data) {
1244+
1245+ if (page >= 64) {
1246+#ifdef MIFAREDEBUG
1247+ PN532DEBUGPRINT.println(F("Page value out of range"));
1248+#endif
1249+ // Return Failed Signal
1250+ return 0;
1251+ }
1252+
1253+#ifdef MIFAREDEBUG
1254+ PN532DEBUGPRINT.print(F("Trying to write 4 byte page"));
1255+ PN532DEBUGPRINT.println(page);
1256+#endif
1257+
1258+ /* Prepare the first command */
1259+ pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
1260+ pn532_packetbuffer[1] = 1; /* Card number */
1261+ pn532_packetbuffer[2] =
1262+ MIFARE_ULTRALIGHT_CMD_WRITE; /* Mifare Ultralight Write command = 0xA2 */
1263+ pn532_packetbuffer[3] = page; /* Page Number (0..63 for most cases) */
1264+ memcpy(pn532_packetbuffer + 4, data, 4); /* Data Payload */
1265+
1266+ /* Send the command */
1267+ if (!sendCommandCheckAck(pn532_packetbuffer, 8)) {
1268+#ifdef MIFAREDEBUG
1269+ PN532DEBUGPRINT.println(F("Failed to receive ACK for write command"));
1270+#endif
1271+
1272+ // Return Failed Signal
1273+ return 0;
1274+ }
1275+ delay(10);
1276+
1277+ /* Read the response packet */
1278+ readdata(pn532_packetbuffer, 26);
1279+
1280+ // Return OK Signal
1281+ return 1;
1282+}
1283+
1284+/***** NTAG2xx Functions ******/
1285+
1286+/**************************************************************************/
1287+/*!
1288+ @brief Tries to read an entire 4-byte page at the specified address.
1289+
1290+ @param page The page number (0..63 in most cases)
1291+ @param buffer Pointer to the byte array that will hold the
1292+ retrieved data (if any)
1293+ @return 1 on success, 0 on error.
1294+*/
1295+/**************************************************************************/
1296+uint8_t Adafruit_PN532::ntag2xx_ReadPage(uint8_t page, uint8_t *buffer) {
1297+ // TAG Type PAGES USER START USER STOP
1298+ // -------- ----- ---------- ---------
1299+ // NTAG 203 42 4 39
1300+ // NTAG 213 45 4 39
1301+ // NTAG 215 135 4 129
1302+ // NTAG 216 231 4 225
1303+
1304+ if (page >= 231) {
1305+#ifdef MIFAREDEBUG
1306+ PN532DEBUGPRINT.println(F("Page value out of range"));
1307+#endif
1308+ return 0;
1309+ }
1310+
1311+#ifdef MIFAREDEBUG
1312+ PN532DEBUGPRINT.print(F("Reading page "));
1313+ PN532DEBUGPRINT.println(page);
1314+#endif
1315+
1316+ /* Prepare the command */
1317+ pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
1318+ pn532_packetbuffer[1] = 1; /* Card number */
1319+ pn532_packetbuffer[2] = MIFARE_CMD_READ; /* Mifare Read command = 0x30 */
1320+ pn532_packetbuffer[3] = page; /* Page Number (0..63 in most cases) */
1321+
1322+ /* Send the command */
1323+ if (!sendCommandCheckAck(pn532_packetbuffer, 4)) {
1324+#ifdef MIFAREDEBUG
1325+ PN532DEBUGPRINT.println(F("Failed to receive ACK for write command"));
1326+#endif
1327+ return 0;
1328+ }
1329+
1330+ /* Read the response packet */
1331+ readdata(pn532_packetbuffer, 26);
1332+#ifdef MIFAREDEBUG
1333+ PN532DEBUGPRINT.println(F("Received: "));
1334+ Adafruit_PN532::PrintHexChar(pn532_packetbuffer, 26);
1335+#endif
1336+
1337+ /* If byte 8 isn't 0x00 we probably have an error */
1338+ if (pn532_packetbuffer[7] == 0x00) {
1339+ /* Copy the 4 data bytes to the output buffer */
1340+ /* Block content starts at byte 9 of a valid response */
1341+ /* Note that the command actually reads 16 byte or 4 */
1342+ /* pages at a time ... we simply discard the last 12 */
1343+ /* bytes */
1344+ memcpy(buffer, pn532_packetbuffer + 8, 4);
1345+ } else {
1346+#ifdef MIFAREDEBUG
1347+ PN532DEBUGPRINT.println(F("Unexpected response reading block: "));
1348+ Adafruit_PN532::PrintHexChar(pn532_packetbuffer, 26);
1349+#endif
1350+ return 0;
1351+ }
1352+
1353+/* Display data for debug if requested */
1354+#ifdef MIFAREDEBUG
1355+ PN532DEBUGPRINT.print(F("Page "));
1356+ PN532DEBUGPRINT.print(page);
1357+ PN532DEBUGPRINT.println(F(":"));
1358+ Adafruit_PN532::PrintHexChar(buffer, 4);
1359+#endif
1360+
1361+ // Return OK signal
1362+ return 1;
1363+}
1364+
1365+/**************************************************************************/
1366+/*!
1367+ Tries to write an entire 4-byte page at the specified block
1368+ address.
1369+
1370+ @param page The page number to write. (0..63 for most cases)
1371+ @param data The byte array that contains the data to write.
1372+ Should be exactly 4 bytes long.
1373+
1374+ @returns 1 if everything executed properly, 0 for an error
1375+*/
1376+/**************************************************************************/
1377+uint8_t Adafruit_PN532::ntag2xx_WritePage(uint8_t page, uint8_t *data) {
1378+ // TAG Type PAGES USER START USER STOP
1379+ // -------- ----- ---------- ---------
1380+ // NTAG 203 42 4 39
1381+ // NTAG 213 45 4 39
1382+ // NTAG 215 135 4 129
1383+ // NTAG 216 231 4 225
1384+
1385+ if ((page < 4) || (page > 225)) {
1386+#ifdef MIFAREDEBUG
1387+ PN532DEBUGPRINT.println(F("Page value out of range"));
1388+#endif
1389+ // Return Failed Signal
1390+ return 0;
1391+ }
1392+
1393+#ifdef MIFAREDEBUG
1394+ PN532DEBUGPRINT.print(F("Trying to write 4 byte page"));
1395+ PN532DEBUGPRINT.println(page);
1396+#endif
1397+
1398+ /* Prepare the first command */
1399+ pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
1400+ pn532_packetbuffer[1] = 1; /* Card number */
1401+ pn532_packetbuffer[2] =
1402+ MIFARE_ULTRALIGHT_CMD_WRITE; /* Mifare Ultralight Write command = 0xA2 */
1403+ pn532_packetbuffer[3] = page; /* Page Number (0..63 for most cases) */
1404+ memcpy(pn532_packetbuffer + 4, data, 4); /* Data Payload */
1405+
1406+ /* Send the command */
1407+ if (!sendCommandCheckAck(pn532_packetbuffer, 8)) {
1408+#ifdef MIFAREDEBUG
1409+ PN532DEBUGPRINT.println(F("Failed to receive ACK for write command"));
1410+#endif
1411+
1412+ // Return Failed Signal
1413+ return 0;
1414+ }
1415+ delay(10);
1416+
1417+ /* Read the response packet */
1418+ readdata(pn532_packetbuffer, 26);
1419+
1420+ // Return OK Signal
1421+ return 1;
1422+}
1423+
1424+/**************************************************************************/
1425+/*!
1426+ Writes an NDEF URI Record starting at the specified page (4..nn)
1427+
1428+ Note that this function assumes that the NTAG2xx card is
1429+ already formatted to work as an "NFC Forum Tag".
1430+
1431+ @param uriIdentifier The uri identifier code (0 = none, 0x01 =
1432+ "http://www.", etc.)
1433+ @param url The uri text to write (null-terminated string).
1434+ @param dataLen The size of the data area for overflow checks.
1435+
1436+ @returns 1 if everything executed properly, 0 for an error
1437+*/
1438+/**************************************************************************/
1439+uint8_t Adafruit_PN532::ntag2xx_WriteNDEFURI(uint8_t uriIdentifier, char *url,
1440+ uint8_t dataLen) {
1441+ uint8_t pageBuffer[4] = {0, 0, 0, 0};
1442+
1443+ // Remove NDEF record overhead from the URI data (pageHeader below)
1444+ uint8_t wrapperSize = 12;
1445+
1446+ // Figure out how long the string is
1447+ uint8_t len = strlen(url);
1448+
1449+ // Make sure the URI payload will fit in dataLen (include 0xFE trailer)
1450+ if ((len < 1) || (len + 1 > (dataLen - wrapperSize)))
1451+ return 0;
1452+
1453+ // Setup the record header
1454+ // See NFCForum-TS-Type-2-Tag_1.1.pdf for details
1455+ uint8_t pageHeader[12] = {
1456+ /* NDEF Lock Control TLV (must be first and always present) */
1457+ 0x01, /* Tag Field (0x01 = Lock Control TLV) */
1458+ 0x03, /* Payload Length (always 3) */
1459+ 0xA0, /* The position inside the tag of the lock bytes (upper 4 = page
1460+ address, lower 4 = byte offset) */
1461+ 0x10, /* Size in bits of the lock area */
1462+ 0x44, /* Size in bytes of a page and the number of bytes each lock bit can
1463+ lock (4 bit + 4 bits) */
1464+ /* NDEF Message TLV - URI Record */
1465+ 0x03, /* Tag Field (0x03 = NDEF Message) */
1466+ (uint8_t)(len + 5), /* Payload Length (not including 0xFE trailer) */
1467+ 0xD1, /* NDEF Record Header (TNF=0x1:Well known record + SR + ME + MB) */
1468+ 0x01, /* Type Length for the record type indicator */
1469+ (uint8_t)(len + 1), /* Payload len */
1470+ 0x55, /* Record Type Indicator (0x55 or 'U' = URI Record) */
1471+ uriIdentifier /* URI Prefix (ex. 0x01 = "http://www.") */
1472+ };
1473+
1474+ // Write 12 byte header (three pages of data starting at page 4)
1475+ memcpy(pageBuffer, pageHeader, 4);
1476+ if (!(ntag2xx_WritePage(4, pageBuffer)))
1477+ return 0;
1478+ memcpy(pageBuffer, pageHeader + 4, 4);
1479+ if (!(ntag2xx_WritePage(5, pageBuffer)))
1480+ return 0;
1481+ memcpy(pageBuffer, pageHeader + 8, 4);
1482+ if (!(ntag2xx_WritePage(6, pageBuffer)))
1483+ return 0;
1484+
1485+ // Write URI (starting at page 7)
1486+ uint8_t currentPage = 7;
1487+ char *urlcopy = url;
1488+ while (len) {
1489+ if (len < 4) {
1490+ memset(pageBuffer, 0, 4);
1491+ memcpy(pageBuffer, urlcopy, len);
1492+ pageBuffer[len] = 0xFE; // NDEF record footer
1493+ if (!(ntag2xx_WritePage(currentPage, pageBuffer)))
1494+ return 0;
1495+ // DONE!
1496+ return 1;
1497+ } else if (len == 4) {
1498+ memcpy(pageBuffer, urlcopy, len);
1499+ if (!(ntag2xx_WritePage(currentPage, pageBuffer)))
1500+ return 0;
1501+ memset(pageBuffer, 0, 4);
1502+ pageBuffer[0] = 0xFE; // NDEF record footer
1503+ currentPage++;
1504+ if (!(ntag2xx_WritePage(currentPage, pageBuffer)))
1505+ return 0;
1506+ // DONE!
1507+ return 1;
1508+ } else {
1509+ // More than one page of data left
1510+ memcpy(pageBuffer, urlcopy, 4);
1511+ if (!(ntag2xx_WritePage(currentPage, pageBuffer)))
1512+ return 0;
1513+ currentPage++;
1514+ urlcopy += 4;
1515+ len -= 4;
1516+ }
1517+ }
1518+
1519+ // Seems that everything was OK (?!)
1520+ return 1;
1521+}
1522+
1523+/************** high level communication functions (handles both I2C and SPI) */
1524+
1525+/**************************************************************************/
1526+/*!
1527+ @brief Tries to read the SPI or I2C ACK signal
1528+*/
1529+/**************************************************************************/
1530+bool Adafruit_PN532::readack() {
1531+ uint8_t ackbuff[6];
1532+
1533+ if (spi_dev) {
1534+ uint8_t cmd = PN532_SPI_DATAREAD;
1535+ spi_dev->write_then_read(&cmd, 1, ackbuff, 6);
1536+ } else if (i2c_dev || ser_dev) {
1537+ readdata(ackbuff, 6);
1538+ }
1539+
1540+ return (0 == memcmp((char *)ackbuff, (char *)pn532ack, 6));
1541+}
1542+
1543+/**************************************************************************/
1544+/*!
1545+ @brief Return true if the PN532 is ready with a response.
1546+*/
1547+/**************************************************************************/
1548+bool Adafruit_PN532::isready() {
1549+ if (spi_dev) {
1550+ // SPI ready check via Status Request
1551+ uint8_t cmd = PN532_SPI_STATREAD;
1552+ uint8_t reply;
1553+ spi_dev->write_then_read(&cmd, 1, &reply, 1);
1554+ return reply == PN532_SPI_READY;
1555+ } else if (i2c_dev) {
1556+ // I2C ready check via reading RDY byte
1557+ uint8_t rdy[1];
1558+ i2c_dev->read(rdy, 1);
1559+ return rdy[0] == PN532_I2C_READY;
1560+ } else if (ser_dev) {
1561+ // Serial ready check based on non-zero read buffer
1562+ return (ser_dev->available() != 0);
1563+ } else if (_irq != -1) {
1564+ uint8_t x = digitalRead(_irq);
1565+ return x == 0;
1566+ }
1567+ return false;
1568+}
1569+
1570+/**************************************************************************/
1571+/*!
1572+ @brief Waits until the PN532 is ready.
1573+
1574+ @param timeout Timeout before giving up
1575+*/
1576+/**************************************************************************/
1577+bool Adafruit_PN532::waitready(uint16_t timeout) {
1578+ uint16_t timer = 0;
1579+ while (!isready()) {
1580+ if (timeout != 0) {
1581+ timer += 10;
1582+ if (timer > timeout) {
1583+#ifdef PN532DEBUG
1584+ PN532DEBUGPRINT.println("TIMEOUT!");
1585+#endif
1586+ return false;
1587+ }
1588+ }
1589+ delay(10);
1590+ }
1591+ return true;
1592+}
1593+
1594+/**************************************************************************/
1595+/*!
1596+ @brief Reads n bytes of data from the PN532 via SPI or I2C.
1597+
1598+ @param buff Pointer to the buffer where data will be written
1599+ @param n Number of bytes to be read
1600+*/
1601+/**************************************************************************/
1602+void Adafruit_PN532::readdata(uint8_t *buff, uint8_t n) {
1603+ if (spi_dev) {
1604+ // SPI read
1605+ uint8_t cmd = PN532_SPI_DATAREAD;
1606+ spi_dev->write_then_read(&cmd, 1, buff, n);
1607+ } else if (i2c_dev) {
1608+ // I2C read
1609+ uint8_t rbuff[n + 1]; // +1 for leading RDY byte
1610+ i2c_dev->read(rbuff, n + 1);
1611+ for (uint8_t i = 0; i < n; i++) {
1612+ buff[i] = rbuff[i + 1];
1613+ }
1614+ } else if (ser_dev) {
1615+ // Serial read
1616+ ser_dev->readBytes(buff, n);
1617+ }
1618+#ifdef PN532DEBUG
1619+ PN532DEBUGPRINT.print(F("Reading: "));
1620+ for (uint8_t i = 0; i < n; i++) {
1621+ PN532DEBUGPRINT.print(F(" 0x"));
1622+ PN532DEBUGPRINT.print(buff[i], HEX);
1623+ }
1624+ PN532DEBUGPRINT.println();
1625+#endif
1626+}
1627+
1628+/**************************************************************************/
1629+/*!
1630+ @brief set the PN532 as iso14443a Target behaving as a SmartCard
1631+ @return true on success, false otherwise.
1632+ @note Author: Salvador Mendoza (salmg.net) new functions:
1633+ -AsTarget
1634+ -getDataTarget
1635+ -setDataTarget
1636+*/
1637+/**************************************************************************/
1638+uint8_t Adafruit_PN532::AsTarget() {
1639+ pn532_packetbuffer[0] = 0x8C;
1640+ uint8_t target[] = {
1641+ 0x8C, // INIT AS TARGET
1642+ 0x00, // MODE -> BITFIELD
1643+ 0x08, 0x00, // SENS_RES - MIFARE PARAMS
1644+ 0xdc, 0x44, 0x20, // NFCID1T
1645+ 0x60, // SEL_RES
1646+ 0x01, 0xfe, // NFCID2T MUST START WITH 01fe - FELICA PARAMS - POL_RES
1647+ 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xc0,
1648+ 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, // PAD
1649+ 0xff, 0xff, // SYSTEM CODE
1650+ 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44,
1651+ 0x33, 0x22, 0x11, 0x01, 0x00, // NFCID3t MAX 47 BYTES ATR_RES
1652+ 0x0d, 0x52, 0x46, 0x49, 0x44, 0x49, 0x4f,
1653+ 0x74, 0x20, 0x50, 0x4e, 0x35, 0x33, 0x32 // HISTORICAL BYTES
1654+ };
1655+ if (!sendCommandCheckAck(target, sizeof(target)))
1656+ return false;
1657+
1658+ // read data packet
1659+ readdata(pn532_packetbuffer, 8);
1660+
1661+ int offset = 6;
1662+ return (pn532_packetbuffer[offset] == 0x15);
1663+}
1664+/**************************************************************************/
1665+/*!
1666+ @brief Retrieve response from the emulation mode
1667+
1668+ @param cmd = data
1669+ @param cmdlen = data length
1670+ @return true on success, false otherwise.
1671+*/
1672+/**************************************************************************/
1673+uint8_t Adafruit_PN532::getDataTarget(uint8_t *cmd, uint8_t *cmdlen) {
1674+ uint8_t length;
1675+ pn532_packetbuffer[0] = 0x86;
1676+ if (!sendCommandCheckAck(pn532_packetbuffer, 1, 1000)) {
1677+ PN532DEBUGPRINT.println(F("Error en ack"));
1678+ return false;
1679+ }
1680+
1681+ // read data packet
1682+ readdata(pn532_packetbuffer, 64);
1683+ length = pn532_packetbuffer[3] - 3;
1684+
1685+ // if (length > *responseLength) {// Bug, should avoid it in the reading
1686+ // target data
1687+ // length = *responseLength; // silent truncation...
1688+ //}
1689+
1690+ for (int i = 0; i < length; ++i) {
1691+ cmd[i] = pn532_packetbuffer[8 + i];
1692+ }
1693+ *cmdlen = length;
1694+ return true;
1695+}
1696+
1697+/**************************************************************************/
1698+/*!
1699+ @brief Set data in PN532 in the emulation mode
1700+
1701+ @param cmd = data
1702+ @param cmdlen = data length
1703+ @return true on success, false otherwise.
1704+*/
1705+/**************************************************************************/
1706+uint8_t Adafruit_PN532::setDataTarget(uint8_t *cmd, uint8_t cmdlen) {
1707+ uint8_t length;
1708+ // cmd1[0] = 0x8E; Must!
1709+
1710+ if (!sendCommandCheckAck(cmd, cmdlen))
1711+ return false;
1712+
1713+ // read data packet
1714+ readdata(pn532_packetbuffer, 8);
1715+ length = pn532_packetbuffer[3] - 3;
1716+ for (int i = 0; i < length; ++i) {
1717+ cmd[i] = pn532_packetbuffer[8 + i];
1718+ }
1719+ // cmdl = 0
1720+ cmdlen = length;
1721+
1722+ int offset = 6;
1723+ return (pn532_packetbuffer[offset] == 0x15);
1724+}
1725+
1726+/**************************************************************************/
1727+/*!
1728+ @brief Writes a command to the PN532, automatically inserting the
1729+ preamble and required frame details (checksum, len, etc.)
1730+
1731+ @param cmd Pointer to the command buffer
1732+ @param cmdlen Command length in bytes
1733+*/
1734+/**************************************************************************/
1735+void Adafruit_PN532::writecommand(uint8_t *cmd, uint8_t cmdlen) {
1736+ if (spi_dev) {
1737+ // SPI command write.
1738+ uint8_t checksum;
1739+ uint8_t packet[9 + cmdlen];
1740+ uint8_t *p = packet;
1741+ cmdlen++;
1742+
1743+ p[0] = PN532_SPI_DATAWRITE;
1744+ p++;
1745+
1746+ p[0] = PN532_PREAMBLE;
1747+ p++;
1748+ p[0] = PN532_STARTCODE1;
1749+ p++;
1750+ p[0] = PN532_STARTCODE2;
1751+ p++;
1752+ checksum = PN532_PREAMBLE + PN532_STARTCODE1 + PN532_STARTCODE2;
1753+
1754+ p[0] = cmdlen;
1755+ p++;
1756+ p[0] = ~cmdlen + 1;
1757+ p++;
1758+
1759+ p[0] = PN532_HOSTTOPN532;
1760+ p++;
1761+ checksum += PN532_HOSTTOPN532;
1762+
1763+ for (uint8_t i = 0; i < cmdlen - 1; i++) {
1764+ p[0] = cmd[i];
1765+ p++;
1766+ checksum += cmd[i];
1767+ }
1768+
1769+ p[0] = ~checksum;
1770+ p++;
1771+ p[0] = PN532_POSTAMBLE;
1772+ p++;
1773+
1774+#ifdef PN532DEBUG
1775+ Serial.print("Sending : ");
1776+ for (int i = 1; i < 8 + cmdlen; i++) {
1777+ Serial.print("0x");
1778+ Serial.print(packet[i], HEX);
1779+ Serial.print(", ");
1780+ }
1781+ Serial.println();
1782+#endif
1783+
1784+ spi_dev->write(packet, 8 + cmdlen);
1785+ } else if (i2c_dev || ser_dev) {
1786+ // I2C or Serial command write.
1787+ uint8_t packet[8 + cmdlen];
1788+ uint8_t LEN = cmdlen + 1;
1789+
1790+ packet[0] = PN532_PREAMBLE;
1791+ packet[1] = PN532_STARTCODE1;
1792+ packet[2] = PN532_STARTCODE2;
1793+ packet[3] = LEN;
1794+ packet[4] = ~LEN + 1;
1795+ packet[5] = PN532_HOSTTOPN532;
1796+ uint8_t sum = 0;
1797+ for (uint8_t i = 0; i < cmdlen; i++) {
1798+ packet[6 + i] = cmd[i];
1799+ sum += cmd[i];
1800+ }
1801+ packet[6 + cmdlen] = ~(PN532_HOSTTOPN532 + sum) + 1;
1802+ packet[7 + cmdlen] = PN532_POSTAMBLE;
1803+
1804+#ifdef PN532DEBUG
1805+ Serial.print("Sending : ");
1806+ for (int i = 1; i < 8 + cmdlen; i++) {
1807+ Serial.print("0x");
1808+ Serial.print(packet[i], HEX);
1809+ Serial.print(", ");
1810+ }
1811+ Serial.println();
1812+#endif
1813+
1814+ if (i2c_dev) {
1815+ i2c_dev->write(packet, 8 + cmdlen);
1816+ } else {
1817+ ser_dev->write(packet, 8 + cmdlen);
1818+ }
1819+ }
1820+}
A src/libs/Adafruit_PN532.h View
@@ -0,0 +1,223 @@
1+/**************************************************************************/
2+/*!
3+ @file Adafruit_PN532.h
4+
5+ v2.0 - Refactored to add I2C support from Adafruit_NFCShield_I2C library.
6+
7+ v1.1 - Added full command list
8+ - Added 'verbose' mode flag to constructor to toggle debug output
9+ - Changed readPassiveTargetID() to return variable length values
10+*/
11+/**************************************************************************/
12+
13+#ifndef ADAFRUIT_PN532_H
14+#define ADAFRUIT_PN532_H
15+
16+#include "Arduino.h"
17+
18+#include <Adafruit_I2CDevice.h>
19+#include <Adafruit_SPIDevice.h>
20+
21+#define PN532_PREAMBLE (0x00) ///< Command sequence start, byte 1/3
22+#define PN532_STARTCODE1 (0x00) ///< Command sequence start, byte 2/3
23+#define PN532_STARTCODE2 (0xFF) ///< Command sequence start, byte 3/3
24+#define PN532_POSTAMBLE (0x00) ///< EOD
25+
26+#define PN532_HOSTTOPN532 (0xD4) ///< Host-to-PN532
27+#define PN532_PN532TOHOST (0xD5) ///< PN532-to-host
28+
29+// PN532 Commands
30+#define PN532_COMMAND_DIAGNOSE (0x00) ///< Diagnose
31+#define PN532_COMMAND_GETFIRMWAREVERSION (0x02) ///< Get firmware version
32+#define PN532_COMMAND_GETGENERALSTATUS (0x04) ///< Get general status
33+#define PN532_COMMAND_READREGISTER (0x06) ///< Read register
34+#define PN532_COMMAND_WRITEREGISTER (0x08) ///< Write register
35+#define PN532_COMMAND_READGPIO (0x0C) ///< Read GPIO
36+#define PN532_COMMAND_WRITEGPIO (0x0E) ///< Write GPIO
37+#define PN532_COMMAND_SETSERIALBAUDRATE (0x10) ///< Set serial baud rate
38+#define PN532_COMMAND_SETPARAMETERS (0x12) ///< Set parameters
39+#define PN532_COMMAND_SAMCONFIGURATION (0x14) ///< SAM configuration
40+#define PN532_COMMAND_POWERDOWN (0x16) ///< Power down
41+#define PN532_COMMAND_RFCONFIGURATION (0x32) ///< RF config
42+#define PN532_COMMAND_RFREGULATIONTEST (0x58) ///< RF regulation test
43+#define PN532_COMMAND_INJUMPFORDEP (0x56) ///< Jump for DEP
44+#define PN532_COMMAND_INJUMPFORPSL (0x46) ///< Jump for PSL
45+#define PN532_COMMAND_INLISTPASSIVETARGET (0x4A) ///< List passive target
46+#define PN532_COMMAND_INATR (0x50) ///< ATR
47+#define PN532_COMMAND_INPSL (0x4E) ///< PSL
48+#define PN532_COMMAND_INDATAEXCHANGE (0x40) ///< Data exchange
49+#define PN532_COMMAND_INCOMMUNICATETHRU (0x42) ///< Communicate through
50+#define PN532_COMMAND_INDESELECT (0x44) ///< Deselect
51+#define PN532_COMMAND_INRELEASE (0x52) ///< Release
52+#define PN532_COMMAND_INSELECT (0x54) ///< Select
53+#define PN532_COMMAND_INAUTOPOLL (0x60) ///< Auto poll
54+#define PN532_COMMAND_TGINITASTARGET (0x8C) ///< Init as target
55+#define PN532_COMMAND_TGSETGENERALBYTES (0x92) ///< Set general bytes
56+#define PN532_COMMAND_TGGETDATA (0x86) ///< Get data
57+#define PN532_COMMAND_TGSETDATA (0x8E) ///< Set data
58+#define PN532_COMMAND_TGSETMETADATA (0x94) ///< Set metadata
59+#define PN532_COMMAND_TGGETINITIATORCOMMAND (0x88) ///< Get initiator command
60+#define PN532_COMMAND_TGRESPONSETOINITIATOR (0x90) ///< Response to initiator
61+#define PN532_COMMAND_TGGETTARGETSTATUS (0x8A) ///< Get target status
62+
63+#define PN532_RESPONSE_INDATAEXCHANGE (0x41) ///< Data exchange
64+#define PN532_RESPONSE_INLISTPASSIVETARGET (0x4B) ///< List passive target
65+
66+#define PN532_WAKEUP (0x55) ///< Wake
67+
68+#define PN532_SPI_STATREAD (0x02) ///< Stat read
69+#define PN532_SPI_DATAWRITE (0x01) ///< Data write
70+#define PN532_SPI_DATAREAD (0x03) ///< Data read
71+#define PN532_SPI_READY (0x01) ///< Ready
72+
73+//#define PN532_I2C_ADDRESS (0x48 >> 1) ///< Default I2C address
74+// My fucking clone board for some goddamn reason uses the address 0x28
75+#define PN532_I2C_ADDRESS (0x28)
76+#define PN532_I2C_READBIT (0x01) ///< Read bit
77+#define PN532_I2C_BUSY (0x00) ///< Busy
78+#define PN532_I2C_READY (0x01) ///< Ready
79+#define PN532_I2C_READYTIMEOUT (20) ///< Ready timeout
80+
81+#define PN532_MIFARE_ISO14443A (0x00) ///< MiFare
82+
83+// Mifare Commands
84+#define MIFARE_CMD_AUTH_A (0x60) ///< Auth A
85+#define MIFARE_CMD_AUTH_B (0x61) ///< Auth B
86+#define MIFARE_CMD_READ (0x30) ///< Read
87+#define MIFARE_CMD_WRITE (0xA0) ///< Write
88+#define MIFARE_CMD_TRANSFER (0xB0) ///< Transfer
89+#define MIFARE_CMD_DECREMENT (0xC0) ///< Decrement
90+#define MIFARE_CMD_INCREMENT (0xC1) ///< Increment
91+#define MIFARE_CMD_STORE (0xC2) ///< Store
92+#define MIFARE_ULTRALIGHT_CMD_WRITE (0xA2) ///< Write (MiFare Ultralight)
93+
94+// Prefixes for NDEF Records (to identify record type)
95+#define NDEF_URIPREFIX_NONE (0x00) ///< No prefix
96+#define NDEF_URIPREFIX_HTTP_WWWDOT (0x01) ///< HTTP www. prefix
97+#define NDEF_URIPREFIX_HTTPS_WWWDOT (0x02) ///< HTTPS www. prefix
98+#define NDEF_URIPREFIX_HTTP (0x03) ///< HTTP prefix
99+#define NDEF_URIPREFIX_HTTPS (0x04) ///< HTTPS prefix
100+#define NDEF_URIPREFIX_TEL (0x05) ///< Tel prefix
101+#define NDEF_URIPREFIX_MAILTO (0x06) ///< Mailto prefix
102+#define NDEF_URIPREFIX_FTP_ANONAT (0x07) ///< FTP
103+#define NDEF_URIPREFIX_FTP_FTPDOT (0x08) ///< FTP dot
104+#define NDEF_URIPREFIX_FTPS (0x09) ///< FTPS
105+#define NDEF_URIPREFIX_SFTP (0x0A) ///< SFTP
106+#define NDEF_URIPREFIX_SMB (0x0B) ///< SMB
107+#define NDEF_URIPREFIX_NFS (0x0C) ///< NFS
108+#define NDEF_URIPREFIX_FTP (0x0D) ///< FTP
109+#define NDEF_URIPREFIX_DAV (0x0E) ///< DAV
110+#define NDEF_URIPREFIX_NEWS (0x0F) ///< NEWS
111+#define NDEF_URIPREFIX_TELNET (0x10) ///< Telnet prefix
112+#define NDEF_URIPREFIX_IMAP (0x11) ///< IMAP prefix
113+#define NDEF_URIPREFIX_RTSP (0x12) ///< RTSP
114+#define NDEF_URIPREFIX_URN (0x13) ///< URN
115+#define NDEF_URIPREFIX_POP (0x14) ///< POP
116+#define NDEF_URIPREFIX_SIP (0x15) ///< SIP
117+#define NDEF_URIPREFIX_SIPS (0x16) ///< SIPS
118+#define NDEF_URIPREFIX_TFTP (0x17) ///< TFPT
119+#define NDEF_URIPREFIX_BTSPP (0x18) ///< BTSPP
120+#define NDEF_URIPREFIX_BTL2CAP (0x19) ///< BTL2CAP
121+#define NDEF_URIPREFIX_BTGOEP (0x1A) ///< BTGOEP
122+#define NDEF_URIPREFIX_TCPOBEX (0x1B) ///< TCPOBEX
123+#define NDEF_URIPREFIX_IRDAOBEX (0x1C) ///< IRDAOBEX
124+#define NDEF_URIPREFIX_FILE (0x1D) ///< File
125+#define NDEF_URIPREFIX_URN_EPC_ID (0x1E) ///< URN EPC ID
126+#define NDEF_URIPREFIX_URN_EPC_TAG (0x1F) ///< URN EPC tag
127+#define NDEF_URIPREFIX_URN_EPC_PAT (0x20) ///< URN EPC pat
128+#define NDEF_URIPREFIX_URN_EPC_RAW (0x21) ///< URN EPC raw
129+#define NDEF_URIPREFIX_URN_EPC (0x22) ///< URN EPC
130+#define NDEF_URIPREFIX_URN_NFC (0x23) ///< URN NFC
131+
132+#define PN532_GPIO_VALIDATIONBIT (0x80) ///< GPIO validation bit
133+#define PN532_GPIO_P30 (0) ///< GPIO 30
134+#define PN532_GPIO_P31 (1) ///< GPIO 31
135+#define PN532_GPIO_P32 (2) ///< GPIO 32
136+#define PN532_GPIO_P33 (3) ///< GPIO 33
137+#define PN532_GPIO_P34 (4) ///< GPIO 34
138+#define PN532_GPIO_P35 (5) ///< GPIO 35
139+
140+/**
141+ * @brief Class for working with Adafruit PN532 NFC/RFID breakout boards.
142+ */
143+class Adafruit_PN532 {
144+public:
145+ Adafruit_PN532(uint8_t clk, uint8_t miso, uint8_t mosi,
146+ uint8_t ss); // Software SPI
147+ Adafruit_PN532(uint8_t ss, SPIClass *theSPI = &SPI); // Hardware SPI
148+ Adafruit_PN532(uint8_t irq, uint8_t reset,
149+ TwoWire *theWire = &Wire); // Hardware I2C
150+ Adafruit_PN532(uint8_t reset, HardwareSerial *theSer); // Hardware UART
151+ bool begin(void);
152+
153+ void reset(void);
154+ void wakeup(void);
155+
156+ // Generic PN532 functions
157+ bool SAMConfig(void);
158+ uint32_t getFirmwareVersion(void);
159+ bool sendCommandCheckAck(uint8_t *cmd, uint8_t cmdlen,
160+ uint16_t timeout = 100);
161+ bool writeGPIO(uint8_t pinstate);
162+ uint8_t readGPIO(void);
163+ bool setPassiveActivationRetries(uint8_t maxRetries);
164+
165+ // ISO14443A functions
166+ bool readPassiveTargetID(
167+ uint8_t cardbaudrate, uint8_t *uid, uint8_t *uidLength,
168+ uint16_t timeout = 0); // timeout 0 means no timeout - will block forever.
169+ bool startPassiveTargetIDDetection(uint8_t cardbaudrate);
170+ bool readDetectedPassiveTargetID(uint8_t *uid, uint8_t *uidLength);
171+ bool inDataExchange(uint8_t *send, uint8_t sendLength, uint8_t *response,
172+ uint8_t *responseLength);
173+ bool inListPassiveTarget();
174+ uint8_t AsTarget();
175+ uint8_t getDataTarget(uint8_t *cmd, uint8_t *cmdlen);
176+ uint8_t setDataTarget(uint8_t *cmd, uint8_t cmdlen);
177+
178+ // Mifare Classic functions
179+ bool mifareclassic_IsFirstBlock(uint32_t uiBlock);
180+ bool mifareclassic_IsTrailerBlock(uint32_t uiBlock);
181+ uint8_t mifareclassic_AuthenticateBlock(uint8_t *uid, uint8_t uidLen,
182+ uint32_t blockNumber,
183+ uint8_t keyNumber, uint8_t *keyData);
184+ uint8_t mifareclassic_ReadDataBlock(uint8_t blockNumber, uint8_t *data);
185+ uint8_t mifareclassic_WriteDataBlock(uint8_t blockNumber, uint8_t *data);
186+ uint8_t mifareclassic_FormatNDEF(void);
187+ uint8_t mifareclassic_WriteNDEFURI(uint8_t sectorNumber,
188+ uint8_t uriIdentifier, const char *url);
189+
190+ // Mifare Ultralight functions
191+ uint8_t mifareultralight_ReadPage(uint8_t page, uint8_t *buffer);
192+ uint8_t mifareultralight_WritePage(uint8_t page, uint8_t *data);
193+
194+ // NTAG2xx functions
195+ uint8_t ntag2xx_ReadPage(uint8_t page, uint8_t *buffer);
196+ uint8_t ntag2xx_WritePage(uint8_t page, uint8_t *data);
197+ uint8_t ntag2xx_WriteNDEFURI(uint8_t uriIdentifier, char *url,
198+ uint8_t dataLen);
199+
200+ // Help functions to display formatted text
201+ static void PrintHex(const byte *data, const uint32_t numBytes);
202+ static void PrintHexChar(const byte *pbtData, const uint32_t numBytes);
203+
204+private:
205+ int8_t _irq = -1, _reset = -1, _cs = -1;
206+ int8_t _uid[7]; // ISO14443A uid
207+ int8_t _uidLen; // uid len
208+ int8_t _key[6]; // Mifare Classic key
209+ int8_t _inListedTag; // Tg number of inlisted tag.
210+
211+ // Low level communication functions that handle both SPI and I2C.
212+ void readdata(uint8_t *buff, uint8_t n);
213+ void writecommand(uint8_t *cmd, uint8_t cmdlen);
214+ bool isready();
215+ bool waitready(uint16_t timeout);
216+ bool readack();
217+
218+ Adafruit_SPIDevice *spi_dev = NULL;
219+ Adafruit_I2CDevice *i2c_dev = NULL;
220+ HardwareSerial *ser_dev = NULL;
221+};
222+
223+#endif
R firmware/BleConnectionStatus.cpp → src/libs/BleConnectionStatus.cpp View

[No content changes]

R firmware/BleConnectionStatus.h → src/libs/BleConnectionStatus.h View

[No content changes]

R firmware/BleMouse.cpp → src/libs/BleMouse.cpp View
@@ -140,7 +140,7 @@ void BleMouse::setBatteryLevel(uint8_t level) {
140140
141141 void BleMouse::taskServer(void* pvParameter) {
142142 BleMouse* bleMouseInstance = (BleMouse *) pvParameter; //static_cast<BleMouse *>(pvParameter);
143− BLEDevice::init(String(bleMouseInstance->deviceName.c_str()));
143+ BLEDevice::init(std::string(bleMouseInstance->deviceName.c_str()));
144144 BLEServer *pServer = BLEDevice::createServer();
145145 pServer->setCallbacks(bleMouseInstance->connectionStatus);
146146
@@ -148,7 +148,7 @@ void BleMouse::taskServer(void* pvParameter) {
148148 bleMouseInstance->inputMouse = bleMouseInstance->hid->inputReport(0); // <-- input REPORTID from report map
149149 bleMouseInstance->connectionStatus->inputMouse = bleMouseInstance->inputMouse;
150150
151− bleMouseInstance->hid->manufacturer()->setValue(String(bleMouseInstance->deviceManufacturer.c_str()));
151+ bleMouseInstance->hid->manufacturer()->setValue(std::string(bleMouseInstance->deviceManufacturer.c_str()));
152152
153153 bleMouseInstance->hid->pnp(0x02, 0xe502, 0xa111, 0x0210);
154154 bleMouseInstance->hid->hidInfo(0x00,0x02);
R firmware/BleMouse.h → src/libs/BleMouse.h View

[No content changes]

R firmware/ELECHOUSE_CC1101_SRC_DRV.cpp → src/libs/ELECHOUSE_CC1101_SRC_DRV.cpp View

[No content changes]

R firmware/ELECHOUSE_CC1101_SRC_DRV.h → src/libs/ELECHOUSE_CC1101_SRC_DRV.h View

[No content changes]

R firmware/firmware.ino → src/main.cpp View
@@ -4,12 +4,12 @@
44
55 #include <BLEDevice.h>
66 #include <BLEScan.h>
7−#include <BleMouse.h>
7+#include "libs/BleMouse.h"
88
99 #include <RF24.h>
1010 #include <nRF24L01.h>
1111
12−#include "ELECHOUSE_CC1101_SRC_DRV.h"
12+#include "libs/ELECHOUSE_CC1101_SRC_DRV.h"
1313
1414 #include <WiFi.h>
1515 #include <esp_wifi.h>
@@ -20,12 +20,12 @@
2020 #include <SPI.h>
2121
2222
23−#include "display.h"
23+#include "ui/display.h"
2424 #include "buttons.h"
25−#include "menu.h"
25+#include "ui/menu.h"
2626
2727 #include "config.h"
28−#include "cc1101.h"
28+#include "rf/cc1101.h"
2929
3030 // ================= USB HID =================
3131 USBHIDKeyboard Keyboard;
@@ -116,6 +116,20 @@ void setup()
116116 RADIO_SPI = new SPIClass(FSPI);
117117 RADIO_SPI->begin(NRF_SCK, NRF_MISO, NRF_MOSI);
118118
119+ // ===== CC1101 SPI INIT =====
120+ //SPI.begin(
121+ // cc1101_SCK,
122+ // cc1101_MISO,
123+ // cc1101_MOSI,
124+ // CC1101_CS
125+ //);
126+
127+ //pinMode(CC1101_CS, OUTPUT);
128+ //pinMode(CC1101_2_CS, OUTPUT);
129+
130+ //digitalWrite(CC1101_CS, HIGH);
131+ //digitalWrite(CC1101_2_CS, HIGH);
132+
119133 printSystemUsage();
120134
121135 Serial.println("SYSTEM READY");
A src/nfc.cpp View
@@ -0,0 +1,117 @@
1+#include "nfc.h"
2+
3+#include <Arduino.h>
4+#include <Wire.h>
5+#include <Adafruit_PN532.h>
6+
7+#include "ui/display.h"
8+#include "buttons.h"
9+#include "config.h"
10+
11+#define PN532_IRQ -1
12+#define PN532_RESET -1
13+
14+//Adafruit_PN532 nfc(Wire);
15+Adafruit_PN532 nfc(PN532_IRQ, PN532_RESET, &Wire);
16+
17+void drawWaiting()
18+{
19+ u8g2.clearBuffer();
20+
21+ u8g2.drawStr(10, 20, "PN532 Ready");
22+ u8g2.drawStr(10, 40, "Tap NFC Card");
23+
24+ u8g2.sendBuffer();
25+}
26+
27+void showUID(uint8_t *uid, uint8_t uidLength)
28+{
29+ char line[64];
30+
31+ String uidStr = "";
32+
33+ for (int i = 0; i < uidLength; i++)
34+ {
35+ if (uid[i] < 0x10)
36+ uidStr += "0";
37+
38+ uidStr += String(uid[i], HEX);
39+ uidStr += " ";
40+ }
41+
42+ uidStr.toUpperCase();
43+
44+ u8g2.clearBuffer();
45+
46+ u8g2.drawStr(0, 15, "Card Detected");
47+
48+ snprintf(line, sizeof(line), "UID:");
49+
50+ u8g2.drawStr(0, 35, line);
51+
52+ u8g2.drawStr(0, 50, uidStr.c_str());
53+
54+ u8g2.sendBuffer();
55+}
56+
57+void pn532_init()
58+{
59+ delay(100);
60+ nfc.begin();
61+ delay(100);
62+
63+ uint32_t versiondata = nfc.getFirmwareVersion();
64+
65+ if (!versiondata)
66+ {
67+ Serial.println("PN532 not found");
68+
69+ u8g2.clearBuffer();
70+ u8g2.drawStr(0, 20, "PN532 NOT FOUND");
71+ u8g2.sendBuffer();
72+
73+ delay(2000);
74+ return;
75+ }
76+
77+ Serial.println("PN532 initialized");
78+
79+ nfc.SAMConfig();
80+}
81+
82+void pn532_scan_loop()
83+{
84+ pn532_init();
85+
86+ drawWaiting();
87+
88+ while (1)
89+ {
90+ uint8_t success;
91+ uint8_t uid[7];
92+ uint8_t uidLength;
93+
94+ Serial.println("Scanning...");
95+ success = nfc.readPassiveTargetID(
96+ PN532_MIFARE_ISO14443A,
97+ uid,
98+ &uidLength,
99+ 50
100+ );
101+
102+ if (success)
103+ {
104+ Serial.println("Card detected");
105+
106+ showUID(uid, uidLength);
107+
108+ delay(1000);
109+ }
110+
111+ if (btnBack())
112+ {
113+ delay(150);
114+ break;
115+ }
116+ }
117+}
A src/nfc.h View
@@ -0,0 +1,4 @@
1+#pragma once
2+
3+void pn532_init();
4+void pn532_scan_loop();
R firmware/cc1101.cpp → src/rf/cc1101.cpp View
@@ -1,7 +1,8 @@
11 #include <Arduino.h>
2−#include "ELECHOUSE_CC1101_SRC_DRV.h"
2+#include "../libs/ELECHOUSE_CC1101_SRC_DRV.h"
33 #include "cc1101.h"
4−#include "config.h"
4+#include "../config.h"
5+#include "SPI.h"
56
67 // ===== CONFIG =====
78 #define RAW_BUF_MAX 512
@@ -32,7 +33,7 @@ void IRAM_ATTR pulseISR()
3233
3334 unsigned long duration = now - lastEdgeTime;
3435
35− if (duration < 50) return;
36+ if (duration < 150) return;
3637
3738 captureBuffer[pulseIndex++] = duration;
3839 lastEdgeTime = now;
@@ -44,7 +45,7 @@ void setupOOKMode()
4445 ELECHOUSE_cc1101.SetRx();
4546 ELECHOUSE_cc1101.setMHZ(currentFreq);
4647
47− ELECHOUSE_cc1101.setModulation(0); // ASK/OOK
48+ ELECHOUSE_cc1101.setModulation(2); // ASK/OOK
4849 ELECHOUSE_cc1101.setDRate(dataRate);
4950 ELECHOUSE_cc1101.setDeviation(0);
5051 ELECHOUSE_cc1101.setRxBW(rxBW);
@@ -53,14 +54,30 @@ void setupOOKMode()
5354 }
5455
5556 // ===== INIT (LAZY, SAFE) =====
57+// ================= CC1101 INIT =================
5658 bool initCC1101()
5759 {
58− if (cc1101Inited)
59− return true;
60+ Serial.println();
61+ Serial.println("===== CC1101 INIT =====");
6062
61− Serial.println("Initializing CC1101...");
63+ // ===== SPI =====
64+ SPI.begin(
65+ cc1101_SCK,
66+ cc1101_MISO,
67+ cc1101_MOSI,
68+ CC1101_CS
69+ );
6270
63− // IMPORTANT: no detachInterrupt here (causes crash if not installed)
71+ pinMode(CC1101_CS, OUTPUT);
72+ digitalWrite(CC1101_CS, HIGH);
73+
74+ delay(100);
75+
76+ // ===== GDO =====
77+ ELECHOUSE_cc1101.setGDO(
78+ CC1101_GDO0,
79+ -1
80+ );
6481
6582 ELECHOUSE_cc1101.setSpiPin(
6683 cc1101_SCK,
@@ -69,7 +86,8 @@ bool initCC1101()
6986 CC1101_CS
7087 );
7188
72− ELECHOUSE_cc1101.setGDO(CC1101_GDO0, CC1101_GDO2);
89+ // ===== DETECT =====
90+ Serial.println("Checking chip...");
7391
7492 if (!ELECHOUSE_cc1101.getCC1101())
7593 {
@@ -77,19 +95,42 @@ bool initCC1101()
7795 return false;
7896 }
7997
80− delay(10); // let SPI settle
98+ Serial.println("✅ CC1101 FOUND");
99+
100+ // ===== IMPORTANT =====
101+ // DO NOT CALL Init()
102+ // it freezes on some ESP32-S3 setups
81103
82− ELECHOUSE_cc1101.Init(); // THIS WAS YOUR FREEZE POINT
83− setupOOKMode();
104+ // ===== MANUAL CONFIG =====
105+ ELECHOUSE_cc1101.setMHZ(currentFreq);
106+
107+ // 2 = ASK/OOK
108+ ELECHOUSE_cc1101.setModulation(2);
109+
110+ ELECHOUSE_cc1101.setDRate(dataRate);
111+
112+ ELECHOUSE_cc1101.setRxBW(rxBW);
113+
114+ ELECHOUSE_cc1101.setDeviation(0);
115+
116+ // disable sync requirement
117+ ELECHOUSE_cc1101.setSyncMode(0);
118+
119+ ELECHOUSE_cc1101.setPA(powerLevel);
120+
121+ // async serial mode
122+ ELECHOUSE_cc1101.setCCMode(0);
123+
124+ // enter RX
125+ ELECHOUSE_cc1101.SetRx();
84126
85127 pinMode(CC1101_GDO0, INPUT);
86128
87− Serial.println("✅ CC1101 READY");
129+ Serial.println("✅ RX MODE READY");
88130
89131 cc1101Inited = true;
90132 return true;
91133 }
92−
93134 // ===== CAPTURE CONTROL =====
94135 void startCapture()
95136 {
@@ -103,7 +144,7 @@ void startCapture()
103144 CHANGE
104145 );
105146
106− Serial.println("Capture started");
147+ Serial.println("Looking for RF... ");
107148 }
108149
109150 bool isCC1101Ready() {
@@ -131,20 +172,34 @@ void printCapture()
131172 }
132173
133174
134−// ===== REPLAY =====
175+// ================= REPLAY =================
135176 void replaySignal()
136177 {
137− Serial.println("Replaying...");
178+ Serial.println();
179+ Serial.println("Replaying signal...");
180+
181+ stopCapture();
138182
139183 ELECHOUSE_cc1101.SetTx();
184+
140185 pinMode(CC1101_GDO0, OUTPUT);
141186
142187 for (int i = 0; i < pulseIndex; i++)
143188 {
144− digitalWrite(CC1101_GDO0, (i % 2 == 0) ? HIGH : LOW);
189+ digitalWrite(
190+ CC1101_GDO0,
191+ (i % 2 == 0) ? HIGH : LOW
192+ );
193+
145194 delayMicroseconds(captureBuffer[i]);
146195 }
147196
148197 digitalWrite(CC1101_GDO0, LOW);
198+
149199 ELECHOUSE_cc1101.SetRx();
200+
201+ pinMode(CC1101_GDO0, INPUT);
202+
203+ Serial.println("Replay complete");
150204 }
205+
R firmware/cc1101.h → src/rf/cc1101.h View

[No content changes]

R firmware/nrf24.cpp → src/rf/nrf24.cpp View
@@ -1,8 +1,8 @@
11 #include <Arduino.h>
22 #include <RF24.h>
3−#include "buttons.h"
43 #include "nrf24.h"
5−#include "display.h"
4+#include "../ui/display.h"
5+#include "../buttons.h"
66 #define JAM_DURATION 500
77
88 extern SPIClass *RADIO_SPI;
R firmware/nrf24.h → src/rf/nrf24.h View

[No content changes]

R firmware/sysinfo.cpp → src/sysinfo.cpp View
@@ -1,5 +1,5 @@
11 #include <Arduino.h>
2−#include "display.h"
2+#include "ui/display.h"
33 #include "buttons.h"
44 #include <esp_chip_info.h>
55 #include <esp_heap_caps.h>
R firmware/sysinfo.h → src/sysinfo.h View

[No content changes]

R firmware/display.cpp → src/ui/display.cpp View

[No content changes]

R firmware/display.h → src/ui/display.h View

[No content changes]

R firmware/menu.cpp → src/ui/menu.cpp View
@@ -3,11 +3,11 @@
33 #include "display.h"
44 #include "buttons.h"
55 #include "badusb.h"
6−#include "nrf24.h"
7−#include "cc1101.h"
6+#include "rf/nrf24.h"
7+#include "rf/cc1101.h"
88 #include "blescanner.h"
9−#include "wifi_scan.h"
10−#include "wifi_analyzer.h"
9+#include "wifi/wifi_scan.h"
10+#include "wifi/wifi_analyzer.h"
1111 #include "device_check.h"
1212 #include "ble_mouse.h"
1313 #include "sysinfo.h"
R firmware/menu.h → src/ui/menu.h View

[No content changes]

R firmware/wifi_analyzer.cpp → src/wifi/wifi_analyzer.cpp View
@@ -2,8 +2,8 @@
22 #include <WiFi.h>
33 #include <esp_wifi.h>
44
5−#include "display.h"
6−#include "buttons.h"
5+#include "../ui/display.h"
6+#include "../buttons.h"
77
88 // ===== CONFIG =====
99 #define GRAPH_WIDTH 128
R firmware/wifi_analyzer.h → src/wifi/wifi_analyzer.h View

[No content changes]

R firmware/wifi_scan.cpp → src/wifi/wifi_scan.cpp View
@@ -1,7 +1,7 @@
11 #include <Arduino.h>
22 #include <WiFi.h>
3−#include "display.h"
4−#include "buttons.h"
3+#include "../ui/display.h"
4+#include "../buttons.h"
55
66 #define MAX_NETWORKS 30
77
R firmware/wifi_scan.h → src/wifi/wifi_scan.h View

[No content changes]

A test/Adafruit_PN532.cpp View
@@ -0,0 +1,1820 @@
1+/**************************************************************************/
2+/*!
3+ @file Adafruit_PN532.cpp
4+
5+ @section intro_sec Introduction
6+
7+ Driver for NXP's PN532 NFC/13.56MHz RFID Transceiver
8+
9+ This is a library for the Adafruit PN532 NFC/RFID breakout boards
10+ This library works with the Adafruit NFC breakout
11+ ----> https://www.adafruit.com/products/364
12+
13+ Check out the links above for our tutorials and wiring diagrams
14+ These chips use SPI or I2C to communicate.
15+
16+ Adafruit invests time and resources providing this open source code,
17+ please support Adafruit and open-source hardware by purchasing
18+ products from Adafruit!
19+
20+ @section author Author
21+
22+ Adafruit Industries
23+
24+ @section license License
25+
26+ BSD (see license.txt)
27+
28+ @section HISTORY
29+
30+ v2.2 - Added startPassiveTargetIDDetection() to start card detection and
31+ readDetectedPassiveTargetID() to read it, useful when using the
32+ IRQ pin.
33+
34+ v2.1 - Added NTAG2xx helper functions
35+
36+ v2.0 - Refactored to add I2C support from Adafruit_NFCShield_I2C library.
37+
38+ v1.4 - Added setPassiveActivationRetries()
39+
40+ v1.2 - Added writeGPIO()
41+ - Added readGPIO()
42+
43+ v1.1 - Changed readPassiveTargetID() to handle multiple UID sizes
44+ - Added the following helper functions for text display
45+ static void PrintHex(const byte * data, const uint32_t numBytes)
46+ static void PrintHexChar(const byte * pbtData, const uint32_t
47+ numBytes)
48+ - Added the following Mifare Classic functions:
49+ bool mifareclassic_IsFirstBlock (uint32_t uiBlock)
50+ bool mifareclassic_IsTrailerBlock (uint32_t uiBlock)
51+ uint8_t mifareclassic_AuthenticateBlock (uint8_t * uid, uint8_t
52+ uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t * keyData) uint8_t
53+ mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t * data) uint8_t
54+ mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t * data)
55+ - Added the following Mifare Ultalight functions:
56+ uint8_t mifareultralight_ReadPage (uint8_t page, uint8_t * buffer)
57+*/
58+/**************************************************************************/
59+
60+#include "Adafruit_PN532.h"
61+
62+byte pn532ack[] = {0x00, 0x00, 0xFF,
63+ 0x00, 0xFF, 0x00}; ///< ACK message from PN532
64+byte pn532response_firmwarevers[] = {
65+ 0x00, 0x00, 0xFF,
66+ 0x06, 0xFA, 0xD5}; ///< Expected firmware version message from PN532
67+
68+// Uncomment these lines to enable debug output for PN532(SPI) and/or MIFARE
69+// related code
70+
71+// #define PN532DEBUG
72+// #define MIFAREDEBUG
73+
74+// If using Native Port on Arduino Zero or Due define as SerialUSB
75+#define PN532DEBUGPRINT Serial ///< Fixed name for debug Serial instance
76+// #define PN532DEBUGPRINT SerialUSB ///< Fixed name for debug Serial instance
77+
78+#define PN532_PACKBUFFSIZ 64 ///< Packet buffer size in bytes
79+byte pn532_packetbuffer[PN532_PACKBUFFSIZ]; ///< Packet buffer used in various
80+ ///< transactions
81+
82+/**************************************************************************/
83+/*!
84+ @brief Instantiates a new PN532 class using software SPI.
85+
86+ @param clk SPI clock pin (SCK)
87+ @param miso SPI MISO pin
88+ @param mosi SPI MOSI pin
89+ @param ss SPI chip select pin (CS/SSEL)
90+*/
91+/**************************************************************************/
92+Adafruit_PN532::Adafruit_PN532(uint8_t clk, uint8_t miso, uint8_t mosi,
93+ uint8_t ss) {
94+ _cs = ss;
95+ spi_dev = new Adafruit_SPIDevice(ss, clk, miso, mosi, 1000000,
96+ SPI_BITORDER_LSBFIRST, SPI_MODE0);
97+}
98+
99+/**************************************************************************/
100+/*!
101+ @brief Instantiates a new PN532 class using I2C.
102+
103+ @param irq Location of the IRQ pin
104+ @param reset Location of the RSTPD_N pin
105+ @param theWire pointer to I2C bus to use
106+*/
107+/**************************************************************************/
108+Adafruit_PN532::Adafruit_PN532(uint8_t irq, uint8_t reset, TwoWire *theWire)
109+ : _irq(irq), _reset(reset) {
110+ pinMode(_irq, INPUT);
111+ pinMode(_reset, OUTPUT);
112+ i2c_dev = new Adafruit_I2CDevice(PN532_I2C_ADDRESS, theWire);
113+}
114+
115+/**************************************************************************/
116+/*!
117+ @brief Instantiates a new PN532 class using hardware SPI.
118+
119+ @param ss SPI chip select pin (CS/SSEL)
120+ @param theSPI pointer to the SPI bus to use
121+*/
122+/**************************************************************************/
123+Adafruit_PN532::Adafruit_PN532(uint8_t ss, SPIClass *theSPI) {
124+ _cs = ss;
125+ spi_dev = new Adafruit_SPIDevice(ss, 1000000, SPI_BITORDER_LSBFIRST,
126+ SPI_MODE0, theSPI);
127+}
128+
129+/**************************************************************************/
130+/*!
131+ @brief Instantiates a new PN532 class using hardware UART (HSU).
132+
133+ @param reset Location of the RSTPD_N pin
134+ @param theSer pointer to HardWare Serial bus to use
135+*/
136+/**************************************************************************/
137+Adafruit_PN532::Adafruit_PN532(uint8_t reset, HardwareSerial *theSer)
138+ : _reset(reset) {
139+ pinMode(_reset, OUTPUT);
140+ ser_dev = theSer;
141+}
142+
143+/**************************************************************************/
144+/*!
145+ @brief Setups the HW
146+
147+ @returns true if successful, otherwise false
148+*/
149+/**************************************************************************/
150+bool Adafruit_PN532::begin() {
151+ if (spi_dev) {
152+ // SPI initialization
153+ if (!spi_dev->begin()) {
154+ return false;
155+ }
156+ } else if (i2c_dev) {
157+ // I2C initialization
158+ // PN532 will fail address check since its asleep, so suppress
159+ if (!i2c_dev->begin(false)) {
160+ return false;
161+ }
162+ } else if (ser_dev) {
163+ ser_dev->begin(115200);
164+ // clear out anything in read buffer
165+ while (ser_dev->available())
166+ ser_dev->read();
167+ } else {
168+ // no interface specified
169+ return false;
170+ }
171+ reset(); // HW reset - put in known state
172+ delay(10);
173+ wakeup(); // hey! wakeup!
174+ return true;
175+}
176+
177+/**************************************************************************/
178+/*!
179+ @brief Perform a hardware reset. Requires reset pin to have been provided.
180+*/
181+/**************************************************************************/
182+void Adafruit_PN532::reset(void) {
183+ // see Datasheet p.209, Fig.48 for timings
184+ if (_reset != -1) {
185+ digitalWrite(_reset, LOW);
186+ delay(1); // min 20ns
187+ digitalWrite(_reset, HIGH);
188+ delay(2); // max 2ms
189+ }
190+}
191+
192+/**************************************************************************/
193+/*!
194+ @brief Wakeup from LowVbat mode into Normal Mode.
195+*/
196+/**************************************************************************/
197+void Adafruit_PN532::wakeup(void) {
198+ // interface specific wakeups - each one is unique!
199+ if (spi_dev) {
200+ // hold CS low for 2ms
201+ digitalWrite(_cs, LOW);
202+ delay(2);
203+ } else if (ser_dev) {
204+ uint8_t w[3] = {0x55, 0x00, 0x00};
205+ ser_dev->write(w, 3);
206+ delay(2);
207+ }
208+
209+ // PN532 will clock stretch I2C during SAMConfig as a "wakeup"
210+
211+ // need to config SAM to stay in Normal Mode
212+ SAMConfig();
213+}
214+
215+/**************************************************************************/
216+/*!
217+ @brief Prints a hexadecimal value in plain characters
218+
219+ @param data Pointer to the byte data
220+ @param numBytes Data length in bytes
221+*/
222+/**************************************************************************/
223+void Adafruit_PN532::PrintHex(const byte *data, const uint32_t numBytes) {
224+ uint32_t szPos;
225+ for (szPos = 0; szPos < numBytes; szPos++) {
226+ PN532DEBUGPRINT.print(F("0x"));
227+ // Append leading 0 for small values
228+ if (data[szPos] <= 0xF)
229+ PN532DEBUGPRINT.print(F("0"));
230+ PN532DEBUGPRINT.print(data[szPos] & 0xff, HEX);
231+ if ((numBytes > 1) && (szPos != numBytes - 1)) {
232+ PN532DEBUGPRINT.print(F(" "));
233+ }
234+ }
235+ PN532DEBUGPRINT.println();
236+}
237+
238+/**************************************************************************/
239+/*!
240+ @brief Prints a hexadecimal value in plain characters, along with
241+ the char equivalents in the following format
242+
243+ 00 00 00 00 00 00 ......
244+
245+ @param data Pointer to the byte data
246+ @param numBytes Data length in bytes
247+*/
248+/**************************************************************************/
249+void Adafruit_PN532::PrintHexChar(const byte *data, const uint32_t numBytes) {
250+ uint32_t szPos;
251+ for (szPos = 0; szPos < numBytes; szPos++) {
252+ // Append leading 0 for small values
253+ if (data[szPos] <= 0xF)
254+ PN532DEBUGPRINT.print(F("0"));
255+ PN532DEBUGPRINT.print(data[szPos], HEX);
256+ if ((numBytes > 1) && (szPos != numBytes - 1)) {
257+ PN532DEBUGPRINT.print(F(" "));
258+ }
259+ }
260+ PN532DEBUGPRINT.print(F(" "));
261+ for (szPos = 0; szPos < numBytes; szPos++) {
262+ if (data[szPos] <= 0x1F)
263+ PN532DEBUGPRINT.print(F("."));
264+ else
265+ PN532DEBUGPRINT.print((char)data[szPos]);
266+ }
267+ PN532DEBUGPRINT.println();
268+}
269+
270+/**************************************************************************/
271+/*!
272+ @brief Checks the firmware version of the PN5xx chip
273+
274+ @returns The chip's firmware version and ID
275+*/
276+/**************************************************************************/
277+uint32_t Adafruit_PN532::getFirmwareVersion(void) {
278+ uint32_t response;
279+
280+ pn532_packetbuffer[0] = PN532_COMMAND_GETFIRMWAREVERSION;
281+
282+ if (!sendCommandCheckAck(pn532_packetbuffer, 1)) {
283+ return 0;
284+ }
285+
286+ // read data packet
287+ readdata(pn532_packetbuffer, 13);
288+
289+ // check some basic stuff
290+ if (0 != memcmp((char *)pn532_packetbuffer,
291+ (char *)pn532response_firmwarevers, 6)) {
292+#ifdef PN532DEBUG
293+ PN532DEBUGPRINT.println(F("Firmware doesn't match!"));
294+#endif
295+ return 0;
296+ }
297+
298+ int offset = 7;
299+ response = pn532_packetbuffer[offset++];
300+ response <<= 8;
301+ response |= pn532_packetbuffer[offset++];
302+ response <<= 8;
303+ response |= pn532_packetbuffer[offset++];
304+ response <<= 8;
305+ response |= pn532_packetbuffer[offset++];
306+
307+ return response;
308+}
309+
310+/**************************************************************************/
311+/*!
312+ @brief Sends a command and waits a specified period for the ACK
313+
314+ @param cmd Pointer to the command buffer
315+ @param cmdlen The size of the command in bytes
316+ @param timeout timeout before giving up
317+
318+ @returns 1 if everything is OK, 0 if timeout occured before an
319+ ACK was recieved
320+*/
321+/**************************************************************************/
322+// default timeout of one second
323+bool Adafruit_PN532::sendCommandCheckAck(uint8_t *cmd, uint8_t cmdlen,
324+ uint16_t timeout) {
325+
326+ // I2C works without using IRQ pin by polling for RDY byte
327+ // seems to work best with some delays between transactions
328+ uint8_t SLOWDOWN = 0;
329+ if (i2c_dev || spi_dev) // SPI and I2C need 1ms slow for page reads
330+ SLOWDOWN = 1;
331+
332+ // write the command
333+ writecommand(cmd, cmdlen);
334+
335+ // I2C TUNING
336+ delay(SLOWDOWN);
337+
338+ // Wait for chip to say its ready!
339+ if (!waitready(timeout)) {
340+ return false;
341+ }
342+
343+#ifdef PN532DEBUG
344+ if (spi_dev == NULL) {
345+ PN532DEBUGPRINT.println(F("IRQ received"));
346+ }
347+#endif
348+
349+ // read acknowledgement
350+ if (!readack()) {
351+#ifdef PN532DEBUG
352+ PN532DEBUGPRINT.println(F("No ACK frame received!"));
353+#endif
354+ return false;
355+ }
356+
357+ // I2C TUNING
358+ delay(SLOWDOWN);
359+
360+ // Wait for chip to say its ready!
361+ if (!waitready(timeout)) {
362+ return false;
363+ }
364+
365+ return true; // ack'd command
366+}
367+
368+/**************************************************************************/
369+/*!
370+ @brief Writes an 8-bit value that sets the state of the PN532's GPIO
371+ pins.
372+ @param pinstate P3 pins state.
373+
374+ @warning This function is provided exclusively for board testing and
375+ is dangerous since it will throw an error if any pin other
376+ than the ones marked "Can be used as GPIO" are modified! All
377+ pins that can not be used as GPIO should ALWAYS be left high
378+ (value = 1) or the system will become unstable and a HW reset
379+ will be required to recover the PN532.
380+
381+ pinState[0] = P30 Can be used as GPIO
382+ pinState[1] = P31 Can be used as GPIO
383+ pinState[2] = P32 *** RESERVED (Must be 1!) ***
384+ pinState[3] = P33 Can be used as GPIO
385+ pinState[4] = P34 *** RESERVED (Must be 1!) ***
386+ pinState[5] = P35 Can be used as GPIO
387+
388+ @return 1 if everything executed properly, 0 for an error
389+*/
390+/**************************************************************************/
391+bool Adafruit_PN532::writeGPIO(uint8_t pinstate) {
392+ // uint8_t errorbit;
393+
394+ // Make sure pinstate does not try to toggle P32 or P34
395+ pinstate |= (1 << PN532_GPIO_P32) | (1 << PN532_GPIO_P34);
396+
397+ // Fill command buffer
398+ pn532_packetbuffer[0] = PN532_COMMAND_WRITEGPIO;
399+ pn532_packetbuffer[1] = PN532_GPIO_VALIDATIONBIT | pinstate; // P3 Pins
400+ pn532_packetbuffer[2] = 0x00; // P7 GPIO Pins (not used ... taken by SPI)
401+
402+#ifdef PN532DEBUG
403+ PN532DEBUGPRINT.print(F("Writing P3 GPIO: "));
404+ PN532DEBUGPRINT.println(pn532_packetbuffer[1], HEX);
405+#endif
406+
407+ // Send the WRITEGPIO command (0x0E)
408+ if (!sendCommandCheckAck(pn532_packetbuffer, 3))
409+ return 0x0;
410+
411+ // Read response packet (00 FF PLEN PLENCHECKSUM D5 CMD+1(0x0F) DATACHECKSUM
412+ // 00)
413+ readdata(pn532_packetbuffer, 8);
414+
415+#ifdef PN532DEBUG
416+ PN532DEBUGPRINT.print(F("Received: "));
417+ PrintHex(pn532_packetbuffer, 8);
418+ PN532DEBUGPRINT.println();
419+#endif
420+
421+ int offset = 6;
422+ return (pn532_packetbuffer[offset] == 0x0F);
423+}
424+
425+/**************************************************************************/
426+/*!
427+ Reads the state of the PN532's GPIO pins
428+
429+ @returns An 8-bit value containing the pin state where:
430+
431+ pinState[0] = P30
432+ pinState[1] = P31
433+ pinState[2] = P32
434+ pinState[3] = P33
435+ pinState[4] = P34
436+ pinState[5] = P35
437+*/
438+/**************************************************************************/
439+uint8_t Adafruit_PN532::readGPIO(void) {
440+ pn532_packetbuffer[0] = PN532_COMMAND_READGPIO;
441+
442+ // Send the READGPIO command (0x0C)
443+ if (!sendCommandCheckAck(pn532_packetbuffer, 1))
444+ return 0x0;
445+
446+ // Read response packet (00 FF PLEN PLENCHECKSUM D5 CMD+1(0x0D) P3 P7 IO1
447+ // DATACHECKSUM 00)
448+ readdata(pn532_packetbuffer, 11);
449+
450+ /* READGPIO response should be in the following format:
451+
452+ byte Description
453+ ------------- ------------------------------------------
454+ b0..5 Frame header and preamble (with I2C there is an extra 0x00)
455+ b6 P3 GPIO Pins
456+ b7 P7 GPIO Pins (not used ... taken by SPI)
457+ b8 Interface Mode Pins (not used ... bus select pins)
458+ b9..10 checksum */
459+
460+ int p3offset = 7;
461+
462+#ifdef PN532DEBUG
463+ PN532DEBUGPRINT.print(F("Received: "));
464+ PrintHex(pn532_packetbuffer, 11);
465+ PN532DEBUGPRINT.println();
466+ PN532DEBUGPRINT.print(F("P3 GPIO: 0x"));
467+ PN532DEBUGPRINT.println(pn532_packetbuffer[p3offset], HEX);
468+ PN532DEBUGPRINT.print(F("P7 GPIO: 0x"));
469+ PN532DEBUGPRINT.println(pn532_packetbuffer[p3offset + 1], HEX);
470+ PN532DEBUGPRINT.print(F("IO GPIO: 0x"));
471+ PN532DEBUGPRINT.println(pn532_packetbuffer[p3offset + 2], HEX);
472+ // Note: You can use the IO GPIO value to detect the serial bus being used
473+ switch (pn532_packetbuffer[p3offset + 2]) {
474+ case 0x00: // Using UART
475+ PN532DEBUGPRINT.println(F("Using UART (IO = 0x00)"));
476+ break;
477+ case 0x01: // Using I2C
478+ PN532DEBUGPRINT.println(F("Using I2C (IO = 0x01)"));
479+ break;
480+ case 0x02: // Using SPI
481+ PN532DEBUGPRINT.println(F("Using SPI (IO = 0x02)"));
482+ break;
483+ }
484+#endif
485+
486+ return pn532_packetbuffer[p3offset];
487+}
488+
489+/**************************************************************************/
490+/*!
491+ @brief Configures the SAM (Secure Access Module)
492+ @return true on success, false otherwise.
493+*/
494+/**************************************************************************/
495+bool Adafruit_PN532::SAMConfig(void) {
496+ pn532_packetbuffer[0] = PN532_COMMAND_SAMCONFIGURATION;
497+ pn532_packetbuffer[1] = 0x01; // normal mode;
498+ pn532_packetbuffer[2] = 0x14; // timeout 50ms * 20 = 1 second
499+ pn532_packetbuffer[3] = 0x01; // use IRQ pin!
500+
501+ if (!sendCommandCheckAck(pn532_packetbuffer, 4))
502+ return false;
503+
504+ // read data packet
505+ readdata(pn532_packetbuffer, 9);
506+
507+ int offset = 6;
508+ return (pn532_packetbuffer[offset] == 0x15);
509+}
510+
511+/**************************************************************************/
512+/*!
513+ Sets the MxRtyPassiveActivation byte of the RFConfiguration register
514+
515+ @param maxRetries 0xFF to wait forever, 0x00..0xFE to timeout
516+ after mxRetries
517+
518+ @returns 1 if everything executed properly, 0 for an error
519+*/
520+/**************************************************************************/
521+bool Adafruit_PN532::setPassiveActivationRetries(uint8_t maxRetries) {
522+ pn532_packetbuffer[0] = PN532_COMMAND_RFCONFIGURATION;
523+ pn532_packetbuffer[1] = 5; // Config item 5 (MaxRetries)
524+ pn532_packetbuffer[2] = 0xFF; // MxRtyATR (default = 0xFF)
525+ pn532_packetbuffer[3] = 0x01; // MxRtyPSL (default = 0x01)
526+ pn532_packetbuffer[4] = maxRetries;
527+
528+#ifdef MIFAREDEBUG
529+ PN532DEBUGPRINT.print(F("Setting MxRtyPassiveActivation to "));
530+ PN532DEBUGPRINT.print(maxRetries, DEC);
531+ PN532DEBUGPRINT.println(F(" "));
532+#endif
533+
534+ if (!sendCommandCheckAck(pn532_packetbuffer, 5))
535+ return 0x0; // no ACK
536+
537+ return 1;
538+}
539+
540+/***** ISO14443A Commands ******/
541+
542+/**************************************************************************/
543+/*!
544+ @brief Waits for an ISO14443A target to enter the field and reads
545+ its ID.
546+
547+ @param cardbaudrate Baud rate of the card
548+ @param uid Pointer to the array that will be populated
549+ with the card's UID (up to 7 bytes)
550+ @param uidLength Pointer to the variable that will hold the
551+ length of the card's UID.
552+ @param timeout Timeout in milliseconds.
553+
554+ @return 1 if everything executed properly, 0 for an error
555+*/
556+/**************************************************************************/
557+bool Adafruit_PN532::readPassiveTargetID(uint8_t cardbaudrate, uint8_t *uid,
558+ uint8_t *uidLength, uint16_t timeout) {
559+ pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET;
560+ pn532_packetbuffer[1] = 1; // max 1 cards at once (we can set this to 2 later)
561+ pn532_packetbuffer[2] = cardbaudrate;
562+
563+ if (!sendCommandCheckAck(pn532_packetbuffer, 3, timeout)) {
564+#ifdef PN532DEBUG
565+ PN532DEBUGPRINT.println(F("No card(s) read"));
566+#endif
567+ return 0x0; // no cards read
568+ }
569+
570+ return readDetectedPassiveTargetID(uid, uidLength);
571+}
572+
573+/**************************************************************************/
574+/*!
575+ @brief Put the reader in detection mode, non blocking so interrupts
576+ must be enabled.
577+ @param cardbaudrate Baud rate of the card
578+ @return 1 if everything executed properly, 0 for an error
579+*/
580+/**************************************************************************/
581+bool Adafruit_PN532::startPassiveTargetIDDetection(uint8_t cardbaudrate) {
582+ pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET;
583+ pn532_packetbuffer[1] = 1; // max 1 cards at once (we can set this to 2 later)
584+ pn532_packetbuffer[2] = cardbaudrate;
585+
586+ return sendCommandCheckAck(pn532_packetbuffer, 3);
587+}
588+
589+/**************************************************************************/
590+/*!
591+ Reads the ID of the passive target the reader has deteceted.
592+
593+ @param uid Pointer to the array that will be populated
594+ with the card's UID (up to 7 bytes)
595+ @param uidLength Pointer to the variable that will hold the
596+ length of the card's UID.
597+
598+ @returns 1 if everything executed properly, 0 for an error
599+*/
600+/**************************************************************************/
601+bool Adafruit_PN532::readDetectedPassiveTargetID(uint8_t *uid,
602+ uint8_t *uidLength) {
603+ // read data packet
604+ readdata(pn532_packetbuffer, 20);
605+ // check some basic stuff
606+
607+ /* ISO14443A card response should be in the following format:
608+
609+ byte Description
610+ ------------- ------------------------------------------
611+ b0..6 Frame header and preamble
612+ b7 Tags Found
613+ b8 Tag Number (only one used in this example)
614+ b9..10 SENS_RES
615+ b11 SEL_RES
616+ b12 NFCID Length
617+ b13..NFCIDLen NFCID */
618+
619+#ifdef MIFAREDEBUG
620+ PN532DEBUGPRINT.print(F("Found "));
621+ PN532DEBUGPRINT.print(pn532_packetbuffer[7], DEC);
622+ PN532DEBUGPRINT.println(F(" tags"));
623+#endif
624+ if (pn532_packetbuffer[7] != 1)
625+ return 0;
626+
627+ uint16_t sens_res = pn532_packetbuffer[9];
628+ sens_res <<= 8;
629+ sens_res |= pn532_packetbuffer[10];
630+#ifdef MIFAREDEBUG
631+ PN532DEBUGPRINT.print(F("ATQA: 0x"));
632+ PN532DEBUGPRINT.println(sens_res, HEX);
633+ PN532DEBUGPRINT.print(F("SAK: 0x"));
634+ PN532DEBUGPRINT.println(pn532_packetbuffer[11], HEX);
635+#endif
636+
637+ /* Card appears to be Mifare Classic */
638+ *uidLength = pn532_packetbuffer[12];
639+#ifdef MIFAREDEBUG
640+ PN532DEBUGPRINT.print(F("UID:"));
641+#endif
642+ for (uint8_t i = 0; i < pn532_packetbuffer[12]; i++) {
643+ uid[i] = pn532_packetbuffer[13 + i];
644+#ifdef MIFAREDEBUG
645+ PN532DEBUGPRINT.print(F(" 0x"));
646+ PN532DEBUGPRINT.print(uid[i], HEX);
647+#endif
648+ }
649+#ifdef MIFAREDEBUG
650+ PN532DEBUGPRINT.println();
651+#endif
652+
653+ return 1;
654+}
655+
656+/**************************************************************************/
657+/*!
658+ @brief Exchanges an APDU with the currently inlisted peer
659+
660+ @param send Pointer to data to send
661+ @param sendLength Length of the data to send
662+ @param response Pointer to response data
663+ @param responseLength Pointer to the response data length
664+ @return true on success, false otherwise.
665+*/
666+/**************************************************************************/
667+bool Adafruit_PN532::inDataExchange(uint8_t *send, uint8_t sendLength,
668+ uint8_t *response,
669+ uint8_t *responseLength) {
670+ if (sendLength > PN532_PACKBUFFSIZ - 2) {
671+#ifdef PN532DEBUG
672+ PN532DEBUGPRINT.println(F("APDU length too long for packet buffer"));
673+#endif
674+ return false;
675+ }
676+ uint8_t i;
677+
678+ pn532_packetbuffer[0] = 0x40; // PN532_COMMAND_INDATAEXCHANGE;
679+ pn532_packetbuffer[1] = _inListedTag;
680+ for (i = 0; i < sendLength; ++i) {
681+ pn532_packetbuffer[i + 2] = send[i];
682+ }
683+
684+ if (!sendCommandCheckAck(pn532_packetbuffer, sendLength + 2, 1000)) {
685+#ifdef PN532DEBUG
686+ PN532DEBUGPRINT.println(F("Could not send APDU"));
687+#endif
688+ return false;
689+ }
690+
691+ if (!waitready(1000)) {
692+#ifdef PN532DEBUG
693+ PN532DEBUGPRINT.println(F("Response never received for APDU..."));
694+#endif
695+ return false;
696+ }
697+
698+ readdata(pn532_packetbuffer, sizeof(pn532_packetbuffer));
699+
700+ if (pn532_packetbuffer[0] == 0 && pn532_packetbuffer[1] == 0 &&
701+ pn532_packetbuffer[2] == 0xff) {
702+ uint8_t length = pn532_packetbuffer[3];
703+ if (pn532_packetbuffer[4] != (uint8_t)(~length + 1)) {
704+#ifdef PN532DEBUG
705+ PN532DEBUGPRINT.println(F("Length check invalid"));
706+ PN532DEBUGPRINT.println(length, HEX);
707+ PN532DEBUGPRINT.println((~length) + 1, HEX);
708+#endif
709+ return false;
710+ }
711+ if (pn532_packetbuffer[5] == PN532_PN532TOHOST &&
712+ pn532_packetbuffer[6] == PN532_RESPONSE_INDATAEXCHANGE) {
713+ if ((pn532_packetbuffer[7] & 0x3f) != 0) {
714+#ifdef PN532DEBUG
715+ PN532DEBUGPRINT.println(F("Status code indicates an error"));
716+#endif
717+ return false;
718+ }
719+
720+ length -= 3;
721+
722+ if (length > *responseLength) {
723+ length = *responseLength; // silent truncation...
724+ }
725+
726+ for (i = 0; i < length; ++i) {
727+ response[i] = pn532_packetbuffer[8 + i];
728+ }
729+ *responseLength = length;
730+
731+ return true;
732+ } else {
733+ PN532DEBUGPRINT.print(F("Don't know how to handle this command: "));
734+ PN532DEBUGPRINT.println(pn532_packetbuffer[6], HEX);
735+ return false;
736+ }
737+ } else {
738+ PN532DEBUGPRINT.println(F("Preamble missing"));
739+ return false;
740+ }
741+}
742+
743+/**************************************************************************/
744+/*!
745+ @brief 'InLists' a passive target. PN532 acting as reader/initiator,
746+ peer acting as card/responder.
747+ @return true on success, false otherwise.
748+*/
749+/**************************************************************************/
750+bool Adafruit_PN532::inListPassiveTarget() {
751+ pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET;
752+ pn532_packetbuffer[1] = 1;
753+ pn532_packetbuffer[2] = 0;
754+
755+#ifdef PN532DEBUG
756+ PN532DEBUGPRINT.print(F("About to inList passive target"));
757+#endif
758+
759+ if (!sendCommandCheckAck(pn532_packetbuffer, 3, 1000)) {
760+#ifdef PN532DEBUG
761+ PN532DEBUGPRINT.println(F("Could not send inlist message"));
762+#endif
763+ return false;
764+ }
765+
766+ if (!waitready(30000)) {
767+ return false;
768+ }
769+
770+ readdata(pn532_packetbuffer, sizeof(pn532_packetbuffer));
771+
772+ if (pn532_packetbuffer[0] == 0 && pn532_packetbuffer[1] == 0 &&
773+ pn532_packetbuffer[2] == 0xff) {
774+ uint8_t length = pn532_packetbuffer[3];
775+ if (pn532_packetbuffer[4] != (uint8_t)(~length + 1)) {
776+#ifdef PN532DEBUG
777+ PN532DEBUGPRINT.println(F("Length check invalid"));
778+ PN532DEBUGPRINT.println(length, HEX);
779+ PN532DEBUGPRINT.println((~length) + 1, HEX);
780+#endif
781+ return false;
782+ }
783+ if (pn532_packetbuffer[5] == PN532_PN532TOHOST &&
784+ pn532_packetbuffer[6] == PN532_RESPONSE_INLISTPASSIVETARGET) {
785+ if (pn532_packetbuffer[7] != 1) {
786+#ifdef PN532DEBUG
787+ PN532DEBUGPRINT.println(F("Unhandled number of targets inlisted"));
788+#endif
789+ PN532DEBUGPRINT.println(F("Number of tags inlisted:"));
790+ PN532DEBUGPRINT.println(pn532_packetbuffer[7]);
791+ return false;
792+ }
793+
794+ _inListedTag = pn532_packetbuffer[8];
795+ PN532DEBUGPRINT.print(F("Tag number: "));
796+ PN532DEBUGPRINT.println(_inListedTag);
797+
798+ return true;
799+ } else {
800+#ifdef PN532DEBUG
801+ PN532DEBUGPRINT.print(F("Unexpected response to inlist passive host"));
802+#endif
803+ return false;
804+ }
805+ } else {
806+#ifdef PN532DEBUG
807+ PN532DEBUGPRINT.println(F("Preamble missing"));
808+#endif
809+ return false;
810+ }
811+
812+ return true;
813+}
814+
815+/***** Mifare Classic Functions ******/
816+
817+/**************************************************************************/
818+/*!
819+ @brief Indicates whether the specified block number is the first block
820+ in the sector (block 0 relative to the current sector)
821+ @param uiBlock Block number to test.
822+ @return true if first block, false otherwise.
823+*/
824+/**************************************************************************/
825+bool Adafruit_PN532::mifareclassic_IsFirstBlock(uint32_t uiBlock) {
826+ // Test if we are in the small or big sectors
827+ if (uiBlock < 128)
828+ return ((uiBlock) % 4 == 0);
829+ else
830+ return ((uiBlock) % 16 == 0);
831+}
832+
833+/**************************************************************************/
834+/*!
835+ @brief Indicates whether the specified block number is the sector
836+ trailer.
837+ @param uiBlock Block number to test.
838+ @return true if sector trailer, false otherwise.
839+*/
840+/**************************************************************************/
841+bool Adafruit_PN532::mifareclassic_IsTrailerBlock(uint32_t uiBlock) {
842+ // Test if we are in the small or big sectors
843+ if (uiBlock < 128)
844+ return ((uiBlock + 1) % 4 == 0);
845+ else
846+ return ((uiBlock + 1) % 16 == 0);
847+}
848+
849+/**************************************************************************/
850+/*!
851+ Tries to authenticate a block of memory on a MIFARE card using the
852+ INDATAEXCHANGE command. See section 7.3.8 of the PN532 User Manual
853+ for more information on sending MIFARE and other commands.
854+
855+ @param uid Pointer to a byte array containing the card UID
856+ @param uidLen The length (in bytes) of the card's UID (Should
857+ be 4 for MIFARE Classic)
858+ @param blockNumber The block number to authenticate. (0..63 for
859+ 1KB cards, and 0..255 for 4KB cards).
860+ @param keyNumber Which key type to use during authentication
861+ (0 = MIFARE_CMD_AUTH_A, 1 = MIFARE_CMD_AUTH_B)
862+ @param keyData Pointer to a byte array containing the 6 byte
863+ key value
864+
865+ @returns 1 if everything executed properly, 0 for an error
866+*/
867+/**************************************************************************/
868+uint8_t Adafruit_PN532::mifareclassic_AuthenticateBlock(uint8_t *uid,
869+ uint8_t uidLen,
870+ uint32_t blockNumber,
871+ uint8_t keyNumber,
872+ uint8_t *keyData) {
873+ // uint8_t len;
874+ uint8_t i;
875+
876+ // Hang on to the key and uid data
877+ memcpy(_key, keyData, 6);
878+ memcpy(_uid, uid, uidLen);
879+ _uidLen = uidLen;
880+
881+#ifdef MIFAREDEBUG
882+ PN532DEBUGPRINT.print(F("Trying to authenticate card "));
883+ Adafruit_PN532::PrintHex(_uid, _uidLen);
884+ PN532DEBUGPRINT.print(F("Using authentication KEY "));
885+ PN532DEBUGPRINT.print(keyNumber ? 'B' : 'A');
886+ PN532DEBUGPRINT.print(F(": "));
887+ Adafruit_PN532::PrintHex(_key, 6);
888+#endif
889+
890+ // Prepare the authentication command //
891+ pn532_packetbuffer[0] =
892+ PN532_COMMAND_INDATAEXCHANGE; /* Data Exchange Header */
893+ pn532_packetbuffer[1] = 1; /* Max card numbers */
894+ pn532_packetbuffer[2] = (keyNumber) ? MIFARE_CMD_AUTH_B : MIFARE_CMD_AUTH_A;
895+ pn532_packetbuffer[3] =
896+ blockNumber; /* Block Number (1K = 0..63, 4K = 0..255 */
897+ memcpy(pn532_packetbuffer + 4, _key, 6);
898+ for (i = 0; i < _uidLen; i++) {
899+ pn532_packetbuffer[10 + i] = _uid[i]; /* 4 byte card ID */
900+ }
901+
902+ if (!sendCommandCheckAck(pn532_packetbuffer, 10 + _uidLen))
903+ return 0;
904+
905+ // Read the response packet
906+ readdata(pn532_packetbuffer, 12);
907+
908+ // check if the response is valid and we are authenticated???
909+ // for an auth success it should be bytes 5-7: 0xD5 0x41 0x00
910+ // Mifare auth error is technically byte 7: 0x14 but anything other and 0x00
911+ // is not good
912+ if (pn532_packetbuffer[7] != 0x00) {
913+#ifdef PN532DEBUG
914+ PN532DEBUGPRINT.print(F("Authentification failed: "));
915+ Adafruit_PN532::PrintHexChar(pn532_packetbuffer, 12);
916+#endif
917+ return 0;
918+ }
919+
920+ return 1;
921+}
922+
923+/**************************************************************************/
924+/*!
925+ Tries to read an entire 16-byte data block at the specified block
926+ address.
927+
928+ @param blockNumber The block number to authenticate. (0..63 for
929+ 1KB cards, and 0..255 for 4KB cards).
930+ @param data Pointer to the byte array that will hold the
931+ retrieved data (if any)
932+
933+ @returns 1 if everything executed properly, 0 for an error
934+*/
935+/**************************************************************************/
936+uint8_t Adafruit_PN532::mifareclassic_ReadDataBlock(uint8_t blockNumber,
937+ uint8_t *data) {
938+#ifdef MIFAREDEBUG
939+ PN532DEBUGPRINT.print(F("Trying to read 16 bytes from block "));
940+ PN532DEBUGPRINT.println(blockNumber);
941+#endif
942+
943+ /* Prepare the command */
944+ pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
945+ pn532_packetbuffer[1] = 1; /* Card number */
946+ pn532_packetbuffer[2] = MIFARE_CMD_READ; /* Mifare Read command = 0x30 */
947+ pn532_packetbuffer[3] =
948+ blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */
949+
950+ /* Send the command */
951+ if (!sendCommandCheckAck(pn532_packetbuffer, 4)) {
952+#ifdef MIFAREDEBUG
953+ PN532DEBUGPRINT.println(F("Failed to receive ACK for read command"));
954+#endif
955+ return 0;
956+ }
957+
958+ /* Read the response packet */
959+ readdata(pn532_packetbuffer, 26);
960+
961+ /* If byte 8 isn't 0x00 we probably have an error */
962+ if (pn532_packetbuffer[7] != 0x00) {
963+#ifdef MIFAREDEBUG
964+ PN532DEBUGPRINT.println(F("Unexpected response"));
965+ Adafruit_PN532::PrintHexChar(pn532_packetbuffer, 26);
966+#endif
967+ return 0;
968+ }
969+
970+ /* Copy the 16 data bytes to the output buffer */
971+ /* Block content starts at byte 9 of a valid response */
972+ memcpy(data, pn532_packetbuffer + 8, 16);
973+
974+/* Display data for debug if requested */
975+#ifdef MIFAREDEBUG
976+ PN532DEBUGPRINT.print(F("Block "));
977+ PN532DEBUGPRINT.println(blockNumber);
978+ Adafruit_PN532::PrintHexChar(data, 16);
979+#endif
980+
981+ return 1;
982+}
983+
984+/**************************************************************************/
985+/*!
986+ Tries to write an entire 16-byte data block at the specified block
987+ address.
988+
989+ @param blockNumber The block number to authenticate. (0..63 for
990+ 1KB cards, and 0..255 for 4KB cards).
991+ @param data The byte array that contains the data to write.
992+
993+ @returns 1 if everything executed properly, 0 for an error
994+*/
995+/**************************************************************************/
996+uint8_t Adafruit_PN532::mifareclassic_WriteDataBlock(uint8_t blockNumber,
997+ uint8_t *data) {
998+#ifdef MIFAREDEBUG
999+ PN532DEBUGPRINT.print(F("Trying to write 16 bytes to block "));
1000+ PN532DEBUGPRINT.println(blockNumber);
1001+#endif
1002+
1003+ /* Prepare the first command */
1004+ pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
1005+ pn532_packetbuffer[1] = 1; /* Card number */
1006+ pn532_packetbuffer[2] = MIFARE_CMD_WRITE; /* Mifare Write command = 0xA0 */
1007+ pn532_packetbuffer[3] =
1008+ blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */
1009+ memcpy(pn532_packetbuffer + 4, data, 16); /* Data Payload */
1010+
1011+ /* Send the command */
1012+ if (!sendCommandCheckAck(pn532_packetbuffer, 20)) {
1013+#ifdef MIFAREDEBUG
1014+ PN532DEBUGPRINT.println(F("Failed to receive ACK for write command"));
1015+#endif
1016+ return 0;
1017+ }
1018+ delay(10);
1019+
1020+ /* Read the response packet */
1021+ readdata(pn532_packetbuffer, 26);
1022+
1023+ return 1;
1024+}
1025+
1026+/**************************************************************************/
1027+/*!
1028+ Formats a Mifare Classic card to store NDEF Records
1029+
1030+ @returns 1 if everything executed properly, 0 for an error
1031+*/
1032+/**************************************************************************/
1033+uint8_t Adafruit_PN532::mifareclassic_FormatNDEF(void) {
1034+ uint8_t sectorbuffer1[16] = {0x14, 0x01, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1,
1035+ 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1};
1036+ uint8_t sectorbuffer2[16] = {0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1,
1037+ 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1};
1038+ uint8_t sectorbuffer3[16] = {0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0x78, 0x77,
1039+ 0x88, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
1040+
1041+ // Note 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 must be used for key A
1042+ // for the MAD sector in NDEF records (sector 0)
1043+
1044+ // Write block 1 and 2 to the card
1045+ if (!(mifareclassic_WriteDataBlock(1, sectorbuffer1)))
1046+ return 0;
1047+ if (!(mifareclassic_WriteDataBlock(2, sectorbuffer2)))
1048+ return 0;
1049+ // Write key A and access rights card
1050+ if (!(mifareclassic_WriteDataBlock(3, sectorbuffer3)))
1051+ return 0;
1052+
1053+ // Seems that everything was OK (?!)
1054+ return 1;
1055+}
1056+
1057+/**************************************************************************/
1058+/*!
1059+ Writes an NDEF URI Record to the specified sector (1..15)
1060+
1061+ Note that this function assumes that the Mifare Classic card is
1062+ already formatted to work as an "NFC Forum Tag" and uses a MAD1
1063+ file system. You can use the NXP TagWriter app on Android to
1064+ properly format cards for this.
1065+
1066+ @param sectorNumber The sector that the URI record should be written
1067+ to (can be 1..15 for a 1K card)
1068+ @param uriIdentifier The uri identifier code (0 = none, 0x01 =
1069+ "http://www.", etc.)
1070+ @param url The uri text to write (max 38 characters).
1071+
1072+ @returns 1 if everything executed properly, 0 for an error
1073+*/
1074+/**************************************************************************/
1075+uint8_t Adafruit_PN532::mifareclassic_WriteNDEFURI(uint8_t sectorNumber,
1076+ uint8_t uriIdentifier,
1077+ const char *url) {
1078+ // Figure out how long the string is
1079+ uint8_t len = strlen(url);
1080+
1081+ // Make sure we're within a 1K limit for the sector number
1082+ if ((sectorNumber < 1) || (sectorNumber > 15))
1083+ return 0;
1084+
1085+ // Make sure the URI payload is between 1 and 38 chars
1086+ if ((len < 1) || (len > 38))
1087+ return 0;
1088+
1089+ // Note 0xD3 0xF7 0xD3 0xF7 0xD3 0xF7 must be used for key A
1090+ // in NDEF records
1091+
1092+ // Setup the sector buffer (w/pre-formatted TLV wrapper and NDEF message)
1093+ uint8_t sectorbuffer1[16] = {0x00,
1094+ 0x00,
1095+ 0x03,
1096+ (uint8_t)(len + 5),
1097+ 0xD1,
1098+ 0x01,
1099+ (uint8_t)(len + 1),
1100+ 0x55,
1101+ uriIdentifier,
1102+ 0x00,
1103+ 0x00,
1104+ 0x00,
1105+ 0x00,
1106+ 0x00,
1107+ 0x00,
1108+ 0x00};
1109+ uint8_t sectorbuffer2[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1110+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1111+ uint8_t sectorbuffer3[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1112+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1113+ uint8_t sectorbuffer4[16] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0x7F, 0x07,
1114+ 0x88, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
1115+ if (len <= 6) {
1116+ // Unlikely we'll get a url this short, but why not ...
1117+ memcpy(sectorbuffer1 + 9, url, len);
1118+ sectorbuffer1[len + 9] = 0xFE;
1119+ } else if (len == 7) {
1120+ // 0xFE needs to be wrapped around to next block
1121+ memcpy(sectorbuffer1 + 9, url, len);
1122+ sectorbuffer2[0] = 0xFE;
1123+ } else if ((len > 7) && (len <= 22)) {
1124+ // Url fits in two blocks
1125+ memcpy(sectorbuffer1 + 9, url, 7);
1126+ memcpy(sectorbuffer2, url + 7, len - 7);
1127+ sectorbuffer2[len - 7] = 0xFE;
1128+ } else if (len == 23) {
1129+ // 0xFE needs to be wrapped around to final block
1130+ memcpy(sectorbuffer1 + 9, url, 7);
1131+ memcpy(sectorbuffer2, url + 7, len - 7);
1132+ sectorbuffer3[0] = 0xFE;
1133+ } else {
1134+ // Url fits in three blocks
1135+ memcpy(sectorbuffer1 + 9, url, 7);
1136+ memcpy(sectorbuffer2, url + 7, 16);
1137+ memcpy(sectorbuffer3, url + 23, len - 24);
1138+ sectorbuffer3[len - 22] = 0xFE;
1139+ }
1140+
1141+ // Now write all three blocks back to the card
1142+ if (!(mifareclassic_WriteDataBlock(sectorNumber * 4, sectorbuffer1)))
1143+ return 0;
1144+ if (!(mifareclassic_WriteDataBlock((sectorNumber * 4) + 1, sectorbuffer2)))
1145+ return 0;
1146+ if (!(mifareclassic_WriteDataBlock((sectorNumber * 4) + 2, sectorbuffer3)))
1147+ return 0;
1148+ if (!(mifareclassic_WriteDataBlock((sectorNumber * 4) + 3, sectorbuffer4)))
1149+ return 0;
1150+
1151+ // Seems that everything was OK (?!)
1152+ return 1;
1153+}
1154+
1155+/***** Mifare Ultralight Functions ******/
1156+
1157+/**************************************************************************/
1158+/*!
1159+ @brief Tries to read an entire 4-byte page at the specified address.
1160+
1161+ @param page The page number (0..63 in most cases)
1162+ @param buffer Pointer to the byte array that will hold the
1163+ retrieved data (if any)
1164+ @return 1 on success, 0 on error.
1165+*/
1166+/**************************************************************************/
1167+uint8_t Adafruit_PN532::mifareultralight_ReadPage(uint8_t page,
1168+ uint8_t *buffer) {
1169+ if (page >= 64) {
1170+#ifdef MIFAREDEBUG
1171+ PN532DEBUGPRINT.println(F("Page value out of range"));
1172+#endif
1173+ return 0;
1174+ }
1175+
1176+#ifdef MIFAREDEBUG
1177+ PN532DEBUGPRINT.print(F("Reading page "));
1178+ PN532DEBUGPRINT.println(page);
1179+#endif
1180+
1181+ /* Prepare the command */
1182+ pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
1183+ pn532_packetbuffer[1] = 1; /* Card number */
1184+ pn532_packetbuffer[2] = MIFARE_CMD_READ; /* Mifare Read command = 0x30 */
1185+ pn532_packetbuffer[3] = page; /* Page Number (0..63 in most cases) */
1186+
1187+ /* Send the command */
1188+ if (!sendCommandCheckAck(pn532_packetbuffer, 4)) {
1189+#ifdef MIFAREDEBUG
1190+ PN532DEBUGPRINT.println(F("Failed to receive ACK for write command"));
1191+#endif
1192+ return 0;
1193+ }
1194+
1195+ /* Read the response packet */
1196+ readdata(pn532_packetbuffer, 26);
1197+#ifdef MIFAREDEBUG
1198+ PN532DEBUGPRINT.println(F("Received: "));
1199+ Adafruit_PN532::PrintHexChar(pn532_packetbuffer, 26);
1200+#endif
1201+
1202+ /* If byte 8 isn't 0x00 we probably have an error */
1203+ if (pn532_packetbuffer[7] == 0x00) {
1204+ /* Copy the 4 data bytes to the output buffer */
1205+ /* Block content starts at byte 9 of a valid response */
1206+ /* Note that the command actually reads 16 byte or 4 */
1207+ /* pages at a time ... we simply discard the last 12 */
1208+ /* bytes */
1209+ memcpy(buffer, pn532_packetbuffer + 8, 4);
1210+ } else {
1211+#ifdef MIFAREDEBUG
1212+ PN532DEBUGPRINT.println(F("Unexpected response reading block: "));
1213+ Adafruit_PN532::PrintHexChar(pn532_packetbuffer, 26);
1214+#endif
1215+ return 0;
1216+ }
1217+
1218+/* Display data for debug if requested */
1219+#ifdef MIFAREDEBUG
1220+ PN532DEBUGPRINT.print(F("Page "));
1221+ PN532DEBUGPRINT.print(page);
1222+ PN532DEBUGPRINT.println(F(":"));
1223+ Adafruit_PN532::PrintHexChar(buffer, 4);
1224+#endif
1225+
1226+ // Return OK signal
1227+ return 1;
1228+}
1229+
1230+/**************************************************************************/
1231+/*!
1232+ Tries to write an entire 4-byte page at the specified block
1233+ address.
1234+
1235+ @param page The page number to write. (0..63 for most cases)
1236+ @param data The byte array that contains the data to write.
1237+ Should be exactly 4 bytes long.
1238+
1239+ @returns 1 if everything executed properly, 0 for an error
1240+*/
1241+/**************************************************************************/
1242+uint8_t Adafruit_PN532::mifareultralight_WritePage(uint8_t page,
1243+ uint8_t *data) {
1244+
1245+ if (page >= 64) {
1246+#ifdef MIFAREDEBUG
1247+ PN532DEBUGPRINT.println(F("Page value out of range"));
1248+#endif
1249+ // Return Failed Signal
1250+ return 0;
1251+ }
1252+
1253+#ifdef MIFAREDEBUG
1254+ PN532DEBUGPRINT.print(F("Trying to write 4 byte page"));
1255+ PN532DEBUGPRINT.println(page);
1256+#endif
1257+
1258+ /* Prepare the first command */
1259+ pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
1260+ pn532_packetbuffer[1] = 1; /* Card number */
1261+ pn532_packetbuffer[2] =
1262+ MIFARE_ULTRALIGHT_CMD_WRITE; /* Mifare Ultralight Write command = 0xA2 */
1263+ pn532_packetbuffer[3] = page; /* Page Number (0..63 for most cases) */
1264+ memcpy(pn532_packetbuffer + 4, data, 4); /* Data Payload */
1265+
1266+ /* Send the command */
1267+ if (!sendCommandCheckAck(pn532_packetbuffer, 8)) {
1268+#ifdef MIFAREDEBUG
1269+ PN532DEBUGPRINT.println(F("Failed to receive ACK for write command"));
1270+#endif
1271+
1272+ // Return Failed Signal
1273+ return 0;
1274+ }
1275+ delay(10);
1276+
1277+ /* Read the response packet */
1278+ readdata(pn532_packetbuffer, 26);
1279+
1280+ // Return OK Signal
1281+ return 1;
1282+}
1283+
1284+/***** NTAG2xx Functions ******/
1285+
1286+/**************************************************************************/
1287+/*!
1288+ @brief Tries to read an entire 4-byte page at the specified address.
1289+
1290+ @param page The page number (0..63 in most cases)
1291+ @param buffer Pointer to the byte array that will hold the
1292+ retrieved data (if any)
1293+ @return 1 on success, 0 on error.
1294+*/
1295+/**************************************************************************/
1296+uint8_t Adafruit_PN532::ntag2xx_ReadPage(uint8_t page, uint8_t *buffer) {
1297+ // TAG Type PAGES USER START USER STOP
1298+ // -------- ----- ---------- ---------
1299+ // NTAG 203 42 4 39
1300+ // NTAG 213 45 4 39
1301+ // NTAG 215 135 4 129
1302+ // NTAG 216 231 4 225
1303+
1304+ if (page >= 231) {
1305+#ifdef MIFAREDEBUG
1306+ PN532DEBUGPRINT.println(F("Page value out of range"));
1307+#endif
1308+ return 0;
1309+ }
1310+
1311+#ifdef MIFAREDEBUG
1312+ PN532DEBUGPRINT.print(F("Reading page "));
1313+ PN532DEBUGPRINT.println(page);
1314+#endif
1315+
1316+ /* Prepare the command */
1317+ pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
1318+ pn532_packetbuffer[1] = 1; /* Card number */
1319+ pn532_packetbuffer[2] = MIFARE_CMD_READ; /* Mifare Read command = 0x30 */
1320+ pn532_packetbuffer[3] = page; /* Page Number (0..63 in most cases) */
1321+
1322+ /* Send the command */
1323+ if (!sendCommandCheckAck(pn532_packetbuffer, 4)) {
1324+#ifdef MIFAREDEBUG
1325+ PN532DEBUGPRINT.println(F("Failed to receive ACK for write command"));
1326+#endif
1327+ return 0;
1328+ }
1329+
1330+ /* Read the response packet */
1331+ readdata(pn532_packetbuffer, 26);
1332+#ifdef MIFAREDEBUG
1333+ PN532DEBUGPRINT.println(F("Received: "));
1334+ Adafruit_PN532::PrintHexChar(pn532_packetbuffer, 26);
1335+#endif
1336+
1337+ /* If byte 8 isn't 0x00 we probably have an error */
1338+ if (pn532_packetbuffer[7] == 0x00) {
1339+ /* Copy the 4 data bytes to the output buffer */
1340+ /* Block content starts at byte 9 of a valid response */
1341+ /* Note that the command actually reads 16 byte or 4 */
1342+ /* pages at a time ... we simply discard the last 12 */
1343+ /* bytes */
1344+ memcpy(buffer, pn532_packetbuffer + 8, 4);
1345+ } else {
1346+#ifdef MIFAREDEBUG
1347+ PN532DEBUGPRINT.println(F("Unexpected response reading block: "));
1348+ Adafruit_PN532::PrintHexChar(pn532_packetbuffer, 26);
1349+#endif
1350+ return 0;
1351+ }
1352+
1353+/* Display data for debug if requested */
1354+#ifdef MIFAREDEBUG
1355+ PN532DEBUGPRINT.print(F("Page "));
1356+ PN532DEBUGPRINT.print(page);
1357+ PN532DEBUGPRINT.println(F(":"));
1358+ Adafruit_PN532::PrintHexChar(buffer, 4);
1359+#endif
1360+
1361+ // Return OK signal
1362+ return 1;
1363+}
1364+
1365+/**************************************************************************/
1366+/*!
1367+ Tries to write an entire 4-byte page at the specified block
1368+ address.
1369+
1370+ @param page The page number to write. (0..63 for most cases)
1371+ @param data The byte array that contains the data to write.
1372+ Should be exactly 4 bytes long.
1373+
1374+ @returns 1 if everything executed properly, 0 for an error
1375+*/
1376+/**************************************************************************/
1377+uint8_t Adafruit_PN532::ntag2xx_WritePage(uint8_t page, uint8_t *data) {
1378+ // TAG Type PAGES USER START USER STOP
1379+ // -------- ----- ---------- ---------
1380+ // NTAG 203 42 4 39
1381+ // NTAG 213 45 4 39
1382+ // NTAG 215 135 4 129
1383+ // NTAG 216 231 4 225
1384+
1385+ if ((page < 4) || (page > 225)) {
1386+#ifdef MIFAREDEBUG
1387+ PN532DEBUGPRINT.println(F("Page value out of range"));
1388+#endif
1389+ // Return Failed Signal
1390+ return 0;
1391+ }
1392+
1393+#ifdef MIFAREDEBUG
1394+ PN532DEBUGPRINT.print(F("Trying to write 4 byte page"));
1395+ PN532DEBUGPRINT.println(page);
1396+#endif
1397+
1398+ /* Prepare the first command */
1399+ pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
1400+ pn532_packetbuffer[1] = 1; /* Card number */
1401+ pn532_packetbuffer[2] =
1402+ MIFARE_ULTRALIGHT_CMD_WRITE; /* Mifare Ultralight Write command = 0xA2 */
1403+ pn532_packetbuffer[3] = page; /* Page Number (0..63 for most cases) */
1404+ memcpy(pn532_packetbuffer + 4, data, 4); /* Data Payload */
1405+
1406+ /* Send the command */
1407+ if (!sendCommandCheckAck(pn532_packetbuffer, 8)) {
1408+#ifdef MIFAREDEBUG
1409+ PN532DEBUGPRINT.println(F("Failed to receive ACK for write command"));
1410+#endif
1411+
1412+ // Return Failed Signal
1413+ return 0;
1414+ }
1415+ delay(10);
1416+
1417+ /* Read the response packet */
1418+ readdata(pn532_packetbuffer, 26);
1419+
1420+ // Return OK Signal
1421+ return 1;
1422+}
1423+
1424+/**************************************************************************/
1425+/*!
1426+ Writes an NDEF URI Record starting at the specified page (4..nn)
1427+
1428+ Note that this function assumes that the NTAG2xx card is
1429+ already formatted to work as an "NFC Forum Tag".
1430+
1431+ @param uriIdentifier The uri identifier code (0 = none, 0x01 =
1432+ "http://www.", etc.)
1433+ @param url The uri text to write (null-terminated string).
1434+ @param dataLen The size of the data area for overflow checks.
1435+
1436+ @returns 1 if everything executed properly, 0 for an error
1437+*/
1438+/**************************************************************************/
1439+uint8_t Adafruit_PN532::ntag2xx_WriteNDEFURI(uint8_t uriIdentifier, char *url,
1440+ uint8_t dataLen) {
1441+ uint8_t pageBuffer[4] = {0, 0, 0, 0};
1442+
1443+ // Remove NDEF record overhead from the URI data (pageHeader below)
1444+ uint8_t wrapperSize = 12;
1445+
1446+ // Figure out how long the string is
1447+ uint8_t len = strlen(url);
1448+
1449+ // Make sure the URI payload will fit in dataLen (include 0xFE trailer)
1450+ if ((len < 1) || (len + 1 > (dataLen - wrapperSize)))
1451+ return 0;
1452+
1453+ // Setup the record header
1454+ // See NFCForum-TS-Type-2-Tag_1.1.pdf for details
1455+ uint8_t pageHeader[12] = {
1456+ /* NDEF Lock Control TLV (must be first and always present) */
1457+ 0x01, /* Tag Field (0x01 = Lock Control TLV) */
1458+ 0x03, /* Payload Length (always 3) */
1459+ 0xA0, /* The position inside the tag of the lock bytes (upper 4 = page
1460+ address, lower 4 = byte offset) */
1461+ 0x10, /* Size in bits of the lock area */
1462+ 0x44, /* Size in bytes of a page and the number of bytes each lock bit can
1463+ lock (4 bit + 4 bits) */
1464+ /* NDEF Message TLV - URI Record */
1465+ 0x03, /* Tag Field (0x03 = NDEF Message) */
1466+ (uint8_t)(len + 5), /* Payload Length (not including 0xFE trailer) */
1467+ 0xD1, /* NDEF Record Header (TNF=0x1:Well known record + SR + ME + MB) */
1468+ 0x01, /* Type Length for the record type indicator */
1469+ (uint8_t)(len + 1), /* Payload len */
1470+ 0x55, /* Record Type Indicator (0x55 or 'U' = URI Record) */
1471+ uriIdentifier /* URI Prefix (ex. 0x01 = "http://www.") */
1472+ };
1473+
1474+ // Write 12 byte header (three pages of data starting at page 4)
1475+ memcpy(pageBuffer, pageHeader, 4);
1476+ if (!(ntag2xx_WritePage(4, pageBuffer)))
1477+ return 0;
1478+ memcpy(pageBuffer, pageHeader + 4, 4);
1479+ if (!(ntag2xx_WritePage(5, pageBuffer)))
1480+ return 0;
1481+ memcpy(pageBuffer, pageHeader + 8, 4);
1482+ if (!(ntag2xx_WritePage(6, pageBuffer)))
1483+ return 0;
1484+
1485+ // Write URI (starting at page 7)
1486+ uint8_t currentPage = 7;
1487+ char *urlcopy = url;
1488+ while (len) {
1489+ if (len < 4) {
1490+ memset(pageBuffer, 0, 4);
1491+ memcpy(pageBuffer, urlcopy, len);
1492+ pageBuffer[len] = 0xFE; // NDEF record footer
1493+ if (!(ntag2xx_WritePage(currentPage, pageBuffer)))
1494+ return 0;
1495+ // DONE!
1496+ return 1;
1497+ } else if (len == 4) {
1498+ memcpy(pageBuffer, urlcopy, len);
1499+ if (!(ntag2xx_WritePage(currentPage, pageBuffer)))
1500+ return 0;
1501+ memset(pageBuffer, 0, 4);
1502+ pageBuffer[0] = 0xFE; // NDEF record footer
1503+ currentPage++;
1504+ if (!(ntag2xx_WritePage(currentPage, pageBuffer)))
1505+ return 0;
1506+ // DONE!
1507+ return 1;
1508+ } else {
1509+ // More than one page of data left
1510+ memcpy(pageBuffer, urlcopy, 4);
1511+ if (!(ntag2xx_WritePage(currentPage, pageBuffer)))
1512+ return 0;
1513+ currentPage++;
1514+ urlcopy += 4;
1515+ len -= 4;
1516+ }
1517+ }
1518+
1519+ // Seems that everything was OK (?!)
1520+ return 1;
1521+}
1522+
1523+/************** high level communication functions (handles both I2C and SPI) */
1524+
1525+/**************************************************************************/
1526+/*!
1527+ @brief Tries to read the SPI or I2C ACK signal
1528+*/
1529+/**************************************************************************/
1530+bool Adafruit_PN532::readack() {
1531+ uint8_t ackbuff[6];
1532+
1533+ if (spi_dev) {
1534+ uint8_t cmd = PN532_SPI_DATAREAD;
1535+ spi_dev->write_then_read(&cmd, 1, ackbuff, 6);
1536+ } else if (i2c_dev || ser_dev) {
1537+ readdata(ackbuff, 6);
1538+ }
1539+
1540+ return (0 == memcmp((char *)ackbuff, (char *)pn532ack, 6));
1541+}
1542+
1543+/**************************************************************************/
1544+/*!
1545+ @brief Return true if the PN532 is ready with a response.
1546+*/
1547+/**************************************************************************/
1548+bool Adafruit_PN532::isready() {
1549+ if (spi_dev) {
1550+ // SPI ready check via Status Request
1551+ uint8_t cmd = PN532_SPI_STATREAD;
1552+ uint8_t reply;
1553+ spi_dev->write_then_read(&cmd, 1, &reply, 1);
1554+ return reply == PN532_SPI_READY;
1555+ } else if (i2c_dev) {
1556+ // I2C ready check via reading RDY byte
1557+ uint8_t rdy[1];
1558+ i2c_dev->read(rdy, 1);
1559+ return rdy[0] == PN532_I2C_READY;
1560+ } else if (ser_dev) {
1561+ // Serial ready check based on non-zero read buffer
1562+ return (ser_dev->available() != 0);
1563+ } else if (_irq != -1) {
1564+ uint8_t x = digitalRead(_irq);
1565+ return x == 0;
1566+ }
1567+ return false;
1568+}
1569+
1570+/**************************************************************************/
1571+/*!
1572+ @brief Waits until the PN532 is ready.
1573+
1574+ @param timeout Timeout before giving up
1575+*/
1576+/**************************************************************************/
1577+bool Adafruit_PN532::waitready(uint16_t timeout) {
1578+ uint16_t timer = 0;
1579+ while (!isready()) {
1580+ if (timeout != 0) {
1581+ timer += 10;
1582+ if (timer > timeout) {
1583+#ifdef PN532DEBUG
1584+ PN532DEBUGPRINT.println("TIMEOUT!");
1585+#endif
1586+ return false;
1587+ }
1588+ }
1589+ delay(10);
1590+ }
1591+ return true;
1592+}
1593+
1594+/**************************************************************************/
1595+/*!
1596+ @brief Reads n bytes of data from the PN532 via SPI or I2C.
1597+
1598+ @param buff Pointer to the buffer where data will be written
1599+ @param n Number of bytes to be read
1600+*/
1601+/**************************************************************************/
1602+void Adafruit_PN532::readdata(uint8_t *buff, uint8_t n) {
1603+ if (spi_dev) {
1604+ // SPI read
1605+ uint8_t cmd = PN532_SPI_DATAREAD;
1606+ spi_dev->write_then_read(&cmd, 1, buff, n);
1607+ } else if (i2c_dev) {
1608+ // I2C read
1609+ uint8_t rbuff[n + 1]; // +1 for leading RDY byte
1610+ i2c_dev->read(rbuff, n + 1);
1611+ for (uint8_t i = 0; i < n; i++) {
1612+ buff[i] = rbuff[i + 1];
1613+ }
1614+ } else if (ser_dev) {
1615+ // Serial read
1616+ ser_dev->readBytes(buff, n);
1617+ }
1618+#ifdef PN532DEBUG
1619+ PN532DEBUGPRINT.print(F("Reading: "));
1620+ for (uint8_t i = 0; i < n; i++) {
1621+ PN532DEBUGPRINT.print(F(" 0x"));
1622+ PN532DEBUGPRINT.print(buff[i], HEX);
1623+ }
1624+ PN532DEBUGPRINT.println();
1625+#endif
1626+}
1627+
1628+/**************************************************************************/
1629+/*!
1630+ @brief set the PN532 as iso14443a Target behaving as a SmartCard
1631+ @return true on success, false otherwise.
1632+ @note Author: Salvador Mendoza (salmg.net) new functions:
1633+ -AsTarget
1634+ -getDataTarget
1635+ -setDataTarget
1636+*/
1637+/**************************************************************************/
1638+uint8_t Adafruit_PN532::AsTarget() {
1639+ pn532_packetbuffer[0] = 0x8C;
1640+ uint8_t target[] = {
1641+ 0x8C, // INIT AS TARGET
1642+ 0x00, // MODE -> BITFIELD
1643+ 0x08, 0x00, // SENS_RES - MIFARE PARAMS
1644+ 0xdc, 0x44, 0x20, // NFCID1T
1645+ 0x60, // SEL_RES
1646+ 0x01, 0xfe, // NFCID2T MUST START WITH 01fe - FELICA PARAMS - POL_RES
1647+ 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xc0,
1648+ 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, // PAD
1649+ 0xff, 0xff, // SYSTEM CODE
1650+ 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44,
1651+ 0x33, 0x22, 0x11, 0x01, 0x00, // NFCID3t MAX 47 BYTES ATR_RES
1652+ 0x0d, 0x52, 0x46, 0x49, 0x44, 0x49, 0x4f,
1653+ 0x74, 0x20, 0x50, 0x4e, 0x35, 0x33, 0x32 // HISTORICAL BYTES
1654+ };
1655+ if (!sendCommandCheckAck(target, sizeof(target)))
1656+ return false;
1657+
1658+ // read data packet
1659+ readdata(pn532_packetbuffer, 8);
1660+
1661+ int offset = 6;
1662+ return (pn532_packetbuffer[offset] == 0x15);
1663+}
1664+/**************************************************************************/
1665+/*!
1666+ @brief Retrieve response from the emulation mode
1667+
1668+ @param cmd = data
1669+ @param cmdlen = data length
1670+ @return true on success, false otherwise.
1671+*/
1672+/**************************************************************************/
1673+uint8_t Adafruit_PN532::getDataTarget(uint8_t *cmd, uint8_t *cmdlen) {
1674+ uint8_t length;
1675+ pn532_packetbuffer[0] = 0x86;
1676+ if (!sendCommandCheckAck(pn532_packetbuffer, 1, 1000)) {
1677+ PN532DEBUGPRINT.println(F("Error en ack"));
1678+ return false;
1679+ }
1680+
1681+ // read data packet
1682+ readdata(pn532_packetbuffer, 64);
1683+ length = pn532_packetbuffer[3] - 3;
1684+
1685+ // if (length > *responseLength) {// Bug, should avoid it in the reading
1686+ // target data
1687+ // length = *responseLength; // silent truncation...
1688+ //}
1689+
1690+ for (int i = 0; i < length; ++i) {
1691+ cmd[i] = pn532_packetbuffer[8 + i];
1692+ }
1693+ *cmdlen = length;
1694+ return true;
1695+}
1696+
1697+/**************************************************************************/
1698+/*!
1699+ @brief Set data in PN532 in the emulation mode
1700+
1701+ @param cmd = data
1702+ @param cmdlen = data length
1703+ @return true on success, false otherwise.
1704+*/
1705+/**************************************************************************/
1706+uint8_t Adafruit_PN532::setDataTarget(uint8_t *cmd, uint8_t cmdlen) {
1707+ uint8_t length;
1708+ // cmd1[0] = 0x8E; Must!
1709+
1710+ if (!sendCommandCheckAck(cmd, cmdlen))
1711+ return false;
1712+
1713+ // read data packet
1714+ readdata(pn532_packetbuffer, 8);
1715+ length = pn532_packetbuffer[3] - 3;
1716+ for (int i = 0; i < length; ++i) {
1717+ cmd[i] = pn532_packetbuffer[8 + i];
1718+ }
1719+ // cmdl = 0
1720+ cmdlen = length;
1721+
1722+ int offset = 6;
1723+ return (pn532_packetbuffer[offset] == 0x15);
1724+}
1725+
1726+/**************************************************************************/
1727+/*!
1728+ @brief Writes a command to the PN532, automatically inserting the
1729+ preamble and required frame details (checksum, len, etc.)
1730+
1731+ @param cmd Pointer to the command buffer
1732+ @param cmdlen Command length in bytes
1733+*/
1734+/**************************************************************************/
1735+void Adafruit_PN532::writecommand(uint8_t *cmd, uint8_t cmdlen) {
1736+ if (spi_dev) {
1737+ // SPI command write.
1738+ uint8_t checksum;
1739+ uint8_t packet[9 + cmdlen];
1740+ uint8_t *p = packet;
1741+ cmdlen++;
1742+
1743+ p[0] = PN532_SPI_DATAWRITE;
1744+ p++;
1745+
1746+ p[0] = PN532_PREAMBLE;
1747+ p++;
1748+ p[0] = PN532_STARTCODE1;
1749+ p++;
1750+ p[0] = PN532_STARTCODE2;
1751+ p++;
1752+ checksum = PN532_PREAMBLE + PN532_STARTCODE1 + PN532_STARTCODE2;
1753+
1754+ p[0] = cmdlen;
1755+ p++;
1756+ p[0] = ~cmdlen + 1;
1757+ p++;
1758+
1759+ p[0] = PN532_HOSTTOPN532;
1760+ p++;
1761+ checksum += PN532_HOSTTOPN532;
1762+
1763+ for (uint8_t i = 0; i < cmdlen - 1; i++) {
1764+ p[0] = cmd[i];
1765+ p++;
1766+ checksum += cmd[i];
1767+ }
1768+
1769+ p[0] = ~checksum;
1770+ p++;
1771+ p[0] = PN532_POSTAMBLE;
1772+ p++;
1773+
1774+#ifdef PN532DEBUG
1775+ Serial.print("Sending : ");
1776+ for (int i = 1; i < 8 + cmdlen; i++) {
1777+ Serial.print("0x");
1778+ Serial.print(packet[i], HEX);
1779+ Serial.print(", ");
1780+ }
1781+ Serial.println();
1782+#endif
1783+
1784+ spi_dev->write(packet, 8 + cmdlen);
1785+ } else if (i2c_dev || ser_dev) {
1786+ // I2C or Serial command write.
1787+ uint8_t packet[8 + cmdlen];
1788+ uint8_t LEN = cmdlen + 1;
1789+
1790+ packet[0] = PN532_PREAMBLE;
1791+ packet[1] = PN532_STARTCODE1;
1792+ packet[2] = PN532_STARTCODE2;
1793+ packet[3] = LEN;
1794+ packet[4] = ~LEN + 1;
1795+ packet[5] = PN532_HOSTTOPN532;
1796+ uint8_t sum = 0;
1797+ for (uint8_t i = 0; i < cmdlen; i++) {
1798+ packet[6 + i] = cmd[i];
1799+ sum += cmd[i];
1800+ }
1801+ packet[6 + cmdlen] = ~(PN532_HOSTTOPN532 + sum) + 1;
1802+ packet[7 + cmdlen] = PN532_POSTAMBLE;
1803+
1804+#ifdef PN532DEBUG
1805+ Serial.print("Sending : ");
1806+ for (int i = 1; i < 8 + cmdlen; i++) {
1807+ Serial.print("0x");
1808+ Serial.print(packet[i], HEX);
1809+ Serial.print(", ");
1810+ }
1811+ Serial.println();
1812+#endif
1813+
1814+ if (i2c_dev) {
1815+ i2c_dev->write(packet, 8 + cmdlen);
1816+ } else {
1817+ ser_dev->write(packet, 8 + cmdlen);
1818+ }
1819+ }
1820+}
A test/Adafruit_PN532.h View
@@ -0,0 +1,223 @@
1+/**************************************************************************/
2+/*!
3+ @file Adafruit_PN532.h
4+
5+ v2.0 - Refactored to add I2C support from Adafruit_NFCShield_I2C library.
6+
7+ v1.1 - Added full command list
8+ - Added 'verbose' mode flag to constructor to toggle debug output
9+ - Changed readPassiveTargetID() to return variable length values
10+*/
11+/**************************************************************************/
12+
13+#ifndef ADAFRUIT_PN532_H
14+#define ADAFRUIT_PN532_H
15+
16+#include "Arduino.h"
17+
18+#include <Adafruit_I2CDevice.h>
19+#include <Adafruit_SPIDevice.h>
20+
21+#define PN532_PREAMBLE (0x00) ///< Command sequence start, byte 1/3
22+#define PN532_STARTCODE1 (0x00) ///< Command sequence start, byte 2/3
23+#define PN532_STARTCODE2 (0xFF) ///< Command sequence start, byte 3/3
24+#define PN532_POSTAMBLE (0x00) ///< EOD
25+
26+#define PN532_HOSTTOPN532 (0xD4) ///< Host-to-PN532
27+#define PN532_PN532TOHOST (0xD5) ///< PN532-to-host
28+
29+// PN532 Commands
30+#define PN532_COMMAND_DIAGNOSE (0x00) ///< Diagnose
31+#define PN532_COMMAND_GETFIRMWAREVERSION (0x02) ///< Get firmware version
32+#define PN532_COMMAND_GETGENERALSTATUS (0x04) ///< Get general status
33+#define PN532_COMMAND_READREGISTER (0x06) ///< Read register
34+#define PN532_COMMAND_WRITEREGISTER (0x08) ///< Write register
35+#define PN532_COMMAND_READGPIO (0x0C) ///< Read GPIO
36+#define PN532_COMMAND_WRITEGPIO (0x0E) ///< Write GPIO
37+#define PN532_COMMAND_SETSERIALBAUDRATE (0x10) ///< Set serial baud rate
38+#define PN532_COMMAND_SETPARAMETERS (0x12) ///< Set parameters
39+#define PN532_COMMAND_SAMCONFIGURATION (0x14) ///< SAM configuration
40+#define PN532_COMMAND_POWERDOWN (0x16) ///< Power down
41+#define PN532_COMMAND_RFCONFIGURATION (0x32) ///< RF config
42+#define PN532_COMMAND_RFREGULATIONTEST (0x58) ///< RF regulation test
43+#define PN532_COMMAND_INJUMPFORDEP (0x56) ///< Jump for DEP
44+#define PN532_COMMAND_INJUMPFORPSL (0x46) ///< Jump for PSL
45+#define PN532_COMMAND_INLISTPASSIVETARGET (0x4A) ///< List passive target
46+#define PN532_COMMAND_INATR (0x50) ///< ATR
47+#define PN532_COMMAND_INPSL (0x4E) ///< PSL
48+#define PN532_COMMAND_INDATAEXCHANGE (0x40) ///< Data exchange
49+#define PN532_COMMAND_INCOMMUNICATETHRU (0x42) ///< Communicate through
50+#define PN532_COMMAND_INDESELECT (0x44) ///< Deselect
51+#define PN532_COMMAND_INRELEASE (0x52) ///< Release
52+#define PN532_COMMAND_INSELECT (0x54) ///< Select
53+#define PN532_COMMAND_INAUTOPOLL (0x60) ///< Auto poll
54+#define PN532_COMMAND_TGINITASTARGET (0x8C) ///< Init as target
55+#define PN532_COMMAND_TGSETGENERALBYTES (0x92) ///< Set general bytes
56+#define PN532_COMMAND_TGGETDATA (0x86) ///< Get data
57+#define PN532_COMMAND_TGSETDATA (0x8E) ///< Set data
58+#define PN532_COMMAND_TGSETMETADATA (0x94) ///< Set metadata
59+#define PN532_COMMAND_TGGETINITIATORCOMMAND (0x88) ///< Get initiator command
60+#define PN532_COMMAND_TGRESPONSETOINITIATOR (0x90) ///< Response to initiator
61+#define PN532_COMMAND_TGGETTARGETSTATUS (0x8A) ///< Get target status
62+
63+#define PN532_RESPONSE_INDATAEXCHANGE (0x41) ///< Data exchange
64+#define PN532_RESPONSE_INLISTPASSIVETARGET (0x4B) ///< List passive target
65+
66+#define PN532_WAKEUP (0x55) ///< Wake
67+
68+#define PN532_SPI_STATREAD (0x02) ///< Stat read
69+#define PN532_SPI_DATAWRITE (0x01) ///< Data write
70+#define PN532_SPI_DATAREAD (0x03) ///< Data read
71+#define PN532_SPI_READY (0x01) ///< Ready
72+
73+// My fucking clone board for some goddamn reason uses the address 0x28
74+//#define PN532_I2C_ADDRESS (0x48 >> 1) ///< Default I2C address
75+#define PN532_I2C_ADDRESS (0x28)
76+#define PN532_I2C_READBIT (0x01) ///< Read bit
77+#define PN532_I2C_BUSY (0x00) ///< Busy
78+#define PN532_I2C_READY (0x01) ///< Ready
79+#define PN532_I2C_READYTIMEOUT (20) ///< Ready timeout
80+
81+#define PN532_MIFARE_ISO14443A (0x00) ///< MiFare
82+
83+// Mifare Commands
84+#define MIFARE_CMD_AUTH_A (0x60) ///< Auth A
85+#define MIFARE_CMD_AUTH_B (0x61) ///< Auth B
86+#define MIFARE_CMD_READ (0x30) ///< Read
87+#define MIFARE_CMD_WRITE (0xA0) ///< Write
88+#define MIFARE_CMD_TRANSFER (0xB0) ///< Transfer
89+#define MIFARE_CMD_DECREMENT (0xC0) ///< Decrement
90+#define MIFARE_CMD_INCREMENT (0xC1) ///< Increment
91+#define MIFARE_CMD_STORE (0xC2) ///< Store
92+#define MIFARE_ULTRALIGHT_CMD_WRITE (0xA2) ///< Write (MiFare Ultralight)
93+
94+// Prefixes for NDEF Records (to identify record type)
95+#define NDEF_URIPREFIX_NONE (0x00) ///< No prefix
96+#define NDEF_URIPREFIX_HTTP_WWWDOT (0x01) ///< HTTP www. prefix
97+#define NDEF_URIPREFIX_HTTPS_WWWDOT (0x02) ///< HTTPS www. prefix
98+#define NDEF_URIPREFIX_HTTP (0x03) ///< HTTP prefix
99+#define NDEF_URIPREFIX_HTTPS (0x04) ///< HTTPS prefix
100+#define NDEF_URIPREFIX_TEL (0x05) ///< Tel prefix
101+#define NDEF_URIPREFIX_MAILTO (0x06) ///< Mailto prefix
102+#define NDEF_URIPREFIX_FTP_ANONAT (0x07) ///< FTP
103+#define NDEF_URIPREFIX_FTP_FTPDOT (0x08) ///< FTP dot
104+#define NDEF_URIPREFIX_FTPS (0x09) ///< FTPS
105+#define NDEF_URIPREFIX_SFTP (0x0A) ///< SFTP
106+#define NDEF_URIPREFIX_SMB (0x0B) ///< SMB
107+#define NDEF_URIPREFIX_NFS (0x0C) ///< NFS
108+#define NDEF_URIPREFIX_FTP (0x0D) ///< FTP
109+#define NDEF_URIPREFIX_DAV (0x0E) ///< DAV
110+#define NDEF_URIPREFIX_NEWS (0x0F) ///< NEWS
111+#define NDEF_URIPREFIX_TELNET (0x10) ///< Telnet prefix
112+#define NDEF_URIPREFIX_IMAP (0x11) ///< IMAP prefix
113+#define NDEF_URIPREFIX_RTSP (0x12) ///< RTSP
114+#define NDEF_URIPREFIX_URN (0x13) ///< URN
115+#define NDEF_URIPREFIX_POP (0x14) ///< POP
116+#define NDEF_URIPREFIX_SIP (0x15) ///< SIP
117+#define NDEF_URIPREFIX_SIPS (0x16) ///< SIPS
118+#define NDEF_URIPREFIX_TFTP (0x17) ///< TFPT
119+#define NDEF_URIPREFIX_BTSPP (0x18) ///< BTSPP
120+#define NDEF_URIPREFIX_BTL2CAP (0x19) ///< BTL2CAP
121+#define NDEF_URIPREFIX_BTGOEP (0x1A) ///< BTGOEP
122+#define NDEF_URIPREFIX_TCPOBEX (0x1B) ///< TCPOBEX
123+#define NDEF_URIPREFIX_IRDAOBEX (0x1C) ///< IRDAOBEX
124+#define NDEF_URIPREFIX_FILE (0x1D) ///< File
125+#define NDEF_URIPREFIX_URN_EPC_ID (0x1E) ///< URN EPC ID
126+#define NDEF_URIPREFIX_URN_EPC_TAG (0x1F) ///< URN EPC tag
127+#define NDEF_URIPREFIX_URN_EPC_PAT (0x20) ///< URN EPC pat
128+#define NDEF_URIPREFIX_URN_EPC_RAW (0x21) ///< URN EPC raw
129+#define NDEF_URIPREFIX_URN_EPC (0x22) ///< URN EPC
130+#define NDEF_URIPREFIX_URN_NFC (0x23) ///< URN NFC
131+
132+#define PN532_GPIO_VALIDATIONBIT (0x80) ///< GPIO validation bit
133+#define PN532_GPIO_P30 (0) ///< GPIO 30
134+#define PN532_GPIO_P31 (1) ///< GPIO 31
135+#define PN532_GPIO_P32 (2) ///< GPIO 32
136+#define PN532_GPIO_P33 (3) ///< GPIO 33
137+#define PN532_GPIO_P34 (4) ///< GPIO 34
138+#define PN532_GPIO_P35 (5) ///< GPIO 35
139+
140+/**
141+ * @brief Class for working with Adafruit PN532 NFC/RFID breakout boards.
142+ */
143+class Adafruit_PN532 {
144+public:
145+ Adafruit_PN532(uint8_t clk, uint8_t miso, uint8_t mosi,
146+ uint8_t ss); // Software SPI
147+ Adafruit_PN532(uint8_t ss, SPIClass *theSPI = &SPI); // Hardware SPI
148+ Adafruit_PN532(uint8_t irq, uint8_t reset,
149+ TwoWire *theWire = &Wire); // Hardware I2C
150+ Adafruit_PN532(uint8_t reset, HardwareSerial *theSer); // Hardware UART
151+ bool begin(void);
152+
153+ void reset(void);
154+ void wakeup(void);
155+
156+ // Generic PN532 functions
157+ bool SAMConfig(void);
158+ uint32_t getFirmwareVersion(void);
159+ bool sendCommandCheckAck(uint8_t *cmd, uint8_t cmdlen,
160+ uint16_t timeout = 100);
161+ bool writeGPIO(uint8_t pinstate);
162+ uint8_t readGPIO(void);
163+ bool setPassiveActivationRetries(uint8_t maxRetries);
164+
165+ // ISO14443A functions
166+ bool readPassiveTargetID(
167+ uint8_t cardbaudrate, uint8_t *uid, uint8_t *uidLength,
168+ uint16_t timeout = 0); // timeout 0 means no timeout - will block forever.
169+ bool startPassiveTargetIDDetection(uint8_t cardbaudrate);
170+ bool readDetectedPassiveTargetID(uint8_t *uid, uint8_t *uidLength);
171+ bool inDataExchange(uint8_t *send, uint8_t sendLength, uint8_t *response,
172+ uint8_t *responseLength);
173+ bool inListPassiveTarget();
174+ uint8_t AsTarget();
175+ uint8_t getDataTarget(uint8_t *cmd, uint8_t *cmdlen);
176+ uint8_t setDataTarget(uint8_t *cmd, uint8_t cmdlen);
177+
178+ // Mifare Classic functions
179+ bool mifareclassic_IsFirstBlock(uint32_t uiBlock);
180+ bool mifareclassic_IsTrailerBlock(uint32_t uiBlock);
181+ uint8_t mifareclassic_AuthenticateBlock(uint8_t *uid, uint8_t uidLen,
182+ uint32_t blockNumber,
183+ uint8_t keyNumber, uint8_t *keyData);
184+ uint8_t mifareclassic_ReadDataBlock(uint8_t blockNumber, uint8_t *data);
185+ uint8_t mifareclassic_WriteDataBlock(uint8_t blockNumber, uint8_t *data);
186+ uint8_t mifareclassic_FormatNDEF(void);
187+ uint8_t mifareclassic_WriteNDEFURI(uint8_t sectorNumber,
188+ uint8_t uriIdentifier, const char *url);
189+
190+ // Mifare Ultralight functions
191+ uint8_t mifareultralight_ReadPage(uint8_t page, uint8_t *buffer);
192+ uint8_t mifareultralight_WritePage(uint8_t page, uint8_t *data);
193+
194+ // NTAG2xx functions
195+ uint8_t ntag2xx_ReadPage(uint8_t page, uint8_t *buffer);
196+ uint8_t ntag2xx_WritePage(uint8_t page, uint8_t *data);
197+ uint8_t ntag2xx_WriteNDEFURI(uint8_t uriIdentifier, char *url,
198+ uint8_t dataLen);
199+
200+ // Help functions to display formatted text
201+ static void PrintHex(const byte *data, const uint32_t numBytes);
202+ static void PrintHexChar(const byte *pbtData, const uint32_t numBytes);
203+
204+private:
205+ int8_t _irq = -1, _reset = -1, _cs = -1;
206+ int8_t _uid[7]; // ISO14443A uid
207+ int8_t _uidLen; // uid len
208+ int8_t _key[6]; // Mifare Classic key
209+ int8_t _inListedTag; // Tg number of inlisted tag.
210+
211+ // Low level communication functions that handle both SPI and I2C.
212+ void readdata(uint8_t *buff, uint8_t n);
213+ void writecommand(uint8_t *cmd, uint8_t cmdlen);
214+ bool isready();
215+ bool waitready(uint16_t timeout);
216+ bool readack();
217+
218+ Adafruit_SPIDevice *spi_dev = NULL;
219+ Adafruit_I2CDevice *i2c_dev = NULL;
220+ HardwareSerial *ser_dev = NULL;
221+};
222+
223+#endif
A test/ELECHOUSE_CC1101_SRC_DRV.cpp View
@@ -0,0 +1,1309 @@
1+/*
2+ ELECHOUSE_CC1101.cpp - CC1101 module library
3+ Copyright (c) 2010 Michael.
4+ Author: Michael, <www.elechouse.com>
5+ Version: November 12, 2010
6+
7+ This library is designed to use CC1101/CC1100 module on Arduino platform.
8+ CC1101/CC1100 module is an useful wireless module.Using the functions of the
9+ library, you can easily send and receive data by the CC1101/CC1100 module.
10+ Just have fun!
11+ For the details, please refer to the datasheet of CC1100/CC1101.
12+----------------------------------------------------------------------------------------------------------------
13+cc1101 Driver for RC Switch. Mod by Little Satan. With permission to modify and publish Wilson Shen (ELECHOUSE).
14+----------------------------------------------------------------------------------------------------------------
15+*/
16+#include <SPI.h>
17+#include "ELECHOUSE_CC1101_SRC_DRV.h"
18+#include <Arduino.h>
19+
20+/****************************************************************/
21+#define WRITE_BURST 0x40 //write burst
22+#define READ_SINGLE 0x80 //read single
23+#define READ_BURST 0xC0 //read burst
24+#define BYTES_IN_RXFIFO 0x7F //byte number in RXfifo
25+#define max_modul 6
26+
27+SPIClass CCSPI(HSPI);
28+
29+byte modulation = 2;
30+byte frend0;
31+byte chan = 0;
32+int pa = 12;
33+byte last_pa;
34+byte SCK_PIN;
35+byte MISO_PIN;
36+byte MOSI_PIN;
37+byte SS_PIN;
38+byte GDO0;
39+byte GDO2;
40+byte SCK_PIN_M[max_modul];
41+byte MISO_PIN_M[max_modul];
42+byte MOSI_PIN_M[max_modul];
43+byte SS_PIN_M[max_modul];
44+byte GDO0_M[max_modul];
45+byte GDO2_M[max_modul];
46+byte gdo_set=0;
47+bool spi = 0;
48+bool ccmode = 0;
49+float MHz = 433.92;
50+byte m4RxBw = 0;
51+byte m4DaRa;
52+byte m2DCOFF;
53+byte m2MODFM;
54+byte m2MANCH;
55+byte m2SYNCM;
56+byte m1FEC;
57+byte m1PRE;
58+byte m1CHSP;
59+byte pc1PQT;
60+byte pc1CRC_AF;
61+byte pc1APP_ST;
62+byte pc1ADRCHK;
63+byte pc0WDATA;
64+byte pc0PktForm;
65+byte pc0CRC_EN;
66+byte pc0LenConf;
67+byte trxstate = 0;
68+byte clb1[2]= {24,28};
69+byte clb2[2]= {31,38};
70+byte clb3[2]= {65,76};
71+byte clb4[2]= {77,79};
72+
73+/****************************************************************/
74+uint8_t PA_TABLE[8] {0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00};
75+// -30 -20 -15 -10 0 5 7 10
76+uint8_t PA_TABLE_315[8] {0x12,0x0D,0x1C,0x34,0x51,0x85,0xCB,0xC2,}; //300 - 348
77+uint8_t PA_TABLE_433[8] {0x12,0x0E,0x1D,0x34,0x60,0x84,0xC8,0xC0,}; //387 - 464
78+// -30 -20 -15 -10 -6 0 5 7 10 12
79+uint8_t PA_TABLE_868[10] {0x03,0x17,0x1D,0x26,0x37,0x50,0x86,0xCD,0xC5,0xC0,}; //779 - 899.99
80+// -30 -20 -15 -10 -6 0 5 7 10 11
81+uint8_t PA_TABLE_915[10] {0x03,0x0E,0x1E,0x27,0x38,0x8E,0x84,0xCC,0xC3,0xC0,}; //900 - 928
82+/****************************************************************
83+*FUNCTION NAME:SpiStart
84+*FUNCTION :spi communication start
85+*INPUT :none
86+*OUTPUT :none
87+****************************************************************/
88+void ELECHOUSE_CC1101::SpiStart(void)
89+{
90+ // initialize the SPI pins
91+ pinMode(SCK_PIN, OUTPUT);
92+ pinMode(MOSI_PIN, OUTPUT);
93+ pinMode(MISO_PIN, INPUT);
94+ pinMode(SS_PIN, OUTPUT);
95+
96+ // enable SPI
97+ #ifdef ESP32
98+ CCSPI.begin(SCK_PIN, MISO_PIN, MOSI_PIN, SS_PIN);
99+ #else
100+ CCSPI.begin();
101+ #endif
102+}
103+/****************************************************************
104+*FUNCTION NAME:SpiEnd
105+*FUNCTION :spi communication disable
106+*INPUT :none
107+*OUTPUT :none
108+****************************************************************/
109+void ELECHOUSE_CC1101::SpiEnd(void)
110+{
111+ // disable SPI
112+ CCSPI.endTransaction();
113+ CCSPI.end();
114+}
115+/****************************************************************
116+*FUNCTION NAME: GDO_Set()
117+*FUNCTION : set GDO0,GDO2 pin for serial pinmode.
118+*INPUT : none
119+*OUTPUT : none
120+****************************************************************/
121+void ELECHOUSE_CC1101::GDO_Set (void)
122+{
123+ pinMode(GDO0, OUTPUT);
124+ pinMode(GDO2, INPUT);
125+}
126+/****************************************************************
127+*FUNCTION NAME: GDO_Set()
128+*FUNCTION : set GDO0 for internal transmission mode.
129+*INPUT : none
130+*OUTPUT : none
131+****************************************************************/
132+void ELECHOUSE_CC1101::GDO0_Set (void)
133+{
134+ pinMode(GDO0, INPUT);
135+}
136+/****************************************************************
137+*FUNCTION NAME:Reset
138+*FUNCTION :CC1101 reset //details refer datasheet of CC1101/CC1100//
139+*INPUT :none
140+*OUTPUT :none
141+****************************************************************/
142+void ELECHOUSE_CC1101::Reset (void)
143+{
144+ digitalWrite(SS_PIN, LOW);
145+ delay(1);
146+ digitalWrite(SS_PIN, HIGH);
147+ delay(1);
148+ digitalWrite(SS_PIN, LOW);
149+ while(digitalRead(MISO_PIN));
150+ CCSPI.transfer(CC1101_SRES);
151+ while(digitalRead(MISO_PIN));
152+ digitalWrite(SS_PIN, HIGH);
153+}
154+/****************************************************************
155+*FUNCTION NAME:Init
156+*FUNCTION :CC1101 initialization
157+*INPUT :none
158+*OUTPUT :none
159+****************************************************************/
160+void ELECHOUSE_CC1101::Init(void)
161+{
162+ setSpi();
163+ SpiStart(); //spi initialization
164+ digitalWrite(SS_PIN, HIGH);
165+ digitalWrite(SCK_PIN, HIGH);
166+ digitalWrite(MOSI_PIN, LOW);
167+ Reset(); //CC1101 reset
168+ RegConfigSettings(); //CC1101 register config
169+ SpiEnd();
170+}
171+/****************************************************************
172+*FUNCTION NAME:SpiWriteReg
173+*FUNCTION :CC1101 write data to register
174+*INPUT :addr: register address; value: register value
175+*OUTPUT :none
176+****************************************************************/
177+void ELECHOUSE_CC1101::SpiWriteReg(byte addr, byte value)
178+{
179+ SpiStart();
180+ digitalWrite(SS_PIN, LOW);
181+ while(digitalRead(MISO_PIN));
182+ CCSPI.transfer(addr);
183+ CCSPI.transfer(value);
184+ digitalWrite(SS_PIN, HIGH);
185+ SpiEnd();
186+}
187+/****************************************************************
188+*FUNCTION NAME:SpiWriteBurstReg
189+*FUNCTION :CC1101 write burst data to register
190+*INPUT :addr: register address; buffer:register value array; num:number to write
191+*OUTPUT :none
192+****************************************************************/
193+void ELECHOUSE_CC1101::SpiWriteBurstReg(byte addr, byte *buffer, byte num)
194+{
195+ byte i, temp;
196+ SpiStart();
197+ temp = addr | WRITE_BURST;
198+ digitalWrite(SS_PIN, LOW);
199+ while(digitalRead(MISO_PIN));
200+ CCSPI.transfer(temp);
201+ for (i = 0; i < num; i++)
202+ {
203+ CCSPI.transfer(buffer[i]);
204+ }
205+ digitalWrite(SS_PIN, HIGH);
206+ SpiEnd();
207+}
208+/****************************************************************
209+*FUNCTION NAME:SpiStrobe
210+*FUNCTION :CC1101 Strobe
211+*INPUT :strobe: command; //refer define in CC1101.h//
212+*OUTPUT :none
213+****************************************************************/
214+void ELECHOUSE_CC1101::SpiStrobe(byte strobe)
215+{
216+ SpiStart();
217+ digitalWrite(SS_PIN, LOW);
218+ while(digitalRead(MISO_PIN));
219+ CCSPI.transfer(strobe);
220+ digitalWrite(SS_PIN, HIGH);
221+ SpiEnd();
222+}
223+/****************************************************************
224+*FUNCTION NAME:SpiReadReg
225+*FUNCTION :CC1101 read data from register
226+*INPUT :addr: register address
227+*OUTPUT :register value
228+****************************************************************/
229+byte ELECHOUSE_CC1101::SpiReadReg(byte addr)
230+{
231+ byte temp, value;
232+ SpiStart();
233+ temp = addr| READ_SINGLE;
234+ digitalWrite(SS_PIN, LOW);
235+ while(digitalRead(MISO_PIN));
236+ CCSPI.transfer(temp);
237+ value=CCSPI.transfer(0);
238+ digitalWrite(SS_PIN, HIGH);
239+ SpiEnd();
240+ return value;
241+}
242+
243+/****************************************************************
244+*FUNCTION NAME:SpiReadBurstReg
245+*FUNCTION :CC1101 read burst data from register
246+*INPUT :addr: register address; buffer:array to store register value; num: number to read
247+*OUTPUT :none
248+****************************************************************/
249+void ELECHOUSE_CC1101::SpiReadBurstReg(byte addr, byte *buffer, byte num)
250+{
251+ byte i,temp;
252+ SpiStart();
253+ temp = addr | READ_BURST;
254+ digitalWrite(SS_PIN, LOW);
255+ while(digitalRead(MISO_PIN));
256+ CCSPI.transfer(temp);
257+ for(i=0;i<num;i++)
258+ {
259+ buffer[i]=CCSPI.transfer(0);
260+ }
261+ digitalWrite(SS_PIN, HIGH);
262+ SpiEnd();
263+}
264+
265+/****************************************************************
266+*FUNCTION NAME:SpiReadStatus
267+*FUNCTION :CC1101 read status register
268+*INPUT :addr: register address
269+*OUTPUT :status value
270+****************************************************************/
271+byte ELECHOUSE_CC1101::SpiReadStatus(byte addr)
272+{
273+ byte value,temp;
274+ SpiStart();
275+ temp = addr | READ_BURST;
276+ digitalWrite(SS_PIN, LOW);
277+ while(digitalRead(MISO_PIN));
278+ CCSPI.transfer(temp);
279+ value=CCSPI.transfer(0);
280+ digitalWrite(SS_PIN, HIGH);
281+ SpiEnd();
282+ return value;
283+}
284+/****************************************************************
285+*FUNCTION NAME:SPI pin Settings
286+*FUNCTION :Set Spi pins
287+*INPUT :none
288+*OUTPUT :none
289+****************************************************************/
290+void ELECHOUSE_CC1101::setSpi(void){
291+ if (spi == 0){
292+ #if defined __AVR_ATmega168__ || defined __AVR_ATmega328P__
293+ SCK_PIN = 13; MISO_PIN = 12; MOSI_PIN = 11; SS_PIN = 10;
294+ #elif defined __AVR_ATmega1280__ || defined __AVR_ATmega2560__
295+ SCK_PIN = 52; MISO_PIN = 50; MOSI_PIN = 51; SS_PIN = 53;
296+ #elif ESP8266
297+ SCK_PIN = 14; MISO_PIN = 12; MOSI_PIN = 13; SS_PIN = 15;
298+ #elif ESP32
299+ SCK_PIN = 18; MISO_PIN = 19; MOSI_PIN = 23; SS_PIN = 5;
300+ #else
301+ SCK_PIN = 13; MISO_PIN = 12; MOSI_PIN = 11; SS_PIN = 10;
302+ #endif
303+}
304+}
305+/****************************************************************
306+*FUNCTION NAME:COSTUM SPI
307+*FUNCTION :set costum spi pins.
308+*INPUT :none
309+*OUTPUT :none
310+****************************************************************/
311+void ELECHOUSE_CC1101::setSpiPin(byte sck, byte miso, byte mosi, byte ss){
312+ spi = 1;
313+ SCK_PIN = sck;
314+ MISO_PIN = miso;
315+ MOSI_PIN = mosi;
316+ SS_PIN = ss;
317+}
318+/****************************************************************
319+*FUNCTION NAME:COSTUM SPI
320+*FUNCTION :set costum spi pins.
321+*INPUT :none
322+*OUTPUT :none
323+****************************************************************/
324+void ELECHOUSE_CC1101::addSpiPin(byte sck, byte miso, byte mosi, byte ss, byte modul){
325+ spi = 1;
326+ SCK_PIN_M[modul] = sck;
327+ MISO_PIN_M[modul] = miso;
328+ MOSI_PIN_M[modul] = mosi;
329+ SS_PIN_M[modul] = ss;
330+}
331+/****************************************************************
332+*FUNCTION NAME:GDO Pin settings
333+*FUNCTION :set GDO Pins
334+*INPUT :none
335+*OUTPUT :none
336+****************************************************************/
337+void ELECHOUSE_CC1101::setGDO(byte gdo0, byte gdo2){
338+GDO0 = gdo0;
339+GDO2 = gdo2;
340+GDO_Set();
341+}
342+/****************************************************************
343+*FUNCTION NAME:GDO0 Pin setting
344+*FUNCTION :set GDO0 Pin
345+*INPUT :none
346+*OUTPUT :none
347+****************************************************************/
348+void ELECHOUSE_CC1101::setGDO0(byte gdo0){
349+GDO0 = gdo0;
350+GDO0_Set();
351+}
352+/****************************************************************
353+*FUNCTION NAME:GDO Pin settings
354+*FUNCTION :add GDO Pins
355+*INPUT :none
356+*OUTPUT :none
357+****************************************************************/
358+void ELECHOUSE_CC1101::addGDO(byte gdo0, byte gdo2, byte modul){
359+GDO0_M[modul] = gdo0;
360+GDO2_M[modul] = gdo2;
361+gdo_set=2;
362+GDO_Set();
363+}
364+/****************************************************************
365+*FUNCTION NAME:add GDO0 Pin
366+*FUNCTION :add GDO0 Pin
367+*INPUT :none
368+*OUTPUT :none
369+****************************************************************/
370+void ELECHOUSE_CC1101::addGDO0(byte gdo0, byte modul){
371+GDO0_M[modul] = gdo0;
372+gdo_set=1;
373+GDO0_Set();
374+}
375+/****************************************************************
376+*FUNCTION NAME:set Modul
377+*FUNCTION :change modul
378+*INPUT :none
379+*OUTPUT :none
380+****************************************************************/
381+void ELECHOUSE_CC1101::setModul(byte modul){
382+ SCK_PIN = SCK_PIN_M[modul];
383+ MISO_PIN = MISO_PIN_M[modul];
384+ MOSI_PIN = MOSI_PIN_M[modul];
385+ SS_PIN = SS_PIN_M[modul];
386+ if (gdo_set==1){
387+ GDO0 = GDO0_M[modul];
388+ }
389+ else if (gdo_set==2){
390+ GDO0 = GDO0_M[modul];
391+ GDO2 = GDO2_M[modul];
392+ }
393+}
394+/****************************************************************
395+*FUNCTION NAME:CCMode
396+*FUNCTION :Format of RX and TX data
397+*INPUT :none
398+*OUTPUT :none
399+****************************************************************/
400+void ELECHOUSE_CC1101::setCCMode(bool s){
401+ccmode = s;
402+if (ccmode == 1){
403+SpiWriteReg(CC1101_IOCFG2, 0x0B);
404+SpiWriteReg(CC1101_IOCFG0, 0x06);
405+SpiWriteReg(CC1101_PKTCTRL0, 0x05);
406+SpiWriteReg(CC1101_MDMCFG3, 0xF8);
407+SpiWriteReg(CC1101_MDMCFG4,11+m4RxBw);
408+}else{
409+SpiWriteReg(CC1101_IOCFG2, 0x0D);
410+SpiWriteReg(CC1101_IOCFG0, 0x0D);
411+SpiWriteReg(CC1101_PKTCTRL0, 0x32);
412+SpiWriteReg(CC1101_MDMCFG3, 0x93);
413+SpiWriteReg(CC1101_MDMCFG4, 7+m4RxBw);
414+}
415+setModulation(modulation);
416+}
417+/****************************************************************
418+*FUNCTION NAME:Modulation
419+*FUNCTION :set CC1101 Modulation
420+*INPUT :none
421+*OUTPUT :none
422+****************************************************************/
423+void ELECHOUSE_CC1101::setModulation(byte m){
424+if (m>4){m=4;}
425+modulation = m;
426+Split_MDMCFG2();
427+switch (m)
428+{
429+case 0: m2MODFM=0x00; frend0=0x10; break; // 2-FSK
430+case 1: m2MODFM=0x10; frend0=0x10; break; // GFSK
431+case 2: m2MODFM=0x30; frend0=0x11; break; // ASK
432+case 3: m2MODFM=0x40; frend0=0x10; break; // 4-FSK
433+case 4: m2MODFM=0x70; frend0=0x10; break; // MSK
434+}
435+SpiWriteReg(CC1101_MDMCFG2, m2DCOFF+m2MODFM+m2MANCH+m2SYNCM);
436+SpiWriteReg(CC1101_FREND0, frend0);
437+setPA(pa);
438+}
439+/****************************************************************
440+*FUNCTION NAME:PA Power
441+*FUNCTION :set CC1101 PA Power
442+*INPUT :none
443+*OUTPUT :none
444+****************************************************************/
445+void ELECHOUSE_CC1101::setPA(int p)
446+{
447+int a;
448+pa = p;
449+
450+if (MHz >= 300 && MHz <= 348){
451+if (pa <= -30){a = PA_TABLE_315[0];}
452+else if (pa > -30 && pa <= -20){a = PA_TABLE_315[1];}
453+else if (pa > -20 && pa <= -15){a = PA_TABLE_315[2];}
454+else if (pa > -15 && pa <= -10){a = PA_TABLE_315[3];}
455+else if (pa > -10 && pa <= 0){a = PA_TABLE_315[4];}
456+else if (pa > 0 && pa <= 5){a = PA_TABLE_315[5];}
457+else if (pa > 5 && pa <= 7){a = PA_TABLE_315[6];}
458+else if (pa > 7){a = PA_TABLE_315[7];}
459+last_pa = 1;
460+}
461+else if (MHz >= 378 && MHz <= 464){
462+if (pa <= -30){a = PA_TABLE_433[0];}
463+else if (pa > -30 && pa <= -20){a = PA_TABLE_433[1];}
464+else if (pa > -20 && pa <= -15){a = PA_TABLE_433[2];}
465+else if (pa > -15 && pa <= -10){a = PA_TABLE_433[3];}
466+else if (pa > -10 && pa <= 0){a = PA_TABLE_433[4];}
467+else if (pa > 0 && pa <= 5){a = PA_TABLE_433[5];}
468+else if (pa > 5 && pa <= 7){a = PA_TABLE_433[6];}
469+else if (pa > 7){a = PA_TABLE_433[7];}
470+last_pa = 2;
471+}
472+else if (MHz >= 779 && MHz <= 899.99){
473+if (pa <= -30){a = PA_TABLE_868[0];}
474+else if (pa > -30 && pa <= -20){a = PA_TABLE_868[1];}
475+else if (pa > -20 && pa <= -15){a = PA_TABLE_868[2];}
476+else if (pa > -15 && pa <= -10){a = PA_TABLE_868[3];}
477+else if (pa > -10 && pa <= -6){a = PA_TABLE_868[4];}
478+else if (pa > -6 && pa <= 0){a = PA_TABLE_868[5];}
479+else if (pa > 0 && pa <= 5){a = PA_TABLE_868[6];}
480+else if (pa > 5 && pa <= 7){a = PA_TABLE_868[7];}
481+else if (pa > 7 && pa <= 10){a = PA_TABLE_868[8];}
482+else if (pa > 10){a = PA_TABLE_868[9];}
483+last_pa = 3;
484+}
485+else if (MHz >= 900 && MHz <= 928){
486+if (pa <= -30){a = PA_TABLE_915[0];}
487+else if (pa > -30 && pa <= -20){a = PA_TABLE_915[1];}
488+else if (pa > -20 && pa <= -15){a = PA_TABLE_915[2];}
489+else if (pa > -15 && pa <= -10){a = PA_TABLE_915[3];}
490+else if (pa > -10 && pa <= -6){a = PA_TABLE_915[4];}
491+else if (pa > -6 && pa <= 0){a = PA_TABLE_915[5];}
492+else if (pa > 0 && pa <= 5){a = PA_TABLE_915[6];}
493+else if (pa > 5 && pa <= 7){a = PA_TABLE_915[7];}
494+else if (pa > 7 && pa <= 10){a = PA_TABLE_915[8];}
495+else if (pa > 10){a = PA_TABLE_915[9];}
496+last_pa = 4;
497+}
498+if (modulation == 2){
499+PA_TABLE[0] = 0;
500+PA_TABLE[1] = a;
501+}else{
502+PA_TABLE[0] = a;
503+PA_TABLE[1] = 0;
504+}
505+SpiWriteBurstReg(CC1101_PATABLE,PA_TABLE,8);
506+}
507+/****************************************************************
508+*FUNCTION NAME:Frequency Calculator
509+*FUNCTION :Calculate the basic frequency.
510+*INPUT :none
511+*OUTPUT :none
512+****************************************************************/
513+void ELECHOUSE_CC1101::setMHZ(float mhz){
514+byte freq2 = 0;
515+byte freq1 = 0;
516+byte freq0 = 0;
517+
518+MHz = mhz;
519+
520+for (bool i = 0; i==0;){
521+if (mhz >= 26){
522+mhz-=26;
523+freq2+=1;
524+}
525+else if (mhz >= 0.1015625){
526+mhz-=0.1015625;
527+freq1+=1;
528+}
529+else if (mhz >= 0.00039675){
530+mhz-=0.00039675;
531+freq0+=1;
532+}
533+else{i=1;}
534+}
535+if (freq0 > 255){freq1+=1;freq0-=256;}
536+
537+SpiWriteReg(CC1101_FREQ2, freq2);
538+SpiWriteReg(CC1101_FREQ1, freq1);
539+SpiWriteReg(CC1101_FREQ0, freq0);
540+
541+Calibrate();
542+}
543+/****************************************************************
544+*FUNCTION NAME:Calibrate
545+*FUNCTION :Calibrate frequency
546+*INPUT :none
547+*OUTPUT :none
548+****************************************************************/
549+void ELECHOUSE_CC1101::Calibrate(void){
550+
551+if (MHz >= 300 && MHz <= 348){
552+SpiWriteReg(CC1101_FSCTRL0, map(MHz, 300, 348, clb1[0], clb1[1]));
553+if (MHz < 322.88){SpiWriteReg(CC1101_TEST0,0x0B);}
554+else{
555+SpiWriteReg(CC1101_TEST0,0x09);
556+int s = ELECHOUSE_cc1101.SpiReadStatus(CC1101_FSCAL2);
557+if (s<32){SpiWriteReg(CC1101_FSCAL2, s+32);}
558+if (last_pa != 1){setPA(pa);}
559+}
560+}
561+else if (MHz >= 378 && MHz <= 464){
562+SpiWriteReg(CC1101_FSCTRL0, map(MHz, 378, 464, clb2[0], clb2[1]));
563+if (MHz < 430.5){SpiWriteReg(CC1101_TEST0,0x0B);}
564+else{
565+SpiWriteReg(CC1101_TEST0,0x09);
566+int s = ELECHOUSE_cc1101.SpiReadStatus(CC1101_FSCAL2);
567+if (s<32){SpiWriteReg(CC1101_FSCAL2, s+32);}
568+if (last_pa != 2){setPA(pa);}
569+}
570+}
571+else if (MHz >= 779 && MHz <= 899.99){
572+SpiWriteReg(CC1101_FSCTRL0, map(MHz, 779, 899, clb3[0], clb3[1]));
573+if (MHz < 861){SpiWriteReg(CC1101_TEST0,0x0B);}
574+else{
575+SpiWriteReg(CC1101_TEST0,0x09);
576+int s = ELECHOUSE_cc1101.SpiReadStatus(CC1101_FSCAL2);
577+if (s<32){SpiWriteReg(CC1101_FSCAL2, s+32);}
578+if (last_pa != 3){setPA(pa);}
579+}
580+}
581+else if (MHz >= 900 && MHz <= 928){
582+SpiWriteReg(CC1101_FSCTRL0, map(MHz, 900, 928, clb4[0], clb4[1]));
583+SpiWriteReg(CC1101_TEST0,0x09);
584+int s = ELECHOUSE_cc1101.SpiReadStatus(CC1101_FSCAL2);
585+if (s<32){SpiWriteReg(CC1101_FSCAL2, s+32);}
586+if (last_pa != 4){setPA(pa);}
587+}
588+}
589+/****************************************************************
590+*FUNCTION NAME:Calibration offset
591+*FUNCTION :Set calibration offset
592+*INPUT :none
593+*OUTPUT :none
594+****************************************************************/
595+void ELECHOUSE_CC1101::setClb(byte b, byte s, byte e){
596+if (b == 1){
597+clb1[0]=s;
598+clb1[1]=e;
599+}
600+else if (b == 2){
601+clb2[0]=s;
602+clb2[1]=e;
603+}
604+else if (b == 3){
605+clb3[0]=s;
606+clb3[1]=e;
607+}
608+else if (b == 4){
609+clb4[0]=s;
610+clb4[1]=e;
611+}
612+}
613+/****************************************************************
614+*FUNCTION NAME:getCC1101
615+*FUNCTION :Test Spi connection and return 1 when true.
616+*INPUT :none
617+*OUTPUT :none
618+****************************************************************/
619+bool ELECHOUSE_CC1101::getCC1101(void){
620+setSpi();
621+if (SpiReadStatus(0x31)>0){
622+return 1;
623+}else{
624+return 0;
625+}
626+}
627+/****************************************************************
628+*FUNCTION NAME:getMode
629+*FUNCTION :Return the Mode. Sidle = 0, TX = 1, Rx = 2.
630+*INPUT :none
631+*OUTPUT :none
632+****************************************************************/
633+byte ELECHOUSE_CC1101::getMode(void){
634+return trxstate;
635+}
636+/****************************************************************
637+*FUNCTION NAME:Set Sync_Word
638+*FUNCTION :Sync Word
639+*INPUT :none
640+*OUTPUT :none
641+****************************************************************/
642+void ELECHOUSE_CC1101::setSyncWord(byte sh, byte sl){
643+SpiWriteReg(CC1101_SYNC1, sh);
644+SpiWriteReg(CC1101_SYNC0, sl);
645+}
646+/****************************************************************
647+*FUNCTION NAME:Set ADDR
648+*FUNCTION :Address used for packet filtration. Optional broadcast addresses are 0 (0x00) and 255 (0xFF).
649+*INPUT :none
650+*OUTPUT :none
651+****************************************************************/
652+void ELECHOUSE_CC1101::setAddr(byte v){
653+SpiWriteReg(CC1101_ADDR, v);
654+}
655+/****************************************************************
656+*FUNCTION NAME:Set PQT
657+*FUNCTION :Preamble quality estimator threshold
658+*INPUT :none
659+*OUTPUT :none
660+****************************************************************/
661+void ELECHOUSE_CC1101::setPQT(byte v){
662+Split_PKTCTRL1();
663+pc1PQT = 0;
664+if (v>7){v=7;}
665+pc1PQT = v*32;
666+SpiWriteReg(CC1101_PKTCTRL1, pc1PQT+pc1CRC_AF+pc1APP_ST+pc1ADRCHK);
667+}
668+/****************************************************************
669+*FUNCTION NAME:Set CRC_AUTOFLUSH
670+*FUNCTION :Enable automatic flush of RX FIFO when CRC is not OK
671+*INPUT :none
672+*OUTPUT :none
673+****************************************************************/
674+void ELECHOUSE_CC1101::setCRC_AF(bool v){
675+Split_PKTCTRL1();
676+pc1CRC_AF = 0;
677+if (v==1){pc1CRC_AF=8;}
678+SpiWriteReg(CC1101_PKTCTRL1, pc1PQT+pc1CRC_AF+pc1APP_ST+pc1ADRCHK);
679+}
680+/****************************************************************
681+*FUNCTION NAME:Set APPEND_STATUS
682+*FUNCTION :When enabled, two status bytes will be appended to the payload of the packet
683+*INPUT :none
684+*OUTPUT :none
685+****************************************************************/
686+void ELECHOUSE_CC1101::setAppendStatus(bool v){
687+Split_PKTCTRL1();
688+pc1APP_ST = 0;
689+if (v==1){pc1APP_ST=4;}
690+SpiWriteReg(CC1101_PKTCTRL1, pc1PQT+pc1CRC_AF+pc1APP_ST+pc1ADRCHK);
691+}
692+/****************************************************************
693+*FUNCTION NAME:Set ADR_CHK
694+*FUNCTION :Controls address check configuration of received packages
695+*INPUT :none
696+*OUTPUT :none
697+****************************************************************/
698+void ELECHOUSE_CC1101::setAdrChk(byte v){
699+Split_PKTCTRL1();
700+pc1ADRCHK = 0;
701+if (v>3){v=3;}
702+pc1ADRCHK = v;
703+SpiWriteReg(CC1101_PKTCTRL1, pc1PQT+pc1CRC_AF+pc1APP_ST+pc1ADRCHK);
704+}
705+/****************************************************************
706+*FUNCTION NAME:Set WHITE_DATA
707+*FUNCTION :Turn data whitening on / off.
708+*INPUT :none
709+*OUTPUT :none
710+****************************************************************/
711+void ELECHOUSE_CC1101::setWhiteData(bool v){
712+Split_PKTCTRL0();
713+pc0WDATA = 0;
714+if (v == 1){pc0WDATA=64;}
715+SpiWriteReg(CC1101_PKTCTRL0, pc0WDATA+pc0PktForm+pc0CRC_EN+pc0LenConf);
716+}
717+/****************************************************************
718+*FUNCTION NAME:Set PKT_FORMAT
719+*FUNCTION :Format of RX and TX data
720+*INPUT :none
721+*OUTPUT :none
722+****************************************************************/
723+void ELECHOUSE_CC1101::setPktFormat(byte v){
724+Split_PKTCTRL0();
725+pc0PktForm = 0;
726+if (v>3){v=3;}
727+pc0PktForm = v*16;
728+SpiWriteReg(CC1101_PKTCTRL0, pc0WDATA+pc0PktForm+pc0CRC_EN+pc0LenConf);
729+}
730+/****************************************************************
731+*FUNCTION NAME:Set CRC
732+*FUNCTION :CRC calculation in TX and CRC check in RX
733+*INPUT :none
734+*OUTPUT :none
735+****************************************************************/
736+void ELECHOUSE_CC1101::setCrc(bool v){
737+Split_PKTCTRL0();
738+pc0CRC_EN = 0;
739+if (v==1){pc0CRC_EN=4;}
740+SpiWriteReg(CC1101_PKTCTRL0, pc0WDATA+pc0PktForm+pc0CRC_EN+pc0LenConf);
741+}
742+/****************************************************************
743+*FUNCTION NAME:Set LENGTH_CONFIG
744+*FUNCTION :Configure the packet length
745+*INPUT :none
746+*OUTPUT :none
747+****************************************************************/
748+void ELECHOUSE_CC1101::setLengthConfig(byte v){
749+Split_PKTCTRL0();
750+pc0LenConf = 0;
751+if (v>3){v=3;}
752+pc0LenConf = v;
753+SpiWriteReg(CC1101_PKTCTRL0, pc0WDATA+pc0PktForm+pc0CRC_EN+pc0LenConf);
754+}
755+/****************************************************************
756+*FUNCTION NAME:Set PACKET_LENGTH
757+*FUNCTION :Indicates the packet length
758+*INPUT :none
759+*OUTPUT :none
760+****************************************************************/
761+void ELECHOUSE_CC1101::setPacketLength(byte v){
762+SpiWriteReg(CC1101_PKTLEN, v);
763+}
764+/****************************************************************
765+*FUNCTION NAME:Set DCFILT_OFF
766+*FUNCTION :Disable digital DC blocking filter before demodulator
767+*INPUT :none
768+*OUTPUT :none
769+****************************************************************/
770+void ELECHOUSE_CC1101::setDcFilterOff(bool v){
771+Split_MDMCFG2();
772+m2DCOFF = 0;
773+if (v==1){m2DCOFF=128;}
774+SpiWriteReg(CC1101_MDMCFG2, m2DCOFF+m2MODFM+m2MANCH+m2SYNCM);
775+}
776+/****************************************************************
777+*FUNCTION NAME:Set MANCHESTER
778+*FUNCTION :Enables Manchester encoding/decoding
779+*INPUT :none
780+*OUTPUT :none
781+****************************************************************/
782+void ELECHOUSE_CC1101::setManchester(bool v){
783+Split_MDMCFG2();
784+m2MANCH = 0;
785+if (v==1){m2MANCH=8;}
786+SpiWriteReg(CC1101_MDMCFG2, m2DCOFF+m2MODFM+m2MANCH+m2SYNCM);
787+}
788+/****************************************************************
789+*FUNCTION NAME:Set SYNC_MODE
790+*FUNCTION :Combined sync-word qualifier mode
791+*INPUT :none
792+*OUTPUT :none
793+****************************************************************/
794+void ELECHOUSE_CC1101::setSyncMode(byte v){
795+Split_MDMCFG2();
796+m2SYNCM = 0;
797+if (v>7){v=7;}
798+m2SYNCM=v;
799+SpiWriteReg(CC1101_MDMCFG2, m2DCOFF+m2MODFM+m2MANCH+m2SYNCM);
800+}
801+/****************************************************************
802+*FUNCTION NAME:Set FEC
803+*FUNCTION :Enable Forward Error Correction (FEC)
804+*INPUT :none
805+*OUTPUT :none
806+****************************************************************/
807+void ELECHOUSE_CC1101::setFEC(bool v){
808+Split_MDMCFG1();
809+m1FEC=0;
810+if (v==1){m1FEC=128;}
811+SpiWriteReg(CC1101_MDMCFG1, m1FEC+m1PRE+m1CHSP);
812+}
813+/****************************************************************
814+*FUNCTION NAME:Set PRE
815+*FUNCTION :Sets the minimum number of preamble bytes to be transmitted.
816+*INPUT :none
817+*OUTPUT :none
818+****************************************************************/
819+void ELECHOUSE_CC1101::setPRE(byte v){
820+Split_MDMCFG1();
821+m1PRE=0;
822+if (v>7){v=7;}
823+m1PRE = v*16;
824+SpiWriteReg(CC1101_MDMCFG1, m1FEC+m1PRE+m1CHSP);
825+}
826+/****************************************************************
827+*FUNCTION NAME:Set Channel
828+*FUNCTION :none
829+*INPUT :none
830+*OUTPUT :none
831+****************************************************************/
832+void ELECHOUSE_CC1101::setChannel(byte ch){
833+chan = ch;
834+SpiWriteReg(CC1101_CHANNR, chan);
835+}
836+/****************************************************************
837+*FUNCTION NAME:Set Channel spacing
838+*FUNCTION :none
839+*INPUT :none
840+*OUTPUT :none
841+****************************************************************/
842+void ELECHOUSE_CC1101::setChsp(float f){
843+Split_MDMCFG1();
844+byte MDMCFG0 = 0;
845+m1CHSP = 0;
846+if (f > 405.456543){f = 405.456543;}
847+if (f < 25.390625){f = 25.390625;}
848+for (int i = 0; i<5; i++){
849+if (f <= 50.682068){
850+f -= 25.390625;
851+f /= 0.0991825;
852+MDMCFG0 = f;
853+float s1 = (f - MDMCFG0) *10;
854+if (s1 >= 5){MDMCFG0++;}
855+i = 5;
856+}else{
857+m1CHSP++;
858+f/=2;
859+}
860+}
861+SpiWriteReg(19,m1CHSP+m1FEC+m1PRE);
862+SpiWriteReg(20,MDMCFG0);
863+}
864+/****************************************************************
865+*FUNCTION NAME:Set Receive bandwidth
866+*FUNCTION :none
867+*INPUT :none
868+*OUTPUT :none
869+****************************************************************/
870+void ELECHOUSE_CC1101::setRxBW(float f){
871+Split_MDMCFG4();
872+int s1 = 3;
873+int s2 = 3;
874+for (int i = 0; i<3; i++){
875+if (f > 101.5625){f/=2; s1--;}
876+else{i=3;}
877+}
878+for (int i = 0; i<3; i++){
879+if (f > 58.1){f/=1.25; s2--;}
880+else{i=3;}
881+}
882+s1 *= 64;
883+s2 *= 16;
884+m4RxBw = s1 + s2;
885+SpiWriteReg(16,m4RxBw+m4DaRa);
886+}
887+/****************************************************************
888+*FUNCTION NAME:Set Data Rate
889+*FUNCTION :none
890+*INPUT :none
891+*OUTPUT :none
892+****************************************************************/
893+void ELECHOUSE_CC1101::setDRate(float d){
894+Split_MDMCFG4();
895+float c = d;
896+byte MDMCFG3 = 0;
897+if (c > 1621.83){c = 1621.83;}
898+if (c < 0.0247955){c = 0.0247955;}
899+m4DaRa = 0;
900+for (int i = 0; i<20; i++){
901+if (c <= 0.0494942){
902+c = c - 0.0247955;
903+c = c / 0.00009685;
904+MDMCFG3 = c;
905+float s1 = (c - MDMCFG3) *10;
906+if (s1 >= 5){MDMCFG3++;}
907+i = 20;
908+}else{
909+m4DaRa++;
910+c = c/2;
911+}
912+}
913+SpiWriteReg(16, m4RxBw+m4DaRa);
914+SpiWriteReg(17, MDMCFG3);
915+}
916+/****************************************************************
917+*FUNCTION NAME:Set Devitation
918+*FUNCTION :none
919+*INPUT :none
920+*OUTPUT :none
921+****************************************************************/
922+void ELECHOUSE_CC1101::setDeviation(float d){
923+float f = 1.586914;
924+float v = 0.19836425;
925+int c = 0;
926+if (d > 380.859375){d = 380.859375;}
927+if (d < 1.586914){d = 1.586914;}
928+for (int i = 0; i<255; i++){
929+f+=v;
930+if (c==7){v*=2;c=-1;i+=8;}
931+if (f>=d){c=i;i=255;}
932+c++;
933+}
934+SpiWriteReg(21,c);
935+}
936+/****************************************************************
937+*FUNCTION NAME:Split PKTCTRL0
938+*FUNCTION :none
939+*INPUT :none
940+*OUTPUT :none
941+****************************************************************/
942+void ELECHOUSE_CC1101::Split_PKTCTRL1(void){
943+int calc = SpiReadStatus(7);
944+pc1PQT = 0;
945+pc1CRC_AF = 0;
946+pc1APP_ST = 0;
947+pc1ADRCHK = 0;
948+for (bool i = 0; i==0;){
949+if (calc >= 32){calc-=32; pc1PQT+=32;}
950+else if (calc >= 8){calc-=8; pc1CRC_AF+=8;}
951+else if (calc >= 4){calc-=4; pc1APP_ST+=4;}
952+else {pc1ADRCHK = calc; i=1;}
953+}
954+}
955+/****************************************************************
956+*FUNCTION NAME:Split PKTCTRL0
957+*FUNCTION :none
958+*INPUT :none
959+*OUTPUT :none
960+****************************************************************/
961+void ELECHOUSE_CC1101::Split_PKTCTRL0(void){
962+int calc = SpiReadStatus(8);
963+pc0WDATA = 0;
964+pc0PktForm = 0;
965+pc0CRC_EN = 0;
966+pc0LenConf = 0;
967+for (bool i = 0; i==0;){
968+if (calc >= 64){calc-=64; pc0WDATA+=64;}
969+else if (calc >= 16){calc-=16; pc0PktForm+=16;}
970+else if (calc >= 4){calc-=4; pc0CRC_EN+=4;}
971+else {pc0LenConf = calc; i=1;}
972+}
973+}
974+/****************************************************************
975+*FUNCTION NAME:Split MDMCFG1
976+*FUNCTION :none
977+*INPUT :none
978+*OUTPUT :none
979+****************************************************************/
980+void ELECHOUSE_CC1101::Split_MDMCFG1(void){
981+int calc = SpiReadStatus(19);
982+m1FEC = 0;
983+m1PRE = 0;
984+m1CHSP = 0;
985+int s2 = 0;
986+for (bool i = 0; i==0;){
987+if (calc >= 128){calc-=128; m1FEC+=128;}
988+else if (calc >= 16){calc-=16; m1PRE+=16;}
989+else {m1CHSP = calc; i=1;}
990+}
991+}
992+/****************************************************************
993+*FUNCTION NAME:Split MDMCFG2
994+*FUNCTION :none
995+*INPUT :none
996+*OUTPUT :none
997+****************************************************************/
998+void ELECHOUSE_CC1101::Split_MDMCFG2(void){
999+int calc = SpiReadStatus(18);
1000+m2DCOFF = 0;
1001+m2MODFM = 0;
1002+m2MANCH = 0;
1003+m2SYNCM = 0;
1004+for (bool i = 0; i==0;){
1005+if (calc >= 128){calc-=128; m2DCOFF+=128;}
1006+else if (calc >= 16){calc-=16; m2MODFM+=16;}
1007+else if (calc >= 8){calc-=8; m2MANCH+=8;}
1008+else{m2SYNCM = calc; i=1;}
1009+}
1010+}
1011+/****************************************************************
1012+*FUNCTION NAME:Split MDMCFG4
1013+*FUNCTION :none
1014+*INPUT :none
1015+*OUTPUT :none
1016+****************************************************************/
1017+void ELECHOUSE_CC1101::Split_MDMCFG4(void){
1018+int calc = SpiReadStatus(16);
1019+m4RxBw = 0;
1020+m4DaRa = 0;
1021+for (bool i = 0; i==0;){
1022+if (calc >= 64){calc-=64; m4RxBw+=64;}
1023+else if (calc >= 16){calc -= 16; m4RxBw+=16;}
1024+else{m4DaRa = calc; i=1;}
1025+}
1026+}
1027+/****************************************************************
1028+*FUNCTION NAME:RegConfigSettings
1029+*FUNCTION :CC1101 register config //details refer datasheet of CC1101/CC1100//
1030+*INPUT :none
1031+*OUTPUT :none
1032+****************************************************************/
1033+void ELECHOUSE_CC1101::RegConfigSettings(void)
1034+{
1035+ SpiWriteReg(CC1101_FSCTRL1, 0x06);
1036+
1037+ setCCMode(ccmode);
1038+ setMHZ(MHz);
1039+
1040+ SpiWriteReg(CC1101_MDMCFG1, 0x02);
1041+ SpiWriteReg(CC1101_MDMCFG0, 0xF8);
1042+ SpiWriteReg(CC1101_CHANNR, chan);
1043+ SpiWriteReg(CC1101_DEVIATN, 0x47);
1044+ SpiWriteReg(CC1101_FREND1, 0x56);
1045+ SpiWriteReg(CC1101_MCSM0 , 0x18);
1046+ SpiWriteReg(CC1101_FOCCFG, 0x16);
1047+ SpiWriteReg(CC1101_BSCFG, 0x1C);
1048+ SpiWriteReg(CC1101_AGCCTRL2, 0xC7);
1049+ SpiWriteReg(CC1101_AGCCTRL1, 0x00);
1050+ SpiWriteReg(CC1101_AGCCTRL0, 0xB2);
1051+ SpiWriteReg(CC1101_FSCAL3, 0xE9);
1052+ SpiWriteReg(CC1101_FSCAL2, 0x2A);
1053+ SpiWriteReg(CC1101_FSCAL1, 0x00);
1054+ SpiWriteReg(CC1101_FSCAL0, 0x1F);
1055+ SpiWriteReg(CC1101_FSTEST, 0x59);
1056+ SpiWriteReg(CC1101_TEST2, 0x81);
1057+ SpiWriteReg(CC1101_TEST1, 0x35);
1058+ SpiWriteReg(CC1101_TEST0, 0x09);
1059+ SpiWriteReg(CC1101_PKTCTRL1, 0x04);
1060+ SpiWriteReg(CC1101_ADDR, 0x00);
1061+ SpiWriteReg(CC1101_PKTLEN, 0x00);
1062+}
1063+/****************************************************************
1064+*FUNCTION NAME:SetTx
1065+*FUNCTION :set CC1101 send data
1066+*INPUT :none
1067+*OUTPUT :none
1068+****************************************************************/
1069+void ELECHOUSE_CC1101::SetTx(void)
1070+{
1071+ SpiStrobe(CC1101_SIDLE);
1072+ SpiStrobe(CC1101_STX); //start send
1073+ trxstate=1;
1074+}
1075+/****************************************************************
1076+*FUNCTION NAME:SetRx
1077+*FUNCTION :set CC1101 to receive state
1078+*INPUT :none
1079+*OUTPUT :none
1080+****************************************************************/
1081+void ELECHOUSE_CC1101::SetRx(void)
1082+{
1083+ SpiStrobe(CC1101_SIDLE);
1084+ SpiStrobe(CC1101_SRX); //start receive
1085+ trxstate=2;
1086+}
1087+/****************************************************************
1088+*FUNCTION NAME:SetTx
1089+*FUNCTION :set CC1101 send data and change frequency
1090+*INPUT :none
1091+*OUTPUT :none
1092+****************************************************************/
1093+void ELECHOUSE_CC1101::SetTx(float mhz)
1094+{
1095+ SpiStrobe(CC1101_SIDLE);
1096+ setMHZ(mhz);
1097+ SpiStrobe(CC1101_STX); //start send
1098+ trxstate=1;
1099+}
1100+/****************************************************************
1101+*FUNCTION NAME:SetRx
1102+*FUNCTION :set CC1101 to receive state and change frequency
1103+*INPUT :none
1104+*OUTPUT :none
1105+****************************************************************/
1106+void ELECHOUSE_CC1101::SetRx(float mhz)
1107+{
1108+ SpiStrobe(CC1101_SIDLE);
1109+ setMHZ(mhz);
1110+ SpiStrobe(CC1101_SRX); //start receive
1111+ trxstate=2;
1112+}
1113+/****************************************************************
1114+*FUNCTION NAME:RSSI Level
1115+*FUNCTION :Calculating the RSSI Level
1116+*INPUT :none
1117+*OUTPUT :none
1118+****************************************************************/
1119+int ELECHOUSE_CC1101::getRssi(void)
1120+{
1121+int rssi;
1122+rssi=SpiReadStatus(CC1101_RSSI);
1123+if (rssi >= 128){rssi = (rssi-256)/2-74;}
1124+else{rssi = (rssi/2)-74;}
1125+return rssi;
1126+}
1127+/****************************************************************
1128+*FUNCTION NAME:LQI Level
1129+*FUNCTION :get Lqi state
1130+*INPUT :none
1131+*OUTPUT :none
1132+****************************************************************/
1133+byte ELECHOUSE_CC1101::getLqi(void)
1134+{
1135+byte lqi;
1136+lqi=SpiReadStatus(CC1101_LQI);
1137+return lqi;
1138+}
1139+/****************************************************************
1140+*FUNCTION NAME:SetSres
1141+*FUNCTION :Reset CC1101
1142+*INPUT :none
1143+*OUTPUT :none
1144+****************************************************************/
1145+void ELECHOUSE_CC1101::setSres(void)
1146+{
1147+ SpiStrobe(CC1101_SRES);
1148+ trxstate=0;
1149+}
1150+/****************************************************************
1151+*FUNCTION NAME:setSidle
1152+*FUNCTION :set Rx / TX Off
1153+*INPUT :none
1154+*OUTPUT :none
1155+****************************************************************/
1156+void ELECHOUSE_CC1101::setSidle(void)
1157+{
1158+ SpiStrobe(CC1101_SIDLE);
1159+ trxstate=0;
1160+}
1161+/****************************************************************
1162+*FUNCTION NAME:goSleep
1163+*FUNCTION :set cc1101 Sleep on
1164+*INPUT :none
1165+*OUTPUT :none
1166+****************************************************************/
1167+void ELECHOUSE_CC1101::goSleep(void){
1168+ trxstate=0;
1169+ SpiStrobe(0x36);//Exit RX / TX, turn off frequency synthesizer and exit
1170+ SpiStrobe(0x39);//Enter power down mode when CSn goes high.
1171+}
1172+/****************************************************************
1173+*FUNCTION NAME:Char direct SendData
1174+*FUNCTION :use CC1101 send data
1175+*INPUT :txBuffer: data array to send; size: number of data to send, no more than 61
1176+*OUTPUT :none
1177+****************************************************************/
1178+void ELECHOUSE_CC1101::SendData(char *txchar)
1179+{
1180+int len = strlen(txchar);
1181+byte chartobyte[len];
1182+for (int i = 0; i<len; i++){chartobyte[i] = txchar[i];}
1183+SendData(chartobyte,len);
1184+}
1185+/****************************************************************
1186+*FUNCTION NAME:SendData
1187+*FUNCTION :use CC1101 send data
1188+*INPUT :txBuffer: data array to send; size: number of data to send, no more than 61
1189+*OUTPUT :none
1190+****************************************************************/
1191+void ELECHOUSE_CC1101::SendData(byte *txBuffer,byte size)
1192+{
1193+ SpiWriteReg(CC1101_TXFIFO,size);
1194+ SpiWriteBurstReg(CC1101_TXFIFO,txBuffer,size); //write data to send
1195+ SpiStrobe(CC1101_SIDLE);
1196+ SpiStrobe(CC1101_STX); //start send
1197+ while (!digitalRead(GDO0)); // Wait for GDO0 to be set -> sync transmitted
1198+ while (digitalRead(GDO0)); // Wait for GDO0 to be cleared -> end of packet
1199+ SpiStrobe(CC1101_SFTX); //flush TXfifo
1200+ trxstate=1;
1201+}
1202+/****************************************************************
1203+*FUNCTION NAME:Char direct SendData
1204+*FUNCTION :use CC1101 send data without GDO
1205+*INPUT :txBuffer: data array to send; size: number of data to send, no more than 61
1206+*OUTPUT :none
1207+****************************************************************/
1208+void ELECHOUSE_CC1101::SendData(char *txchar,int t)
1209+{
1210+int len = strlen(txchar);
1211+byte chartobyte[len];
1212+for (int i = 0; i<len; i++){chartobyte[i] = txchar[i];}
1213+SendData(chartobyte,len,t);
1214+}
1215+/****************************************************************
1216+*FUNCTION NAME:SendData
1217+*FUNCTION :use CC1101 send data without GDO
1218+*INPUT :txBuffer: data array to send; size: number of data to send, no more than 61
1219+*OUTPUT :none
1220+****************************************************************/
1221+void ELECHOUSE_CC1101::SendData(byte *txBuffer,byte size,int t)
1222+{
1223+ SpiWriteReg(CC1101_TXFIFO,size);
1224+ SpiWriteBurstReg(CC1101_TXFIFO,txBuffer,size); //write data to send
1225+ SpiStrobe(CC1101_SIDLE);
1226+ SpiStrobe(CC1101_STX); //start send
1227+ delay(t);
1228+ SpiStrobe(CC1101_SFTX); //flush TXfifo
1229+ trxstate=1;
1230+}
1231+/****************************************************************
1232+*FUNCTION NAME:Check CRC
1233+*FUNCTION :none
1234+*INPUT :none
1235+*OUTPUT :none
1236+****************************************************************/
1237+bool ELECHOUSE_CC1101::CheckCRC(void){
1238+byte lqi=SpiReadStatus(CC1101_LQI);
1239+bool crc_ok = bitRead(lqi,7);
1240+if (crc_ok == 1){
1241+return 1;
1242+}else{
1243+SpiStrobe(CC1101_SFRX);
1244+SpiStrobe(CC1101_SRX);
1245+return 0;
1246+}
1247+}
1248+/****************************************************************
1249+*FUNCTION NAME:CheckRxFifo
1250+*FUNCTION :check receive data or not
1251+*INPUT :none
1252+*OUTPUT :flag: 0 no data; 1 receive data
1253+****************************************************************/
1254+bool ELECHOUSE_CC1101::CheckRxFifo(int t){
1255+if(trxstate!=2){SetRx();}
1256+if(SpiReadStatus(CC1101_RXBYTES) & BYTES_IN_RXFIFO){
1257+delay(t);
1258+return 1;
1259+}else{
1260+return 0;
1261+}
1262+}
1263+/****************************************************************
1264+*FUNCTION NAME:CheckReceiveFlag
1265+*FUNCTION :check receive data or not
1266+*INPUT :none
1267+*OUTPUT :flag: 0 no data; 1 receive data
1268+****************************************************************/
1269+byte ELECHOUSE_CC1101::CheckReceiveFlag(void)
1270+{
1271+ if(trxstate!=2){SetRx();}
1272+ if(digitalRead(GDO0)) //receive data
1273+ {
1274+ while (digitalRead(GDO0));
1275+ return 1;
1276+ }
1277+ else // no data
1278+ {
1279+ return 0;
1280+ }
1281+}
1282+/****************************************************************
1283+*FUNCTION NAME:ReceiveData
1284+*FUNCTION :read data received from RXfifo
1285+*INPUT :rxBuffer: buffer to store data
1286+*OUTPUT :size of data received
1287+****************************************************************/
1288+byte ELECHOUSE_CC1101::ReceiveData(byte *rxBuffer)
1289+{
1290+ byte size;
1291+ byte status[2];
1292+
1293+ if(SpiReadStatus(CC1101_RXBYTES) & BYTES_IN_RXFIFO)
1294+ {
1295+ size=SpiReadReg(CC1101_RXFIFO);
1296+ SpiReadBurstReg(CC1101_RXFIFO,rxBuffer,size);
1297+ SpiReadBurstReg(CC1101_RXFIFO,status,2);
1298+ SpiStrobe(CC1101_SFRX);
1299+ SpiStrobe(CC1101_SRX);
1300+ return size;
1301+ }
1302+ else
1303+ {
1304+ SpiStrobe(CC1101_SFRX);
1305+ SpiStrobe(CC1101_SRX);
1306+ return 0;
1307+ }
1308+}
1309+ELECHOUSE_CC1101 ELECHOUSE_cc1101;
A test/ELECHOUSE_CC1101_SRC_DRV.h View
@@ -0,0 +1,194 @@
1+/*
2+ ELECHOUSE_CC1101.cpp - CC1101 module library
3+ Copyright (c) 2010 Michael.
4+ Author: Michael, <www.elechouse.com>
5+ Version: November 12, 2010
6+
7+ This library is designed to use CC1101/CC1100 module on Arduino platform.
8+ CC1101/CC1100 module is an useful wireless module.Using the functions of the
9+ library, you can easily send and receive data by the CC1101/CC1100 module.
10+ Just have fun!
11+ For the details, please refer to the datasheet of CC1100/CC1101.
12+----------------------------------------------------------------------------------------------------------------
13+cc1101 Driver for RC Switch. Mod by Little Satan. With permission to modify and publish Wilson Shen (ELECHOUSE).
14+----------------------------------------------------------------------------------------------------------------
15+*/
16+#ifndef ELECHOUSE_CC1101_SRC_DRV_h
17+#define ELECHOUSE_CC1101_SRC_DRV_h
18+
19+#include <Arduino.h>
20+
21+//***************************************CC1101 define**************************************************//
22+// CC1101 CONFIG REGSITER
23+#define CC1101_IOCFG2 0x00 // GDO2 output pin configuration
24+#define CC1101_IOCFG1 0x01 // GDO1 output pin configuration
25+#define CC1101_IOCFG0 0x02 // GDO0 output pin configuration
26+#define CC1101_FIFOTHR 0x03 // RX FIFO and TX FIFO thresholds
27+#define CC1101_SYNC1 0x04 // Sync word, high INT8U
28+#define CC1101_SYNC0 0x05 // Sync word, low INT8U
29+#define CC1101_PKTLEN 0x06 // Packet length
30+#define CC1101_PKTCTRL1 0x07 // Packet automation control
31+#define CC1101_PKTCTRL0 0x08 // Packet automation control
32+#define CC1101_ADDR 0x09 // Device address
33+#define CC1101_CHANNR 0x0A // Channel number
34+#define CC1101_FSCTRL1 0x0B // Frequency synthesizer control
35+#define CC1101_FSCTRL0 0x0C // Frequency synthesizer control
36+#define CC1101_FREQ2 0x0D // Frequency control word, high INT8U
37+#define CC1101_FREQ1 0x0E // Frequency control word, middle INT8U
38+#define CC1101_FREQ0 0x0F // Frequency control word, low INT8U
39+#define CC1101_MDMCFG4 0x10 // Modem configuration
40+#define CC1101_MDMCFG3 0x11 // Modem configuration
41+#define CC1101_MDMCFG2 0x12 // Modem configuration
42+#define CC1101_MDMCFG1 0x13 // Modem configuration
43+#define CC1101_MDMCFG0 0x14 // Modem configuration
44+#define CC1101_DEVIATN 0x15 // Modem deviation setting
45+#define CC1101_MCSM2 0x16 // Main Radio Control State Machine configuration
46+#define CC1101_MCSM1 0x17 // Main Radio Control State Machine configuration
47+#define CC1101_MCSM0 0x18 // Main Radio Control State Machine configuration
48+#define CC1101_FOCCFG 0x19 // Frequency Offset Compensation configuration
49+#define CC1101_BSCFG 0x1A // Bit Synchronization configuration
50+#define CC1101_AGCCTRL2 0x1B // AGC control
51+#define CC1101_AGCCTRL1 0x1C // AGC control
52+#define CC1101_AGCCTRL0 0x1D // AGC control
53+#define CC1101_WOREVT1 0x1E // High INT8U Event 0 timeout
54+#define CC1101_WOREVT0 0x1F // Low INT8U Event 0 timeout
55+#define CC1101_WORCTRL 0x20 // Wake On Radio control
56+#define CC1101_FREND1 0x21 // Front end RX configuration
57+#define CC1101_FREND0 0x22 // Front end TX configuration
58+#define CC1101_FSCAL3 0x23 // Frequency synthesizer calibration
59+#define CC1101_FSCAL2 0x24 // Frequency synthesizer calibration
60+#define CC1101_FSCAL1 0x25 // Frequency synthesizer calibration
61+#define CC1101_FSCAL0 0x26 // Frequency synthesizer calibration
62+#define CC1101_RCCTRL1 0x27 // RC oscillator configuration
63+#define CC1101_RCCTRL0 0x28 // RC oscillator configuration
64+#define CC1101_FSTEST 0x29 // Frequency synthesizer calibration control
65+#define CC1101_PTEST 0x2A // Production test
66+#define CC1101_AGCTEST 0x2B // AGC test
67+#define CC1101_TEST2 0x2C // Various test settings
68+#define CC1101_TEST1 0x2D // Various test settings
69+#define CC1101_TEST0 0x2E // Various test settings
70+
71+//CC1101 Strobe commands
72+#define CC1101_SRES 0x30 // Reset chip.
73+#define CC1101_SFSTXON 0x31 // Enable and calibrate frequency synthesizer (if MCSM0.FS_AUTOCAL=1).
74+ // If in RX/TX: Go to a wait state where only the synthesizer is
75+ // running (for quick RX / TX turnaround).
76+#define CC1101_SXOFF 0x32 // Turn off crystal oscillator.
77+#define CC1101_SCAL 0x33 // Calibrate frequency synthesizer and turn it off
78+ // (enables quick start).
79+#define CC1101_SRX 0x34 // Enable RX. Perform calibration first if coming from IDLE and
80+ // MCSM0.FS_AUTOCAL=1.
81+#define CC1101_STX 0x35 // In IDLE state: Enable TX. Perform calibration first if
82+ // MCSM0.FS_AUTOCAL=1. If in RX state and CCA is enabled:
83+ // Only go to TX if channel is clear.
84+#define CC1101_SIDLE 0x36 // Exit RX / TX, turn off frequency synthesizer and exit
85+ // Wake-On-Radio mode if applicable.
86+#define CC1101_SAFC 0x37 // Perform AFC adjustment of the frequency synthesizer
87+#define CC1101_SWOR 0x38 // Start automatic RX polling sequence (Wake-on-Radio)
88+#define CC1101_SPWD 0x39 // Enter power down mode when CSn goes high.
89+#define CC1101_SFRX 0x3A // Flush the RX FIFO buffer.
90+#define CC1101_SFTX 0x3B // Flush the TX FIFO buffer.
91+#define CC1101_SWORRST 0x3C // Reset real time clock.
92+#define CC1101_SNOP 0x3D // No operation. May be used to pad strobe commands to two
93+ // INT8Us for simpler software.
94+//CC1101 STATUS REGSITER
95+#define CC1101_PARTNUM 0x30
96+#define CC1101_VERSION 0x31
97+#define CC1101_FREQEST 0x32
98+#define CC1101_LQI 0x33
99+#define CC1101_RSSI 0x34
100+#define CC1101_MARCSTATE 0x35
101+#define CC1101_WORTIME1 0x36
102+#define CC1101_WORTIME0 0x37
103+#define CC1101_PKTSTATUS 0x38
104+#define CC1101_VCO_VC_DAC 0x39
105+#define CC1101_TXBYTES 0x3A
106+#define CC1101_RXBYTES 0x3B
107+
108+//CC1101 PATABLE,TXFIFO,RXFIFO
109+#define CC1101_PATABLE 0x3E
110+#define CC1101_TXFIFO 0x3F
111+#define CC1101_RXFIFO 0x3F
112+
113+//************************************* class **************************************************//
114+class ELECHOUSE_CC1101
115+{
116+private:
117+ void SpiStart(void);
118+ void SpiEnd(void);
119+ void GDO_Set (void);
120+ void GDO0_Set (void);
121+ void Reset (void);
122+ void setSpi(void);
123+ void RegConfigSettings(void);
124+ void Calibrate(void);
125+ void Split_PKTCTRL0(void);
126+ void Split_PKTCTRL1(void);
127+ void Split_MDMCFG1(void);
128+ void Split_MDMCFG2(void);
129+ void Split_MDMCFG4(void);
130+public:
131+ void Init(void);
132+ byte SpiReadStatus(byte addr);
133+ void setSpiPin(byte sck, byte miso, byte mosi, byte ss);
134+ void addSpiPin(byte sck, byte miso, byte mosi, byte ss, byte modul);
135+ void setGDO(byte gdo0, byte gdo2);
136+ void setGDO0(byte gdo0);
137+ void addGDO(byte gdo0, byte gdo2, byte modul);
138+ void addGDO0(byte gdo0, byte modul);
139+ void setModul(byte modul);
140+ void setCCMode(bool s);
141+ void setModulation(byte m);
142+ void setPA(int p);
143+ void setMHZ(float mhz);
144+ void setChannel(byte chnl);
145+ void setChsp(float f);
146+ void setRxBW(float f);
147+ void setDRate(float d);
148+ void setDeviation(float d);
149+ void SetTx(void);
150+ void SetRx(void);
151+ void SetTx(float mhz);
152+ void SetRx(float mhz);
153+ int getRssi(void);
154+ byte getLqi(void);
155+ void setSres(void);
156+ void setSidle(void);
157+ void goSleep(void);
158+ void SendData(byte *txBuffer, byte size);
159+ void SendData(char *txchar);
160+ void SendData(byte *txBuffer, byte size, int t);
161+ void SendData(char *txchar, int t);
162+ byte CheckReceiveFlag(void);
163+ byte ReceiveData(byte *rxBuffer);
164+ bool CheckCRC(void);
165+ void SpiStrobe(byte strobe);
166+ void SpiWriteReg(byte addr, byte value);
167+ void SpiWriteBurstReg(byte addr, byte *buffer, byte num);
168+ byte SpiReadReg(byte addr);
169+ void SpiReadBurstReg(byte addr, byte *buffer, byte num);
170+ void setClb(byte b, byte s, byte e);
171+ bool getCC1101(void);
172+ byte getMode(void);
173+ void setSyncWord(byte sh, byte sl);
174+ void setAddr(byte v);
175+ void setWhiteData(bool v);
176+ void setPktFormat(byte v);
177+ void setCrc(bool v);
178+ void setLengthConfig(byte v);
179+ void setPacketLength(byte v);
180+ void setDcFilterOff(bool v);
181+ void setManchester(bool v);
182+ void setSyncMode(byte v);
183+ void setFEC(bool v);
184+ void setPRE(byte v);
185+ void setPQT(byte v);
186+ void setCRC_AF(bool v);
187+ void setAppendStatus(bool v);
188+ void setAdrChk(byte v);
189+ bool CheckRxFifo(int t);
190+};
191+
192+extern ELECHOUSE_CC1101 ELECHOUSE_cc1101;
193+
194+#endif
A test/test.ino View
@@ -0,0 +1,267 @@
1+#include <Arduino.h>
2+#include <SPI.h>
3+#include <RF24.h>
4+#include <U8g2lib.h>
5+#include <WiFi.h>
6+#include "esp_bt.h"
7+
8+// ================= NRF24 =================
9+#define CE1_PIN 10
10+#define CSN1_PIN 11
11+
12+#define CE2_PIN 12
13+#define CSN2_PIN 13
14+
15+#define NRF_SCK 18
16+#define NRF_MISO 16
17+#define NRF_MOSI 17
18+
19+// ================= OLED ==================
20+#define OLED_SDA_PIN 8
21+#define OLED_SCL_PIN 9
22+
23+// ================= Buttons ===============
24+#define BTN_UP 4
25+
26+// =========================================
27+
28+// Third radio optional
29+#define CE3_PIN 46
30+#define CSN3_PIN 48
31+
32+SPIClass *NRF_SPI = nullptr;
33+
34+// RF24 radios
35+RF24 RadioA(CE1_PIN, CSN1_PIN);
36+RF24 RadioB(CE2_PIN, CSN2_PIN);
37+
38+// OLED
39+U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(
40+ U8G2_R0,
41+ U8X8_PIN_NONE,
42+ OLED_SCL_PIN,
43+ OLED_SDA_PIN
44+);
45+
46+enum OperationMode {
47+ DEACTIVE_MODE,
48+ BLE_MODULE,
49+ Bluetooth_MODULE
50+};
51+
52+OperationMode currentMode = DEACTIVE_MODE;
53+
54+// BLE advertising channels
55+const byte ble_channels[] = {2, 26, 80};
56+
57+// Bluetooth hopping channels
58+//const byte bluetooth_channels[] = {
59+// 32, 34, 46, 48, 50, 52,
60+// 0, 1, 2, 4, 6, 8,
61+// 22, 24, 26, 28, 30,
62+// 74, 76, 78, 80
63+//};
64+
65+const byte bluetooth_channels[] = {
66+ 12, 17, 22, 27, 32,
67+ 37, 42, 47, 52, 57,
68+ 62, 67, 72
69+};
70+
71+volatile bool modeChangeRequested = false;
72+
73+unsigned long lastButtonPressTime = 0;
74+const unsigned long debounceDelay = 500;
75+
76+// =========================================
77+// NRF CONFIG
78+// =========================================
79+
80+void configureNrf(RF24 &radio) {
81+
82+ radio.begin(NRF_SPI);
83+
84+ radio.setAutoAck(false);
85+ radio.stopListening();
86+
87+ radio.setRetries(0, 0);
88+ radio.setPALevel(RF24_PA_MAX);
89+ radio.setDataRate(RF24_2MBPS);
90+
91+ radio.disableCRC();
92+}
93+
94+// =========================================
95+
96+void IRAM_ATTR handleButtonPress() {
97+
98+ unsigned long currentTime = millis();
99+
100+ if (currentTime - lastButtonPressTime > debounceDelay) {
101+ modeChangeRequested = true;
102+ lastButtonPressTime = currentTime;
103+ }
104+}
105+
106+// =========================================
107+
108+void configureRadio(RF24 &radio) {
109+
110+ configureNrf(radio);
111+
112+ radio.startConstCarrier(
113+ RF24_PA_MAX,
114+ 40
115+ );
116+}
117+
118+// =========================================
119+
120+void initializeRadios() {
121+
122+ if (currentMode == DEACTIVE_MODE) {
123+
124+ RadioA.powerDown();
125+ RadioB.powerDown();
126+
127+ return;
128+ }
129+
130+ configureRadio(RadioA);
131+ configureRadio(RadioB);
132+}
133+
134+// =========================================
135+
136+void updateOLED() {
137+
138+ u8g2.clearBuffer();
139+
140+ u8g2.setFont(u8g2_font_6x10_tr);
141+
142+ u8g2.setCursor(0, 12);
143+ u8g2.print("Mode:");
144+
145+ u8g2.setCursor(50, 12);
146+
147+ if (currentMode == BLE_MODULE) {
148+ u8g2.print("BLE");
149+ }
150+ else if (currentMode == Bluetooth_MODULE) {
151+ u8g2.print("BT");
152+ }
153+ else {
154+ u8g2.print("OFF");
155+ }
156+
157+ u8g2.setCursor(0, 30);
158+ u8g2.print("R1:");
159+ u8g2.print(RadioA.isChipConnected());
160+
161+ u8g2.setCursor(0, 45);
162+ u8g2.print("R2:");
163+ u8g2.print(RadioB.isChipConnected());
164+
165+ u8g2.setCursor(0, 60);
166+ u8g2.print("R3:");
167+
168+ u8g2.sendBuffer();
169+}
170+
171+// =========================================
172+
173+void checkModeChange() {
174+
175+ if (!modeChangeRequested)
176+ return;
177+
178+ modeChangeRequested = false;
179+
180+ currentMode =
181+ static_cast<OperationMode>(
182+ (currentMode + 1) % 3
183+ );
184+
185+ initializeRadios();
186+
187+ updateOLED();
188+}
189+
190+// =========================================
191+// SETUP
192+// =========================================
193+
194+void setup() {
195+
196+ Serial.begin(115200);
197+
198+ // Disable ESP32 radios
199+ esp_bt_controller_deinit();
200+
201+ WiFi.mode(WIFI_OFF);
202+ btStop();
203+
204+ // SPI
205+ NRF_SPI = new SPIClass(FSPI);
206+
207+ NRF_SPI->begin(
208+ NRF_SCK,
209+ NRF_MISO,
210+ NRF_MOSI
211+ );
212+
213+ // OLED
214+ u8g2.begin();
215+
216+ // Button
217+ pinMode(BTN_UP, INPUT_PULLUP);
218+
219+ attachInterrupt(
220+ digitalPinToInterrupt(BTN_UP),
221+ handleButtonPress,
222+ FALLING
223+ );
224+
225+ initializeRadios();
226+
227+ updateOLED();
228+
229+ Serial.println("Jammer initialized");
230+}
231+
232+// =========================================
233+// LOOP
234+// =========================================
235+
236+void loop() {
237+
238+ checkModeChange();
239+
240+ if (currentMode == BLE_MODULE) {
241+
242+ byte channel =
243+ ble_channels[
244+ random(
245+ sizeof(ble_channels)
246+ )
247+ ];
248+
249+ RadioA.setChannel(channel);
250+ RadioB.setChannel(channel);
251+ }
252+
253+ else if (currentMode == Bluetooth_MODULE) {
254+
255+ byte channel =
256+ bluetooth_channels[
257+ random(
258+ sizeof(bluetooth_channels)
259+ )
260+ ];
261+
262+ RadioA.setChannel(channel);
263+ RadioB.setChannel(channel);
264+ }
265+
266+ delay(5);
267+}