-
Notifications
You must be signed in to change notification settings - Fork 1
/
CLRC663.cpp
198 lines (169 loc) · 8.63 KB
/
CLRC663.cpp
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
#include <Arduino.h>
#include <Wire.h>
#include "CLRC663.h"
Clrc663::Clrc663(uint8_t address) : addr(address)
{
}
uint8_t Clrc663::read_reg(Reg reg)
{
Wire.beginTransmission(addr);
Wire.write(reg);
Wire.endTransmission();
Wire.requestFrom(addr, (uint8_t)1);
return Wire.read();
}
void Clrc663::write_reg(Reg reg, uint8_t val)
{
Wire.beginTransmission(addr);
Wire.write(reg);
Wire.write(val);
Wire.endTransmission();
}
void Clrc663::irq_wait(uint8_t irq0en, uint8_t irq1en)
{
write_reg(IRQ0En, irq0en);
write_reg(IRQ1En, irq1en);
while (!(read_reg(IRQ1) & 0x40)); //Wait untill global interrupt set
write_reg(IRQ0En, 0x00);
write_reg(IRQ1En, 0x00);
}
void Clrc663::iso_14443A_init()
{
//> Configure Timers
write_reg(T0Control, 0x98); //Starts at the end of Tx. Stops after Rx of first data. Auto-reloaded. 13.56 MHz input clock.
write_reg(T1Control, 0x92); //Starts at the end of Tx. Stops after Rx of first data. Input clock - cascaded with Timer-0.
write_reg(T2Control, 0x20); //Set Timer-2, T2Control_Reg: Timer used for LFO trimming
write_reg(T2ReloadHi, 0x03); //Set Timer-2 reload value (T2ReloadHi_Reg and T2ReloadLo_Reg)
write_reg(T2ReloadLo, 0xFF); //
write_reg(T3Control, 0x00); // Not started automatically. Not reloaded. Input clock 13.56 MHz
write_reg(FIFOControl, 0x10);
write_reg(WaterLevel, 0xFE); //Set WaterLevel =(FIFO length -1),cause fifo length has been set to 255=0xff,so water level is oxfe
write_reg(RxBitCtrl, 0x80); //RxBitCtrl_Reg(0x0c) Received bit after collision are replaced with 1.
write_reg(DrvMod, 0x80); //DrvMod reg(0x28), Tx2Inv=1,Inverts transmitter 1 at TX1 pin
write_reg(TxAmp, 0x00); // TxAmp_Reg(0x29),output amplitude 0: TVDD -100 mV(maxmum)
write_reg(DrvCon, 0x01); // TxCon register (address 2Ah),TxEnvelope
write_reg(Txl, 0x05); //
write_reg(RxSofD, 0x00); //
write_reg(Rcv, 0x12); //
//> =============================================
//> LoadProtocol( bTxProtocol=0, bRxProtocol=0)
//> =============================================
write_reg(Command, Idle); // Terminate any running command.
write_reg(FIFOControl, 0xB0); // Flush_FiFo,low alert
write_reg(IRQ0, 0x7F); // Clear all IRQ 0,1 flags
write_reg(IRQ1, 0x7F); //
//> Write in Fifo: Tx and Rx protocol numbers(0,0)
write_reg(FIFOData, 0x00); //
write_reg(FIFOData, 0x00); //
write_reg(Command, LoadProtocol); // Start RC663 command "Load Protocol"=0x0d
irq_wait(0x10, 0x00); // Wait for idle interrupt meaning the command has finished
write_reg(FIFOControl, 0xB0); // Flush_FiFo
// Apply RegisterSet
//
//> Configure CRC-16 calculation, preset value(0x6363) for Tx&Rx
write_reg(TxCrcPreset, 0x18); //means preset value is 6363,and uses CRC 16,but CRC is not automaticlly apended to the data
write_reg(RxCrcPreset, 0x18); //
write_reg(TxDataNum, 0x08); //
write_reg(TxModWidth, 0x20); // Length of the pulse modulation in carrier clks+1
write_reg(TxSym10BurstLen, 0x00); // Symbol 1 and 0 burst lengths = 8 bits.
write_reg(FrameCon, 0xCF); // Start symbol=Symbol2, Stop symbol=Symbol3
write_reg(RxCtrl, 0x04); // Set Rx Baudrate 106 kBaud
write_reg(RxThreshold, 0x32); // Set min-levels for Rx and phase shift
write_reg(RxAna, 0x00);
write_reg(RxWait, 0x90); // Set Rx waiting time
write_reg(TXWaitCtrl, 0xC0);
write_reg(TxWaitLo, 0x0B);
write_reg(T0ReloadHi, 0x08); // Set Timeout. Write T0,T1 reload values(hi,Low)
write_reg(T0ReloadLo, 0xD8);
write_reg(T1ReloadHi, 0x00);
write_reg(T1ReloadLo, 0x00);
write_reg(DrvMod, 0x81); // Write DrvMod register
//> MIFARE Crypto1 state is further disabled.
write_reg(Status, 0x00);
}
void Clrc663::transmit_enable(bool enable)
{
write_reg(DrvMod, enable ? 0x89 : 0x81);
}
int Clrc663::iso_14443A_reqa(uint8_t *atqa)
{
atqa[0] = 0;
atqa[1] = 0;
//> =============================================
//> I14443p3a_Sw_RequestA
//> =============================================
write_reg(TXWaitCtrl, 0xC0); // TxWaitStart at the end of Rx data
write_reg(TxWaitLo, 0x0B); // Set min.time between Rx and Tx or between two Tx
write_reg(T0ReloadHi, 0x08); //> Set timeout for this command cmd. Init reload values for timers-0,1
write_reg(T0ReloadLo, 0x94);
write_reg(T1ReloadHi, 0x00);
write_reg(T1ReloadLo, 0x00);
write_reg(RxWait, 0x90); // bit9,If set to 1, the RxWait time is RxWait x(0.5/DBFreq). bit0--bit6,Defines the time after sending, where every input is ignored
write_reg(TxDataNum, 0x0F);
//> ---------------------
//> Send the ReqA command
//> ---------------------
write_reg(Command, Idle); // Terminate any running command.
write_reg(FIFOControl, 0xB0); // Flush_FiFo
write_reg(IRQ0, 0x7F); // Clear all IRQ 0,1 flags
write_reg(IRQ1, 0x7F); //
delay(10);
write_reg(FIFOData, 0x26); //Write ReqA=26(wake up all the idle card ,not sleeping,0x52) into FIFO
write_reg(Command, Transceive); // Start RC663 command "Transcieve"=0x07. Activate Rx after Tx finishes.
irq_wait(0x18, 0x2); // Wait for idle, tx, or timer1, not sure why
uint8_t len = read_reg(FIFOLength); //read FIFO length
for (int i = 0; i < len; ++i) {
atqa[i] = read_reg(FIFOData); // Read FIFO, expecting: the two byte ATQA,we could tell from ATQA how long the UID is ,4、7、10 byte?,then decide wether to go through the subsquent anti-collision procedure
}
return len;
}
int Clrc663::iso_14443A_select(uint8_t *uid)
{
// Get UID, Apply cascade level-1
write_reg(TxDataNum, 0x08); //BIT3 If cleared - it is possible to send a single symbol pattern.If set - data is sent.
write_reg(RxBitCtrl, 0x00); //
write_reg(Command, Idle); // Terminate any running command.
write_reg(FIFOControl, 0xB0); // Flush_FiFo
write_reg(FIFOData, 0x93); //Write "Select" cmd into FIFO (SEL=93, NVB=20,cascade level-1)
write_reg(FIFOData, 0x20); //字节计数=2
write_reg(Command, Transceive); //Start tranceive command
irq_wait(0x18, 0x2); // Wait for idle, tx, or timer1, not sure why
uint8_t len = read_reg(FIFOLength);//read FIFO length
for (int i = 0; i < len; i++) {
uid[i] = read_reg(FIFOData); // Read FIFO,Expected - Complete UID (one PICC in HF)
}
//now we got UID ,we continue to use this UID to select the card
//this command needs CRC appended
write_reg(TxCrcPreset, 0x19); //preset value is6363,use crc16,crc is apended to the data stream
write_reg(RxCrcPreset, 0x19); //
write_reg(Command, Idle); // Terminate any running command.
write_reg(FIFOControl, 0xB0); // Flush_FiFo
write_reg(FIFOData, 0x93); //select
write_reg(FIFOData, 0x70); //字节计数=7
for (int i = 0; i < len; i++) {
write_reg(FIFOData, uid[i]); // Read FIFO,Expected - Complete UID (one PICC in HF)
}
write_reg(Command, Transceive); //Start tranceive command ,expecting to receive SAK ,select acknowlegement
irq_wait(0x18, 0x2); // Wait for idle, tx, or timer1, not sure why
uint8_t sak = read_reg(FIFOData); // Read FIFO,Expecting SAK,here wo should next level of anti-collision
//if SAK's bit2=1,then UID is not finished yet
//结束防冲突环.Here we assuming the UID is 4 bytes ,so just finish the anti-collision loop
return len; //sak & 0x02 ? -1 : 0;
}
int Clrc663::iso_14443A_rats(uint8_t *ats)
{
write_reg(TxCrcPreset, 0x19); //preset value is6363,use crc16,crc is apended to the data stream
write_reg(RxCrcPreset, 0x19); //
write_reg(Command, Idle); // Terminate any running command.
write_reg(FIFOControl, 0xB0); // Flush_FiFo
write_reg(FIFOData, 0xE0); //RATS,E0为命令,
write_reg(FIFOData, 0x80); //5为FSDI(5对应于64,8对应于256), 1为CID(card ID),为此卡在此次通信中的临时ID
write_reg(Command, Transceive); //Start tranceive command ,expecting to receive SAK ,select acknowlegement
irq_wait(0x18, 0x2); // Wait for idle, tx, or timer1, not sure why
uint8_t len = read_reg(FIFOLength);//read FIFO length
for (int i = 0; i < len; i++) {
ats[i] = read_reg(FIFOData); // Read FIFO,Expecting ATS,after receiving the ATS the PICC enters protocol state,ready to process APDUs
}
return len;
}
/* vim: set expandtab ts=2 sw=2: */