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 ISO14443A_CL_UID_OFFSET 0
29 #define ISO14443A_CL_UID_SIZE 4
30 #define ISO14443A_CL_BCC_OFFSET 4
31 #define ISO14443A_CL_BCC_SIZE 1 /* Byte */
32 #define ISO14443A_CL_FRAME_SIZE ((ISO14443A_CL_UID_SIZE + ISO14443A_CL_BCC_SIZE) * 8) /* UID[N...N+3] || BCCN */
33 #define ISO14443A_SAK_INCOMPLETE 0x04
34 #define ISO14443A_SAK_COMPLETE_COMPLIANT 0x20
35 #define ISO14443A_SAK_COMPLETE_NOT_COMPLIANT 0x00
36 
37 #define ISO14443A_ATQA_FRAME_SIZE (2 * 8) /* Bit */
38 #define ISO14443A_SAK_FRAME_SIZE (3 * 8) /* Bit */
39 
40 #define ISO14443A_UID0_RANDOM 0x08
41 #define ISO14443A_UID0_CT 0x88
42 
43 #define ISO14443A_CRCA_SIZE 2
44 
45 #define ISO14443A_CALC_BCC(ByteBuffer) \
46  ( ByteBuffer[0] ^ ByteBuffer[1] ^ ByteBuffer[2] ^ ByteBuffer[3] )
47 
48 void ISO14443AAppendCRCA(void* Buffer, uint16_t ByteCount);
49 bool ISO14443ACheckCRCA(const void* Buffer, uint16_t ByteCount);
50 
51 INLINE bool ISO14443ASelect(void* Buffer, uint16_t* BitCount, uint8_t* UidCL, uint8_t SAKValue);
52 INLINE bool ISO14443AWakeUp(void* Buffer, uint16_t* BitCount, uint16_t ATQAValue, bool FromHalt);
53 
54 INLINE
55 bool ISO14443ASelect(void* Buffer, uint16_t* BitCount, uint8_t* UidCL, uint8_t SAKValue)
56 {
57  uint8_t* DataPtr = (uint8_t*) Buffer;
58  uint8_t NVB = DataPtr[1];
59  //uint8_t CollisionByteCount = (NVB >> 4) & 0x0F;
60  //uint8_t CollisionBitCount = (NVB >> 0) & 0x0F;
61 
62  switch (NVB) {
63  case ISO14443A_NVB_AC_START:
64  /* Start of anticollision procedure.
65  * Send whole UID CLn + BCC */
66  DataPtr[0] = UidCL[0];
67  DataPtr[1] = UidCL[1];
68  DataPtr[2] = UidCL[2];
69  DataPtr[3] = UidCL[3];
70  DataPtr[4] = ISO14443A_CALC_BCC(DataPtr);
71 
72  *BitCount = ISO14443A_CL_FRAME_SIZE;
73 
74  return false;
75 
76  case ISO14443A_NVB_AC_END:
77  /* End of anticollision procedure.
78  * Send SAK CLn if we are selected. */
79  if ( (DataPtr[2] == UidCL[0]) &&
80  (DataPtr[3] == UidCL[1]) &&
81  (DataPtr[4] == UidCL[2]) &&
82  (DataPtr[5] == UidCL[3]) ) {
83 
84  DataPtr[0] = SAKValue;
85  ISO14443AAppendCRCA(Buffer, 1);
86 
87  *BitCount = ISO14443A_SAK_FRAME_SIZE;
88  return true;
89  } else {
90  /* We have not been selected. Don't send anything. */
91  *BitCount = 0;
92  return false;
93  }
94  default:
95  {
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  {
108  DataPtr[0] = UidCL[0];
109  DataPtr[1] = UidCL[1];
110  DataPtr[2] = UidCL[2];
111  DataPtr[3] = UidCL[3];
112  DataPtr[4] = ISO14443A_CALC_BCC(DataPtr);
113 
114  *BitCount = ISO14443A_CL_FRAME_SIZE;
115  } else {
116  *BitCount = 0;
117  }
118  return false;
119  }
120  /* TODO: No anticollision supported */
121  *BitCount = 0;
122  return false;
123  }
124 }
125 
126 INLINE
127 bool ISO14443AWakeUp(void* Buffer, uint16_t* BitCount, uint16_t ATQAValue, bool FromHalt)
128 {
129  uint8_t* DataPtr = (uint8_t*) Buffer;
130 
131  if ( ((! FromHalt) && (DataPtr[0] == ISO14443A_CMD_REQA)) ||
132  (DataPtr[0] == ISO14443A_CMD_WUPA) ){
133  DataPtr[0] = (ATQAValue >> 0) & 0x00FF;
134  DataPtr[1] = (ATQAValue >> 8) & 0x00FF;
135 
136  *BitCount = ISO14443A_ATQA_FRAME_SIZE;
137 
138  return true;
139  } else {
140  *BitCount = 0;
141 
142  return false;
143  }
144 }
145 
146 #endif