Chameleon-Mini
ISO14443-3A.h
1 /*
2  * ISO14443-2A.h
3  *
4  * Created on: 19.03.2013
5  * Author: skuser
6  */
7 
8 #ifndef ISO14443_3A_H_
9 #define ISO14443_3A_H_
10 
11 #include "../Common.h"
12 #include <string.h>
13 
14 #define ISO14443A_UID_SIZE_SINGLE 4 /* bytes */
15 #define ISO14443A_UID_SIZE_DOUBLE 7
16 #define ISO14443A_UID_SIZE_TRIPLE 10
17 
18 #define ISO14443A_CMD_REQA 0x26
19 #define ISO14443A_CMD_WUPA 0x52
20 #define ISO14443A_CMD_SELECT_CL1 0x93
21 #define ISO14443A_CMD_SELECT_CL2 0x95
22 #define ISO14443A_CMD_SELECT_CL3 0x97
23 #define ISO14443A_CMD_HLTA 0x50
24 
25 #define ISO14443A_NVB_AC_START 0x20
26 #define ISO14443A_NVB_AC_END 0x70
27 
28 #define IsSelectCmd(Buffer) ((Buffer[0] == ISO14443A_CMD_SELECT_CL1) || \
29  (Buffer[0] == ISO14443A_CMD_SELECT_CL2) || \
30  (Buffer[0] == ISO14443A_CMD_SELECT_CL3))
31 #define IsCmdSelectRound1(Buffer) (IsSelectCmd(Buffer) && (Buffer[1] == ISO14443A_NVB_AC_START))
32 #define IsCmdSelectRound2(Buffer) (IsSelectCmd(Buffer) && (Buffer[1] == ISO14443A_NVB_AC_END))
33 
34 #define ISO14443A_CL_UID_OFFSET 0
35 #define ISO14443A_CL_UID_SIZE 4
36 #define ISO14443A_CL_BCC_OFFSET 4
37 #define ISO14443A_CL_BCC_SIZE 1 /* Byte */
38 #define ISO14443A_CL_FRAME_SIZE ((ISO14443A_CL_UID_SIZE + ISO14443A_CL_BCC_SIZE) * 8) /* UID[N...N+3] || BCCN */
39 #define ISO14443A_SAK_INCOMPLETE 0x24 // 0x04
40 #define ISO14443A_SAK_COMPLETE_COMPLIANT 0x20
41 #define ISO14443A_SAK_COMPLETE_NOT_COMPLIANT 0x00
42 
43 #define ISO14443A_ATQA_FRAME_SIZE_BYTES (2) /* in Bytes */
44 #define ISO14443A_ATQA_FRAME_SIZE (2 * BITS_PER_BYTE) /* in Bits */
45 #define ISO14443A_SAK_FRAME_SIZE (3 * BITS_PER_BYTE) /* in Bits */
46 #define ISO14443A_HLTA_FRAME_SIZE (2 * BITS_PER_BYTE) /* in Bits */
47 
48 #define ISO14443A_UID0_RANDOM 0x08
49 #define ISO14443A_UID0_CT 0x88
50 
51 #define ISO14443A_CRCA_SIZE 2
52 
53 #define ISO14443A_CALC_BCC(ByteBuffer) \
54  ( ByteBuffer[0] ^ ByteBuffer[1] ^ ByteBuffer[2] ^ ByteBuffer[3] )
55 
56 void ISO14443AAppendCRCA(void *Buffer, uint16_t ByteCount);
57 bool ISO14443ACheckCRCA(const void *Buffer, uint16_t ByteCount);
58 
59 INLINE bool ISO14443ASelect(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, uint8_t SAKValue);
60 INLINE bool ISO14443AWakeUp(void *Buffer, uint16_t *BitCount, uint16_t ATQAValue, bool FromHalt);
61 
62 INLINE
63 bool ISO14443ASelect(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, uint8_t SAKValue) {
64  uint8_t *DataPtr = (uint8_t *) Buffer;
65  uint8_t NVB = DataPtr[1];
66 
67  switch (NVB) {
68  case ISO14443A_NVB_AC_START:
69  /* Start of anticollision procedure.
70  * Send whole UID CLn + BCC */
71  DataPtr[0] = UidCL[0];
72  DataPtr[1] = UidCL[1];
73  DataPtr[2] = UidCL[2];
74  DataPtr[3] = UidCL[3];
75  DataPtr[4] = ISO14443A_CALC_BCC(DataPtr);
76  *BitCount = ISO14443A_CL_FRAME_SIZE;
77  return false;
78 
79  case ISO14443A_NVB_AC_END:
80  /* End of anticollision procedure.
81  * Send SAK CLn if we are selected. */
82  if ((DataPtr[2] == UidCL[0]) &&
83  (DataPtr[3] == UidCL[1]) &&
84  (DataPtr[4] == UidCL[2]) &&
85  (DataPtr[5] == UidCL[3])) {
86  DataPtr[0] = SAKValue;
87  ISO14443AAppendCRCA(Buffer, 1);
88  *BitCount = ISO14443A_SAK_FRAME_SIZE;
89  return true;
90  } else {
91  /* We have not been selected. Don't send anything. */
92  *BitCount = 0;
93  return false;
94  }
95  default: {
96  uint8_t CollisionByteCount = ((NVB >> 4) & 0x0f) - 2;
97  uint8_t CollisionBitCount = (NVB >> 0) & 0x0f;
98  uint8_t mask = 0xFF >> (8 - CollisionBitCount);
99  // Since the UidCL does not contain the BCC, we have to distinguish here
100  if (
101  ((CollisionByteCount == 5 || (CollisionByteCount == 4 && CollisionBitCount > 0)) && memcmp(UidCL, &DataPtr[2], 4) == 0 && (ISO14443A_CALC_BCC(UidCL) & mask) == (DataPtr[6] & mask))
102  ||
103  (CollisionByteCount == 4 && CollisionBitCount == 0 && memcmp(UidCL, &DataPtr[2], 4) == 0)
104  ||
105  (CollisionByteCount < 4 && memcmp(UidCL, &DataPtr[2], CollisionByteCount) == 0 && (UidCL[CollisionByteCount] & mask) == (DataPtr[CollisionByteCount + 2] & mask))
106  ) {
107  DataPtr[0] = UidCL[0];
108  DataPtr[1] = UidCL[1];
109  DataPtr[2] = UidCL[2];
110  DataPtr[3] = UidCL[3];
111  DataPtr[4] = ISO14443A_CALC_BCC(DataPtr);
112 
113  *BitCount = ISO14443A_CL_FRAME_SIZE;
114  } else {
115  *BitCount = 0;
116  }
117  return false;
118  }
119  /* TODO: No anticollision supported */
120  *BitCount = 0;
121  return false;
122  }
123 }
124 
125 #ifdef CONFIG_MF_DESFIRE_SUPPORT
126 bool ISO14443ASelectDesfire(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, uint8_t SAKValue);
127 #endif
128 
129 INLINE
130 bool ISO14443AWakeUp(void *Buffer, uint16_t *BitCount, uint16_t ATQAValue, bool FromHalt) {
131  uint8_t *DataPtr = (uint8_t *) Buffer;
132 
133  if (((! FromHalt) && (DataPtr[0] == ISO14443A_CMD_REQA)) ||
134  (DataPtr[0] == ISO14443A_CMD_WUPA)) {
135  DataPtr[0] = (ATQAValue >> 0) & 0x00FF;
136  DataPtr[1] = (ATQAValue >> 8) & 0x00FF;
137 
138  *BitCount = ISO14443A_ATQA_FRAME_SIZE;
139 
140  return true;
141  } else {
142  *BitCount = 0;
143 
144  return false;
145  }
146 }
147 
148 #endif