BOOL q5_read_block(BYTE *response, BYTE block) { BYTE tmp[39], retry, reset= FALSE; if(block > Q5_DATABLOCKS - 1) return FALSE; // create 6 or 38 bit command block: Q5_DIRECT_ACCESS + PWD_Mode + [PWD] + 3 bits address memset(tmp, '\0', 39); memcpy(tmp, Q5_DIRECT_ACCESS, 2); if(PWD_Mode) { tmp[2]= '1'; hextobinstring(tmp + 3, Password); inttobinstring(tmp + 34, (unsigned int) block, 3); } else { tmp[2]= '0'; inttobinstring(tmp + 3, (unsigned int) block, 3); } retry= RFIDlerConfig.Repeat; while(retry--) { //DEBUG_PIN_4= !DEBUG_PIN_4; //DEBUG_PIN_4= !DEBUG_PIN_4; if(q5_send_command(response, tmp, strlen(tmp), reset, NO_SYNC, 32)) return TRUE; // try resetting tag reset= TRUE; } return FALSE; }
// optional verify as writing config block may casue next read to fail BOOL q5_write_block(BYTE block, BYTE *data, BOOL lock, BOOL verify) { BYTE tmp[71], p; if(block > Q5_DATABLOCKS - 1) return FALSE; // create 38 or 70 bit command block: Q5_STD_WRITE_P0 + [PWD] + Lock Bit + 32 bits Data + 3 bits address memset(tmp, '\0', sizeof(tmp)); // command memcpy(tmp, Q5_STD_WRITE_P0, 2); p= 2; // password if(PWD_Mode) { hextobinstring(tmp + p, Password); p += 32; } // lockbit inttobinstring(tmp + p, (unsigned int) lock, 1); ++p; // data hextobinstring(tmp + p, data); p += Q5_BLOCKSIZE; // address inttobinstring(tmp + p, (unsigned int) block, 3); p += 3; // send if(!q5_send_command(NULL, tmp, strlen(tmp), NO_RESET, NO_SYNC, 0)) return FALSE; // no ack, so read back and verify // delay for long enough to allow write plus TX->RX period Delay_us((Q5_WRITE_DELAY * RFIDlerConfig.FrameClock + RFIDlerConfig.RWD_Wait_Switch_TX_RX * RFIDlerConfig.FrameClock) / 100L); if(!verify) return TRUE; if(!q5_read_block(tmp, block)) return FALSE; if(memcmp(tmp, data, HEXDIGITS(Q5_BLOCKSIZE)) != 0) return FALSE; return TRUE; }
// read page - 32 bits // pages 2 - 15 are probably not readable! BOOL hitag1_read_page(BYTE *response, BYTE block) { BYTE tmp[HITAG1_BLOCKSIZE + 6]; // 32 bits plus 6 sync bits if(block > HITAG1_DATABLOCKS - 1) return FALSE; // get tag's UID for select command if(!hitag1_get_uid(tmp)) return FALSE; // select for read/write hitag1_select(tmp, tmp); // create 12 bit command block: HITAG1_RDPPAGE + 8 bits address strcpy(tmp, HITAG1_RDPPAGE); inttobinstring(tmp + 4, (unsigned int) block, 8); tmp[12]= '\0'; // ??? docs say 6 sync bits! if(!hitag1_send_command(tmp, tmp, NO_RESET, NO_SYNC, HITAG1_BLOCKSIZE + 1, NO_ACK)) return FALSE; // check sync if(tmp[0] != 0x01) return FALSE; binarraytohex(response, tmp + 1, HITAG1_BLOCKSIZE); return TRUE; }
BOOL hitag1_write_page(BYTE block, BYTE *data) { BYTE crc, command[21], tmp[33], tmp1[4]; if(block > HITAG1_DATABLOCKS - 1) return FALSE; // get tag's UID for select command if(!hitag1_get_uid(tmp)) return FALSE; // select for read/write hitag1_select(tmp, tmp); // convert data to binstring for send if(hextobinstring(tmp, data) != 32) return FALSE; // create and send 12 bit command block: HITAG1_WRPPAGE (4 bits) + 8 bit address memcpy(command, HITAG1_WRPPAGE, 4); inttobinstring(command + 4, (unsigned int) block, 8); command[12]= '\0'; if(!hitag1_send_command(tmp1, command, NO_RESET, NO_SYNC, 0, ACK)) return FALSE; // delay to switch back to write mode Delay_us((RFIDlerConfig.RWD_Wait_Switch_RX_TX * RFIDlerConfig.FrameClock) / 100); // now send data if(!hitag1_send_command(tmp1, tmp, NO_RESET, NO_SYNC, 0, ACK)) return FALSE; // read back and verify // delay for long enough to allow write plus RX->TX period Delay_us((HITAG1_WRITE_DELAY * RFIDlerConfig.FrameClock + RFIDlerConfig.RWD_Wait_Switch_RX_TX * RFIDlerConfig.FrameClock) / 100); if(!hitag1_read_page(tmp, block)) return FALSE; if(memcmp(tmp, data, 8) != 0) return FALSE; return TRUE; }
BOOL hitag2_read_page(BYTE *response, BYTE block) { BYTE tmp[37]; if(block > HITAG2_DATABLOCKS - 1) return FALSE; // create 10 bit command block: HITAG2_READ_PAGE + 3 bits address + invert(HITAG2_READ_PAGE + 3 bits address) memcpy(tmp, HITAG2_READ_PAGE, 2); inttobinstring(tmp + 2, (unsigned int) block, 3); invertbinstring(tmp + 5, tmp); tmp[10]= '\0'; // encrypt command if in crypto mode if(CryptoActive) hitag2_binstring_crypt(tmp, tmp); // send with RX->TX delay and no reset if(!rwd_send(tmp, strlen(tmp), NO_RESET, BLOCK, RWD_STATE_WAKING, RFIDlerConfig.FrameClock, 0, RFIDlerConfig.RWD_Wait_Switch_RX_TX, RFIDlerConfig.RWD_Zero_Period, RFIDlerConfig.RWD_One_Period, RFIDlerConfig.RWD_Gap_Period, RFIDlerConfig.RWD_Wait_Switch_TX_RX)) return FALSE; // skip 1/2 bit to synchronise manchester HW_Skip_Bits= 1; if(read_ask_data(RFIDlerConfig.FrameClock, RFIDlerConfig.DataRate, tmp, 37, RFIDlerConfig.Sync, RFIDlerConfig.SyncBits, RFIDlerConfig.Timeout, ONESHOT_READ, BINARY) == 37) { // check sync bits if (memcmp(tmp, Hitag2Sync, 5) != 0) return FALSE; binarraytohex(response, tmp + 5, 32); // decrypt if(CryptoActive) return hitag2_hex_crypt(response, response); return TRUE; } return FALSE; }
BOOL hitag2_write_page(BYTE block, BYTE *data) { BYTE command[11], tmp[37], tmp1[37], tmp2[37], tmphex[9]; if(block > HITAG2_DATABLOCKS - 1) return FALSE; // create 10 bit command block: HITAG2_WRIE_PAGE + 3 bits address + invert(HITAG2_WRITE_PAGE + 3 bits address) memcpy(command, HITAG2_WRITE_PAGE, 2); inttobinstring(command + 2, (unsigned int) block, 3); invertbinstring(command + 5, command); command[10]= '\0'; // encrypt command if in crypto mode if(CryptoActive) hitag2_binstring_crypt(tmp, command); else memcpy(tmp, command, 11); // convert data to binstring for send if(hextobinstring(tmp1, data) != 32) return FALSE; // send command with RX->TX delay and no reset if(!rwd_send(tmp, strlen(tmp), NO_RESET, BLOCK, RWD_STATE_WAKING, RFIDlerConfig.FrameClock, 0, RFIDlerConfig.RWD_Wait_Switch_RX_TX, RFIDlerConfig.RWD_Zero_Period, RFIDlerConfig.RWD_One_Period, RFIDlerConfig.RWD_Gap_Period, RFIDlerConfig.RWD_Wait_Switch_TX_RX)) return FALSE; // skip 1/2 bit to synchronise manchester HW_Skip_Bits= 1; // get ACK - 10 bytes + sync if(read_ask_data(RFIDlerConfig.FrameClock, RFIDlerConfig.DataRate, tmp2, 15, RFIDlerConfig.Sync, RFIDlerConfig.SyncBits, RFIDlerConfig.Timeout, ONESHOT_READ, BINARY) == 15) { // check sync bits if (memcmp(tmp2, Hitag2Sync, 5) != 0) return FALSE; // decrypt if(CryptoActive) hitag2_binarray_crypt(tmp2 + 5, tmp2 + 5, 10); // check ACK - should be our original command echo'd back binarraytobinstring(tmp2 + 5, tmp2 + 5, 10); if(memcmp(command, tmp2 + 5, 10) != 0) return FALSE; } // encrypt data if in crypto mode if(CryptoActive) hitag2_binstring_crypt(tmp1, tmp1); // send data with RX->TX delay and no reset if(!rwd_send(tmp1, strlen(tmp1), NO_RESET, BLOCK, RWD_STATE_WAKING, RFIDlerConfig.FrameClock, 0, RFIDlerConfig.RWD_Wait_Switch_RX_TX, RFIDlerConfig.RWD_Zero_Period, RFIDlerConfig.RWD_One_Period, RFIDlerConfig.RWD_Gap_Period, RFIDlerConfig.RWD_Wait_Switch_TX_RX)) return FALSE; // no ack, so read back and verify // delay for long enough to allow write plus RX->TX period Delay_us((HITAG2_WRITE_DELAY * RFIDlerConfig.FrameClock + RFIDlerConfig.RWD_Wait_Switch_RX_TX * RFIDlerConfig.FrameClock) / 100); if(!hitag2_read_page(tmp, block)) return FALSE; if(memcmp(tmp, data, 8) != 0) return FALSE; return TRUE; }