-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
rfid.hpp
211 lines (163 loc) · 7.49 KB
/
rfid.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
// SPDX-License-Identifier: GPL-3.0-or-later
//
// Copyright (c) 2019-2023 plan44.ch / Lukas Zeller, Zurich, Switzerland
//
// Author: Lukas Zeller <[email protected]>
//
// Based on code by Miguel Balboa (circuitito.com), Jan, 2012,
// "RFID.h - Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI W AND R BY COOQROBOT."
// which was based on code by Dr.Leong (WWW.B2CQSHOP.COM)
// and was modified by Paul Kourany to run on Spark Core with added support for Software SPI, Mar, 2014.
//
// This file is part of p44utils.
//
// p44utils is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// p44utils is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with p44utils. If not, see <http://www.gnu.org/licenses/>.
//
#ifndef rfid_hpp
#define rfid_hpp
#include "p44utils_main.hpp"
#ifndef ENABLE_RFID
#define ENABLE_RFID 1
#endif
#if ENABLE_RFID
#include <stdio.h>
#include "digitalio.hpp"
#include "spi.hpp"
#define DEFAULT_COMMAND_TIMEOUT (250*MilliSecond)
using namespace std;
namespace p44 {
class RFIDError : public Error
{
public:
// Errors
typedef enum {
OK,
ChipTimeout, ///< timeout
ChipErr, ///< chip error
UnknownCmd, ///< unknown command
BadAnswer, ///< bad answer (e.g. wrong number of bits, checksum error)
IRQTimeout, ///< IRQ timeout (irqHandler() not called soon enough)
} ErrorCodes;
static const char *domain() { return "RFID"; }
virtual const char *getErrorDomain() const { return RFIDError::domain(); };
RFIDError(ErrorCodes aError) : Error(ErrorCode(aError)) {};
};
class RFID522 : public P44LoggingObj
{
public:
/// @param aReaderIndex index of reader to select, RFID522::Deselect = none selected
typedef boost::function<void (int aReaderIndex)> SelectCB;
static const int Deselect = -1; ///< pseudo-index to deselect all readers
/// execPICCCmd result callback
typedef boost::function<void (ErrorPtr aErr, uint16_t aResultBits, const string aResult)> ExecResultCB;
private:
SPIDevicePtr mSpiDev;
int mReaderIndex;
SelectCB mReaderSelectFunc;
// execPICCCmd state
ExecResultCB mExecResultCB;
uint8_t mCmd; ///< the command being executed
uint8_t mIrqEn; ///< enabled IRQs
uint8_t mWaitIrq; ///< IRQs we are waiting for to terminate execPICCCmd
uint16_t mChipTimer; ///< the chip timer (preload) value to set
bool mUseIrqWatchdog;
MLTicket mIrqWatchdog;
MLMicroSeconds mCmdStart;
MLMicroSeconds mCmdTimeout;
public:
/// create RFID522 reader instance
/// @param aSPIGenericDev a generic SPI device for the bus this reader is connected to
/// @param aReaderIndex the selection address of this reader
/// @param aReaderSelectFunc will be called to select this particular reader by aSelectAddress
/// @param aChipTimer the chip timer (preload) value to set, 0 means using default
/// @param aUserIrqWatchdog if set, the IRQ watchdog is used
/// @param aCmdTimeout command timeout
RFID522(
SPIDevicePtr aSPIGenericDev, int aReaderIndex, SelectCB aReaderSelectFunc,
uint16_t aChipTimer = 0, bool aUseIrqWatchdog = false, MLMicroSeconds aCmdTimeout = DEFAULT_COMMAND_TIMEOUT
);
virtual ~RFID522();
/// @return the object type (used for context descriptions such as logging context)
virtual string contextType() const P44_OVERRIDE { return "RFID522"; };
/// @return the object type (used for context descriptions such as logging context)
virtual string contextId() const P44_OVERRIDE;
/// get this reader's index
int getReaderIndex() { return mReaderIndex; };
/// init this reader
/// @param aRegValPairs byte pairs of register addresses/values for extra initialisation
/// @return true if version register did return a sensible value, false when no or malfunctioning reader is connected
bool init(const string aRegValPairs);
void reset();
/// must be called when external IRQ line (possibly common to multiple readers) gets active
/// @return true if reader still waits for an interrupt
bool irqHandler();
/// check for Type A (MiFare) card
/// @param aStatusCB returns ok when there is a card, Error otherwise
/// @param aWait - repeat command until there is an answer from a card (ok or error), do not timeout
void probeTypeA(StatusCB aStatusCB, bool aWait = false);
/// run anticollision procedure and return card nUID
/// @param aResultCB returns card nUID as response or error
/// @param aStoreNUID if set, the winning card's nUID is stored for selecting later
void antiCollision(ExecResultCB aResultCB, bool aStoreNUID = false);
/// switch the energy field
void energyField(bool aEnable);
/// abort running command
void returnToIdle();
/// continue transceiving (e.g. probing)
void continueTransceiving();
private:
/// write single byte to a register
void writeReg(uint8_t aReg, uint8_t aVal);
/// write multiple bytes to FIFO data register
void writeFIFO(const uint8_t* aData, size_t aNumBytes);
/// read single byte from a register
uint8_t readReg(uint8_t aReg);
/// read multiple bytes from FIFO data register
void readFIFO(uint8_t* aData, size_t aNumBytes);
/// set some bits in a register (read-modify-write)
void setRegBits(uint8_t reg, uint8_t mask);
/// clear some bits in a register (read-modify-write)
void clrRegBits(uint8_t reg, uint8_t mask);
/// set the timeout timer
void setTimer(uint16_t aTimerReload);
/// execute PICC command
//void execPICCCmd(uint8_t aCmd, uint8_t *aTxDataP, uint8_t aTxBytes, uint8_t *aRxDataP, uint16_t &aRxBits);
void execPICCCmd(uint8_t aCmd, const string aTxData, uint8_t aBitFraming, ExecResultCB aResultCB);
// execPICCCmd helpers
void execResult(ErrorPtr aErr, uint16_t aResultBits = 0, const string aResult = "");
void commandTimeout();
void irqTimeout(MLTimer &aTimer);
/// Search for cards in field
/// @param aReqCmd - REQA, REQB, WUPA, WUPB
/// @param aWait - repeat command until there is an answer from a card (ok or error), do not timeout
/// @param aStatusCB called to report card (ATQx received: ok, error otherwise)
void requestPICC(uint8_t aReqCmd, bool aWait, StatusCB aStatusCB);
// requestPICC helper
void requestResponse(uint8_t aReqCmd, StatusCB aStatusCB, bool aWait, ErrorPtr aErr, uint16_t aResultBits, const string aResult);
// anticoll and readCardSerial helper
void anticollResponse(ExecResultCB aResultCB, bool aStoreNUID, ErrorPtr aErr, uint16_t aResultBits, const string aResult);
void calculateCRC(uint8_t *pIndata, uint8_t len, uint8_t *pOutData);
/*
uint8_t auth(uint8_t authMode, uint8_t BlockAddr, uint8_t *Sectorkey, uint8_t *serNum);
uint8_t read(uint8_t blockAddr, uint8_t *recvData);
uint8_t write(uint8_t blockAddr, uint8_t *writeData);
void halt();
*/
uint8_t serNum[5]; // the serial number.
uint8_t AserNum[5]; // the serial number of the current section.
};
typedef boost::intrusive_ptr<RFID522> RFID522Ptr;
} // namespace p44
#endif // ENABLE_RFID
#endif /* rfid_hpp */