From 4b63f940f1cd052084a77b21365caea3570f8b1d Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 20 Oct 2017 20:27:44 +0200 Subject: [PATCH] CHG: FeliCa implemenation by @satsuoni --- armsrc/Makefile | 3 + armsrc/appmain.c | 12 ++ armsrc/apps.h | 5 + armsrc/fpgaloader.h | 10 ++ client/cmdhf.c | 116 ++++++++++++++++- client/cmdhffelica.c | 274 ++++++++++++++++++++++++++++++++++------ client/cmdhffelica.h | 5 + common/protocols.h | 61 +++++++++ fpga/fpga_hf.bit | Bin 42175 -> 42175 bytes fpga/fpga_hf.v | 67 ++++++++-- fpga/fpga_lf.bit | Bin 42175 -> 42175 bytes fpga/fpga_lf.v | 2 +- fpga/fpga_nfc.bit | Bin 42176 -> 42176 bytes fpga/fpga_nfc.v | 38 ++++-- fpga/hi_flite.v | 269 +++++++++++++++++++-------------------- fpga/hi_read_rx_xcorr.v | 27 ++-- fpga/hi_read_tx.v | 19 ++- fpga/hi_simulate.v | 9 +- fpga/hi_sniffer.v | 17 ++- include/usb_cmd.h | 3 + 20 files changed, 705 insertions(+), 232 deletions(-) diff --git a/armsrc/Makefile b/armsrc/Makefile index 15e04bbd1..1e40148da 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -21,6 +21,7 @@ APP_CFLAGS = -DWITH_CRC \ -DWITH_ISO14443b \ -DWITH_ISO14443a \ -DWITH_ICLASS \ + -DWITH_FELICA \ -DWITH_HFSNOOP \ -DWITH_HF_YOUNG \ -fno-strict-aliasing -ffunction-sections -fdata-sections @@ -45,6 +46,7 @@ SRC_LF = lfops.c hitag2.c hitagS.c lfsampling.c pcf7931.c lfdemod.c SRC_ISO15693 = iso15693.c iso15693tools.c SRC_ISO14443a = iso14443a.c mifareutil.c mifarecmd.c mifaresniff.c epa.c SRC_ISO14443b = iso14443b.c +SRC_FELICA = felica.c SRC_CRAPTO1 = crypto1.c des.c aes.c desfire_key.c desfire_crypto.c mifaredesfire.c SRC_CRC = iso14443crc.c crc.c crc16.c crc32.c SRC_EMV = tlv.c emvdataels.c emvutil.c emvcmd.c @@ -93,6 +95,7 @@ ARMSRC = fpgaloader.c \ $(SRC_ICLASS) \ $(SRC_EMV) \ $(SRC_CRC) \ + $(SRC_FELICA) \ parity.c \ usb_cdc.c \ cmd.c \ diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 46a1a3439..8dbf412e3 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -766,6 +766,18 @@ void UsbPacketReceived(uint8_t *packet, int len) { break; #endif +#ifdef WITH_FELICA + case CMD_FELICA_LITE_SIM: + HfSimLite(c->arg[0]); + break; + case CMD_FELICA_SNOOP: + HfSnoopISO18(c->arg[0], c->arg[1]); + break; + case CMD_FELICA_LITE_DUMP: + HfDumpFelicaLiteS(); + break; +#endif + #ifdef WITH_ISO14443a case CMD_SNOOP_ISO_14443a: SniffIso14443a(c->arg[0]); diff --git a/armsrc/apps.h b/armsrc/apps.h index 2661d32c4..d23efa17f 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -233,6 +233,11 @@ bool cmd_send(uint32_t cmd, uint32_t arg0, uint32_t arg1, uint32_t arg2, void* d // util.h void HfSnoop(int , int); +//felica.c +extern void HfSnoopISO18(uint32_t samples, uint32_t triggers); +extern void HfSimLite(uint64_t uid); +extern void HfDumpFelicaLiteS(); + //EMV functions // emvcmd.h extern void EMVTransaction(void); diff --git a/armsrc/fpgaloader.h b/armsrc/fpgaloader.h index 9e1b31cbe..557a136ea 100644 --- a/armsrc/fpgaloader.h +++ b/armsrc/fpgaloader.h @@ -85,4 +85,14 @@ extern void switch_off(); #define FPGA_HF_ISO14443A_READER_LISTEN (3<<0) #define FPGA_HF_ISO14443A_READER_MOD (4<<0) + +//options for Felica. +#define FPGA_MAJOR_MODE_ISO18092 (5<<5) +#define FPGA_HF_ISO18092_FLAG_NOMOD (1<<0) //disable modulation module +#define FPGA_HF_ISO18092_FLAG_424K (2<<0) // should enable 414k mode (untested). No autodetect +#define FPGA_HF_ISO18092_FLAG_READER (4<<0) // enables antenna power, to act as a reader instead of tag + + + + #endif \ No newline at end of file diff --git a/client/cmdhf.c b/client/cmdhf.c index 3f59533ae..8051ac463 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -745,6 +745,114 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui return tracepos; } +void printFelica(uint16_t traceLen, uint8_t *trace) +{ + PrintAndLog(" Gap | Src | Data | CRC | Annotation |"); + PrintAndLog("--------|-----|---------------------------------|----------|-------------------|"); + uint16_t tracepos=0; + //I am stripping SYNC + while(tracepos=traceLen) break; + uint16_t gap= (uint16_t)trace[tracepos+1]+((uint16_t)trace[tracepos]>>8); + uint16_t crc_ok=trace[tracepos+2]; + tracepos+=3; + if(tracepos+3>=traceLen) break; + uint16_t len=trace[tracepos+2]; + //printf("!!! %02x %02x %02x %02x %02x %02x %d",trace[tracepos+0],trace[tracepos+1],trace[tracepos+2],trace[tracepos+3],trace[tracepos+4],trace[tracepos+5],len); + tracepos+=3; //skip SYNC + if(tracepos+len+1>=traceLen) break; + uint8_t cmd=trace[tracepos]; + uint8_t isResponse=cmd&1; + char line[32][110]; + for (int j = 0; j < len+1 && j/8 < 32; j++) + { + snprintf(line[j/8]+(( j % 8) * 4), 110, " %02x ", trace[tracepos+j]); + } + char expbuf[50]; + switch(cmd) + { + case FELICA_POLL_REQ:snprintf(expbuf,49,"Poll Req");break; + case FELICA_POLL_ACK :snprintf(expbuf,49,"Poll Resp");break; + + case FELICA_REQSRV_REQ :snprintf(expbuf,49,"Request Srvc Req");break; +case FELICA_REQSRV_ACK :snprintf(expbuf,49,"Request Srv Resp");break; + +case FELICA_RDBLK_REQ :snprintf(expbuf,49,"Read block(s) Req");break; +case FELICA_RDBLK_ACK :snprintf(expbuf,49,"Read block(s) Resp");break; + +case FELICA_WRTBLK_REQ :snprintf(expbuf,49,"Write block(s) Req");break; +case FELICA_WRTBLK_ACK :snprintf(expbuf,49,"Write block(s) Resp");break; +case FELICA_SRCHSYSCODE_REQ :snprintf(expbuf,49,"Search syscode Req");break; +case FELICA_SRCHSYSCODE_ACK :snprintf(expbuf,49,"Search syscode Resp");break; + +case FELICA_REQSYSCODE_REQ :snprintf(expbuf,49,"Request syscode Req");break; +case FELICA_REQSYSCODE_ACK :snprintf(expbuf,49,"Request syscode Resp");break; + +case FELICA_AUTH1_REQ :snprintf(expbuf,49,"Auth1 Req");break; +case FELICA_AUTH1_ACK :snprintf(expbuf,49,"Auth1 Resp");break; + +case FELICA_AUTH2_REQ :snprintf(expbuf,49,"Auth2 Req");break; +case FELICA_AUTH2_ACK :snprintf(expbuf,49,"Auth2 Resp");break; + +case FELICA_RDSEC_REQ :snprintf(expbuf,49,"Secure read Req");break; +case FELICA_RDSEC_ACK :snprintf(expbuf,49,"Secure read Resp");break; + +case FELICA_WRTSEC_REQ :snprintf(expbuf,49,"Secure write Req");break; +case FELICA_WRTSEC_ACK :snprintf(expbuf,49,"Secure write Resp");break; + +case FELICA_REQSRV2_REQ :snprintf(expbuf,49,"Request Srvc v2 Req");break; +case FELICA_REQSRV2_ACK :snprintf(expbuf,49,"Request Srvc v2 Resp");break; + +case FELICA_GETSTATUS_REQ :snprintf(expbuf,49,"Get status Req");break; +case FELICA_GETSTATUS_ACK :snprintf(expbuf,49,"Get status Resp");break; + +case FELICA_OSVER_REQ :snprintf(expbuf,49,"Get OS Version Req");break; +case FELICA_OSVER_ACK :snprintf(expbuf,49,"Get OS Version Resp");break; + +case FELICA_RESET_MODE_REQ :snprintf(expbuf,49,"Reset mode Req");break; +case FELICA_RESET_MODE_ACK :snprintf(expbuf,49,"Reset mode Resp");break; + +case FELICA_AUTH1V2_REQ :snprintf(expbuf,49,"Auth1 v2 Req");break; +case FELICA_AUTH1V2_ACK :snprintf(expbuf,49,"Auth1 v2 Resp");break; + +case FELICA_AUTH2V2_REQ :snprintf(expbuf,49,"Auth2 v2 Req");break; +case FELICA_AUTH2V2_ACK :snprintf(expbuf,49,"Auth2 v2 Resp");break; + +case FELICA_RDSECV2_REQ :snprintf(expbuf,49,"Secure read v2 Req");break; +case FELICA_RDSECV2_ACK :snprintf(expbuf,49,"Secure read v2 Resp");break; +case FELICA_WRTSECV2_REQ :snprintf(expbuf,49,"Secure write v2 Req");break; +case FELICA_WRTSECV2_ACK :snprintf(expbuf,49,"Secure write v2 Resp");break; + +case FELICA_UPDATE_RNDID_REQ :snprintf(expbuf,49,"Update IDr Req");break; +case FELICA_UPDATE_RNDID_ACK :snprintf(expbuf,49,"Update IDr Resp");break; + default: snprintf(expbuf,49,"Unknown");break; + } + + int num_lines = MIN((len )/16 + 1, 16); + for (int j = 0; j < num_lines ; j++) + { + if (j == 0) { + PrintAndLog("%7d | %s |%-32s |%02x %02x %s| %s", + gap, + (isResponse ? "Tag" : "Rdr"), + line[j], + trace[tracepos+len], + trace[tracepos+len+1], + (crc_ok) ? "OK" : "NG", + expbuf); + } else { + PrintAndLog(" | |%-32s | | ", + line[j]); + } + } + tracepos+=len+1; + } + PrintAndLog(""); + +} + + int usage_hf_list(){ PrintAndLog("List protocol data in trace buffer."); PrintAndLog("Usage: hf list [f][c]"); @@ -863,6 +971,12 @@ int CmdHFList(const char *Cmd) { PrintAndLog("Recorded Activity (TraceLen = %d bytes)", traceLen); PrintAndLog(""); + if(protocol==FELICA) +{ +printFelica(traceLen,trace); +} +else +{ PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer"); if ( protocol == ISO_14443A ) PrintAndLog("iso14443a - All times are in carrier periods (1/13.56Mhz)"); @@ -882,7 +996,7 @@ int CmdHFList(const char *Cmd) { while(tracepos < traceLen) { tracepos = printTraceLine(tracepos, traceLen, trace, protocol, showWaitCycles, markCRCBytes); } - +} free(trace); return 0; } diff --git a/client/cmdhffelica.c b/client/cmdhffelica.c index aeebd919b..643a7b744 100644 --- a/client/cmdhffelica.c +++ b/client/cmdhffelica.c @@ -13,23 +13,44 @@ static int CmdHelp(const char *Cmd); int usage_hf_felica_sim(void) { PrintAndLog("\n Emulating ISO/18092 FeliCa tag \n"); - PrintAndLog("usage: hf felica sim [h] t u [v]"); + PrintAndLog("usage: hf felica sim [h] t [v]"); PrintAndLog("options: "); PrintAndLog(" h : This help"); PrintAndLog(" t : 1 = FeliCa"); - PrintAndLog(" : 2 = FeliCaS"); + PrintAndLog(" : 2 = FeliCaLiteS"); PrintAndLog(" v : (Optional) Verbose"); PrintAndLog("samples:"); - PrintAndLog(" hf felica sim t 1 u 11223344556677"); + PrintAndLog(" hf felica sim t 1 "); return 0; } + int usage_hf_felica_sniff(void){ PrintAndLog("It get data from the field and saves it into command buffer."); PrintAndLog("Buffer accessible from command 'hf list felica'"); - PrintAndLog("Usage: hf felica sniff [c][r]"); - PrintAndLog("c - triggered by first data from card"); - PrintAndLog("r - triggered by first 7-bit request from reader (REQ,WUP,...)"); - PrintAndLog("sample: hf felica sniff c r"); + PrintAndLog("Usage: hf felica sniff "); + PrintAndLog(" s samples to skip (decimal)"); + PrintAndLog(" t triggers to skip (decimal)"); + PrintAndLog("samples:"); + PrintAndLog(" hf felica sniff s 1000"); + return 0; +} +int usage_hf_felica_simlite(void) { + PrintAndLog("\n Emulating ISO/18092 FeliCa Lite tag \n"); + PrintAndLog("usage: hf felica litesim [h] u "); + PrintAndLog("options: "); + PrintAndLog(" h : This help"); + PrintAndLog(" uid : UID in hexsymbol"); + PrintAndLog("samples:"); + PrintAndLog(" hf felica litesim 11223344556677"); + return 0; +} +int usage_hf_felica_dumplite(void) { + PrintAndLog("\n Dump ISO/18092 FeliCa Lite tag \n"); + PrintAndLog("usage: hf felica litedump [h]"); + PrintAndLog("options: "); + PrintAndLog(" h : This help"); + PrintAndLog("samples:"); + PrintAndLog(" hf felica litedump"); return 0; } int usage_hf_felica_raw(void){ @@ -66,13 +87,6 @@ int CmdHFFelicaReader(const char *Cmd) { iso14a_card_select_t card; memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t)); - - /* - 0: couldn't read - 1: OK, with ATS - 2: OK, no ATS - 3: proprietary Anticollision - */ uint64_t select_status = resp.arg[0]; if (select_status == 0) { @@ -81,10 +95,6 @@ int CmdHFFelicaReader(const char *Cmd) { return 0; } - PrintAndLog(" UID : %s", sprint_hex(card.uid, card.uidlen)); - PrintAndLog("ATQA : %02x %02x", card.atqa[1], card.atqa[0]); - PrintAndLog(" SAK : %02x [%d]", card.sak, resp.arg[0]); - return select_status; } @@ -98,8 +108,8 @@ int CmdHFFelicaSim(const char *Cmd) { int uidlen = 0; bool verbose = false; - while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch(param_getchar(Cmd, cmdp)) { + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (param_getchar(Cmd, cmdp)) { case 'h': case 'H': return usage_hf_felica_sim(); @@ -155,22 +165,211 @@ int CmdHFFelicaSim(const char *Cmd) { return 0; } -int CmdHFFelicaSniff(const char *Cmd) { - int param = 0; - uint8_t ctmp; - for (int i = 0; i < 2; i++) { - ctmp = param_getchar(Cmd, i); - if (ctmp == 'h' || ctmp == 'H') return usage_hf_felica_sniff(); - if (ctmp == 'c' || ctmp == 'C') param |= 0x01; - if (ctmp == 'r' || ctmp == 'R') param |= 0x02; - } +int CmdHFFelicaSniff(const char *Cmd) { - UsbCommand c = {CMD_FELICA_SNOOP, {param, 0, 0}}; + uint8_t cmdp = 0; + uint64_t samples2skip = 0; + uint64_t triggers2skip = 0; + bool errors = false; + + while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch(param_getchar(Cmd, cmdp)) { + case 'h': + case 'H': + return usage_hf_felica_sniff(); + case 's': + case 'S': + samples2skip = param_get32ex(Cmd, cmdp+1, 0, 10); + cmdp += 2; + break; + case 't': + case 'T': + triggers2skip = param_get32ex(Cmd, cmdp+1, 0, 10); + cmdp += 2; + break; + default: + PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + //Validations + if (errors || cmdp == 0) return usage_hf_felica_sniff(); + + UsbCommand c = {CMD_FELICA_SNOOP, {samples2skip, triggers2skip, 0}}; clearCommandBuffer(); SendCommand(&c); return 0; } +// uid hex +int CmdHFFelicaSimLite(const char *Cmd) { + + uint64_t uid = param_get64ex(Cmd, 0, 0, 16); + + if (!uid) + return usage_hf_felica_simlite(); + + UsbCommand c = {CMD_FELICA_LITE_SIM, {uid, 0, 0} }; + clearCommandBuffer(); + SendCommand(&c); + return 0; +} + +uint16_t PrintFliteBlock(uint16_t tracepos, uint8_t *trace,uint16_t tracelen) { + if (tracepos+19 >= tracelen) + return tracelen; + + trace += tracepos; + uint8_t blocknum = trace[0]; + uint8_t status1 = trace[1]; + uint8_t status2 = trace[2]; + + char line[110] = {0}; + for (int j = 0; j < 16; j++) { + snprintf(line+( j * 4),110, "%02x ", trace[j+3]); + } + + PrintAndLog( "Block number %02x, status: %02x %02x",blocknum,status1, status2); + switch (blocknum) { + case 0x00: PrintAndLog( "S_PAD0: %s",line);break; + case 0x01: PrintAndLog( "S_PAD1: %s",line);break; + case 0x02: PrintAndLog( "S_PAD2: %s",line);break; + case 0x03: PrintAndLog( "S_PAD3: %s",line);break; + case 0x04: PrintAndLog( "S_PAD4: %s",line);break; + case 0x05: PrintAndLog( "S_PAD5: %s",line);break; + case 0x06: PrintAndLog( "S_PAD6: %s",line);break; + case 0x07: PrintAndLog( "S_PAD7: %s",line);break; + case 0x08: PrintAndLog( "S_PAD8: %s",line);break; + case 0x09: PrintAndLog( "S_PAD9: %s",line);break; + case 0x0a: PrintAndLog( "S_PAD10: %s",line);break; + case 0x0b: PrintAndLog( "S_PAD11: %s",line);break; + case 0x0c: PrintAndLog( "S_PAD12: %s",line);break; + case 0x0d: PrintAndLog( "S_PAD13: %s",line);break; + case 0x0E: { + uint32_t regA = trace[3] + (trace[4]>>8) + (trace[5]>>16) + (trace[6]>>24); + uint32_t regB = trace[7] + (trace[8]>>8) + (trace[9]>>16) + (trace[10]>>24); + line[0] = 0; + for (int j = 0; j < 8; j++) + snprintf(line+( j * 2),110, "%02x", trace[j+11]); + PrintAndLog( "REG: regA: %d regB: %d regC: %s ", regA, regB, line); + } + break; + case 0x80: PrintAndLog( "Random Challenge, WO: %s ", line); break; + case 0x81: PrintAndLog( "MAC, only set on dual read: %s ", line); break; + case 0x82: { + char idd[20]; + char idm[20]; + for (int j = 0; j < 8; j++) + snprintf(idd+( j * 2),20, "%02x", trace[j+3]); + + for (int j = 0; j < 6; j++) + snprintf(idm+( j * 2),20, "%02x", trace[j+13]); + + PrintAndLog( "ID Block, IDd: 0x%s DFC: 0x%02x%02x Arb: %s ", idd, trace[11], trace [12], idm); + } + break; + case 0x83: { + char idm[20]; + char pmm[20]; + for (int j = 0; j < 8; j++) + snprintf(idm+( j * 2),20, "%02x", trace[j+3]); + + for (int j = 0; j < 8; j++) + snprintf(pmm+( j * 2),20, "%02x", trace[j+11]); + + PrintAndLog( "DeviceId: IDm: 0x%s PMm: 0x%s ", idm, pmm); + } + break; + case 0x84: PrintAndLog( "SER_C: 0x%02x%02x ", trace[3], trace[4]); break; + case 0x85: PrintAndLog( "SYS_Cl 0x%02x%02x ", trace[3], trace[4]); break; + case 0x86: PrintAndLog( "CKV (key version): 0x%02x%02x ", trace[3], trace[4]); break; + case 0x87: PrintAndLog( "CK (card key), WO: %s ", line); break; + case 0x88: { + PrintAndLog( "Memory Configuration (MC):"); + PrintAndLog( "MAC needed to write state: %s", trace[3+12]? "on" : "off"); + //order might be off here... + PrintAndLog("Write with MAC for S_PAD : %s ", sprint_bin(trace+3+10, 2) ); + PrintAndLog("Write with AUTH for S_PAD : %s ", sprint_bin(trace+3+8, 2) ); + PrintAndLog("Read after AUTH for S_PAD : %s ", sprint_bin(trace+3+6, 2) ); + PrintAndLog( "MAC needed to write CK and CKV: %s", trace[3+5] ? "on" : "off"); + PrintAndLog( "RF parameter: %02x", (trace[3+4] & 0x7) ); + PrintAndLog( "Compatible with NDEF: %s", trace[3+3] ? "yes" : "no"); + PrintAndLog( "Memory config writable : %s", (trace[3+2] == 0xff) ? "yes" : "no"); + PrintAndLog("RW access for S_PAD : %s ", sprint_bin(trace+3, 2) ); + } + break; + case 0x90: { + PrintAndLog( "Write count, RO: %02x %02x %02x ", trace[3], trace[4], trace[5]); + } + break; + case 0x91: { + PrintAndLog( "MAC_A, RW (auth): %s ", line); + } + break; + case 0x92: { + PrintAndLog( "State:"); + PrintAndLog( "Polling disabled: %s", trace[3+8] ? "yes" : "no"); + PrintAndLog( "Authenticated: %s", trace[3] ? "yes" : "no"); + } + break; + case 0xa0: { + PrintAndLog( "CRC of all bloacks match : %s", (trace[3+2]==0xff) ? "no" : "yes"); + } + break; + default: + PrintAndLog( "INVALID %d: %s", blocknum, line); + break; + } + return tracepos+19; +} + +int CmdHFFelicaDumpLite(const char *Cmd) { + + //usage_hf_felica_dumplite(); + + UsbCommand c = {CMD_FELICA_LITE_DUMP, {0,0,0}}; + clearCommandBuffer(); + SendCommand(&c); + + uint16_t tracepos = 0; + uint8_t *trace; + + trace = malloc(USB_CMD_DATA_SIZE); + if ( trace == NULL ) { + PrintAndLog("Cannot allocate memory for trace"); + return 1; + } + + // Query for the size of the trace + UsbCommand response; + GetFromBigBuf(trace, USB_CMD_DATA_SIZE, 0); + if ( !WaitForResponseTimeout(CMD_ACK, &response, 4000) ) { + PrintAndLog("timeout while waiting for reply."); + return 1; + } + + uint16_t traceLen = response.arg[2]; + if (traceLen > USB_CMD_DATA_SIZE) { + uint8_t *p = realloc(trace, traceLen); + if (p == NULL) { + PrintAndLog("Cannot allocate memory for trace"); + free(trace); + return 2; + } + trace = p; + GetFromBigBuf(trace, traceLen, 0); + WaitForResponse(CMD_ACK, NULL); + } + + PrintAndLog("Recorded Activity (TraceLen = %d bytes)", traceLen); + while (tracepos < traceLen) { + tracepos = PrintFliteBlock(tracepos, trace, traceLen); + } + free(trace); + return 0; +} + int CmdHFFelicaCmdRaw(const char *cmd) { UsbCommand c = {CMD_FELICA_COMMAND, {0, 0, 0}}; bool reply = 1; @@ -323,12 +522,15 @@ void waitCmdFelica(uint8_t iSelect) { } static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"list", CmdHFFelicaList, 0, "[Deprecated] List ISO 18092/FeliCa history"}, - {"reader", CmdHFFelicaReader, 0, "Act like an ISO18092/FeliCa reader"}, - {"sim", CmdHFFelicaSim, 0, " -- Simulate ISO 18092/FeliCa tag"}, - {"sniff", CmdHFFelicaSniff, 0, "sniff ISO 18092/Felica traffic"}, - {"raw", CmdHFFelicaCmdRaw, 0, "Send raw hex data to tag"}, + {"help", CmdHelp, 1, "This help"}, + {"list", CmdHFFelicaList, 0, "[Deprecated] List ISO 18092/FeliCa history"}, + {"reader", CmdHFFelicaReader, 0, "Act like an ISO18092/FeliCa reader"}, + {"sim", CmdHFFelicaSim, 0, " -- Simulate ISO 18092/FeliCa tag"}, + {"sniff", CmdHFFelicaSniff, 0, "sniff ISO 18092/Felica traffic"}, + {"raw", CmdHFFelicaCmdRaw, 0, "Send raw hex data to tag"}, + + {"litesim", CmdHFFelicaSimLite, 0, " - only reply to poll request"}, + {"litedump", CmdHFFelicaDumpLite, 0, "Wait for and try dumping FelicaLite"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdhffelica.h b/client/cmdhffelica.h index 62786c193..bd0ec30ba 100644 --- a/client/cmdhffelica.h +++ b/client/cmdhffelica.h @@ -38,4 +38,9 @@ extern int usage_hf_felica_sniff(void); extern int usage_hf_fFelica_raw(void); void waitCmdFelica(uint8_t iSelect); + +//temp +extern int CmdHFFelicaSimLite(const char *Cmd); +extern int CmdHFFelicaDumpLite(const char *Cmd); + #endif diff --git a/common/protocols.h b/common/protocols.h index 04c203e87..f58b82d36 100644 --- a/common/protocols.h +++ b/common/protocols.h @@ -436,6 +436,67 @@ uint32_t GetT55xxClockBit(uint32_t clock); #define EM4x05_DISABLE_ALLOWED 1<<23 #define EM4x05_READER_TALK_FIRST 1<<24 + + +#define FLITE_SERVICE_RO 0x000B +#define FLITE_SERVICE_RW 0x0009 + +#define FELICA_POLL_REQ 0x00 +#define FELICA_POLL_ACK 0x01 + +#define FELICA_REQSRV_REQ 0x02 +#define FELICA_REQSRV_ACK 0x03 + +#define FELICA_RDBLK_REQ 0x06 +#define FELICA_RDBLK_ACK 0x07 + +#define FELICA_WRTBLK_REQ 0x08 +#define FELICA_WRTBLK_ACK 0x09 + +#define FELICA_SRCHSYSCODE_REQ 0x0a +#define FELICA_SRCHSYSCODE_ACK 0x0b + +#define FELICA_REQSYSCODE_REQ 0x0c +#define FELICA_REQSYSCODE_ACK 0x0d + +#define FELICA_AUTH1_REQ 0x10 +#define FELICA_AUTH1_ACK 0x11 + +#define FELICA_AUTH2_REQ 0x12 +#define FELICA_AUTH2_ACK 0x13 + +#define FELICA_RDSEC_REQ 0x14 +#define FELICA_RDSEC_ACK 0x15 + +#define FELICA_WRTSEC_REQ 0x16 +#define FELICA_WRTSEC_ACK 0x17 + +#define FELICA_REQSRV2_REQ 0x32 +#define FELICA_REQSRV2_ACK 0x33 + +#define FELICA_GETSTATUS_REQ 0x38 +#define FELICA_GETSTATUS_ACK 0x39 + +#define FELICA_OSVER_REQ 0x3c +#define FELICA_OSVER_ACK 0x3d + +#define FELICA_RESET_MODE_REQ 0x3e +#define FELICA_RESET_MODE_ACK 0x3f + +#define FELICA_AUTH1V2_REQ 0x40 +#define FELICA_AUTH1V2_ACK 0x41 + +#define FELICA_AUTH2V2_REQ 0x42 +#define FELICA_AUTH2V2_ACK 0x43 + +#define FELICA_RDSECV2_REQ 0x44 +#define FELICA_RDSECV2_ACK 0x45 +#define FELICA_WRTSECV2_REQ 0x46 +#define FELICA_WRTSECV2_ACK 0x47 + +#define FELICA_UPDATE_RNDID_REQ 0x4C +#define FELICA_UPDATE_RNDID_ACK 0x4D + // iclass / picopass chip config structures and shared routines typedef struct { uint8_t app_limit; //[8] diff --git a/fpga/fpga_hf.bit b/fpga/fpga_hf.bit index 59b25f924a37e36c9b668cc23740be76f2f440ec..77a9331c05527339a2efbe9a5761656af61e534f 100644 GIT binary patch literal 42175 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 bg99fq0RUCcYQV4nJPiji=OAKQ3Tg-dR#X$E literal 42175 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

|gHZ)&{b9>V1}z7j3EZj;o=i3Y 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 diff --git a/fpga/fpga_lf.v b/fpga/fpga_lf.v index 14b3caafe..1b7a11276 100644 --- a/fpga/fpga_lf.v +++ b/fpga/fpga_lf.v @@ -103,7 +103,7 @@ lo_edge_detect le( // Major modes: // 000 -- LF reader (generic) // 001 -- LF edge detect (generic) -// 010 -- LF passthru +// 010 -- LF passthrough mux8 mux_ssp_clk (major_mode, ssp_clk, lr_ssp_clk, le_ssp_clk, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0); mux8 mux_ssp_din (major_mode, ssp_din, lr_ssp_din, 1'b0, lp_ssp_din, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0); diff --git a/fpga/fpga_nfc.bit b/fpga/fpga_nfc.bit index 46483c715a3a6f423e57abc086207b3bbe7a952b..a1e55d24d1e14cdce15dd2a901d18e84da4c1a6d 100644 GIT binary patch literal 42176 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

4a0c`V~{zJHb2h>X0-Z?djk`%0(2VX4aaT< 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 CXS2-! diff --git a/fpga/fpga_nfc.v b/fpga/fpga_nfc.v index dbc608fb5..e2d328b5f 100644 --- a/fpga/fpga_nfc.v +++ b/fpga/fpga_nfc.v @@ -16,6 +16,7 @@ `include "hi_flite.v" `include "util.v" +`include "hi_sniffer.v" module fpga_nfc( input spck, output miso, input mosi, input ncs, @@ -67,11 +68,11 @@ assign major_mode = conf_word[7:5]; // For the high-frequency receive correlator: frequency against which to // correlate. -//wire hi_read_rx_xcorr_848 = conf_word[0]; +wire hi_read_rx_xcorr_848 = conf_word[0]; // and whether to drive the coil (reader) or just short it (snooper) -//wire hi_read_rx_xcorr_snoop = conf_word[1]; +wire hi_read_rx_xcorr_snoop = conf_word[1]; // divide subcarrier frequency by 4 -//wire hi_read_rx_xcorr_quarter = conf_word[2]; +wire hi_read_rx_xcorr_quarter = conf_word[2]; // For the high-frequency simulated tag: what kind of modulation to use. wire [2:0] hi_simulate_mod_type = conf_word[2:0]; @@ -81,6 +82,15 @@ wire [2:0] hi_simulate_mod_type = conf_word[2:0]; // major modes, and use muxes to connect the outputs of the active mode to // the output pins. //----------------------------------------------------------------------------- +hi_sniffer he( + pck0, ck_1356meg, ck_1356megb, + he_pwr_lo, he_pwr_hi, he_pwr_oe1, he_pwr_oe2, he_pwr_oe3, he_pwr_oe4, + adc_d, he_adc_clk, + he_ssp_frame, he_ssp_din, ssp_dout, he_ssp_clk, + cross_hi, cross_lo, + he_dbg, + hi_read_rx_xcorr_848, hi_read_rx_xcorr_snoop, hi_read_rx_xcorr_quarter +); hi_flite hfl( @@ -103,17 +113,17 @@ hi_flite hfl( // 101 -- HF NFC demod, just to copy it for now // 111 -- everything off -mux8 mux_ssp_clk (major_mode, ssp_clk, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, hfl_ssp_clk, 1'b0, 1'b0); -mux8 mux_ssp_din (major_mode, ssp_din, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, hfl_ssp_din, 1'b0, 1'b0); -mux8 mux_ssp_frame (major_mode, ssp_frame, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, hfl_ssp_frame, 1'b0, 1'b0); -mux8 mux_pwr_oe1 (major_mode, pwr_oe1, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, hfl_pwr_oe1, 1'b0, 1'b0); -mux8 mux_pwr_oe2 (major_mode, pwr_oe2, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, hfl_pwr_oe2, 1'b0, 1'b0); -mux8 mux_pwr_oe3 (major_mode, pwr_oe3, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, hfl_pwr_oe3, 1'b0, 1'b0); -mux8 mux_pwr_oe4 (major_mode, pwr_oe4, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, hfl_pwr_oe4, 1'b0, 1'b0); -mux8 mux_pwr_lo (major_mode, pwr_lo, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, hfl_pwr_lo, 1'b0, 1'b0); -mux8 mux_pwr_hi (major_mode, pwr_hi, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, hfl_pwr_hi, 1'b0, 1'b0); -mux8 mux_adc_clk (major_mode, adc_clk, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, hfl_adc_clk, 1'b0, 1'b0); -mux8 mux_dbg (major_mode, dbg, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, hfl_dbg, 1'b0, 1'b0); +mux8 mux_ssp_clk (major_mode, ssp_clk, 1'b0, 1'b0, 1'b0, 1'b0, he_ssp_clk, hfl_ssp_clk, 1'b0, 1'b0); +mux8 mux_ssp_din (major_mode, ssp_din, 1'b0, 1'b0, 1'b0, 1'b0, he_ssp_din, hfl_ssp_din, 1'b0, 1'b0); +mux8 mux_ssp_frame (major_mode, ssp_frame, 1'b0, 1'b0, 1'b0, 1'b0, he_ssp_frame, hfl_ssp_frame, 1'b0, 1'b0); +mux8 mux_pwr_oe1 (major_mode, pwr_oe1, 1'b0, 1'b0, 1'b0, 1'b0, he_pwr_oe1, hfl_pwr_oe1, 1'b0, 1'b0); +mux8 mux_pwr_oe2 (major_mode, pwr_oe2, 1'b0, 1'b0, 1'b0, 1'b0, he_pwr_oe2, hfl_pwr_oe2, 1'b0, 1'b0); +mux8 mux_pwr_oe3 (major_mode, pwr_oe3, 1'b0, 1'b0, 1'b0, 1'b0, he_pwr_oe3, hfl_pwr_oe3, 1'b0, 1'b0); +mux8 mux_pwr_oe4 (major_mode, pwr_oe4, 1'b0, 1'b0, 1'b0, 1'b0, he_pwr_oe4, hfl_pwr_oe4, 1'b0, 1'b0); +mux8 mux_pwr_lo (major_mode, pwr_lo, 1'b0, 1'b0, 1'b0, 1'b0, he_pwr_lo, hfl_pwr_lo, 1'b0, 1'b0); +mux8 mux_pwr_hi (major_mode, pwr_hi, 1'b0, 1'b0, 1'b0, 1'b0, he_pwr_hi, hfl_pwr_hi, 1'b0, 1'b0); +mux8 mux_adc_clk (major_mode, adc_clk, 1'b0, 1'b0, 1'b0, 1'b0, he_adc_clk, hfl_adc_clk, 1'b0, 1'b0); +mux8 mux_dbg (major_mode, dbg, 1'b0, 1'b0, 1'b0, 1'b0, hfl_dbg, hfl_dbg, 1'b0, 1'b0); // In all modes, let the ADC's outputs be enabled. assign adc_noe = 1'b0; diff --git a/fpga/hi_flite.v b/fpga/hi_flite.v index c7b9d4648..8c8e26d39 100644 --- a/fpga/hi_flite.v +++ b/fpga/hi_flite.v @@ -1,15 +1,11 @@ -// Satsuoni, October 2017, Added FeliCa support -// + //this code demodulates and modulates signal as described in ISO/IEC 18092. That includes packets used for Felica, NFC Tag 3, etc. (which do overlap) //simple envelope following algorithm is used (modification of fail0verflow LF one) is used to combat some nasty aliasing effect with testing phone (envelope looked like sine wave) -// only 212 kbps (fc/64) for now 414 is relatively straightforward... +// only 212 kbps (fc/64) for now 414 is relatively straightforward... though for reader, the selection has to come from ARM // modulation waits for - //market sprocket -doesn't really mean anything ;) -`define SNIFFER 3'b000 -`define TAGSIM_LISTEN 3'b001 //same as SNIFFER, really. demod does not distinguish tag from reader -`define TAGSIM_MODULATE 3'b010 -`define TAGSIM_MOD_NODELAY 3'b011 //not implemented yet. for use with commands other than polling, which might require different timing, as per Felica standard +//redefining mod_type: bits 210: bit 2 - reader drive/power on/off, bit 1 - speed bit, 0:212, 1 -424 bit 0: listen or modulate + module hi_flite( pck0, ck_1356meg, ck_1356megb, @@ -18,7 +14,8 @@ module hi_flite( ssp_frame, ssp_din, ssp_dout, ssp_clk, cross_hi, cross_lo, dbg, - mod_type // maybe used + mod_type // used + ); input pck0, ck_1356meg, ck_1356megb; output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4; @@ -28,15 +25,18 @@ module hi_flite( output ssp_frame, ssp_din, ssp_clk; input cross_hi, cross_lo; output dbg; - input [2:0] mod_type; // maybe used. + input [2:0] mod_type; // used. assign dbg=0; -// Most off, oe4 for modulation; No reader emulation (would presumably just require switching power on, but I am not sure) -assign pwr_hi = 1'b0; +wire power= mod_type[2]; +wire speed= mod_type[1]; +wire disabl= mod_type[0]; + +// Most off, oe4 for modulation; +// Trying reader emulation (would presumably just require switching power on, but I am not sure) + //;// 1'b0; assign pwr_lo = 1'b0; -assign pwr_oe1 = 1'b0; -assign pwr_oe2 = 1'b0; -assign pwr_oe3 = 1'b0; + //512x64/fc -wait before ts0, 32768 ticks @@ -51,7 +51,7 @@ assign adc_clk = ck_1356meg; `define ithrmin 91//-13'd8 `define ithrmax 160// 13'd8 - +`define min_bitdelay_212 8 //minimum values and corresponding thresholds reg [8:0] curmin=`imin; @@ -76,9 +76,13 @@ reg did_sync=0; `define bithalf_212 32 //half-bit length for 212 kbit -`define bitlen_212 64 //full-bit length for 212 kbit `define bitmlen_212 63 //bit transition edge -`define bitmhalf_212 31 //mod flip + +`define bithalf_424 16 //half-bit length for 212 kbit +`define bitmlen_424 31 //bit transition edge + +wire [7:0]bithalf= speed ? `bithalf_424 : `bithalf_212; +wire [7:0]bitmlen= speed ? `bitmlen_424 : `bitmlen_212; //ssp clock and current values @@ -98,57 +102,36 @@ reg [8:0] ssp_cnt=9'd0; always @(posedge adc_clk) ssp_cnt <= (ssp_cnt + 1); - -reg getting_arm_data=1'b0; - - -reg [47:0] delayline=48'd0; //48-bit preamble delay line. Just push the data into it starting from first SYNC (1) bit coming from ARM Made this long to keep all ARM data received during preamble -reg [5:0] delay_read_ptr=6'd0; // this is supposed to count ARM delay in the buffer. -reg preamble=0; // whether we are sending preamble - - +//maybe change it so that ARM sends preamble as well. +//then: ready bits sent to ARM, 8 bits sent from ARM (all ones), then preamble (all zeros, presumably) - which starts modulation always @(negedge adc_clk) begin //count fc/64 - transfer bits to ARM at the rate they are received - if(ssp_cnt[5:0] == 6'b000000) + if( ((~speed) && (ssp_cnt[5:0] == 6'b000000)) || (speed &&(ssp_cnt[4:0] == 5'b00000))) begin ssp_clk <= 1'b1; + // if(mod_type[2]) + // begin + // ssp_din<=outp[0];//after_hysteresis; + + //outp<={1'b0,outp[7:1]}; + // end + // else ssp_din <= curbit; - //sample ssp_dout? - if(mod_type==`TAGSIM_MODULATE||mod_type==`TAGSIM_MOD_NODELAY) - begin - delayline<={delayline[46:0],ssp_dout}; - if ((~getting_arm_data) && ssp_dout) - begin - getting_arm_data <=1'b1; - delay_read_ptr<=delay_read_ptr+1; - end - else - begin - if (getting_arm_data & preamble) - begin - delay_read_ptr<=delay_read_ptr+1; - end - end - end - else - begin - getting_arm_data <=1'b0; - delay_read_ptr<=6'd0; - end + //sample ssp_dout end - if(ssp_cnt[5:0] == 6'b100000) + if( ( (~speed) && (ssp_cnt[5:0] == 6'b100000)) ||(speed && ssp_cnt[4:0] == 5'b10000)) ssp_clk <= 1'b0; //create frame pulses. TBH, I still don't know what they do exactly, but they are crucial for ARM->FPGA transfer. If the frame is in the beginning of the byte, transfer slows to a crawl for some reason // took me a day to figure THAT out. - if(ssp_cnt[8:0] == 9'd31) + if(( (~speed) && (ssp_cnt[8:0] == 9'd31))||(speed && ssp_cnt[7:0] == 8'd15)) begin ssp_frame <= 1'b1; end - if(ssp_cnt[8:0] == 9'b1011111) + if(( (~speed) && (ssp_cnt[8:0] == 9'b1011111))||(speed &&ssp_cnt[7:0] == 8'b101111) ) begin ssp_frame <= 1'b0; end @@ -158,7 +141,7 @@ end //send current bit (detected in SNIFF mode or the one being modulated in MOD mode, 0 otherwise) -reg ssp_din; +reg ssp_din;//= outp[0]; @@ -168,28 +151,74 @@ reg prv =1'b1; reg[7:0] mid=8'd128; //for simple error correction in mod/demod detection, use maximum of modded/demodded in given interval. Maybe 1 bit is extra? but better safe than sorry. -//modulated coil. set to 1 to modulate low, 0 to keep signal high -reg mod_sig_coil=1'b0; // set TAGSIM__MODULATE on ARM if we want to write... (frame would get lost if done mid-frame...) // start sending over 1s on ssp->arm when we start sending preamble reg counting_desync=1'b0; // are we counting bits since last frame? reg sending=1'b0; // are we actively modulating? -reg [11:0] bit_counts=12'd0;///for timeslots... only support ts=0 for now, at 212 speed -512 fullbits from end of frame. One hopes. +reg [11:0] bit_counts=12'd0;///for timeslots... only support ts=0 for now, at 212 speed -512 fullbits from end of frame. One hopes. might remove those? +//reg [2:0]old_mod; + +//always @(mod_type) //when moving from modulate_mode +//begin +//if (mod_type[2]==1&&old_mod[2]==0) +// bit_counts=0; +//old_mod=mod_type; +//end +//we need some way to flush bit_counts triggers on mod_type changes don't compile +reg dlay; always @(negedge adc_clk) //every data ping? begin //envelope follow code... //////////// - if ((mod_type==`SNIFFER )||(mod_type==`TAGSIM_LISTEN)) + + //move the counter to the outside... + // if (adc_d>=curminthres||try_sync) + if(fccount==bitmlen) begin + if((~try_sync)&&(adc_d768) // should be over ts0 now, without ARM interference... stop counting... + begin + bit_counts<=0; + // counting_desync<=0; + end + else + if((power)) + bit_counts<=0; + else + bit_counts<=bit_counts+1; + // end + end + else + begin + if((~try_sync)&&(adc_dcurmaxthres) //rising edge begin case (state) 0: begin - curmax <= adc_d>155? adc_d :155; + curmax <= adc_d>`imax? adc_d :`imax; state <= 2; end 1: begin @@ -214,7 +243,7 @@ begin begin case (state) 0: begin - curmin <=adc_d<96? adc_d :96; + curmin <=adc_d<`imin? adc_d :`imin; state <=1; end 1: begin @@ -224,7 +253,7 @@ begin 2: begin curminthres <= ( (curmin>>1)+(curmin>>2)+(curmin>>4)+(curmax>>3)+(curmax>>4)); curmaxthres <= ( (curmax>>1)+(curmax>>2)+(curmax>>4)+(curmin>>3)+(curmin>>4)); - curmin <=adc_d<96? adc_d :96; + curmin <=adc_d<`imin? adc_d :`imin; state <=1; end default: @@ -235,7 +264,7 @@ begin if (~try_sync ) //begin modulation, lower edge... begin try_sync <=1; - counting_desync<=1'b0; + //counting_desync<=1'b0; fccount <= 1; did_sync<=0; curbit<=0; @@ -259,7 +288,7 @@ begin if (tsinceedge>=(128)) begin //we might need to start counting... assuming ARM wants to reply to the frame. - counting_desync<=1'b1; + // counting_desync<=1'b1; bit_counts<=1;// i think? 128 is about 2 bits passed... but 1 also works try_sync<=0; did_sync<=0;//desync @@ -278,32 +307,13 @@ begin end end - //move the counter to the outside... - if (adc_d>=curminthres||try_sync) - if(fccount==`bitmlen_212) - begin - fccount<=0; - if (counting_desync) - begin - - if(bit_counts>768) // should be over ts0 now, without ARM interference... stop counting... - begin - bit_counts<=0; - counting_desync<=0; - end - else - bit_counts<=bit_counts+1; - end - end - else - begin - fccount<=fccount+1; - end + + if (try_sync && tsinceedge<128) begin //detect bits in their middle ssp sampling is in sync, so it would sample all bits in order - if (fccount==`bithalf_212) + if (fccount==bithalf) begin if ((~did_sync) && ((prv==1&&(mid>128))||(prv==0&&(mid<=128)))) begin @@ -336,7 +346,7 @@ begin end else begin - if (fccount==`bitmlen_212) + if (fccount==bitmlen) begin // fccount <=0; prv <=(mid>128)?1:0; @@ -367,61 +377,40 @@ begin begin end sending <=0; - - end //listen mode end - else - begin //sim mode start - //not sure how precise do the time slots have to be... is anything within Ts ok? - //keep counting until 576, just in case - if(fccount==`bitmlen_212) - begin - if (bit_counts==512) // - curbit<=1; - else - begin - if(bit_counts>512) - curbit<=mod_sig_coil;//delayline[delay_read_ptr];//bit_counts[0]; - else - curbit<=0; - end - - fccount<=0; - if (bit_counts<=576) //we don't need to count after that... - begin - bit_counts<=bit_counts+1; - if (bit_counts== 512) //should start sending from next tick... i think? - begin - sending <=1; - mod_sig_coil <=1;//modulate... down? - preamble<=1; - end - else - if (bit_counts== 559) - begin - preamble<=0; - end - end - if (sending) - begin //need next bit - if(preamble) - mod_sig_coil<=1; - else - mod_sig_coil<=~delayline[delay_read_ptr]; - end - end - else - begin - fccount<=fccount+1; - - if ((fccount==`bitmhalf_212)&&(sending)) //flip modulation mid-bit - begin - mod_sig_coil<=~mod_sig_coil;//flip - end - end - end //sim mode end - end +//put modulation here to maintain the correct clock. Seems that some readers are sensitive to that +reg pwr_hi; +reg pwr_oe1; +reg pwr_oe2; +reg pwr_oe3; +reg pwr_oe4; -assign pwr_oe4 = mod_sig_coil & (mod_type == `TAGSIM_MODULATE)&sending; +wire mod=((fccount>=bithalf)^dlay)&(~disabl); + +always @(ck_1356megb or ssp_dout or power or disabl or mod) + begin +if (power) + begin + pwr_hi <= ck_1356megb; + pwr_oe1 <= mod; + pwr_oe2 <= mod; + pwr_oe3 <= mod; + pwr_oe4 <= 1'b0; + end +else + begin + pwr_hi <= 1'b0; + pwr_oe1 <= 1'b0; + pwr_oe2 <= 1'b0; + pwr_oe3 <= 1'b0; + pwr_oe4 <= mod; + end + end +//assign pwr_oe4 = 1'b0;// mod_sig_coil & (modulate_mode)&sending & (~mod_type[2]); +//try shallow mod for reader? +//assign pwr_hi= (mod_type[2]) & ck_1356megb; +//assign pwr_oe1= 1'b0; //mod_sig_coil & (modulate_mode)&sending & (mod_type[2]); +//assign pwr_oe2 = 1'b0;// mod_sig_coil & (modulate_mode)&sending & (mod_type[2]); +//assign pwr_oe3 = 1'b0; //mod_sig_coil & (modulate_mode)&sending & (mod_type[2]); endmodule diff --git a/fpga/hi_read_rx_xcorr.v b/fpga/hi_read_rx_xcorr.v index bbd28b0f5..dc8b01bc5 100644 --- a/fpga/hi_read_rx_xcorr.v +++ b/fpga/hi_read_rx_xcorr.v @@ -10,7 +10,7 @@ module hi_read_rx_xcorr( ssp_frame, ssp_din, ssp_dout, ssp_clk, cross_hi, cross_lo, dbg, - xcorr_is_848, snoop + xcorr_is_848, snoop, xcorr_quarter_freq ); input pck0, ck_1356meg, ck_1356megb; output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4; @@ -20,7 +20,7 @@ module hi_read_rx_xcorr( output ssp_frame, ssp_din, ssp_clk; input cross_hi, cross_lo; output dbg; - input xcorr_is_848, snoop; + input xcorr_is_848, snoop, xcorr_quarter_freq; // Carrier is steady on through this, unless we're snooping. assign pwr_hi = ck_1356megb & (~snoop); @@ -28,18 +28,20 @@ assign pwr_oe1 = 1'b0; assign pwr_oe3 = 1'b0; assign pwr_oe4 = 1'b0; -// Clock divider -reg [0:0] fc_divider; +reg [2:0] fc_div; always @(negedge ck_1356megb) - fc_divider <= fc_divider + 1; -wire fc_div2 = fc_divider[0]; + fc_div <= fc_div + 1; -reg adc_clk; -always @(ck_1356megb) - if (xcorr_is_848) +(* clock_signal = "yes" *) reg adc_clk; // sample frequency, always 16 * fc +always @(ck_1356megb, xcorr_is_848, xcorr_quarter_freq, fc_div) + if (xcorr_is_848 & ~xcorr_quarter_freq) // fc = 847.5 kHz adc_clk <= ck_1356megb; - else - adc_clk <= fc_div2; + else if (~xcorr_is_848 & ~xcorr_quarter_freq) // fc = 424.25 kHz + adc_clk <= fc_div[0]; + else if (xcorr_is_848 & xcorr_quarter_freq) // fc = 212.125 kHz + adc_clk <= fc_div[1]; + else // fc = 106.0625 kHz + adc_clk <= fc_div[2]; // When we're a reader, we just need to do the BPSK demod; but when we're an // eavesdropper, we also need to pick out the commands sent by the reader, @@ -71,8 +73,7 @@ end // so we need a 6-bit counter. reg [5:0] corr_i_cnt; // And a couple of registers in which to accumulate the correlations. -// we would add at most 32 times adc_d, the result can be held in 13 bits. -// Need one additional bit because it can be negative as well +// we would add/sub at most 32 times adc_d, the signed result can be held in 14 bits. reg signed [13:0] corr_i_accum; reg signed [13:0] corr_q_accum; reg signed [7:0] corr_i_out; diff --git a/fpga/hi_read_tx.v b/fpga/hi_read_tx.v index f12e64eb6..23d25deff 100644 --- a/fpga/hi_read_tx.v +++ b/fpga/hi_read_tx.v @@ -12,7 +12,7 @@ module hi_read_tx( ssp_frame, ssp_din, ssp_dout, ssp_clk, cross_hi, cross_lo, dbg, - shallow_modulation + shallow_modulation, speed, power ); input pck0, ck_1356meg, ck_1356megb; output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4; @@ -23,6 +23,8 @@ module hi_read_tx( input cross_hi, cross_lo; output dbg; input shallow_modulation; + input [1:0] speed; + input power; // The high-frequency stuff. For now, for testing, just bring out the carrier, // and allow the ARM to modulate it over the SSP. @@ -32,6 +34,8 @@ reg pwr_oe2; reg pwr_oe3; reg pwr_oe4; always @(ck_1356megb or ssp_dout or shallow_modulation) +begin +if (power) begin if(shallow_modulation) begin @@ -50,6 +54,15 @@ begin pwr_oe4 <= 1'b0; end end +else +begin + pwr_hi <= 1'b0; + pwr_oe1 <= 1'b0; + pwr_oe2 <= 1'b0; + pwr_oe3 <= 1'b0; + pwr_oe4 <= ~ssp_dout; +end +end // Then just divide the 13.56 MHz clock down to produce appropriate clocks // for the synchronous serial port. @@ -59,7 +72,7 @@ reg [6:0] hi_div_by_128; always @(posedge ck_1356meg) hi_div_by_128 <= hi_div_by_128 + 1; -assign ssp_clk = hi_div_by_128[6]; +assign ssp_clk = speed[1]? (speed[0]? hi_div_by_128[3]: hi_div_by_128[4]) : (speed[0]? hi_div_by_128[5]: hi_div_by_128[6]); reg [2:0] hi_byte_div; @@ -76,7 +89,7 @@ assign adc_clk = ck_1356meg; reg after_hysteresis; always @(negedge adc_clk) begin - if(& adc_d[7:0]) after_hysteresis <= 1'b1; + if(& adc_d[7:4]) after_hysteresis <= 1'b1; else if(~(| adc_d[7:0])) after_hysteresis <= 1'b0; end diff --git a/fpga/hi_simulate.v b/fpga/hi_simulate.v index 6139cfad2..0768c29de 100644 --- a/fpga/hi_simulate.v +++ b/fpga/hi_simulate.v @@ -53,11 +53,6 @@ end // Divide 13.56 MHz by 32 to produce the SSP_CLK // The register is bigger to allow higher division factors of up to /128 -// FPGA_HF_SIMULATOR_NO_MODULATION (0<<0) // 0000 -// FPGA_HF_SIMULATOR_MODULATE_BPSK (1<<0) // 0001 -// FPGA_HF_SIMULATOR_MODULATE_212K (2<<0) // 0010 -// FPGA_HF_SIMULATOR_MODULATE_424K (4<<0) // 0100 -// FPGA_HF_SIMULATOR_MODULATE_424K_8BIT 0x5 // 0101 reg [10:0] ssp_clk_divider; always @(posedge adc_clk) @@ -91,8 +86,8 @@ end // Divide SSP_CLK by 8 to produce the byte framing signal; the phase of // this is arbitrary, because it's just a bitstream. // One nasty issue, though: I can't make it work with both rx and tx at -// once. The phase wrt ssp_clk must be changed. -// TODO to find out why that is and make a better fix. +// once. The phase wrt ssp_clk must be changed. TODO to find out why +// that is and make a better fix. reg [2:0] ssp_frame_divider_to_arm; always @(posedge ssp_clk) ssp_frame_divider_to_arm <= (ssp_frame_divider_to_arm + 1); diff --git a/fpga/hi_sniffer.v b/fpga/hi_sniffer.v index 3a989ce62..3d39413a3 100644 --- a/fpga/hi_sniffer.v +++ b/fpga/hi_sniffer.v @@ -17,8 +17,11 @@ module hi_sniffer( output dbg; input xcorr_is_848, snoop, xcorr_quarter_freq; // not used. + +// let's try hi-pass + // We are only snooping, all off. -assign pwr_hi = 1'b0; +assign pwr_hi = ck_1356megb & xcorr_quarter_freq;//1'b0; assign pwr_lo = 1'b0; assign pwr_oe1 = 1'b0; assign pwr_oe2 = 1'b0; @@ -29,8 +32,12 @@ reg ssp_frame; reg [7:0] adc_d_out = 8'd0; reg [2:0] ssp_cnt = 3'd0; -assign adc_clk = ck_1356meg; -assign ssp_clk = ~ck_1356meg; + +reg [12:0] avg=13'd0; + +assign adc_clk = ck_1356megb; +assign ssp_clk = ~ck_1356megb; + always @(posedge ssp_clk) begin @@ -41,7 +48,9 @@ begin if(ssp_cnt[2:0] == 3'b000) // set frame length begin - adc_d_out[7:0] <= adc_d; + // adc_d_out[7:0] <= (alias_buf>>>3) +8'd126;//( $signed(adc_d-adc_d_old)>1 | $signed(adc_d_old-adc_d)>1)? alias_buf+adc_d-adc_d_old:alias_buf; //alias_buf[11:3]+8'd126;//adc_d; + // adc_d_out[7:0]<=adc_d; + adc_d_out[7:0] <=adc_d;//-(avg>>3) +8'd126; ssp_frame <= 1'b1; end else diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 31ebaef12..271954413 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -171,6 +171,9 @@ typedef struct{ #define CMD_FELICA_SIMULATE_TAG 0x03A0 #define CMD_FELICA_SNOOP 0x03A1 #define CMD_FELICA_COMMAND 0x03A2 +//temp +#define CMD_FELICA_LITE_DUMP 0x03AA +#define CMD_FELICA_LITE_SIM 0x03AB // For measurements of the antenna tuning #define CMD_MEASURE_ANTENNA_TUNING 0x0400