+static void hitag_decode_frame_MC(int bitRate, int sofBits, byte_t* rx, size_t* rxlenOrg, int* response, int rawMod[], int rawLen) {
+ size_t rxlen = 0;
+ bool bSkip = true;
+ int lastbit = 1;
+ int tag_sof = 0;
+ int timing = 1;
+ if (bitRate == 8) {
+ timing = 2;
+ }
+
+ for (int i=0; i < rawLen; i++) {
+ int ra = rawMod[i];
+ if (ra >= HITAG_T_EOF) {
+ if (rxlen != 0) {
+ //DbpString("wierd1?");
+ }
+ tag_sof = sofBits;
+
+ // Capture the T0 periods that have passed since last communication or field drop (reset)
+ // We always recieve a 'one' first, which has the falling edge after a half period |-_|
+ *response = ra - HITAG_T_TAG_HALF_PERIOD;
+ } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF / timing) {
+ tag_sof=0;
+ // Manchester coding example |-_|_-|-_| (101)
+ rx[rxlen / 8] |= 0 << (7 - (rxlen % 8));
+ rxlen++;
+ rx[rxlen / 8] |= 1 << (7 - (rxlen % 8));
+ rxlen++;
+ } else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF / timing) {
+ tag_sof=0;
+ // Manchester coding example |_-|...|_-|-_| (0...01)
+ rx[rxlen / 8] |= 0 << (7 - (rxlen % 8));
+ rxlen++;
+ // We have to skip this half period at start and add the 'one' the second time
+ if (!bSkip) {
+ rx[rxlen / 8] |= 1 << (7 - (rxlen % 8));
+ rxlen++;
+ }
+ lastbit = !lastbit;
+ bSkip = !bSkip;
+ } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF / timing) {
+ // Manchester coding example |_-|_-| (00) or |-_|-_| (11)
+ if (tag_sof) {
+ // Ignore bits that are transmitted during SOF
+ tag_sof--;
+ } else {
+ // bit is same as last bit
+ rx[rxlen / 8] |= lastbit << (7 - (rxlen % 8));
+ rxlen++;
+ }
+ } else {
+ // Ignore wierd value, is to small to mean anything
+ }
+ }
+ *rxlenOrg = rxlen;
+}
+
+/*
+static void hitag_decode_frame_AC2K_rising(byte_t* rx, size_t* rxlenOrg, int* response, int rawMod[], int rawLen) {
+ int tag_sof = 1; //skip start of frame
+ size_t rxlen = 0;
+
+ for (int i=0; i < rawLen; i++) {
+ int ra = rawMod[i];
+ if (ra >= HITAG_T_EOF) {
+ if (rxlen != 0) {
+ //DbpString("wierd1?");
+ }
+ // Capture the T0 periods that have passed since last communication or field drop (reset)
+ // We always recieve a 'one' first, which has the falling edge after a half period |-_|
+ tag_sof = 1;
+ *response = ra - HITAG_T_TAG_HALF_PERIOD;
+ } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) {
+ // AC coding example |--__|--__| means 0
+ rx[rxlen / 8] |= 0 << (7 - (rxlen % 8));
+ rxlen++;
+ if (rawMod[i+1] == 0) { //TODO: this is weird - may we miss one capture with current configuration
+ rx[rxlen / 8] |= 0 << (7 - (rxlen % 8));
+ rxlen++;
+ i++; //drop next capture
+ }
+ } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) {
+ if (tag_sof) {
+ // Ignore bits that are transmitted during SOF
+ tag_sof--;
+ } else {
+ // AC coding example |-_-_|-_-_| which means 1
+ //check if another high is coming (only -_-_ = 1) except end of the frame (support 0)
+ if (rawMod[i+1] == 0 || rawMod[i+1] >= HITAG_T_TAG_CAPTURE_TWO_HALF) {
+ rx[rxlen / 8] |= 1 << (7 - (rxlen % 8));
+ rxlen++;
+ i++; //drop next capture
+ } else {
+ Dbprintf("got weird high - %d,%d", ra, rawMod[i+1]);
+ }
+ }
+ } else {
+ // Ignore wierd value, is to small to mean anything
+ }
+ }
+ *rxlenOrg = rxlen;
+}
+*/
+
+static void hitag_decode_frame_AC(int bitRate, int sofBits, byte_t* rx, size_t* rxlenOrg, int* response, int rawMod[], int rawLen) {
+ int tag_sof = 1;
+ size_t rxlen = 0;
+ int timing = 1;
+ if (bitRate == 4) {
+ timing = 2;
+ }
+
+
+ for (int i=0; i < rawLen; i++) {
+ int ra = rawMod[i];
+ if (ra >= HITAG_T_EOF) {
+ if (rxlen != 0) {
+ //DbpString("wierd1?");
+ }
+
+ // Capture the T0 periods that have passed since last communication or field drop (reset)
+ // We always recieve a 'one' first, which has the falling edge after a half period |-_|
+ tag_sof = sofBits;
+ *response = ra - HITAG_T_TAG_HALF_PERIOD;
+ } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF / timing) {
+ tag_sof=0;
+
+ // AC coding example |--__|--__| means 0
+ rx[rxlen / 8] |= 0 << (7 - (rxlen % 8));
+ rxlen++;
+ } else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF / timing) {
+ tag_sof=0;
+
+ if (rawMod[i-1] >= HITAG_T_TAG_CAPTURE_THREE_HALF / timing) {
+ //treat like HITAG_T_TAG_CAPTURE_TWO_HALF
+ if (rawMod[i+1] >= HITAG_T_TAG_CAPTURE_TWO_HALF / timing) {
+ rx[rxlen / 8] |= 1 << (7 - (rxlen % 8));
+ rxlen++;
+ i++; //drop next capture
+ } else {
+ Dbprintf("got weird value - %d,%d", ra, rawMod[i+1]);
+ }
+ } else {
+ //treat like HITAG_T_TAG_CAPTURE_FOUR_HALF
+ rx[rxlen / 8] |= 0 << (7 - (rxlen % 8));
+ rxlen++;
+ }
+ } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF / timing) {
+ if (tag_sof) {
+ // Ignore bits that are transmitted during SOF
+ tag_sof--;
+ } else {
+ // AC coding example |-_-_|-_-_| which means 1
+ //check if another high is coming (only -_-_ = 1) except end of the frame (support 0)
+ if (rawMod[i+1] == 0 || rawMod[i+1] >= HITAG_T_TAG_CAPTURE_TWO_HALF / timing) {
+ rx[rxlen / 8] |= 1 << (7 - (rxlen % 8));
+ rxlen++;
+ i++; //drop next capture
+ } else {
+ Dbprintf("got weird value - %d,%d", ra, rawMod[i+1]);
+ }
+ }
+ } else {
+ // Ignore wierd value, is to small to mean anything
+ }
+ }
+ *rxlenOrg = rxlen;
+}
+
+static void hitag_receive_frame(byte_t* rx, size_t* rxlen, int* response) {
+ int rawMod[200] = {0};
+ int rawLen = 0;
+ int i = 0;
+ int sofBits = 0;
+
+ m = MC4K;
+ if (tag.pstate == READY) {
+ switch (tag.mode) {
+ case STANDARD:
+ m = AC2K;
+ sofBits = 1;
+ break;
+ case ADVANCED:
+ m = AC2K;
+ sofBits = 5; //3 sof bits but 5 captures
+ break;
+ case FAST_ADVANCED:
+ m = AC4K;
+ sofBits = 5; //3 sof bits but 5 captures
+ break;
+ default:
+ break;
+ }
+ } else {
+ switch (tag.mode) {
+ case STANDARD:
+ m = MC4K;
+ sofBits = 0; //in theory 1
+ break;
+ case ADVANCED:
+ m = MC4K;
+ sofBits = 5; //in theory 6
+ break;
+ case FAST_ADVANCED:
+ m = MC8K;
+ sofBits = 5; //in theory 6
+ break;
+ default:
+ break;
+ }
+ }
+
+ //rising AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_RISING | AT91C_TC_ABETRG | AT91C_TC_LDRA_RISING;
+ AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_FALLING | AT91C_TC_ABETRG | AT91C_TC_LDRA_FALLING;
+
+
+ //first capture timing values
+ while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_WAIT_MAX ) {
+ // Check if rising edge in modulation is detected
+ if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) {
+ // Retrieve the new timing values
+ int ra = (AT91C_BASE_TC1->TC_RA / T0);
+
+ LED_B_ON();
+ // Reset timer every frame, we have to capture the last edge for timing
+ AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
+ //AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
+
+ if (rawLen >= 200) { //avoid exception
+ break;
+ }
+ rawMod[rawLen] = ra;
+ rawLen++;
+
+ // We can break this loop if we received the last bit from a frame
+ if (AT91C_BASE_TC1->TC_CV > T0 * HITAG_T_EOF) {
+ if (rawLen > 2) {
+ if (DEBUG >= 2) { Dbprintf("AT91C_BASE_TC1->TC_CV > T0 * HITAG_T_EOF breaking (%d)", rawLen); }
+ break;
+ }
+ }
+ }
+ }
+
+ if (DEBUG >= 2) {
+ for (i=0; i < rawLen; i+=20) {
+ Dbprintf("raw modulation: - %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
+ rawMod[i],rawMod[i+1],rawMod[i+2],rawMod[i+3], rawMod[i+4],rawMod[i+5],rawMod[i+6],rawMod[i+7],
+ rawMod[i+8],rawMod[i+9],rawMod[i+10],rawMod[i+11], rawMod[i+12],rawMod[i+13],rawMod[i+14],rawMod[i+15],
+ rawMod[i+16],rawMod[i+17],rawMod[i+18],rawMod[i+19]
+ );
+ }
+ }
+
+ switch (m) {
+ // DATA | 1 | 0 | 1 | 1 | 0 |
+ // Manchester |--__|__--|--__|--__|__--|
+ // Anti Collision |-_-_|--__|-_-_|-_-_|--__|
+ // |<-->|
+ // | T |
+ case AC2K:
+ if (DEBUG >= 2) { Dbprintf("decoding frame with modulation AC2K"); }
+ hitag_decode_frame_AC(2, sofBits, rx, rxlen, response, rawMod, rawLen);
+ break;
+ case AC4K:
+ if (DEBUG >= 2) { Dbprintf("decoding frame with modulation AC4K"); }
+ hitag_decode_frame_AC(4, sofBits, rx, rxlen, response, rawMod, rawLen);
+ break;
+ case MC4K:
+ if (DEBUG >= 2) { Dbprintf("decoding frame with modulation MC4K"); }
+ hitag_decode_frame_MC(4, sofBits, rx, rxlen, response, rawMod, rawLen);
+ break;
+ case MC8K:
+ if (DEBUG >= 2) { Dbprintf("decoding frame with modulation MC8K"); }
+ hitag_decode_frame_MC(8, sofBits, rx, rxlen, response, rawMod, rawLen);
+ break;
+ }
+
+ LED_B_OFF();
+ if (DEBUG >= 2) {
+ int rb[200] = {0}; int z = 0;
+ for (i = 0; i < 16; i++) { for (int j = 0; j < 8; j++) {
+ rb[z] = 0;
+ if ((rx[i] & ((1 << 7) >> j)) != 0) { rb[z] = 1; }
+ z++;
+ } }
+ for (i=0; i < z; i+=8) {
+ Dbprintf("raw bit: - %d%d%d%d%d%d%d%d", rb[i],rb[i+1],rb[i+2],rb[i+3],rb[i+4],rb[i+5],rb[i+6],rb[i+7] );
+ }
+ }
+}
+
+static void hitag_start_auth(byte_t* tx, size_t* txlen) {
+ *txlen = 5;
+ switch (tag.mode) {
+ case STANDARD:
+ //00110 - 0x30 - STANDARD MODE
+ memcpy(tx, "\x30", nbytes(*txlen));
+ break;
+ case ADVANCED:
+ //11000 - 0xc0 - Advance Mode
+ memcpy(tx, "\xc0", nbytes(*txlen));
+ break;
+ case FAST_ADVANCED:
+ //TODO!
+ break;
+ default: //STANDARD MODE
+ memcpy(tx, "\x30", nbytes(*txlen));
+ break;
+ }
+ tag.pstate = READY;
+ tag.tstate = NO_OP;
+}
+
+static int hitag_read_page(hitag_function htf, uint64_t key, byte_t* rx, size_t* rxlen, byte_t* tx, size_t* txlen, int pageNum) {
+ int i, j, z;
+ int response_bit[200];
+ unsigned char mask = 1;
+ unsigned char crc;
+ unsigned char pageData[32];
+
+ if (pageNum >= tag.max_page) {
+ return -1;
+ }
+ if (tag.pstate == SELECTED && tag.tstate == NO_OP && *rxlen > 0) {
+ //send read request
+ tag.tstate = READING_PAGE;
+ *txlen = 20;
+ crc = CRC_PRESET;
+ tx[0] = 0xc0 + (pageNum / 16);
+ calc_crc(&crc, tx[0], 8);
+ calc_crc(&crc, 0x00 + ((pageNum % 16) * 16), 4);
+ tx[1] = 0x00 + ((pageNum % 16) * 16) + (crc / 16);
+ tx[2] = 0x00 + (crc % 16) * 16;
+ } else if (tag.pstate == SELECTED && tag.tstate == READING_PAGE && *rxlen > 0) {
+ //save received data
+ z = 0;
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 8; j++) {
+ response_bit[z] = 0;
+ if ((rx[i] & ((mask << 7) >> j)) != 0) {
+ response_bit[z] = 1;
+ }
+ if (z < 32) {
+ pageData[z] = response_bit[z];
+ }
+
+ z++;
+ }
+ }
+ for (i = 0; i < 4; i++) {
+ tag.pages[pageNum][i] = 0x0;
+ }
+ for (i = 0; i < 4; i++) {
+ tag.pages[pageNum][i] += ((pageData[i * 8] << 7) | (pageData[1 + (i * 8)] << 6) |
+ (pageData[2 + (i * 8)] << 5) | (pageData[3 + (i * 8)] << 4) |
+ (pageData[4 + (i * 8)] << 3) | (pageData[5 + (i * 8)] << 2) |
+ (pageData[6 + (i * 8)]
+ << 1) | pageData[7 + (i * 8)]);
+ }
+ if (tag.auth && tag.LKP && pageNum == 1) {
+ Dbprintf("Page[%2d]: %02X %02X %02X %02X", pageNum, pwdh0,
+ tag.pages[pageNum][2], tag.pages[pageNum][1], tag.pages[pageNum][0]);
+ } else {
+ Dbprintf("Page[%2d]: %02X %02X %02X %02X", pageNum,
+ tag.pages[pageNum][3], tag.pages[pageNum][2],
+ tag.pages[pageNum][1], tag.pages[pageNum][0]);
+ }
+
+
+ //display key and password if possible
+ if (pageNum == 1 && tag.auth == 1 && tag.LKP) {
+ if (htf == 02) { //RHTS_KEY
+ Dbprintf("Page[ 2]: %02X %02X %02X %02X",
+ (byte_t)(key >> 8) & 0xff,
+ (byte_t) key & 0xff, pwdl1, pwdl0);
+ Dbprintf("Page[ 3]: %02X %02X %02X %02X",
+ (byte_t)(key >> 40) & 0xff,
+ (byte_t)(key >> 32) & 0xff,
+ (byte_t)(key >> 24) & 0xff,
+ (byte_t)(key >> 16) & 0xff);
+ } else {
+ //if the authentication is done with a challenge the key and password are unknown
+ Dbprintf("Page[ 2]: __ __ __ __");
+ Dbprintf("Page[ 3]: __ __ __ __");
+ }
+ }
+
+ *txlen = 20;
+ crc = CRC_PRESET;
+ tx[0] = 0xc0 + ((pageNum+1) / 16);
+ calc_crc(&crc, tx[0], 8);
+ calc_crc(&crc, 0x00 + (((pageNum+1) % 16) * 16), 4);
+ tx[1] = 0x00 + (((pageNum+1) % 16) * 16) + (crc / 16);
+ tx[2] = 0x00 + (crc % 16) * 16;
+
+ return 1;
+ }
+ return 0;
+}
+
+static int hitag_read_block(hitag_function htf, uint64_t key, byte_t* rx, size_t* rxlen, byte_t* tx, size_t* txlen, int blockNum) {
+ int i, j, z;
+ int response_bit[200];
+ unsigned char mask = 1;
+ unsigned char crc;
+ unsigned char blockData[128];
+
+ if (blockNum+4 >= tag.max_page) { //block always = 4 pages
+ return -1;
+ }
+
+ if (tag.pstate == SELECTED && tag.tstate == NO_OP && *rxlen > 0) {
+ //send read request
+ tag.tstate = READING_BLOCK;
+ *txlen = 20;
+ crc = CRC_PRESET;
+ tx[0] = 0xd0 + (blockNum / 16);
+ calc_crc(&crc, tx[0], 8);
+ calc_crc(&crc, 0x00 + ((blockNum % 16) * 16), 4);
+ tx[1] = 0x00 + ((blockNum % 16) * 16) + (crc / 16);
+ tx[2] = 0x00 + (crc % 16) * 16;
+ } else if (tag.pstate == SELECTED && tag.tstate == READING_BLOCK && *rxlen > 0) {
+ //save received data
+ z = 0;
+ for (i = 0; i < 16; i++) {
+ for (j = 0; j < 8; j++) {
+ response_bit[z] = 0;
+ if ((rx[i] & ((mask << 7) >> j)) != 0) {
+ response_bit[z] = 1;
+ }
+ if (z < 128) {
+ blockData[z] = response_bit[z];
+ }
+ z++;
+ }
+ }
+
+ for (z = 0; z < 4; z++) { //4 pages
+ for (i = 0; i < 4; i++) {
+ tag.pages[blockNum+z][i] = 0x0;
+ }
+ }
+ for (z = 0; z < 4; z++) { //4 pages
+ for (i = 0; i < 4; i++) {
+ j = (i * 8) + (z*32); //bit in page + pageStart
+ tag.pages[blockNum+z][i] = ((blockData[j] << 7) | (blockData[1 + j] << 6) |
+ (blockData[2 + j] << 5) | (blockData[3 + j] << 4) |
+ (blockData[4 + j] << 3) | (blockData[5 + j] << 2) |
+ (blockData[6 + j] << 1) | blockData[7 + j]);
+ }
+ }
+ if (DEBUG) {
+ for (z = 0; z < 4; z++) {
+ Dbprintf("Page[%2d]: %02X %02X %02X %02X", blockNum+z,
+ tag.pages[blockNum+z][3], tag.pages[blockNum+z][2],
+ tag.pages[blockNum+z][1], tag.pages[blockNum+z][0]);
+ }
+ }
+ Dbprintf("Block[%2d]: %02X %02X %02X %02X - %02X %02X %02X %02X - %02X %02X %02X %02X - %02X %02X %02X %02X", blockNum,
+ tag.pages[blockNum][3], tag.pages[blockNum][2], tag.pages[blockNum][1], tag.pages[blockNum][0],
+ tag.pages[blockNum+1][3], tag.pages[blockNum+1][2], tag.pages[blockNum+1][1], tag.pages[blockNum+1][0],
+ tag.pages[blockNum+2][3], tag.pages[blockNum+2][2], tag.pages[blockNum+2][1], tag.pages[blockNum+2][0],
+ tag.pages[blockNum+3][3], tag.pages[blockNum+3][2], tag.pages[blockNum+3][1], tag.pages[blockNum+3][0]);
+
+ *txlen = 20;
+ crc = CRC_PRESET;
+ tx[0] = 0xd0 + ((blockNum+4) / 16);
+ calc_crc(&crc, tx[0], 8);
+ calc_crc(&crc, 0x00 + (((blockNum+4) % 16) * 16), 4);
+ tx[1] = 0x00 + (((blockNum+4) % 16) * 16) + (crc / 16);
+ tx[2] = 0x00 + (crc % 16) * 16;
+
+ return 1;
+ }
+ return 0;
+}
+
+