+// performs iso14443a anticollision (optional) and card select procedure
+// fills the uid and cuid pointer unless NULL
+// fills the card info record unless NULL
+// if anticollision is false, then the UID must be provided in uid_ptr[]
+// and num_cascades must be set (1: 4 Byte UID, 2: 7 Byte UID, 3: 10 Byte UID)
+// requests ATS unless no_rats is true
+int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats) {
+ uint8_t sel_all[] = { 0x93,0x20 };
+ uint8_t sel_uid[] = { 0x93,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+ uint8_t rats[] = { 0xE0,0x80,0x00,0x00 }; // FSD=256, FSDI=8, CID=0
+ uint8_t resp[MAX_FRAME_SIZE]; // theoretically. A usual RATS will be much smaller
+ uint8_t resp_par[MAX_PARITY_SIZE];
+ byte_t uid_resp[4];
+ size_t uid_resp_len;
+
+ uint8_t sak = 0x04; // cascade uid
+ int cascade_level = 0;
+ int len;
+
+ // init card struct
+ if(p_hi14a_card) {
+ p_hi14a_card->uidlen = 0;
+ memset(p_hi14a_card->uid, 0, 10);
+ p_hi14a_card->ats_len = 0;
+ }
+
+ if (!GetATQA(resp, resp_par)) {
+ return 0;
+ }
+
+ if(p_hi14a_card) {
+ memcpy(p_hi14a_card->atqa, resp, 2);
+ }
+
+ if (anticollision) {
+ // clear uid
+ if (uid_ptr) {
+ memset(uid_ptr,0,10);
+ }
+ }
+
+ // check for proprietary anticollision:
+ if ((resp[0] & 0x1F) == 0) {
+ return 3;
+ }
+
+ // OK we will select at least at cascade 1, lets see if first byte of UID was 0x88 in
+ // which case we need to make a cascade 2 request and select - this is a long UID
+ // While the UID is not complete, the 3nd bit (from the right) is set in the SAK.
+ for(; sak & 0x04; cascade_level++) {
+ // SELECT_* (L1: 0x93, L2: 0x95, L3: 0x97)
+ sel_uid[0] = sel_all[0] = 0x93 + cascade_level * 2;
+
+ if (anticollision) {
+ // SELECT_ALL
+ ReaderTransmit(sel_all, sizeof(sel_all), NULL);
+ if (!ReaderReceive(resp, resp_par)) return 0;
+
+ if (Demod.collisionPos) { // we had a collision and need to construct the UID bit by bit
+ memset(uid_resp, 0, 4);
+ uint16_t uid_resp_bits = 0;
+ uint16_t collision_answer_offset = 0;
+ // anti-collision-loop:
+ while (Demod.collisionPos) {
+ Dbprintf("Multiple tags detected. Collision after Bit %d", Demod.collisionPos);
+ for (uint16_t i = collision_answer_offset; i < Demod.collisionPos; i++, uid_resp_bits++) { // add valid UID bits before collision point
+ uint16_t UIDbit = (resp[i/8] >> (i % 8)) & 0x01;
+ uid_resp[uid_resp_bits / 8] |= UIDbit << (uid_resp_bits % 8);
+ }
+ uid_resp[uid_resp_bits/8] |= 1 << (uid_resp_bits % 8); // next time select the card(s) with a 1 in the collision position
+ uid_resp_bits++;
+ // construct anticollosion command:
+ sel_uid[1] = ((2 + uid_resp_bits/8) << 4) | (uid_resp_bits & 0x07); // length of data in bytes and bits
+ for (uint16_t i = 0; i <= uid_resp_bits/8; i++) {
+ sel_uid[2+i] = uid_resp[i];
+ }
+ collision_answer_offset = uid_resp_bits%8;
+ ReaderTransmitBits(sel_uid, 16 + uid_resp_bits, NULL);
+ if (!ReaderReceiveOffset(resp, collision_answer_offset, resp_par)) return 0;
+ }
+ // finally, add the last bits and BCC of the UID
+ for (uint16_t i = collision_answer_offset; i < (Demod.len-1)*8; i++, uid_resp_bits++) {
+ uint16_t UIDbit = (resp[i/8] >> (i%8)) & 0x01;
+ uid_resp[uid_resp_bits/8] |= UIDbit << (uid_resp_bits % 8);
+ }
+
+ } else { // no collision, use the response to SELECT_ALL as current uid
+ memcpy(uid_resp, resp, 4);
+ }
+ } else {
+ if (cascade_level < num_cascades - 1) {
+ uid_resp[0] = 0x88;
+ memcpy(uid_resp+1, uid_ptr+cascade_level*3, 3);
+ } else {
+ memcpy(uid_resp, uid_ptr+cascade_level*3, 4);
+ }
+ }
+ uid_resp_len = 4;
+
+ // calculate crypto UID. Always use last 4 Bytes.
+ if(cuid_ptr) {
+ *cuid_ptr = bytes_to_num(uid_resp, 4);
+ }
+
+ // Construct SELECT UID command
+ sel_uid[1] = 0x70; // transmitting a full UID (1 Byte cmd, 1 Byte NVB, 4 Byte UID, 1 Byte BCC, 2 Bytes CRC)
+ memcpy(sel_uid+2, uid_resp, 4); // the UID received during anticollision, or the provided UID
+ sel_uid[6] = sel_uid[2] ^ sel_uid[3] ^ sel_uid[4] ^ sel_uid[5]; // calculate and add BCC
+ AppendCrc14443a(sel_uid, 7); // calculate and add CRC
+ ReaderTransmit(sel_uid, sizeof(sel_uid), NULL);
+
+ // Receive the SAK
+ if (!ReaderReceive(resp, resp_par)) return 0;
+ sak = resp[0];
+
+ // Test if more parts of the uid are coming
+ if ((sak & 0x04) /* && uid_resp[0] == 0x88 */) {
+ // Remove first byte, 0x88 is not an UID byte, it CT, see page 3 of:
+ // http://www.nxp.com/documents/application_note/AN10927.pdf
+ uid_resp[0] = uid_resp[1];
+ uid_resp[1] = uid_resp[2];
+ uid_resp[2] = uid_resp[3];
+ uid_resp_len = 3;
+ }
+
+ if(uid_ptr && anticollision) {
+ memcpy(uid_ptr + (cascade_level*3), uid_resp, uid_resp_len);
+ }
+
+ if(p_hi14a_card) {
+ memcpy(p_hi14a_card->uid + (cascade_level*3), uid_resp, uid_resp_len);
+ p_hi14a_card->uidlen += uid_resp_len;
+ }
+ }
+
+ if(p_hi14a_card) {
+ p_hi14a_card->sak = sak;
+ }
+
+ // PICC compilant with iso14443a-4 ---> (SAK & 0x20 != 0)
+ if( (sak & 0x20) == 0) return 2;
+
+ if (!no_rats) {
+ // Request for answer to select
+ AppendCrc14443a(rats, 2);
+ ReaderTransmit(rats, sizeof(rats), NULL);
+
+ if (!(len = ReaderReceive(resp, resp_par))) return 0;
+
+ if(p_hi14a_card) {
+ memcpy(p_hi14a_card->ats, resp, len);
+ p_hi14a_card->ats_len = len;
+ }
+
+ // reset the PCB block number
+ iso14_pcb_blocknum = 0;
+
+ // set default timeout and delay next transfer based on ATS
+ iso14a_set_ATS_times(resp);
+
+ }
+ return 1;
+}
+
+
+void iso14443a_setup(uint8_t fpga_minor_mode) {
+ FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
+ // Set up the synchronous serial port
+ FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO14443A);
+ // connect Demodulated Signal to ADC: