mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-10-23 06:32:37 +00:00
Simulate COTAG tag implementation
New CLI command `lf cotag sim` with COTAG tag simulation implementation. Detects COTAG reader activation sequence and emulates a COTAG tag. Signed-off-by: andrej@towelbyte.net
This commit is contained in:
1 parent
7f4dfe7472
commit
294fb3c504
8 files changed
+363
-4
No files matched your search
+2
-1
@@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
|
||||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
- Added `lf cotag sim` - simulate COTAG tag (@towelbyte)
|
||||
- Added standalone mode `GDB_GATEWAY` (PM5): GDB Remote Serial Protocol server on the USB CDC link, flash and SRAM access, no probe needed (@nieldk)
|
||||
- Fixed `lf t55xx detect -p` - the password is no longer sent to a tag whose PWD bit could not be confirmed, which could set it and destroy the tag's data; pass `-o` to override (@mfcarroll)
|
||||
- Fixed `hf mf hardnested`/`hf mf autopwn` on PM5 with hardened MIFARE Classic EV1 (#3595, #3664) (@ByteOrderMarc)
|
||||
@@ -293,7 +294,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
||||
- Add support for parsing Finnish Helsinki Regional Transport (HRT) travel cards (@sanduuz)
|
||||
- Added standalone mode `HF_DOEGOX_COMMIT` - DESFire suspended commit without relay (@doegox)
|
||||
- Changed `hf 14b info`- now support Innovatron protocol detection (@kormax)
|
||||
- Improved `lf cotag reader` and `lf cotag demod` - Reimplementation and enhancement of proxmark3 COTAG support
|
||||
- Improved `lf cotag reader` and `lf cotag demod` - Reimplementation and enhancement of proxmark3 COTAG support (@towelbyte)
|
||||
- Added `hf felica sim` command (@kormax)
|
||||
- Added `mad read`, `mad write`, `mad verify`, `mad decode`, `mad encode` commands with typed struct MAD API (@AlxCzl)
|
||||
- Added `hf mfdes getversion` command (@kormax)
|
||||
|
||||
@@ -1865,6 +1865,11 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||
Cotag(payload->mode, true);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_COTAG_SIMULATE: {
|
||||
SimulateCotag((const lf_cotagsim_t *)packet->data.asBytes, true);
|
||||
reply_ng(CMD_LF_COTAG_SIMULATE, PM3_EOPABORTED, NULL, 0);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_HITAG
|
||||
|
||||
+237
@@ -2980,6 +2980,243 @@ void Cotag(uint32_t arg0, bool ledcontrol) {
|
||||
if (ledcontrol) LEDsoff();
|
||||
}
|
||||
|
||||
#define COTAG_STEP_K 32 // samples per box of the step filter
|
||||
|
||||
// a detected activation, for debug output
|
||||
typedef struct {
|
||||
uint32_t dt; // samples between the two rises
|
||||
int32_t thr; // threshold the second rise crossed
|
||||
} cotag_detect_val_t;
|
||||
|
||||
// Block until the reader's activation sequence is detected. Return false on button press or USB data.
|
||||
static bool cotag_activation_sequence_detect(const lf_cotagsim_t *params, cotag_detect_val_t *out) {
|
||||
|
||||
// Reader's tag activation sequence:
|
||||
// - ON 800 us, OFF 2200 us
|
||||
// - ON ~5800 us (the tag is expected to respond in this window)
|
||||
// - OFF ~16500 us (reader's pause if no tag detected, then repeat)
|
||||
//
|
||||
// We detect 2 rising edges between ON(800),OFF(2200),ON(5800), i.e. approx 3000us apart.
|
||||
// Plus minus some tolerance, thus win_lo and win_hi.
|
||||
|
||||
// Number of samples between 2 rising edges to look for an activation sequence
|
||||
const uint32_t win_lo = (3000 - 300) * 12 / (LF_COTAG_DIVISOR + 1);
|
||||
const uint32_t win_hi = (3000 + 300) * 12 / (LF_COTAG_DIVISOR + 1);
|
||||
|
||||
// Samples ring buffer
|
||||
uint8_t ring[2 * COTAG_STEP_K] = {0};
|
||||
uint8_t idx = 0; // points to the oldest sample
|
||||
int32_t sum_new = 0, sum_old = 0; // sum of the newest (oldest) COTAG_STEP_K samples
|
||||
|
||||
int32_t peak_recent_step = 0; // peak of step, scaled by 65536 so the decay below cannot truncate to zero
|
||||
uint32_t sample_cnt = 0;
|
||||
uint32_t last_rise = 0; // sample_cnt at the previous detected rising edge
|
||||
bool armed = true;
|
||||
uint16_t checked = 0;
|
||||
|
||||
for (;;) {
|
||||
WDT_HIT();
|
||||
|
||||
if (++checked >= 4000) {
|
||||
checked = 0;
|
||||
if (BUTTON_PRESS() || data_available()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (FPGA_SSC_RX_Ready() == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t sample = FPGA_SSC_RX_Value();
|
||||
|
||||
// Recalculate sum_new and sum_old.
|
||||
// sample (new) added to sum_new; mid subtracted from sum_new and added to sum_old,
|
||||
// ring[idx] (oldest) subtracted from sum_old and discarded.
|
||||
uint8_t mid = ring[(idx + COTAG_STEP_K) % (2 * COTAG_STEP_K)];
|
||||
sum_new += sample - mid;
|
||||
sum_old += mid - ring[idx];
|
||||
ring[idx] = sample;
|
||||
idx = (idx + 1) % (2 * COTAG_STEP_K);
|
||||
|
||||
if (++sample_cnt < 2 * COTAG_STEP_K) {
|
||||
continue; // wait for the ring buffer to fill up first
|
||||
}
|
||||
|
||||
// Step filter
|
||||
int32_t step = sum_new - sum_old;
|
||||
if (step * 65536 > peak_recent_step) {
|
||||
peak_recent_step = step * 65536; // attack at once
|
||||
} else {
|
||||
peak_recent_step -= peak_recent_step >> 13; // release slowly, tau 2^13 samples
|
||||
}
|
||||
|
||||
// use threshold as half the recent peak step (adapting to reader distance)
|
||||
// (undo scaling by 65536 aka 2^16, then divide by 2: thus >> 17)
|
||||
int32_t thr = MAX(params->thr_floor, peak_recent_step >> 17);
|
||||
|
||||
// Rising edge detection: Schmitt trigger so that we get one event per rise:
|
||||
// trigger once when step >= thr, then disarm, only re-arm if step falls below thr/4
|
||||
if (armed && step >= thr) {
|
||||
armed = false;
|
||||
uint32_t dt = sample_cnt - last_rise; // number of samples since the previous rise
|
||||
|
||||
if (last_rise && dt >= win_lo && dt <= win_hi) {
|
||||
// Activation sequence detected
|
||||
out->dt = dt;
|
||||
out->thr = thr;
|
||||
return true;
|
||||
}
|
||||
last_rise = sample_cnt;
|
||||
|
||||
} else if (step <= thr / 4) {
|
||||
// step enough below the thr, re-arm Schmitt trigger
|
||||
armed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define COTAG_TX_HALFBIT_CYCLES (384 / 2) // Number of samples per half bit
|
||||
#define COTAG_TX_SYNC_HALFBITS 4 // two leading sync 0 bits
|
||||
#define COTAG_TX_MAX_HALFBITS (COTAG_TX_SYNC_HALFBITS + 2 * 8 * LF_COTAG_SIM_DATA_LEN)
|
||||
|
||||
#define COTAG_SSC_STALL 100000
|
||||
#define COTAG_SETTLE_US 10000
|
||||
|
||||
// Discard count samples ("wait count samples"). Return false on error.
|
||||
static bool cotag_skip_samples(uint32_t count) {
|
||||
while (count--) {
|
||||
uint32_t guard = 0;
|
||||
while (FPGA_SSC_RX_Ready() == false) {
|
||||
if (++guard > COTAG_SSC_STALL) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
(void)FPGA_SSC_RX_Value();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint16_t cotag_build_halfbits(uint8_t *half_bits, const uint8_t *data, uint8_t nbits) {
|
||||
|
||||
// Two leading/sync 0 bits, manchester encoded
|
||||
half_bits[0] = 0;
|
||||
half_bits[1] = 1;
|
||||
half_bits[2] = 0;
|
||||
half_bits[3] = 1;
|
||||
|
||||
uint16_t nhb = COTAG_TX_SYNC_HALFBITS;
|
||||
for (uint8_t i = 0; i < nbits; i++) {
|
||||
// bits in reverse order:
|
||||
uint8_t src = nbits - 1 - i;
|
||||
uint8_t bit = (data[src >> 3] >> (7 - (src & 7))) & 1;
|
||||
// manchester encode the bit:
|
||||
half_bits[nhb++] = bit;
|
||||
half_bits[nhb++] = bit ^ 1;
|
||||
}
|
||||
return nhb;
|
||||
}
|
||||
|
||||
// Send COTAG frame's half bits. Return false on button press, USB data, or error.
|
||||
static bool cotag_tx_frame(const uint8_t *half_bits, uint16_t nhb, uint8_t repeats, uint16_t hb_delay_us) {
|
||||
|
||||
Gpio_SSC_DOUT_High();
|
||||
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_COTAG_TX_DIVISOR);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
|
||||
|
||||
bool ok = true;
|
||||
for (uint8_t r = 0; r < repeats && ok; r++) {
|
||||
// Send precomputed half bits. Leading sync bits are sent only at first repetition
|
||||
for (uint16_t i = (r == 0) ? 0 : COTAG_TX_SYNC_HALFBITS; i < nhb; i++) {
|
||||
if (half_bits[i]) {
|
||||
Gpio_SSC_DOUT_Low();
|
||||
} else {
|
||||
Gpio_SSC_DOUT_High();
|
||||
}
|
||||
|
||||
if (hb_delay_us) {
|
||||
SpinDelayUsPrecision(hb_delay_us);
|
||||
} else if (cotag_skip_samples(COTAG_TX_HALFBIT_CYCLES) == false) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (BUTTON_PRESS()) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
WDT_HIT();
|
||||
if (data_available()) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Gpio_SSC_DOUT_High();
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC);
|
||||
Gpio_SSC_DOUT_Low(); // back to "listening"
|
||||
return ok;
|
||||
}
|
||||
|
||||
void SimulateCotag(const lf_cotagsim_t *params, bool ledcontrol) {
|
||||
|
||||
LFSetupFPGAForADC(LF_COTAG_DIVISOR, false);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC);
|
||||
gpio_fpga_mod_only_setup();
|
||||
Gpio_SSC_DOUT_Low();
|
||||
|
||||
BigBuf_free();
|
||||
BigBuf_Clear_ext(false);
|
||||
|
||||
uint8_t *half_bits = BigBuf_calloc(COTAG_TX_MAX_HALFBITS);
|
||||
if (half_bits == NULL) {
|
||||
if (g_dbglevel >= DBG_ERROR) DbpString("SimulateCotag: failed to allocate buffer");
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t nbits = MIN(params->nbits, 8 * LF_COTAG_SIM_DATA_LEN);
|
||||
|
||||
// Precompute the Manchester halfbits to send
|
||||
uint16_t nhb = cotag_build_halfbits(half_bits, params->data, nbits);
|
||||
|
||||
const uint32_t settle = COTAG_SETTLE_US * 12 / (LF_COTAG_DIVISOR + 1);
|
||||
|
||||
cotag_detect_val_t val;
|
||||
|
||||
while (cotag_activation_sequence_detect(params, &val)) {
|
||||
if (nbits) {
|
||||
if (ledcontrol) LED_C_ON();
|
||||
|
||||
// Transmit frame
|
||||
bool ok = cotag_tx_frame(half_bits, nhb, params->repeats, params->hb_delay_us);
|
||||
|
||||
if (ledcontrol) LED_C_OFF();
|
||||
|
||||
if (ok == false) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Done transmitting. Back to our RX sampling divisor:
|
||||
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_COTAG_DIVISOR);
|
||||
|
||||
cotag_skip_samples(settle);
|
||||
}
|
||||
|
||||
// Debug print only after done TXing frame
|
||||
if (params->verbose || nbits == 0) {
|
||||
Dbprintf("COTAG reader activation sequence detected (rise-to-rise " _YELLOW_("%u") " us, threshold %d)",
|
||||
val.dt * (LF_COTAG_DIVISOR + 1) / 12, val.thr);
|
||||
}
|
||||
}
|
||||
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
if (ledcontrol) LEDsoff();
|
||||
BigBuf_free();
|
||||
}
|
||||
|
||||
/*
|
||||
* EM4305 support
|
||||
*/
|
||||
@@ -79,6 +79,7 @@ void EM4xProtectWord(uint32_t data, uint32_t pwd, uint8_t usepwd, bool ledcontro
|
||||
|
||||
void cotag_start_pulse(void);
|
||||
void Cotag(uint32_t arg0, bool ledcontrol);
|
||||
void SimulateCotag(const lf_cotagsim_t *params, bool ledcontrol);
|
||||
void setT55xxConfig(uint8_t persist, const t55xx_configurations_t *c);
|
||||
t55xx_configurations_t *getT55xxConfig(void);
|
||||
void printT55xxConfig(void);
|
||||
|
||||
+79
-1
@@ -38,12 +38,15 @@
|
||||
#define XSTR(x) #x
|
||||
#define STR(x) XSTR(x)
|
||||
|
||||
#define LF_COTAG_DIVISOR 90 // 132 kHz
|
||||
#define LF_COTAG_CLOCK 768
|
||||
#define LF_COTAG_DATA_LEN 128
|
||||
|
||||
#define LF_COTAG_DEF_SAMPLES_READ 500000
|
||||
|
||||
#define LF_COTAG_SIM_FLOOR 128
|
||||
#define LF_COTAG_SIM_MIN_BYTES 8
|
||||
#define LF_COTAG_SIM_MAX_REPEATS 16
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int demod_cotag(int32_t *samples, int num_samples, int clock, int clock_start, double threshold, bool verbose);
|
||||
@@ -540,10 +543,85 @@ static int CmdCOTAGReader(const char *Cmd) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int CmdCOTAGSim(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf cotag sim",
|
||||
"Enables simulation of a COTAG tag.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.\n"
|
||||
"Without " _YELLOW_("`-r`") _CYAN_(" it only reports detected reader activation sequence.\n")
|
||||
_CYAN_("Note: COTAG tag full repeating sequence is 128 bits, but readers seem to care about LSB 64 bits only."),
|
||||
"lf cotag sim --> only detect the reader\n"
|
||||
"lf cotag sim -r A37E0D37000C1337 --> send 64 bits\n"
|
||||
"lf cotag sim -r 0000000000000002A37E0D37000C1337\n"
|
||||
"lf cotag sim --floor 32 --> more sensitive, for a reader further away\n"
|
||||
"lf cotag sim -r A37E0D37000C1337 --hb_delay_us 2909 --> time the half bit instead of counting cycles\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("r", "raw", "<hex>", "raw data to answer with, " STR(LF_COTAG_SIM_MIN_BYTES) " to " STR(LF_COTAG_SIM_DATA_LEN) " bytes (64-128 bits)"),
|
||||
arg_int0("n", "repeat", "<1-" STR(LF_COTAG_SIM_MAX_REPEATS) ">", "repeat data frame this many times per answer (def 1)"),
|
||||
arg_int0(NULL, "floor", "<16-65535>", "minimum rise threshold (def " STR(LF_COTAG_SIM_FLOOR) ")"),
|
||||
arg_int0(NULL, "hb_delay_us", "<2900-2918>", "custom half bit delay [us] (should be around 2909)"),
|
||||
arg_lit0("v", "verbose", "report detected reader activation sequence while answering"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
||||
uint8_t data[LF_COTAG_SIM_DATA_LEN] = {0};
|
||||
int dlen = 0;
|
||||
CLIGetHexWithReturn(ctx, 1, data, &dlen);
|
||||
int repeats = arg_get_int_def(ctx, 2, 1);
|
||||
int thr_floor = arg_get_int_def(ctx, 3, LF_COTAG_SIM_FLOOR);
|
||||
int hb_delay = arg_get_int_def(ctx, 4, 0);
|
||||
bool verbose = arg_get_lit(ctx, 5);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (dlen && (dlen < LF_COTAG_SIM_MIN_BYTES || dlen > LF_COTAG_SIM_DATA_LEN)) {
|
||||
PrintAndLogEx(ERR, "data must be %d to %d bytes (64 to 128 bits), got %d"
|
||||
, LF_COTAG_SIM_MIN_BYTES, LF_COTAG_SIM_DATA_LEN, dlen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (repeats < 1 || repeats > LF_COTAG_SIM_MAX_REPEATS) {
|
||||
PrintAndLogEx(ERR, "repeat must be between 1 and %d", LF_COTAG_SIM_MAX_REPEATS);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (thr_floor < 16 || thr_floor > 0xFFFF) {
|
||||
PrintAndLogEx(ERR, "floor must be between 16 and 65535");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (hb_delay && (hb_delay < 2900 || hb_delay > 2918)) {
|
||||
PrintAndLogEx(ERR, "hb_delay_us must be between 2900 and 2918 us");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
lf_cotagsim_t payload = {
|
||||
.thr_floor = (uint16_t)thr_floor,
|
||||
.hb_delay_us = (uint16_t)hb_delay,
|
||||
.nbits = (uint8_t)(dlen * 8),
|
||||
.repeats = (uint8_t)repeats,
|
||||
.verbose = verbose,
|
||||
};
|
||||
memcpy(payload.data, data, dlen);
|
||||
|
||||
PrintAndLogEx(INFO, "Simulating COTAG tag");
|
||||
if (dlen == 0) {
|
||||
PrintAndLogEx(INFO, "No " _YELLOW_("`-r`") " given, detecting reader activation sequence only");
|
||||
}
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_COTAG_SIMULATE, (uint8_t *)&payload, sizeof(payload));
|
||||
return lfsim_wait_check(CMD_LF_COTAG_SIMULATE);
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdCOTAGDemod, AlwaysAvailable, "demodulate a COTAG tag"},
|
||||
{"reader", CmdCOTAGReader, IfPm3Lf, "attempt to read and extract tag data"},
|
||||
{"sim", CmdCOTAGSim, IfPm3Lf, "simulate a COTAG tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
+23
-2
@@ -11760,6 +11760,27 @@
|
||||
],
|
||||
"usage": "lf cotag reader [-hv@] [-s <dec>] [--divisor <19-255>]"
|
||||
},
|
||||
"lf cotag sim": {
|
||||
"command": "lf cotag sim",
|
||||
"description": "Enables simulation of a COTAG tag. Simulation runs until the button is pressed or another USB command is issued. Without `-r` it only reports detected reader activation sequence. Note: COTAG tag full repeating sequence is 128 bits, but readers seem to care about LSB 64 bits only.",
|
||||
"notes": [
|
||||
"lf cotag sim -> only detect the reader",
|
||||
"lf cotag sim -r A37E0D37000C1337 -> send 64 bits",
|
||||
"lf cotag sim -r 0000000000000002A37E0D37000C1337",
|
||||
"lf cotag sim --floor 32 -> more sensitive, for a reader further away",
|
||||
"lf cotag sim -r A37E0D37000C1337 --hb_delay_us 2909 -> time the half bit instead of counting cycles"
|
||||
],
|
||||
"offline": false,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"-r, --raw <hex> raw data to answer with, 8 to 16 bytes (64-128 bits)",
|
||||
"-n, --repeat <1-16> repeat data frame this many times per answer (def 1)",
|
||||
"--floor <16-65535> minimum rise threshold (def 128)",
|
||||
"--hb_delay_us <2900-2918> custom half bit delay [us] (should be around 2909)",
|
||||
"-v, --verbose report detected reader activation sequence while answering"
|
||||
],
|
||||
"usage": "lf cotag sim [-hv] [-r <hex>] [-n <1-16>] [--floor <16-65535>] [--hb_delay_us <2900-2918>]"
|
||||
},
|
||||
"lf destron clone": {
|
||||
"command": "lf destron clone",
|
||||
"description": "clone a Destron tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
|
||||
@@ -16785,8 +16806,8 @@
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"commands_extracted": 935,
|
||||
"commands_extracted": 936,
|
||||
"extracted_by": "PM3Help2JSON v1.00",
|
||||
"extracted_on": "2026-09-27T19:09:12+00:00"
|
||||
"extracted_on": "2026-10-11T13:59:06+00:00"
|
||||
}
|
||||
}
|
||||
@@ -1119,6 +1119,7 @@ Check column "offline" for their availability.
|
||||
|`lf cotag help `|Y |`This help`
|
||||
|`lf cotag demod `|Y |`demodulate a COTAG tag`
|
||||
|`lf cotag reader `|N |`attempt to read and extract tag data`
|
||||
|`lf cotag sim `|N |`simulate a COTAG tag`
|
||||
|
||||
|
||||
### lf destron
|
||||
|
||||
@@ -380,6 +380,20 @@ typedef struct {
|
||||
uint8_t data[];
|
||||
} PACKED lf_hitag_t;
|
||||
|
||||
#define LF_COTAG_DIVISOR 90
|
||||
#define LF_COTAG_TX_DIVISOR 181
|
||||
|
||||
// For CMD_LF_COTAG_SIMULATE
|
||||
#define LF_COTAG_SIM_DATA_LEN 16 // 128 bits, the longest repeating COTAG frame
|
||||
typedef struct {
|
||||
uint16_t thr_floor; // minimum rise threshold
|
||||
uint16_t hb_delay_us; // optional custom half bit delay [us]
|
||||
uint8_t repeats; // repeat data frame this many times per answer
|
||||
bool verbose;
|
||||
uint8_t nbits; // number of data bits
|
||||
uint8_t data[LF_COTAG_SIM_DATA_LEN];
|
||||
} PACKED lf_cotagsim_t;
|
||||
|
||||
// For CMD_LF_SNIFF_RAW_ADC and CMD_LF_ACQ_RAW_ADC
|
||||
#define LF_SAMPLES_BITS 30
|
||||
#define MAX_LF_SAMPLES ((((uint32_t)1u) << LF_SAMPLES_BITS) - 1)
|
||||
@@ -1092,6 +1106,7 @@ typedef struct {
|
||||
#define CMD_LF_VIKING_CLONE 0x0222
|
||||
#define CMD_LF_T55XX_WAKEUP 0x0224
|
||||
#define CMD_LF_COTAG_READ 0x0225
|
||||
#define CMD_LF_COTAG_SIMULATE 0x022B
|
||||
#define CMD_LF_T55XX_SET_CONFIG 0x0226
|
||||
#define CMD_LF_SAMPLING_PRINT_CONFIG 0x0227
|
||||
#define CMD_LF_SAMPLING_GET_CONFIG 0x0228
|
||||
|
||||
Reference in new issue
Block a user