also needed to include some of icemans timer additions.
case CMD_VIKING_CLONE_TAG:
CopyVikingtoT55xx(c->arg[0], c->arg[1], c->arg[2]);
break;
+ case CMD_COTAG:
+ Cotag(c->arg[0]);
+ break;
#endif
#ifdef WITH_HITAG
//void T55xxReadTrace(void);
void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode);
void EM4xWriteWord(uint32_t Data, uint8_t Address, uint32_t Pwd, uint8_t PwdMode);
+void Cotag(uint32_t arg0);
/// iso14443.h
void SimulateIso14443bTag(void);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
LED_D_OFF();
}
+/*
+Reading a COTAG.
+
+COTAG needs the reader to send a startsequence and the card has an extreme slow datarate.
+because of this, we can "sample" the data signal but we interpreate it to Manchester direct.
+
+READER START SEQUENCE:
+burst 800 us, gap 2.2 msecs
+burst 3.6 msecs gap 2.2 msecs
+burst 800 us gap 2.2 msecs
+pulse 3.6 msecs
+
+This triggers a COTAG tag to response
+*/
+void Cotag(uint32_t arg0) {
+
+#define OFF { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); WaitUS(2035); }
+#define ON(x) { FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); WaitUS((x)); }
+
+ uint8_t rawsignal = arg0 & 0xF;
+
+ LED_A_ON();
+
+ // Switching to LF image on FPGA. This might empty BigBuff
+ FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
+
+ //clear buffer now so it does not interfere with timing later
+ BigBuf_Clear_ext(false);
+
+ // Set up FPGA, 132kHz to power up the tag
+ FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 89);
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
+
+ // Connect the A/D to the peak-detected low-frequency path.
+ SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
+
+ // Now set up the SSC to get the ADC samples that are now streaming at us.
+ FpgaSetupSsc();
+
+ // start clock - 1.5ticks is 1us
+ StartTicks();
+
+ //send COTAG start pulse
+ ON(740) OFF
+ ON(3330) OFF
+ ON(740) OFF
+ ON(1000)
+
+ switch(rawsignal) {
+ case 0: doCotagAcquisition(50000); break;
+ case 1: doCotagAcquisitionManchester(); break;
+ case 2: DoAcquisition_config(TRUE); break;
+ }
+
+ // Turn the field off
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
+ cmd_send(CMD_ACK,0,0,0,0,0);
+ LED_A_OFF();
+}
#include "apps.h"
#include "util.h"
#include "string.h"
-#include "usb_cdc.h" // for usb_poll_validate_length
#include "lfsampling.h"
+#include "usb_cdc.h" // for usb_poll_validate_length
+//#include "ticks.h" // for StartTicks
sample_config config = { 1, 8, 1, 95, 0 } ;
uint32_t sample_total_numbers =0 ;
uint32_t sample_total_saved =0 ;
- while(!BUTTON_PRESS()) {
+ while(!BUTTON_PRESS() && !usb_poll_validate_length() ) {
WDT_HIT();
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
AT91C_BASE_SSC->SSC_THR = 0x43;
**/
uint32_t SampleLF(bool printCfg)
{
- return ReadLF(true, printCfg);
+ uint32_t ret = ReadLF(true, printCfg);
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+ return ret;
}
/**
* Initializes the FPGA for snoop-mode (field off), and acquires the samples.
uint32_t SnoopLF()
{
- return ReadLF(false, true);
+ uint32_t ret = ReadLF(false, true);
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+ return ret;
}
/**
}
}
}
+
+/**
+* acquisition of Cotag LF signal. Similart to other LF, since the Cotag has such long datarate RF/384
+* and is Manchester?, we directly gather the manchester data into bigbuff
+**/
+#define COTAG_T1 384
+#define COTAG_T2 (COTAG_T1>>1)
+#define COTAG_ONE_THRESHOLD 128+30
+#define COTAG_ZERO_THRESHOLD 128-30
+#ifndef COTAG_BITS
+#define COTAG_BITS 264
+#endif
+void doCotagAcquisition(size_t sample_size) {
+
+ uint8_t *dest = BigBuf_get_addr();
+ uint16_t bufsize = BigBuf_max_traceLen();
+
+ if ( bufsize > sample_size )
+ bufsize = sample_size;
+
+ dest[0] = 0;
+ uint8_t sample = 0, firsthigh = 0, firstlow = 0;
+ uint16_t i = 0;
+
+ while (!BUTTON_PRESS() && !usb_poll_validate_length() && (i < bufsize) ) {
+ WDT_HIT();
+ if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
+ AT91C_BASE_SSC->SSC_THR = 0x43;
+ LED_D_ON();
+ }
+
+ if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
+ sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
+ LED_D_OFF();
+
+ // find first peak
+ if ( !firsthigh ) {
+ if (sample < COTAG_ONE_THRESHOLD)
+ continue;
+ firsthigh = 1;
+ }
+ if ( !firstlow ){
+ if (sample > COTAG_ZERO_THRESHOLD )
+ continue;
+ firstlow = 1;
+ }
+
+ ++i;
+
+ if ( sample > COTAG_ONE_THRESHOLD)
+ dest[i] = 255;
+ else if ( sample < COTAG_ZERO_THRESHOLD)
+ dest[i] = 0;
+ else
+ dest[i] = dest[i-1];
+ }
+ }
+}
+
+uint32_t doCotagAcquisitionManchester() {
+
+ uint8_t *dest = BigBuf_get_addr();
+ uint16_t bufsize = BigBuf_max_traceLen();
+
+ if ( bufsize > COTAG_BITS )
+ bufsize = COTAG_BITS;
+
+ dest[0] = 0;
+ uint8_t sample = 0, firsthigh = 0, firstlow = 0;
+ uint16_t sample_counter = 0, period = 0;
+ uint8_t curr = 0, prev = 0;
+
+ while (!BUTTON_PRESS() && !usb_poll_validate_length() && (sample_counter < bufsize) ) {
+ WDT_HIT();
+ if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
+ AT91C_BASE_SSC->SSC_THR = 0x43;
+ LED_D_ON();
+ }
+
+ if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
+ sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
+ LED_D_OFF();
+
+ // find first peak
+ if ( !firsthigh ) {
+ if (sample < COTAG_ONE_THRESHOLD)
+ continue;
+ firsthigh = 1;
+ }
+
+ if ( !firstlow ){
+ if (sample > COTAG_ZERO_THRESHOLD )
+ continue;
+ firstlow = 1;
+ }
+
+ // set sample 255, 0, or previous
+ if ( sample > COTAG_ONE_THRESHOLD){
+ prev = curr;
+ curr = 1;
+ }
+ else if ( sample < COTAG_ZERO_THRESHOLD) {
+ prev = curr;
+ curr = 0;
+ }
+ else {
+ curr = prev;
+ }
+
+ // full T1 periods,
+ if ( period > 0 ) {
+ --period;
+ continue;
+ }
+
+ dest[sample_counter] = curr;
+ ++sample_counter;
+ period = COTAG_T1;
+ }
+ }
+ return sample_counter;
+}
#ifndef LFSAMPLING_H
#define LFSAMPLING_H
+/**
+* acquisition of Cotag LF signal. Similar to other LF, since the Cotag has such long datarate RF/384
+* and is Manchester?, we directly gather the manchester data into bigbuff
+**/
+void doCotagAcquisition(size_t sample_size);
+uint32_t doCotagAcquisitionManchester(void);
+
/**
* acquisition of T55x7 LF signal. Similart to other LF, but adjusted with @marshmellows thresholds
* the data is collected in BigBuf.
}
uint32_t RAMFUNC GetCountUS(){
- return (AT91C_BASE_TC1->TC_CV * 0x8000) + ((AT91C_BASE_TC0->TC_CV / 15) * 10);
+ return (AT91C_BASE_TC1->TC_CV * 0x8000) + ((AT91C_BASE_TC0->TC_CV * 2) / 3); //was /15) * 10);
}
static uint32_t GlobalUsCounter = 0;
// we can use the counter.
while (AT91C_BASE_TC0->TC_CV < 0xFFF0);
}
-
-
+void ResetSspClk(void) {
+ //enable clock of timer and software trigger
+ AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
+ AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
+ AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
+ while (AT91C_BASE_TC2->TC_CV > 0);
+}
uint32_t RAMFUNC GetCountSspClk(){
uint32_t tmp_count;
tmp_count = (AT91C_BASE_TC2->TC_CV << 16) | AT91C_BASE_TC0->TC_CV;
}
}
+// -------------------------------------------------------------------------
+// Timer for bitbanging, or LF stuff when you need a very precis timer
+// 1us = 1.5ticks
+// -------------------------------------------------------------------------
+void StartTicks(void){
+ //initialization of the timer
+ // tc1 is higher 0xFFFF0000
+ // tc0 is lower 0x0000FFFF
+ AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1);
+ AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE;
+ AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
+ AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK | // MCK(48MHz) / 32
+ AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO | AT91C_TC_ACPA_CLEAR |
+ AT91C_TC_ACPC_SET | AT91C_TC_ASWTRG_SET;
+ AT91C_BASE_TC0->TC_RA = 1;
+ AT91C_BASE_TC0->TC_RC = 0;
+
+ AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // timer disable
+ AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_XC1; // from TC0
+
+ AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
+ AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
+ AT91C_BASE_TCB->TCB_BCR = 1;
+
+ // wait until timer becomes zero.
+ while (AT91C_BASE_TC1->TC_CV > 0);
+}
+
+// Wait - Spindelay in ticks.
+// if called with a high number, this will trigger the WDT...
+void WaitTicks(uint32_t ticks){
+ if ( ticks == 0 ) return;
+ ticks += GET_TICKS;
+ while (GET_TICKS < ticks);
+}
+// Wait / Spindelay in us (microseconds)
+// 1us = 1.5ticks.
+void WaitUS(uint16_t us){
+ if ( us == 0 ) return;
+ WaitTicks( (uint32_t)(us * 1.5) );
+}
+void WaitMS(uint16_t ms){
+ if (ms == 0) return;
+ WaitTicks( (uint32_t)(ms * 1500) );
+}
+// Starts Clock and waits until its reset
+void ResetTicks(void){
+ 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_TC1->TC_CV > 0);
+}
+void ResetTimer(AT91PS_TC timer){
+ timer->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
+ while(timer->TC_CV > 0) ;
+}
+// stop clock
+void StopTicks(void){
+ AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
+ AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
+}
+
static uint64_t next_random = 1;
/* Generates a (non-cryptographically secure) 32-bit random number.
void lsl (uint8_t *data, size_t len);
int32_t le24toh (uint8_t data[3]);
-void SpinDelay(int ms);
-void SpinDelayUs(int us);
void LED(int led, int ms);
void LEDsoff();
int BUTTON_CLICKED(int ms);
int BUTTON_HELD(int ms);
void FormatVersionInformation(char *dst, int len, const char *prefix, void *version_information);
+//iceman's ticks.h
+#ifndef GET_TICKS
+# define GET_TICKS (uint32_t)((AT91C_BASE_TC1->TC_CV << 16) | AT91C_BASE_TC0->TC_CV)
+#endif
+
+void SpinDelay(int ms);
+void SpinDelayUs(int us);
+
void StartTickCount();
uint32_t RAMFUNC GetTickCount();
uint32_t RAMFUNC GetDeltaCountUS();
void StartCountSspClk();
+void ResetSspClk(void);
uint32_t RAMFUNC GetCountSspClk();
+extern void StartTicks(void);
+extern void WaitTicks(uint32_t ticks);
+extern void WaitUS(uint16_t us);
+extern void WaitMS(uint16_t ms);
+extern void ResetTicks();
+extern void ResetTimer(AT91PS_TC timer);
+extern void StopTicks(void);
+// end iceman's ticks.h
+
uint32_t prand();
#endif
cmdlfviking.c\
cmdlfpresco.c\
cmdlfpyramid.c\
+ cmdlfcotag.c\
pm3_binlib.c\
scripting.c\
cmdscript.c\
#include "cmdlfpcf7931.h"// for pcf7931 menu
#include "cmdlfpyramid.h"// for pyramid menu
#include "cmdlfviking.h" // for viking menu
+#include "cmdlfcotag.h" // for COTAG menu
+
static int CmdHelp(const char *Cmd);
int CmdLFfind(const char *Cmd)
{
int ans=0;
+ size_t minLength = 1000;
char cmdp = param_getchar(Cmd, 0);
char testRaw = param_getchar(Cmd, 1);
if (strlen(Cmd) > 3 || cmdp == 'h' || cmdp == 'H') {
if (!offline && (cmdp != '1')){
CmdLFRead("s");
getSamples("30000",false);
- } else if (GraphTraceLen < 1000) {
+ } else if (GraphTraceLen < minLength) {
PrintAndLog("Data in Graphbuffer was too small.");
return 0;
}
PrintAndLog("False Positives ARE possible\n");
PrintAndLog("\nChecking for known tags:\n");
+ size_t testLen = minLength;
+ // only run if graphbuffer is just noise as it should be for hitag/cotag
+ if (graphJustNoise(GraphBuffer, testLen)) {
+ // only run these tests if we are in online mode
+ if (!offline && (cmdp != '1')){
+ ans=CmdLFHitagReader("26");
+ if (ans==0) {
+ return 1;
+ }
+ ans=CmdCOTAGRead("");
+ if (ans>0){
+ PrintAndLog("\nValid COTAG ID Found!");
+ return 1;
+ }
+ }
+ return 0;
+ }
+
ans=CmdFSKdemodIO("");
if (ans>0) {
PrintAndLog("\nValid IO Prox ID Found!");
return 1;
}
- size_t testLen = (GraphTraceLen < 500) ? GraphTraceLen : 500;
- // only run if graphbuffer is just noise as it should be for hitag
- if (graphJustNoise(GraphBuffer, testLen)) {
- if (!offline && (cmdp != '1')){
- ans=CmdLFHitagReader("26");
- if (ans==0) {
- return 1;
- }
- }
- }
-
PrintAndLog("\nNo Known Tags Found!\n");
if (testRaw=='u' || testRaw=='U'){
//test unknown tag formats (raw mode)
{
{"help", CmdHelp, 1, "This help"},
{"awid", CmdLFAWID, 1, "{ AWID RFIDs... }"},
+ {"cotag", CmdLFCOTAG, 1, "{ COTAG RFIDs... }"},
{"em4x", CmdLFEM4X, 1, "{ EM4X RFIDs... }"},
{"hid", CmdLFHID, 1, "{ HID RFIDs... }"},
{"hitag", CmdLFHitag, 1, "{ Hitag tags and transponders... }"},
--- /dev/null
+//-----------------------------------------------------------------------------
+// Authored by Iceman
+//
+// This code is licensed to you under the terms of the GNU GPL, version 2 or,
+// at your option, any later version. See the LICENSE.txt file for the text of
+// the license.
+//-----------------------------------------------------------------------------
+// Low frequency COTAG commands
+//-----------------------------------------------------------------------------
+#include "cmdlfcotag.h" // COTAG function declarations
+
+static int CmdHelp(const char *Cmd);
+
+int usage_lf_cotag_read(void){
+ PrintAndLog("Usage: lf COTAG read [h] <signaldata>");
+ PrintAndLog("Options:");
+ PrintAndLog(" h : This help");
+ PrintAndLog(" <0|1|2> : 0 - HIGH/LOW signal; maxlength bigbuff");
+ PrintAndLog(" : 1 - translation of HI/LO into bytes with manchester 0,1");
+ PrintAndLog(" : 2 - raw signal; maxlength bigbuff");
+ PrintAndLog("");
+ PrintAndLog("Sample:");
+ PrintAndLog(" lf cotag read 0");
+ PrintAndLog(" lf cotag read 1");
+ return 0;
+}
+
+// COTAG demod should be able to use GraphBuffer,
+// when data load samples
+int CmdCOTAGDemod(const char *Cmd) {
+
+ uint8_t bits[COTAG_BITS] = {0};
+ size_t bitlen = COTAG_BITS;
+ memcpy(bits, DemodBuffer, COTAG_BITS);
+
+ int err = manrawdecode(bits, &bitlen, 1);
+ if (err){
+ if (g_debugMode) PrintAndLog("DEBUG: Error - COTAG too many errors: %d", err);
+ return -1;
+ }
+
+ setDemodBuf(bits, bitlen, 0);
+
+ //got a good demod
+ uint16_t cn = bytebits_to_byteLSBF(bits+1, 16);
+ uint32_t fc = bytebits_to_byteLSBF(bits+1+16, 8);
+
+ uint32_t raw1 = bytebits_to_byteLSBF(bits, 32);
+ uint32_t raw2 = bytebits_to_byteLSBF(bits+32, 32);
+ uint32_t raw3 = bytebits_to_byteLSBF(bits+64, 32);
+ uint32_t raw4 = bytebits_to_byteLSBF(bits+96, 32);
+
+ /*
+ fc 161: 1010 0001 -> LSB 1000 0101
+ cn 33593 1000 0011 0011 1001 -> LSB 1001 1100 1100 0001
+ cccc cccc cccc cccc ffffffff
+ 0 1001 1100 1100 0001 1000 0101 0000 0000 100001010000000001111011100000011010000010000000000000000000000000000000000000000000000000000000100111001100000110000101000
+ 1001 1100 1100 0001 10000101
+ */
+ PrintAndLog("COTAG Found: FC %u, CN: %u Raw: %08X%08X%08X%08X", fc, cn, raw1 ,raw2, raw3, raw4);
+ return 1;
+}
+
+// When reading a COTAG.
+// 0 = HIGH/LOW signal - maxlength bigbuff
+// 1 = translation for HI/LO into bytes with manchester 0,1 - length 300
+// 2 = raw signal - maxlength bigbuff
+int CmdCOTAGRead(const char *Cmd) {
+
+ if (Cmd[0] == 'h' || Cmd[0] == 'H') return usage_lf_cotag_read();
+
+ uint32_t rawsignal = 1;
+ sscanf(Cmd, "%u", &rawsignal);
+
+ UsbCommand c = {CMD_COTAG, {rawsignal, 0, 0}};
+ clearCommandBuffer();
+ SendCommand(&c);
+ if ( !WaitForResponseTimeout(CMD_ACK, NULL, 7000) ) {
+ PrintAndLog("command execution time out");
+ return -1;
+ }
+
+ switch ( rawsignal ){
+ case 0:
+ case 2: {
+ CmdPlot("");
+ CmdGrid("384");
+ getSamples("", true); break;
+ }
+ case 1: {
+ GetFromBigBuf(DemodBuffer, COTAG_BITS, 0);
+ DemodBufferLen = COTAG_BITS;
+ UsbCommand response;
+ if ( !WaitForResponseTimeout(CMD_ACK, &response, 1000) ) {
+ PrintAndLog("timeout while waiting for reply.");
+ return -1;
+ }
+ return CmdCOTAGDemod("");
+ }
+ }
+ return 0;
+}
+
+static command_t CommandTable[] = {
+ {"help", CmdHelp, 1, "This help"},
+ {"demod", CmdCOTAGDemod, 1, "Tries to decode a COTAG signal"},
+ {"read", CmdCOTAGRead, 0, "Attempt to read and extract tag data"},
+ {NULL, NULL, 0, NULL}
+};
+
+int CmdLFCOTAG(const char *Cmd) {
+ clearCommandBuffer();
+ CmdsParse(CommandTable, Cmd);
+ return 0;
+}
+
+int CmdHelp(const char *Cmd) {
+ CmdsHelp(CommandTable);
+ return 0;
+}
--- /dev/null
+//-----------------------------------------------------------------------------
+// Authored by Iceman
+//
+// This code is licensed to you under the terms of the GNU GPL, version 2 or,
+// at your option, any later version. See the LICENSE.txt file for the text of
+// the license.
+//-----------------------------------------------------------------------------
+// Low frequency COTAG commands
+//-----------------------------------------------------------------------------
+
+#ifndef CMDLFCOTAG_H__
+#define CMDLFCOTAG_H__
+
+#include "proxmark3.h"// Definitions, USB controls, COTAG_BITS
+#include "util.h" // FALSE / TRUE
+#include "cmddata.h" // getSamples
+#include "cmdparser.h"// CmdsParse, CmdsHelp
+#include "cmdmain.h"
+#include "ui.h" // PrintAndLog
+#include "cmdlf.h" // Setconfig
+#include "lfdemod.h" // manrawdecode, bytebits_tobyteLSBF
+
+#ifndef COTAG_BITS
+#define COTAG_BITS 264
+#endif
+
+int CmdLFCOTAG(const char *Cmd);
+int CmdCOTAGRead(const char *Cmd);
+int CmdCOTAGDemod(const char *Cmd);
+
+int usage_lf_cotag_read(void);
+#endif
}
bool graphJustNoise(int *BitStream, int size)
{
- static const uint8_t THRESHOLD = 10; //might not be high enough for noisy environments
+ static const uint8_t THRESHOLD = 15; //might not be high enough for noisy environments
//test samples are not just noise
bool justNoise1 = 1;
for(int idx=0; idx < size && justNoise1 ;idx++){
#define CMD_AWID_DEMOD_FSK 0x0221
#define CMD_VIKING_CLONE_TAG 0x0223
#define CMD_T55XX_WAKEUP 0x0224
+#define CMD_COTAG 0x0225
/* CMD_SET_ADC_MUX: ext1 is 0 for lopkd, 1 for loraw, 2 for hipkd, 3 for hiraw */
CMD_AWID_DEMOD_FSK = 0x0221,
CMD_VIKING_CLONE_TAG = 0x0223,
CMD_T55XX_WAKEUP = 0x0224,
+ CMD_COTAG = 0x0225,
--/* CMD_SET_ADC_MUX: ext1 is 0 for lopkd, 1 for loraw, 2 for hipkd, 3 for hiraw */
--// For the 13.56 MHz tags
#define CMD_AWID_DEMOD_FSK 0x0221
#define CMD_VIKING_CLONE_TAG 0x0223
#define CMD_T55XX_WAKEUP 0x0224
+#define CMD_COTAG 0x0225
/* CMD_SET_ADC_MUX: ext1 is 0 for lopkd, 1 for loraw, 2 for hipkd, 3 for hiraw */