Files
proxmark3/armsrc/lfadc.c
T
dxl e3511c5350 Used HAL layer
in appmain.c and cmd added.
in cmd.c and add some code for test CEP
in em4x50.c(Do not timeout--)
in em4x70.c
in emvsim.c
in epa.c
in felica.c
in felicasim.c
in felicasim.c
in hfops.c
in hfsnoop.c
in hitag2.c
in hitag_common.c(Cross-platform implementation is incomplete.)
in hitagS.c
in hitagu.c
in i2c.c(Incomplete, continue to abstract.)
in i2c_direct.c
in iclass.c
in iso14443a.c(Sniff no finish yet)
in iso14443b.c and fixed bug for st25
in iso15693.c
in legicrf.c
in legicrfsim.c
in lfadc.c(lf_count_edge_periods_ex() improved)
in lfops.c(TI tag no finish yet)
in lfsampling.c
in lfzx.c
in mifarecmd.c
in mifaredesfire.c
in mifaresim.c
in mifaresniff_disabled.c
in mifareutil.c
in pcf7931.c
in sam_xxx
in secc & seos
in start.c
in thinfilm.c
in utils
2026-08-19 15:32:39 +02:00

407 lines
13 KiB
C

//-----------------------------------------------------------------------------
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
// LF ADC read/write implementation
//-----------------------------------------------------------------------------
#include "lfadc.h"
#include "lfsampling.h"
#include "fpga_loader.h"
#include "ticks_apis.h"
#include "fpga_apis.h"
#include "dbprint.h"
#include "appmain.h"
// Sam7s has several timers, we will use the source TIMER_CLOCK1 (aka AT91C_TC_CLKS_TIMER_DIV1_CLOCK)
// TIMER_CLOCK1 = MCK/2, MCK is running at 48 MHz, Timer is running at 48/2 = 24 MHz
// Carrier periods (T0) have duration of 8 microseconds (us), which is 1/125000 per second
// T0 = TIMER_CLOCK1 / 125000 = 192
//#define T0 192
// Sam7s has three counters, we will use the first TIMER_COUNTER_0 (aka TC0)
// using TIMER_CLOCK3 (aka AT91C_TC_CLKS_TIMER_DIV3_CLOCK)
// as a counting signal. TIMER_CLOCK3 = MCK/32, MCK is running at 48 MHz, so the timer is running at 48/32 = 1500 kHz
// Carrier period (T0) have duration of 8 microseconds (us), which is 1/125000 per second (125 kHz frequency)
// T0 = timer/carrier = 1500kHz/125kHz = 1500000/125000 = 6
//#define HITAG_T0 3
//////////////////////////////////////////////////////////////////////////////
// Exported global variables
//////////////////////////////////////////////////////////////////////////////
bool g_logging = false; // TODO DXL 在某些情况下,读不到卡的时候,此处可能会造成内存溢出,需要解决
//////////////////////////////////////////////////////////////////////////////
// Global variables
//////////////////////////////////////////////////////////////////////////////
static bool rising_edge = false;
static lf_adc_init_mode_t g_init_mode = LF_ADC_READER;
static lf_adc_edge_mode_t g_edge_mode = LF_ADC_WAV_REVERSED;
//////////////////////////////////////////////////////////////////////////////
// Auxiliary functions
//////////////////////////////////////////////////////////////////////////////
bool lf_test_periods(size_t expected, size_t count) {
// Compute 10% deviation (integer operation, so rounded down)
size_t diviation = expected / 10;
return ((count > (expected - diviation)) && (count < (expected + diviation)));
}
//////////////////////////////////////////////////////////////////////////////
// Low frequency (LF) adc passthrough functionality
//////////////////////////////////////////////////////////////////////////////
static uint8_t previous_adc_val = 0; // 0xFF;
static uint8_t adc_avg = 0;
static uint8_t adc_max;
static uint8_t adc_min;
uint8_t lf_get_adc_avg(void) {
return adc_avg;
}
void lf_sample_mean(void) {
uint8_t periods = 0;
uint32_t adc_sum = 0;
adc_max = 0;
adc_min = 255;
while (periods < 32) {
if (FPGA_SSC_RX_Ready()) {
const uint8_t adc_val = FPGA_SSC_RX_Value();
if (adc_val < adc_min) adc_min = adc_val;
if (adc_val > adc_max) adc_max = adc_val;
adc_sum += adc_val;
periods++;
}
}
adc_avg = adc_sum >> 5; // division by 32
previous_adc_val = adc_avg;
DBG Dbprintf("LF ADC average %u, max %u, min %u, diff %u", adc_avg, adc_max, adc_min, adc_max - adc_min);
}
static size_t lf_count_edge_periods_ex(size_t max, bool wait, bool detect_gap) {
#define LIMIT_DEV 20
// timeout limit to 100 000 w/o
uint32_t timeout = 100000;
size_t periods = 0;
uint8_t avg_peak = adc_avg + LIMIT_DEV;
uint8_t avg_through = adc_avg - LIMIT_DEV;
while (BUTTON_PRESS() == false) {
WDT_HIT();
timeout--;
if (timeout == 0) {
DBG Dbprintf("Error, timeout for wait adc value rx");
return 0;
}
if (FPGA_SSC_TX_Ready()) {
FPGA_SSC_TX_Value(0x00);
continue;
}
if (FPGA_SSC_RX_Ready() == false) {
continue;
}
periods++; // T0 increment, 1(TO) = 8us, same with 125khz clock.
timeout = 100000; // reset timeout
volatile uint8_t adc_val = FPGA_SSC_RX_Value(); // Get current adc value.
if (g_logging) {
logSampleSimple(adc_val);
}
// Only test field changes if state of adc values matter
if (wait == false) {
// Test if we are locating a field modulation (100% ASK = complete field drop)
if (detect_gap) {
// Only return when the field completely disappeared
if (adc_val == 0) {
return periods;
}
} else {
if (g_edge_mode == LF_ADC_WAV_REVERSED) {
if (rising_edge) {
if ((previous_adc_val > avg_peak) && (adc_val <= previous_adc_val)) {
rising_edge = false;
return periods;
}
} else {
if ((previous_adc_val < avg_through) && (adc_val >= previous_adc_val)) {
rising_edge = true;
return periods;
}
}
} else if (g_edge_mode == LF_ADC_NOT_REVERSED) {
if (rising_edge) {
if (adc_val <= adc_avg && adc_val <= avg_through) {
rising_edge = false;
return periods;
}
} else {
if (adc_val >= avg_peak) {
rising_edge = true;
return periods;
}
}
}
}
}
previous_adc_val = adc_val;
if (periods >= max) {
return 0;
}
}
if (g_logging) {
logSampleSimple(0xFF);
}
return 0;
}
size_t lf_count_edge_periods(size_t max) {
return lf_count_edge_periods_ex(max, false, false);
}
size_t lf_detect_gap(size_t max) {
return lf_count_edge_periods_ex(max, false, true);
}
void lf_reset_counter(void) {
// TODO: find out the correct reset settings for tag and reader mode
// if (g_init_mode == LF_ADC_READER) {
// Reset values for reader mode
rising_edge = false;
previous_adc_val = 0xFF;
// } else {
// Reset values for tag/transponder mode
// rising_edge = false;
// previous_adc_val = 0xFF;
// }
}
bool lf_get_tag_modulation(void) {
return (rising_edge == false);
}
bool lf_get_reader_modulation(void) {
return rising_edge;
}
void lf_wait_periods(size_t periods) {
// wait for detect gap
lf_count_edge_periods_ex(periods, true, false);
}
void lf_init(lf_adc_init_mode_t init_mode, lf_adc_edge_mode_t edge_mode, bool ledcontrol) {
StopTicks();
g_init_mode = init_mode;
g_edge_mode = edge_mode;
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
sample_config *sc = getSamplingConfig();
sc->decimation = 1;
sc->averaging = 0;
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc->divisor);
// Different fpga config for different mode.
switch (g_init_mode) {
case LF_ADC_READER:
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
break;
case LF_ADC_TAG_SIM:
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC);
break;
case LF_ADC_SNIFF:
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC);
// FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_TOGGLE_MODE);
break;
}
// Connect the A/D to the peak-detected low-frequency path.
SetAdcMuxFor(ADC_MUXSEL_LOPKD);
// Now set up the SSC to get the ADC samples that are now streaming at us.
FpgaSetupSsc(FPGA_MAJOR_MODE_LF_READER);
// When in reader mode, give the field a bit of time to settle.
// Optimal timing window for LF ADC measurements to be performed:
// minimum: 313T0 = 313 * 8us = 2504us = 2.50ms - Hitag2 tag internal powerup time
// 280T0 = 280 * 8us = 2240us = 2.24ms - HitagS minimum time before the first command (powerup time)
// maximum: 545T0 = 545 * 8us = 4360us = 4.36ms - Hitag2 command waiting time before it starts transmitting in public mode (if configured so)
// 565T0 = 565 * 8us = 4520us = 4.52ms - HitagS waiting time before entering TTF mode (if configured so)
// Thus (2.50 ms + 4.36 ms) / 2 ~= 3 ms (rounded down to integer), should be a good timing for both tag models
SpinDelay(2); // TODO DXL 之前是 3ms,改成2ms测试hitagU
// TODO DXL 经测试,3ms时hitag2工作的很好,但是hitagu会进入TTF模式导致无法寻卡
// hitagu用2ms延时比较靠谱
// lf_wait_periods(200); // TODO DXL zx8268 用这个时长才能正常寻卡,3ms的话,8268直接开始广播了,没办法通信上了
// Steal this pin from the SSP (SPI communication channel with fpga) and use it to control the modulation
gpio_fpga_mod_only_setup();
Gpio_SSC_DOUT_Low();
/* TODO DXL 暂时注释,看看哪里没用到这些定时器的,如果都没用到,则可以删掉
// Enable peripheral Clock for TIMER_CLOCK 0
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0);
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV4_CLOCK;
// Enable peripheral Clock for TIMER_CLOCK 1
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1);
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV4_CLOCK;
*/
// Clear all leds
if (ledcontrol) LEDsoff();
/* TODO DXL 暂时注释,看看哪里没用到这些定时器的,如果都没用到,则可以删掉
// Reset and enable timers
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
// Assert a sync signal. This sets all timers to 0 on next active clock edge
AT91C_BASE_TCB->TCB_BCR = 1;
*/
// Prepare data trace
uint32_t bufsize = 10000;
// use malloc
if (g_logging) {
initSampleBufferEx(&bufsize, true);
}
lf_sample_mean();
}
void lf_finalize(bool ledcontrol) {
/* TODO DXL 暂时注释,看看哪里没用到这些定时器的,如果都没用到,则可以删掉
// Disable timers
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
// return stolen pin to SSP
AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DOUT;
AT91C_BASE_PIOA->PIO_ASR = GPIO_SSC_DIN | GPIO_SSC_DOUT;
*/
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
if (ledcontrol) LEDsoff();
StartTicks();
}
size_t lf_detect_field_drop(size_t max) {
/*
size_t periods = 0;
// int16_t checked = 0;
while (BUTTON_PRESS() == false) {
// // only every 1000th times, in order to save time when collecting samples.
// if (checked == 4000) {
// if (data_available()) {
// checked = -1;
// break;
// } else {
// checked = 0;
// }
// }
// ++checked;
WDT_HIT();
if (FPGA_SSC_RX_Ready()) {
periods++;
volatile uint8_t adc_val = FPGA_SSC_RX_Value();
if (g_logging) logSampleSimple(adc_val);
if (adc_val == 0) {
rising_edge = false;
return periods;
}
if (periods == max) return 0;
}
}
*/
return 0;
}
void lf_reset_field(size_t periods) {
// FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
Gpio_SSC_DOUT_High();
lf_wait_periods(periods);
Gpio_SSC_DOUT_Low();
// FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
}
void lf_modulation(bool modulation) {
if (modulation) {
Gpio_SSC_DOUT_High();
} else {
Gpio_SSC_DOUT_Low();
}
}
// simulation
static void lf_manchester_send_bit(uint8_t bit) {
lf_modulation(bit != 0);
lf_wait_periods(16);
lf_modulation(bit == 0);
lf_wait_periods(32);
}
// simulation
bool lf_manchester_send_bytes(const uint8_t *frame, size_t frame_len, bool ledcontrol) {
if (ledcontrol)
LED_B_ON();
lf_manchester_send_bit(1);
lf_manchester_send_bit(1);
lf_manchester_send_bit(1);
lf_manchester_send_bit(1);
lf_manchester_send_bit(1);
// Send the content of the frame
for (size_t i = 0; i < frame_len; i++) {
lf_manchester_send_bit((frame[i / 8] >> (7 - (i % 8))) & 1);
}
if (ledcontrol)
LED_B_OFF();
return true;
}