mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2024-11-10 17:49:32 +08:00
chg: hitag write - works
This commit is contained in:
parent
e3ff3a8819
commit
f04be0c044
1 changed files with 195 additions and 179 deletions
370
armsrc/hitag2.c
370
armsrc/hitag2.c
|
@ -1566,8 +1566,8 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
|
||||||
|
|
||||||
LogTrace(rx, nbytes(rxlen), response_start, response_start + response_duration, NULL, false);
|
LogTrace(rx, nbytes(rxlen), response_start, response_start + response_duration, NULL, false);
|
||||||
// TODO when using cumulative time for command_start, pm3 doesn't reply anymore, e.g. on lf hitag read 23 4F4E4D494B52
|
// TODO when using cumulative time for command_start, pm3 doesn't reply anymore, e.g. on lf hitag read 23 4F4E4D494B52
|
||||||
// command_start = response_start + response_duration;
|
command_start = response_start + response_duration;
|
||||||
command_start = 0;
|
// command_start = 0;
|
||||||
// Dbhexdump(nbytes(rxlen), rx, false);
|
// Dbhexdump(nbytes(rxlen), rx, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1590,24 +1590,34 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) {
|
||||||
|
|
||||||
StopTicks();
|
StopTicks();
|
||||||
|
|
||||||
// int frame_count = 0;
|
int frame_count = 0;
|
||||||
int response = 0;
|
uint32_t command_start = 0;
|
||||||
|
uint32_t command_duration = 0;
|
||||||
|
uint32_t response_start = 0;
|
||||||
|
uint32_t response_duration = 0;
|
||||||
uint8_t rx[HITAG_FRAME_LEN];
|
uint8_t rx[HITAG_FRAME_LEN];
|
||||||
size_t rxlen = 0;
|
size_t rxlen = 0;
|
||||||
uint8_t txbuf[HITAG_FRAME_LEN];
|
uint8_t txbuf[HITAG_FRAME_LEN];
|
||||||
uint8_t *tx = txbuf;
|
uint8_t *tx = txbuf;
|
||||||
size_t txlen = 0;
|
size_t txlen = 0;
|
||||||
int lastbit;
|
int t_wait_1;
|
||||||
int reset_sof;
|
int t_wait_1_guard = 8;
|
||||||
int t_wait = HITAG_T_WAIT_MAX;
|
int t_wait_2;
|
||||||
bool bStop;
|
size_t tag_size;
|
||||||
|
bool bStop = false;
|
||||||
|
|
||||||
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
// Raw demodulation/decoding by sampling edge periods
|
||||||
set_tracing(true);
|
size_t periods = 0;
|
||||||
clear_trace();
|
|
||||||
|
|
||||||
// Reset the return status
|
// Reset the return status
|
||||||
bSuccessful = false;
|
bSuccessful = false;
|
||||||
|
bCrypto = false;
|
||||||
|
|
||||||
|
// Clean up trace and prepare it for storing frames
|
||||||
|
set_tracing(true);
|
||||||
|
clear_trace();
|
||||||
|
|
||||||
|
DbpString("Starting Hitag writer family");
|
||||||
|
|
||||||
// Check configuration
|
// Check configuration
|
||||||
switch (htf) {
|
switch (htf) {
|
||||||
|
@ -1642,221 +1652,227 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) {
|
||||||
}
|
}
|
||||||
|
|
||||||
LED_D_ON();
|
LED_D_ON();
|
||||||
|
|
||||||
hitag2_init();
|
hitag2_init();
|
||||||
|
|
||||||
// Configure output and enable pin that is connected to the FPGA (for modulating)
|
// init as reader
|
||||||
AT91C_BASE_PIOA->PIO_OER |= GPIO_SSC_DOUT;
|
lf_init(true);
|
||||||
AT91C_BASE_PIOA->PIO_PER |= GPIO_SSC_DOUT;
|
|
||||||
|
|
||||||
// Set fpga in edge detect with reader field, we can modulate as reader now
|
|
||||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD);
|
|
||||||
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); //125kHz
|
|
||||||
SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
|
|
||||||
|
|
||||||
// Disable modulation at default, which means enable the field
|
|
||||||
LOW(GPIO_SSC_DOUT);
|
|
||||||
|
|
||||||
// Enable Peripheral Clock for
|
|
||||||
// TIMER_CLOCK0, used to measure exact timing before answering
|
|
||||||
// TIMER_CLOCK1, used to capture edges of the tag frames
|
|
||||||
AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1);
|
|
||||||
|
|
||||||
AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME;
|
|
||||||
|
|
||||||
// Disable timer during configuration
|
|
||||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
|
|
||||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
|
|
||||||
|
|
||||||
// TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers
|
|
||||||
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK;
|
|
||||||
|
|
||||||
// TC1: Capture mode, defaul timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger,
|
|
||||||
// external trigger rising edge, load RA on falling edge of TIOA.
|
|
||||||
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK
|
|
||||||
| AT91C_TC_ETRGEDG_FALLING
|
|
||||||
| AT91C_TC_ABETRG
|
|
||||||
| AT91C_TC_LDRA_FALLING;
|
|
||||||
|
|
||||||
// Enable and reset counters
|
|
||||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
|
||||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
|
||||||
|
|
||||||
while (AT91C_BASE_TC0->TC_CV > 0) {};
|
|
||||||
|
|
||||||
// Reset the received frame, frame count and timing info
|
|
||||||
lastbit = 1;
|
|
||||||
bStop = false;
|
|
||||||
|
|
||||||
// Tag specific configuration settings (sof, timings, etc.)
|
// Tag specific configuration settings (sof, timings, etc.)
|
||||||
if (htf < 10) {
|
if (htf < 10) {
|
||||||
// hitagS settings
|
// hitagS settings
|
||||||
reset_sof = 1;
|
t_wait_1 = 204;
|
||||||
t_wait = 200;
|
t_wait_2 = 128;
|
||||||
|
/*tag_size = 256;*/
|
||||||
|
flipped_bit = 0;
|
||||||
|
tag_size = 8;
|
||||||
|
DbpString("Configured for hitagS writer");
|
||||||
} else if (htf < 20) {
|
} else if (htf < 20) {
|
||||||
// hitag1 settings
|
// hitag1 settings
|
||||||
reset_sof = 1;
|
t_wait_1 = 204;
|
||||||
t_wait = 200;
|
t_wait_2 = 128;
|
||||||
|
tag_size = 256;
|
||||||
|
flipped_bit = 0;
|
||||||
|
DbpString("Configured for hitag1 writer");
|
||||||
} else if (htf < 30) {
|
} else if (htf < 30) {
|
||||||
// hitag2 settings
|
// hitag2 settings
|
||||||
reset_sof = 4;
|
t_wait_1 = HITAG_T_WAIT_1_MIN;
|
||||||
t_wait = HITAG_T_WAIT_2_MIN;
|
t_wait_2 = HITAG_T_WAIT_2_MIN;
|
||||||
|
tag_size = 48;
|
||||||
|
DbpString("Configured for hitag2 writer");
|
||||||
} else {
|
} else {
|
||||||
Dbprintf("Error, unknown hitag reader type: %d", htf);
|
Dbprintf("Error, unknown hitag writer type: %d", htf);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t tag_modulation;
|
||||||
|
size_t max_nrzs = (8 * HITAG_FRAME_LEN + 5) * 2; // up to 2 nrzs per bit
|
||||||
|
uint8_t nrz_samples[max_nrzs];
|
||||||
|
size_t nrzs = 0;
|
||||||
|
|
||||||
while (!bStop && !BUTTON_PRESS() && !data_available()) {
|
while (!bStop && !BUTTON_PRESS() && !data_available()) {
|
||||||
|
|
||||||
WDT_HIT();
|
WDT_HIT();
|
||||||
|
|
||||||
// Check if frame was captured and store it
|
|
||||||
if (rxlen > 0) {
|
|
||||||
// frame_count++;
|
|
||||||
LogTrace(rx, nbytes(rxlen), response, response, NULL, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// By default reset the transmission buffer
|
// By default reset the transmission buffer
|
||||||
tx = txbuf;
|
tx = txbuf;
|
||||||
switch (htf) {
|
switch (htf) {
|
||||||
case WHT2F_CRYPTO: {
|
case WHT2F_CRYPTO: {
|
||||||
bStop = !hitag2_crypto(rx, rxlen, tx, &txlen, true);
|
bStop = !hitag2_crypto(rx, rxlen, tx, &txlen, true);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case WHT2F_PASSWORD: {
|
case WHT2F_PASSWORD: {
|
||||||
bStop = !hitag2_password(rx, rxlen, tx, &txlen, true);
|
bStop = !hitag2_password(rx, rxlen, tx, &txlen, true);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
default: {
|
default: {
|
||||||
Dbprintf("Error, unknown function: %d", htf);
|
Dbprintf("Error, unknown function: %d", htf);
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send and store the reader command
|
// Wait for t_wait_2 carrier periods after the last tag bit before transmitting,
|
||||||
// Disable timer 1 with external trigger to avoid triggers during our own modulation
|
lf_wait_periods(t_wait_2);
|
||||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
|
command_start += t_wait_2;
|
||||||
|
|
||||||
// Wait for HITAG_T_WAIT_2 carrier periods after the last tag bit before transmitting,
|
|
||||||
// Since the clock counts since the last falling edge, a 'one' means that the
|
|
||||||
// falling edge occurred halfway the period. with respect to this falling edge,
|
|
||||||
// we need to wait (T_Wait2 + half_tag_period) when the last was a 'one'.
|
|
||||||
// All timer values are in terms of T0 units
|
|
||||||
while (AT91C_BASE_TC0->TC_CV < HITAG_T0 * (t_wait + (HITAG_T_TAG_HALF_PERIOD * lastbit))) {};
|
|
||||||
|
|
||||||
// Transmit the reader frame
|
// Transmit the reader frame
|
||||||
hitag_reader_send_frame(tx, txlen);
|
command_duration = hitag_reader_send_frame(tx, txlen);
|
||||||
|
|
||||||
// Enable and reset external trigger in timer for capturing future frames
|
response_start = command_start + command_duration;
|
||||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
|
||||||
|
|
||||||
// Add transmitted frame to total count
|
// Let the antenna and ADC values settle
|
||||||
|
// And find the position where edge sampling should start
|
||||||
|
lf_wait_periods(t_wait_1 - t_wait_1_guard);
|
||||||
|
response_start += t_wait_1 - t_wait_1_guard;
|
||||||
|
|
||||||
|
// Keep administration of the first edge detection
|
||||||
|
bool waiting_for_first_edge = true;
|
||||||
|
|
||||||
|
// Did we detected any modulaiton at all
|
||||||
|
bool detected_tag_modulation = false;
|
||||||
|
|
||||||
|
// Use the current modulation state as starting point
|
||||||
|
tag_modulation = lf_get_tag_modulation();
|
||||||
|
|
||||||
|
// Reset the number of NRZ samples and use edge detection to detect them
|
||||||
|
nrzs = 0;
|
||||||
|
while (nrzs < max_nrzs) {
|
||||||
|
// Get the timing of the next edge in number of wave periods
|
||||||
|
periods = lf_count_edge_periods(128);
|
||||||
|
|
||||||
|
// Are we dealing with the first incoming edge
|
||||||
|
if (waiting_for_first_edge) {
|
||||||
|
// Just break out of loop after an initial time-out (tag is probably not available)
|
||||||
|
if (periods == 0) break;
|
||||||
|
if (tag_modulation == 0) {
|
||||||
|
// hitag replies always start with 11111 == 1010101010, if we see 0
|
||||||
|
// it means we missed the first period, e.g. if the signal never crossed 0 since reader signal
|
||||||
|
// so let's add it:
|
||||||
|
nrz_samples[nrzs++] = tag_modulation ^ 1;
|
||||||
|
// Register the number of periods that have passed
|
||||||
|
// we missed the begin of response but we know it happened one period of 16 earlier
|
||||||
|
response_start += periods - 16;
|
||||||
|
response_duration = response_start;
|
||||||
|
} else {
|
||||||
|
// Register the number of periods that have passed
|
||||||
|
response_start += periods;
|
||||||
|
response_duration = response_start;
|
||||||
|
}
|
||||||
|
// Indicate that we have dealt with the first edge
|
||||||
|
waiting_for_first_edge = false;
|
||||||
|
// The first edge is always a single NRZ bit, force periods on 16
|
||||||
|
periods = 16;
|
||||||
|
// We have received more than 0 periods, so we have detected a tag response
|
||||||
|
detected_tag_modulation = true;
|
||||||
|
} else {
|
||||||
|
// The function lf_count_edge_periods() returns 0 when a time-out occurs
|
||||||
|
if (periods == 0) {
|
||||||
|
//Dbprintf("Detected timeout after [%d] nrz samples", nrzs);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Evaluate the number of periods before the next edge
|
||||||
|
if (periods > 24 && periods <= 64) {
|
||||||
|
// Detected two sequential equal bits and a modulation switch
|
||||||
|
// NRZ modulation: (11 => --|) or (11 __|)
|
||||||
|
nrz_samples[nrzs++] = tag_modulation;
|
||||||
|
nrz_samples[nrzs++] = tag_modulation;
|
||||||
|
response_duration += periods;
|
||||||
|
// Invert tag modulation state
|
||||||
|
tag_modulation ^= 1;
|
||||||
|
} else if (periods > 0 && periods <= 24) {
|
||||||
|
// Detected one bit and a modulation switch
|
||||||
|
// NRZ modulation: (1 => -|) or (0 _|)
|
||||||
|
nrz_samples[nrzs++] = tag_modulation;
|
||||||
|
response_duration += periods;
|
||||||
|
tag_modulation ^= 1;
|
||||||
|
} else {
|
||||||
|
// The function lf_count_edge_periods() returns > 64 periods, this is not a valid number periods
|
||||||
|
//Dbprintf("Detected unexpected period count: %d", periods);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait some extra time for flash to be programmed
|
||||||
|
//
|
||||||
|
|
||||||
|
// Store the TX frame, we do this now at this point, to avoid delay in processing
|
||||||
|
// and to be able to overwrite the first samples with the trace (since they currently
|
||||||
|
// still use the same memory space)
|
||||||
if (txlen > 0) {
|
if (txlen > 0) {
|
||||||
// frame_count++;
|
frame_count++;
|
||||||
LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2_MIN, HITAG_T_WAIT_2_MIN, NULL, true);
|
LogTrace(tx, nbytes(txlen), command_start, command_start + command_duration, NULL, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset values for receiving frames
|
// Reset values for receiving frames
|
||||||
memset(rx, 0x00, sizeof(rx));
|
memset(rx, 0x00, sizeof(rx));
|
||||||
rxlen = 0;
|
rxlen = 0;
|
||||||
lastbit = 1;
|
|
||||||
bool bSkip = true;
|
|
||||||
int tag_sof = reset_sof;
|
|
||||||
response = 0;
|
|
||||||
uint32_t errorCount = 0;
|
|
||||||
|
|
||||||
// Receive frame, watch for at most T0*EOF periods
|
// If there is no response, just repeat the loop
|
||||||
while (AT91C_BASE_TC1->TC_CV < HITAG_T0 * HITAG_T_WAIT_MAX) {
|
if (!detected_tag_modulation) continue;
|
||||||
// Check if falling edge in tag modulation is detected
|
|
||||||
if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) {
|
|
||||||
// Retrieve the new timing values
|
|
||||||
int ra = (AT91C_BASE_TC1->TC_RA / HITAG_T0);
|
|
||||||
|
|
||||||
// Reset timer every frame, we have to capture the last edge for timing
|
// Make sure we always have an even number of samples. This fixes the problem
|
||||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
// of ending the manchester decoding with a zero. See the example below where
|
||||||
|
// the '|' character is end of modulation
|
||||||
LED_B_ON();
|
// One at the end: ..._-|_____...
|
||||||
|
// Zero at the end: ...-_|_____...
|
||||||
// Capture tag frame (manchester decoding using only falling edges)
|
// The last modulation change of a zero is not detected, but we should take
|
||||||
if (ra >= HITAG_T_EOF) {
|
// the half period in account, otherwise the demodulator will fail.
|
||||||
if (rxlen != 0) {
|
if ((nrzs % 2) != 0) {
|
||||||
//Dbprintf("DEBUG: Wierd1");
|
nrz_samples[nrzs++] = tag_modulation;
|
||||||
}
|
|
||||||
// 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) {
|
|
||||||
// Manchester coding example |-_|_-|-_| (101)
|
|
||||||
|
|
||||||
// need to test to verify we don't exceed memory...
|
|
||||||
// if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) {
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
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) {
|
|
||||||
// Manchester coding example |_-|...|_-|-_| (0...01)
|
|
||||||
|
|
||||||
// need to test to verify we don't exceed memory...
|
|
||||||
// if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) {
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
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) {
|
|
||||||
// Manchester coding example |_-|_-| (00) or |-_|-_| (11)
|
|
||||||
|
|
||||||
// need to test to verify we don't exceed memory...
|
|
||||||
// if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) {
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
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 {
|
|
||||||
// Dbprintf("DEBUG: Wierd2");
|
|
||||||
errorCount++;
|
|
||||||
// Ignore wierd value, is to small to mean anything
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// if we saw over 100 wierd values break it probably isn't hitag...
|
|
||||||
if (errorCount > 100) break;
|
|
||||||
|
|
||||||
// We can break this loop if we received the last bit from a frame
|
|
||||||
if (AT91C_BASE_TC1->TC_CV > HITAG_T0 * HITAG_T_EOF) {
|
|
||||||
if (rxlen > 0) break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait some extra time for flash to be programmed
|
LED_B_ON();
|
||||||
if ((rxlen == 0) && (writestate == WRITE_STATE_PROG)) {
|
|
||||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
// decode bitstream
|
||||||
while (AT91C_BASE_TC0->TC_CV < HITAG_T0 * (HITAG_T_PROG - HITAG_T_WAIT_MAX));
|
manrawdecode((uint8_t *)nrz_samples, &nrzs, true, 0);
|
||||||
|
|
||||||
|
// decode frame
|
||||||
|
|
||||||
|
// Verify if the header consists of five consecutive ones
|
||||||
|
if (nrzs < 5) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < 5; i++) {
|
||||||
|
if (nrz_samples[i] != 1) {
|
||||||
|
Dbprintf("Detected incorrect header, the bit [%d] is zero instead of one, abort", i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i < 5) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pack the response into a byte array
|
||||||
|
for (size_t i = 5; i < nrzs; i++) {
|
||||||
|
uint8_t bit = nrz_samples[i];
|
||||||
|
if (bit > 1) { // When Manchester detects impossible symbol it writes "7"
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rx[rxlen / 8] |= bit << (7 - (rxlen % 8));
|
||||||
|
rxlen++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rxlen % 8 == 1) // skip spurious bit
|
||||||
|
rxlen--;
|
||||||
|
|
||||||
|
// Check if frame was captured and store it
|
||||||
|
if (rxlen > 0) {
|
||||||
|
frame_count++;
|
||||||
|
|
||||||
|
LogTrace(rx, nbytes(rxlen), response_start, response_start + response_duration, NULL, false);
|
||||||
|
command_start = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LEDsoff();
|
|
||||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
|
||||||
set_tracing(false);
|
|
||||||
|
|
||||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
|
out:
|
||||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
|
lf_finalize();
|
||||||
|
Dbprintf("TX/RX frames recorded: %u", frame_count);
|
||||||
|
|
||||||
|
// release allocated memory from BigBuff.
|
||||||
|
BigBuf_free();
|
||||||
StartTicks();
|
StartTicks();
|
||||||
|
|
||||||
reply_mix(CMD_ACK, bSuccessful, 0, 0, (uint8_t *)tag.sectors, 48);
|
reply_mix(CMD_ACK, bSuccessful, 0, 0, (uint8_t *)tag.sectors, tag_size);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue