mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-07-29 19:19:06 -07:00
CHG: merged the forum user @jason 's fixes to LEGIC. *UNTESTED*
CHG: changed the CRC implementations.
This commit is contained in:
parent
83dad64b91
commit
3e134b4c20
16 changed files with 1368 additions and 163 deletions
|
@ -1058,6 +1058,10 @@ void UsbPacketReceived(uint8_t *packet, int len)
|
||||||
LegicRfWriter(c->arg[1], c->arg[0]);
|
LegicRfWriter(c->arg[1], c->arg[0]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CMD_RAW_WRITER_LEGIC_RF:
|
||||||
|
LegicRfRawWriter(c->arg[0], c->arg[1]);
|
||||||
|
break;
|
||||||
|
|
||||||
case CMD_READER_LEGIC_RF:
|
case CMD_READER_LEGIC_RF:
|
||||||
LegicRfReader(c->arg[0], c->arg[1]);
|
LegicRfReader(c->arg[0], c->arg[1]);
|
||||||
break;
|
break;
|
||||||
|
|
920
armsrc/legicrf.c
920
armsrc/legicrf.c
|
@ -325,12 +325,11 @@ static void LegicCommonInit(void) {
|
||||||
crc_init(&legic_crc, 4, 0x19 >> 1, 0x5, 0);
|
crc_init(&legic_crc, 4, 0x19 >> 1, 0x5, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Switch off carrier, make sure tag is reset */
|
||||||
static void switch_off_tag_rwd(void)
|
static void switch_off_tag_rwd(void)
|
||||||
{
|
{
|
||||||
/* Switch off carrier, make sure tag is reset */
|
|
||||||
AT91C_BASE_PIOA->PIO_CODR = GPIO_SSC_DOUT;
|
AT91C_BASE_PIOA->PIO_CODR = GPIO_SSC_DOUT;
|
||||||
SpinDelay(10);
|
SpinDelay(10);
|
||||||
|
|
||||||
WDT_HIT();
|
WDT_HIT();
|
||||||
}
|
}
|
||||||
/* calculate crc for a legic command */
|
/* calculate crc for a legic command */
|
||||||
|
@ -372,11 +371,12 @@ int legic_read_byte(int byte_index, int cmd_sz) {
|
||||||
* * wait until the tag sends back an ACK ('1' bit unencrypted)
|
* * wait until the tag sends back an ACK ('1' bit unencrypted)
|
||||||
* * forward the prng based on the timing
|
* * forward the prng based on the timing
|
||||||
*/
|
*/
|
||||||
|
//int legic_write_byte(int byte, int addr, int addr_sz, int PrngCorrection) {
|
||||||
int legic_write_byte(int byte, int addr, int addr_sz) {
|
int legic_write_byte(int byte, int addr, int addr_sz) {
|
||||||
//do not write UID, CRC, DCF
|
//do not write UID, CRC
|
||||||
if(addr <= 0x06)
|
if(addr <= 0x04) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
//== send write command ==============================
|
//== send write command ==============================
|
||||||
crc_clear(&legic_crc);
|
crc_clear(&legic_crc);
|
||||||
crc_update(&legic_crc, 0, 1); /* CMD_WRITE */
|
crc_update(&legic_crc, 0, 1); /* CMD_WRITE */
|
||||||
|
@ -390,10 +390,13 @@ int legic_write_byte(int byte, int addr, int addr_sz) {
|
||||||
|(0x00 <<0)); //CMD = W
|
|(0x00 <<0)); //CMD = W
|
||||||
uint32_t cmd_sz = addr_sz+1+8+4; //crc+data+cmd
|
uint32_t cmd_sz = addr_sz+1+8+4; //crc+data+cmd
|
||||||
|
|
||||||
legic_prng_forward(2); /* we wait anyways */
|
legic_prng_forward(4); /* we wait anyways */
|
||||||
while(timer->TC_CV < 387) ; /* ~ 258us */
|
while(timer->TC_CV < 387) ; /* ~ 258us */
|
||||||
frame_send_rwd(cmd, cmd_sz);
|
frame_send_rwd(cmd, cmd_sz);
|
||||||
|
|
||||||
|
AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_DIN;
|
||||||
|
AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DIN;
|
||||||
|
|
||||||
//== wait for ack ====================================
|
//== wait for ack ====================================
|
||||||
int t, old_level=0, edges=0;
|
int t, old_level=0, edges=0;
|
||||||
int next_bit_at =0;
|
int next_bit_at =0;
|
||||||
|
@ -413,7 +416,7 @@ int legic_write_byte(int byte, int addr, int addr_sz) {
|
||||||
int c = t/TAG_TIME_BIT;
|
int c = t/TAG_TIME_BIT;
|
||||||
timer->TC_CCR = AT91C_TC_SWTRG;
|
timer->TC_CCR = AT91C_TC_SWTRG;
|
||||||
while(timer->TC_CV > 1) ; /* Wait till the clock has reset */
|
while(timer->TC_CV > 1) ; /* Wait till the clock has reset */
|
||||||
legic_prng_forward(c);
|
legic_prng_forward(c-1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -423,6 +426,11 @@ int legic_write_byte(int byte, int addr, int addr_sz) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int LegicRfReader(int offset, int bytes) {
|
int LegicRfReader(int offset, int bytes) {
|
||||||
|
|
||||||
|
// ice_legic_setup();
|
||||||
|
// ice_legic_select_card();
|
||||||
|
// return 0;
|
||||||
|
|
||||||
int byte_index=0, cmd_sz=0, card_sz=0;
|
int byte_index=0, cmd_sz=0, card_sz=0;
|
||||||
|
|
||||||
LegicCommonInit();
|
LegicCommonInit();
|
||||||
|
@ -434,6 +442,11 @@ int LegicRfReader(int offset, int bytes) {
|
||||||
uint32_t tag_type = perform_setup_phase_rwd(SESSION_IV);
|
uint32_t tag_type = perform_setup_phase_rwd(SESSION_IV);
|
||||||
switch_off_tag_rwd(); //we lose to mutch time with dprintf
|
switch_off_tag_rwd(); //we lose to mutch time with dprintf
|
||||||
switch(tag_type) {
|
switch(tag_type) {
|
||||||
|
case 0x0d:
|
||||||
|
DbpString("MIM22 card found, reading card ...");
|
||||||
|
cmd_sz = 6;
|
||||||
|
card_sz = 22;
|
||||||
|
break;
|
||||||
case 0x1d:
|
case 0x1d:
|
||||||
DbpString("MIM256 card found, reading card ...");
|
DbpString("MIM256 card found, reading card ...");
|
||||||
cmd_sz = 9;
|
cmd_sz = 9;
|
||||||
|
@ -479,6 +492,47 @@ int LegicRfReader(int offset, int bytes) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*int _LegicRfWriter(int bytes, int offset, int addr_sz, uint8_t *BigBuf, int RoundBruteforceValue) {
|
||||||
|
int byte_index=0;
|
||||||
|
|
||||||
|
LED_B_ON();
|
||||||
|
perform_setup_phase_rwd(SESSION_IV);
|
||||||
|
//legic_prng_forward(2);
|
||||||
|
while(byte_index < bytes) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
//check if the DCF should be changed
|
||||||
|
if ( (offset == 0x05) && (bytes == 0x02) ) {
|
||||||
|
//write DCF in reverse order (addr 0x06 before 0x05)
|
||||||
|
r = legic_write_byte(BigBuf[(0x06-byte_index)], (0x06-byte_index), addr_sz, RoundBruteforceValue);
|
||||||
|
//legic_prng_forward(1);
|
||||||
|
if(r == 0) {
|
||||||
|
byte_index++;
|
||||||
|
r = legic_write_byte(BigBuf[(0x06-byte_index)], (0x06-byte_index), addr_sz, RoundBruteforceValue);
|
||||||
|
}
|
||||||
|
//legic_prng_forward(1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
r = legic_write_byte(BigBuf[byte_index+offset], byte_index+offset, addr_sz, RoundBruteforceValue);
|
||||||
|
}
|
||||||
|
if((r != 0) || BUTTON_PRESS()) {
|
||||||
|
Dbprintf("operation aborted @ 0x%03.3x", byte_index);
|
||||||
|
switch_off_tag_rwd();
|
||||||
|
LED_B_OFF();
|
||||||
|
LED_C_OFF();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
WDT_HIT();
|
||||||
|
byte_index++;
|
||||||
|
if(byte_index & 0x10) LED_C_ON(); else LED_C_OFF();
|
||||||
|
}
|
||||||
|
LED_B_OFF();
|
||||||
|
LED_C_OFF();
|
||||||
|
DbpString("write successful");
|
||||||
|
return 0;
|
||||||
|
}*/
|
||||||
|
|
||||||
void LegicRfWriter(int bytes, int offset) {
|
void LegicRfWriter(int bytes, int offset) {
|
||||||
int byte_index=0, addr_sz=0;
|
int byte_index=0, addr_sz=0;
|
||||||
uint8_t *BigBuf = BigBuf_get_addr();
|
uint8_t *BigBuf = BigBuf_get_addr();
|
||||||
|
@ -489,6 +543,14 @@ void LegicRfWriter(int bytes, int offset) {
|
||||||
uint32_t tag_type = perform_setup_phase_rwd(SESSION_IV);
|
uint32_t tag_type = perform_setup_phase_rwd(SESSION_IV);
|
||||||
switch_off_tag_rwd();
|
switch_off_tag_rwd();
|
||||||
switch(tag_type) {
|
switch(tag_type) {
|
||||||
|
case 0x0d:
|
||||||
|
if(offset+bytes > 22) {
|
||||||
|
Dbprintf("Error: can not write to 0x%03.3x on MIM22", offset+bytes);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
addr_sz = 5;
|
||||||
|
Dbprintf("MIM22 card found, writing 0x%02.2x - 0x%02.2x ...", offset, offset+bytes);
|
||||||
|
break;
|
||||||
case 0x1d:
|
case 0x1d:
|
||||||
if(offset+bytes > 0x100) {
|
if(offset+bytes > 0x100) {
|
||||||
Dbprintf("Error: can not write to 0x%03.3x on MIM256", offset+bytes);
|
Dbprintf("Error: can not write to 0x%03.3x on MIM256", offset+bytes);
|
||||||
|
@ -510,11 +572,27 @@ void LegicRfWriter(int bytes, int offset) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 1
|
||||||
LED_B_ON();
|
LED_B_ON();
|
||||||
perform_setup_phase_rwd(SESSION_IV);
|
perform_setup_phase_rwd(SESSION_IV);
|
||||||
legic_prng_forward(2);
|
|
||||||
while(byte_index < bytes) {
|
while(byte_index < bytes) {
|
||||||
int r = legic_write_byte(BigBuf[byte_index+offset], byte_index+offset, addr_sz);
|
int r;
|
||||||
|
|
||||||
|
//check if the DCF should be changed
|
||||||
|
if ( ((byte_index+offset) == 0x05) && (bytes >= 0x02) ) {
|
||||||
|
//write DCF in reverse order (addr 0x06 before 0x05)
|
||||||
|
r = legic_write_byte(BigBuf[(0x06-byte_index)], (0x06-byte_index), addr_sz);
|
||||||
|
|
||||||
|
// write second byte on success...
|
||||||
|
if(r == 0) {
|
||||||
|
byte_index++;
|
||||||
|
r = legic_write_byte(BigBuf[(0x06-byte_index)], (0x06-byte_index), addr_sz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
r = legic_write_byte(BigBuf[byte_index+offset], byte_index+offset, addr_sz);
|
||||||
|
}
|
||||||
if((r != 0) || BUTTON_PRESS()) {
|
if((r != 0) || BUTTON_PRESS()) {
|
||||||
Dbprintf("operation aborted @ 0x%03.3x", byte_index);
|
Dbprintf("operation aborted @ 0x%03.3x", byte_index);
|
||||||
switch_off_tag_rwd();
|
switch_off_tag_rwd();
|
||||||
|
@ -522,6 +600,76 @@ void LegicRfWriter(int bytes, int offset) {
|
||||||
LED_C_OFF();
|
LED_C_OFF();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WDT_HIT();
|
||||||
|
byte_index++;
|
||||||
|
if(byte_index & 0x10) LED_C_ON(); else LED_C_OFF();
|
||||||
|
}
|
||||||
|
LED_B_OFF();
|
||||||
|
LED_C_OFF();
|
||||||
|
DbpString("write successful");
|
||||||
|
#else
|
||||||
|
for(byte_index = -2; byte_index < 200; byte_index++)
|
||||||
|
{
|
||||||
|
Dbprintf("+ Try RndValue %d...", byte_index);
|
||||||
|
if(_LegicRfWriter(bytes, offset, addr_sz, BigBuf, byte_index) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void LegicRfRawWriter(int offset, int byte) {
|
||||||
|
int byte_index=0, addr_sz=0;
|
||||||
|
|
||||||
|
LegicCommonInit();
|
||||||
|
|
||||||
|
DbpString("setting up legic card");
|
||||||
|
uint32_t tag_type = perform_setup_phase_rwd(SESSION_IV);
|
||||||
|
switch_off_tag_rwd();
|
||||||
|
switch(tag_type) {
|
||||||
|
case 0x0d:
|
||||||
|
if(offset > 22) {
|
||||||
|
Dbprintf("Error: can not write to 0x%03.3x on MIM22", offset);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
addr_sz = 5;
|
||||||
|
Dbprintf("MIM22 card found, writing at addr 0x%02.2x - value 0x%02.2x ...", offset, byte);
|
||||||
|
break;
|
||||||
|
case 0x1d:
|
||||||
|
if(offset > 0x100) {
|
||||||
|
Dbprintf("Error: can not write to 0x%03.3x on MIM256", offset);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
addr_sz = 8;
|
||||||
|
Dbprintf("MIM256 card found, writing at addr 0x%02.2x - value 0x%02.2x ...", offset, byte);
|
||||||
|
break;
|
||||||
|
case 0x3d:
|
||||||
|
if(offset > 0x400) {
|
||||||
|
Dbprintf("Error: can not write to 0x%03.3x on MIM1024", offset);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
addr_sz = 10;
|
||||||
|
Dbprintf("MIM1024 card found, writing at addr 0x%03.3x - value 0x%03.3x ...", offset, byte);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Dbprintf("No or unknown card found, aborting");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Dbprintf("integer value: %d offset: %d addr_sz: %d", byte, offset, addr_sz);
|
||||||
|
LED_B_ON();
|
||||||
|
perform_setup_phase_rwd(SESSION_IV);
|
||||||
|
//legic_prng_forward(2);
|
||||||
|
|
||||||
|
int r = legic_write_byte(byte, offset, addr_sz);
|
||||||
|
|
||||||
|
if((r != 0) || BUTTON_PRESS()) {
|
||||||
|
Dbprintf("operation aborted @ 0x%03.3x (%1d)", byte_index, r);
|
||||||
|
switch_off_tag_rwd();
|
||||||
|
LED_B_OFF();
|
||||||
|
LED_C_OFF();
|
||||||
|
return;
|
||||||
|
|
||||||
WDT_HIT();
|
WDT_HIT();
|
||||||
byte_index++;
|
byte_index++;
|
||||||
if(byte_index & 0x10) LED_C_ON(); else LED_C_OFF();
|
if(byte_index & 0x10) LED_C_ON(); else LED_C_OFF();
|
||||||
|
@ -756,3 +904,757 @@ void LegicRfSimulate(int phase, int frame, int reqresp)
|
||||||
LED_C_OFF();
|
LED_C_OFF();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Code up a string of octets at layer 2 (including CRC, we don't generate
|
||||||
|
// that here) so that they can be transmitted to the reader. Doesn't transmit
|
||||||
|
// them yet, just leaves them ready to send in ToSend[].
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// static void CodeLegicAsTag(const uint8_t *cmd, int len)
|
||||||
|
// {
|
||||||
|
// int i;
|
||||||
|
|
||||||
|
// ToSendReset();
|
||||||
|
|
||||||
|
// // Transmit a burst of ones, as the initial thing that lets the
|
||||||
|
// // reader get phase sync. This (TR1) must be > 80/fs, per spec,
|
||||||
|
// // but tag that I've tried (a Paypass) exceeds that by a fair bit,
|
||||||
|
// // so I will too.
|
||||||
|
// for(i = 0; i < 20; i++) {
|
||||||
|
// ToSendStuffBit(1);
|
||||||
|
// ToSendStuffBit(1);
|
||||||
|
// ToSendStuffBit(1);
|
||||||
|
// ToSendStuffBit(1);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Send SOF.
|
||||||
|
// for(i = 0; i < 10; i++) {
|
||||||
|
// ToSendStuffBit(0);
|
||||||
|
// ToSendStuffBit(0);
|
||||||
|
// ToSendStuffBit(0);
|
||||||
|
// ToSendStuffBit(0);
|
||||||
|
// }
|
||||||
|
// for(i = 0; i < 2; i++) {
|
||||||
|
// ToSendStuffBit(1);
|
||||||
|
// ToSendStuffBit(1);
|
||||||
|
// ToSendStuffBit(1);
|
||||||
|
// ToSendStuffBit(1);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// for(i = 0; i < len; i++) {
|
||||||
|
// int j;
|
||||||
|
// uint8_t b = cmd[i];
|
||||||
|
|
||||||
|
// // Start bit
|
||||||
|
// ToSendStuffBit(0);
|
||||||
|
// ToSendStuffBit(0);
|
||||||
|
// ToSendStuffBit(0);
|
||||||
|
// ToSendStuffBit(0);
|
||||||
|
|
||||||
|
// // Data bits
|
||||||
|
// for(j = 0; j < 8; j++) {
|
||||||
|
// if(b & 1) {
|
||||||
|
// ToSendStuffBit(1);
|
||||||
|
// ToSendStuffBit(1);
|
||||||
|
// ToSendStuffBit(1);
|
||||||
|
// ToSendStuffBit(1);
|
||||||
|
// } else {
|
||||||
|
// ToSendStuffBit(0);
|
||||||
|
// ToSendStuffBit(0);
|
||||||
|
// ToSendStuffBit(0);
|
||||||
|
// ToSendStuffBit(0);
|
||||||
|
// }
|
||||||
|
// b >>= 1;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Stop bit
|
||||||
|
// ToSendStuffBit(1);
|
||||||
|
// ToSendStuffBit(1);
|
||||||
|
// ToSendStuffBit(1);
|
||||||
|
// ToSendStuffBit(1);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Send EOF.
|
||||||
|
// for(i = 0; i < 10; i++) {
|
||||||
|
// ToSendStuffBit(0);
|
||||||
|
// ToSendStuffBit(0);
|
||||||
|
// ToSendStuffBit(0);
|
||||||
|
// ToSendStuffBit(0);
|
||||||
|
// }
|
||||||
|
// for(i = 0; i < 2; i++) {
|
||||||
|
// ToSendStuffBit(1);
|
||||||
|
// ToSendStuffBit(1);
|
||||||
|
// ToSendStuffBit(1);
|
||||||
|
// ToSendStuffBit(1);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Convert from last byte pos to length
|
||||||
|
// ToSendMax++;
|
||||||
|
// }
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// The software UART that receives commands from the reader, and its state
|
||||||
|
// variables.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
static struct {
|
||||||
|
enum {
|
||||||
|
STATE_UNSYNCD,
|
||||||
|
STATE_GOT_FALLING_EDGE_OF_SOF,
|
||||||
|
STATE_AWAITING_START_BIT,
|
||||||
|
STATE_RECEIVING_DATA
|
||||||
|
} state;
|
||||||
|
uint16_t shiftReg;
|
||||||
|
int bitCnt;
|
||||||
|
int byteCnt;
|
||||||
|
int byteCntMax;
|
||||||
|
int posCnt;
|
||||||
|
uint8_t *output;
|
||||||
|
} Uart;
|
||||||
|
|
||||||
|
/* Receive & handle a bit coming from the reader.
|
||||||
|
*
|
||||||
|
* This function is called 4 times per bit (every 2 subcarrier cycles).
|
||||||
|
* Subcarrier frequency fs is 212kHz, 1/fs = 4,72us, i.e. function is called every 9,44us
|
||||||
|
*
|
||||||
|
* LED handling:
|
||||||
|
* LED A -> ON once we have received the SOF and are expecting the rest.
|
||||||
|
* LED A -> OFF once we have received EOF or are in error state or unsynced
|
||||||
|
*
|
||||||
|
* Returns: true if we received a EOF
|
||||||
|
* false if we are still waiting for some more
|
||||||
|
*/
|
||||||
|
// static RAMFUNC int HandleLegicUartBit(uint8_t bit)
|
||||||
|
// {
|
||||||
|
// switch(Uart.state) {
|
||||||
|
// case STATE_UNSYNCD:
|
||||||
|
// if(!bit) {
|
||||||
|
// // we went low, so this could be the beginning of an SOF
|
||||||
|
// Uart.state = STATE_GOT_FALLING_EDGE_OF_SOF;
|
||||||
|
// Uart.posCnt = 0;
|
||||||
|
// Uart.bitCnt = 0;
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
|
||||||
|
// case STATE_GOT_FALLING_EDGE_OF_SOF:
|
||||||
|
// Uart.posCnt++;
|
||||||
|
// if(Uart.posCnt == 2) { // sample every 4 1/fs in the middle of a bit
|
||||||
|
// if(bit) {
|
||||||
|
// if(Uart.bitCnt > 9) {
|
||||||
|
// // we've seen enough consecutive
|
||||||
|
// // zeros that it's a valid SOF
|
||||||
|
// Uart.posCnt = 0;
|
||||||
|
// Uart.byteCnt = 0;
|
||||||
|
// Uart.state = STATE_AWAITING_START_BIT;
|
||||||
|
// LED_A_ON(); // Indicate we got a valid SOF
|
||||||
|
// } else {
|
||||||
|
// // didn't stay down long enough
|
||||||
|
// // before going high, error
|
||||||
|
// Uart.state = STATE_UNSYNCD;
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// // do nothing, keep waiting
|
||||||
|
// }
|
||||||
|
// Uart.bitCnt++;
|
||||||
|
// }
|
||||||
|
// if(Uart.posCnt >= 4) Uart.posCnt = 0;
|
||||||
|
// if(Uart.bitCnt > 12) {
|
||||||
|
// // Give up if we see too many zeros without
|
||||||
|
// // a one, too.
|
||||||
|
// LED_A_OFF();
|
||||||
|
// Uart.state = STATE_UNSYNCD;
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
|
||||||
|
// case STATE_AWAITING_START_BIT:
|
||||||
|
// Uart.posCnt++;
|
||||||
|
// if(bit) {
|
||||||
|
// if(Uart.posCnt > 50/2) { // max 57us between characters = 49 1/fs, max 3 etus after low phase of SOF = 24 1/fs
|
||||||
|
// // stayed high for too long between
|
||||||
|
// // characters, error
|
||||||
|
// Uart.state = STATE_UNSYNCD;
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// // falling edge, this starts the data byte
|
||||||
|
// Uart.posCnt = 0;
|
||||||
|
// Uart.bitCnt = 0;
|
||||||
|
// Uart.shiftReg = 0;
|
||||||
|
// Uart.state = STATE_RECEIVING_DATA;
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
|
||||||
|
// case STATE_RECEIVING_DATA:
|
||||||
|
// Uart.posCnt++;
|
||||||
|
// if(Uart.posCnt == 2) {
|
||||||
|
// // time to sample a bit
|
||||||
|
// Uart.shiftReg >>= 1;
|
||||||
|
// if(bit) {
|
||||||
|
// Uart.shiftReg |= 0x200;
|
||||||
|
// }
|
||||||
|
// Uart.bitCnt++;
|
||||||
|
// }
|
||||||
|
// if(Uart.posCnt >= 4) {
|
||||||
|
// Uart.posCnt = 0;
|
||||||
|
// }
|
||||||
|
// if(Uart.bitCnt == 10) {
|
||||||
|
// if((Uart.shiftReg & 0x200) && !(Uart.shiftReg & 0x001))
|
||||||
|
// {
|
||||||
|
// // this is a data byte, with correct
|
||||||
|
// // start and stop bits
|
||||||
|
// Uart.output[Uart.byteCnt] = (Uart.shiftReg >> 1) & 0xff;
|
||||||
|
// Uart.byteCnt++;
|
||||||
|
|
||||||
|
// if(Uart.byteCnt >= Uart.byteCntMax) {
|
||||||
|
// // Buffer overflowed, give up
|
||||||
|
// LED_A_OFF();
|
||||||
|
// Uart.state = STATE_UNSYNCD;
|
||||||
|
// } else {
|
||||||
|
// // so get the next byte now
|
||||||
|
// Uart.posCnt = 0;
|
||||||
|
// Uart.state = STATE_AWAITING_START_BIT;
|
||||||
|
// }
|
||||||
|
// } else if (Uart.shiftReg == 0x000) {
|
||||||
|
// // this is an EOF byte
|
||||||
|
// LED_A_OFF(); // Finished receiving
|
||||||
|
// Uart.state = STATE_UNSYNCD;
|
||||||
|
// if (Uart.byteCnt != 0) {
|
||||||
|
// return TRUE;
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// // this is an error
|
||||||
|
// LED_A_OFF();
|
||||||
|
// Uart.state = STATE_UNSYNCD;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
|
||||||
|
// default:
|
||||||
|
// LED_A_OFF();
|
||||||
|
// Uart.state = STATE_UNSYNCD;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return FALSE;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
static void UartReset()
|
||||||
|
{
|
||||||
|
Uart.byteCntMax = MAX_FRAME_SIZE;
|
||||||
|
Uart.state = STATE_UNSYNCD;
|
||||||
|
Uart.byteCnt = 0;
|
||||||
|
Uart.bitCnt = 0;
|
||||||
|
Uart.posCnt = 0;
|
||||||
|
memset(Uart.output, 0x00, MAX_FRAME_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// static void UartInit(uint8_t *data)
|
||||||
|
// {
|
||||||
|
// Uart.output = data;
|
||||||
|
// UartReset();
|
||||||
|
// }
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// An LEGIC reader. We take layer two commands, code them
|
||||||
|
// appropriately, and then send them to the tag. We then listen for the
|
||||||
|
// tag's response, which we leave in the buffer to be demodulated on the
|
||||||
|
// PC side.
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
enum {
|
||||||
|
DEMOD_UNSYNCD,
|
||||||
|
DEMOD_PHASE_REF_TRAINING,
|
||||||
|
DEMOD_AWAITING_FALLING_EDGE_OF_SOF,
|
||||||
|
DEMOD_GOT_FALLING_EDGE_OF_SOF,
|
||||||
|
DEMOD_AWAITING_START_BIT,
|
||||||
|
DEMOD_RECEIVING_DATA
|
||||||
|
} state;
|
||||||
|
int bitCount;
|
||||||
|
int posCount;
|
||||||
|
int thisBit;
|
||||||
|
uint16_t shiftReg;
|
||||||
|
uint8_t *output;
|
||||||
|
int len;
|
||||||
|
int sumI;
|
||||||
|
int sumQ;
|
||||||
|
} Demod;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handles reception of a bit from the tag
|
||||||
|
*
|
||||||
|
* This function is called 2 times per bit (every 4 subcarrier cycles).
|
||||||
|
* Subcarrier frequency fs is 212kHz, 1/fs = 4,72us, i.e. function is called every 9,44us
|
||||||
|
*
|
||||||
|
* LED handling:
|
||||||
|
* LED C -> ON once we have received the SOF and are expecting the rest.
|
||||||
|
* LED C -> OFF once we have received EOF or are unsynced
|
||||||
|
*
|
||||||
|
* Returns: true if we received a EOF
|
||||||
|
* false if we are still waiting for some more
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SUBCARRIER_DETECT_THRESHOLD
|
||||||
|
# define SUBCARRIER_DETECT_THRESHOLD 8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by max(abs(ci),abs(cq)) + 1/2*min(abs(ci),abs(cq)))
|
||||||
|
#ifndef CHECK_FOR_SUBCARRIER
|
||||||
|
# define CHECK_FOR_SUBCARRIER() { v = MAX(ai, aq) + MIN(halfci, halfcq); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// The soft decision on the bit uses an estimate of just the
|
||||||
|
// quadrant of the reference angle, not the exact angle.
|
||||||
|
// Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by max(abs(ci),abs(cq)) + 1/2*min(abs(ci),abs(cq)))
|
||||||
|
#define MAKE_SOFT_DECISION() { \
|
||||||
|
if(Demod.sumI > 0) \
|
||||||
|
v = ci; \
|
||||||
|
else \
|
||||||
|
v = -ci; \
|
||||||
|
\
|
||||||
|
if(Demod.sumQ > 0) \
|
||||||
|
v += cq; \
|
||||||
|
else \
|
||||||
|
v -= cq; \
|
||||||
|
\
|
||||||
|
}
|
||||||
|
|
||||||
|
static RAMFUNC int HandleLegicSamplesDemod(int ci, int cq)
|
||||||
|
{
|
||||||
|
int v = 0;
|
||||||
|
int ai = ABS(ci);
|
||||||
|
int aq = ABS(cq);
|
||||||
|
int halfci = (ai >> 1);
|
||||||
|
int halfcq = (aq >> 1);
|
||||||
|
|
||||||
|
switch(Demod.state) {
|
||||||
|
case DEMOD_UNSYNCD:
|
||||||
|
|
||||||
|
CHECK_FOR_SUBCARRIER()
|
||||||
|
|
||||||
|
if(v > SUBCARRIER_DETECT_THRESHOLD) { // subcarrier detected
|
||||||
|
Demod.state = DEMOD_PHASE_REF_TRAINING;
|
||||||
|
Demod.sumI = ci;
|
||||||
|
Demod.sumQ = cq;
|
||||||
|
Demod.posCount = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEMOD_PHASE_REF_TRAINING:
|
||||||
|
if(Demod.posCount < 8) {
|
||||||
|
|
||||||
|
CHECK_FOR_SUBCARRIER()
|
||||||
|
|
||||||
|
if (v > SUBCARRIER_DETECT_THRESHOLD) {
|
||||||
|
// set the reference phase (will code a logic '1') by averaging over 32 1/fs.
|
||||||
|
// note: synchronization time > 80 1/fs
|
||||||
|
Demod.sumI += ci;
|
||||||
|
Demod.sumQ += cq;
|
||||||
|
++Demod.posCount;
|
||||||
|
} else {
|
||||||
|
// subcarrier lost
|
||||||
|
Demod.state = DEMOD_UNSYNCD;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Demod.state = DEMOD_AWAITING_FALLING_EDGE_OF_SOF;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEMOD_AWAITING_FALLING_EDGE_OF_SOF:
|
||||||
|
|
||||||
|
MAKE_SOFT_DECISION()
|
||||||
|
|
||||||
|
//Dbprintf("ICE: %d %d %d %d %d", v, Demod.sumI, Demod.sumQ, ci, cq );
|
||||||
|
// logic '0' detected
|
||||||
|
if (v <= 0) {
|
||||||
|
|
||||||
|
Demod.state = DEMOD_GOT_FALLING_EDGE_OF_SOF;
|
||||||
|
|
||||||
|
// start of SOF sequence
|
||||||
|
Demod.posCount = 0;
|
||||||
|
} else {
|
||||||
|
// maximum length of TR1 = 200 1/fs
|
||||||
|
if(Demod.posCount > 25*2) Demod.state = DEMOD_UNSYNCD;
|
||||||
|
}
|
||||||
|
++Demod.posCount;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEMOD_GOT_FALLING_EDGE_OF_SOF:
|
||||||
|
++Demod.posCount;
|
||||||
|
|
||||||
|
MAKE_SOFT_DECISION()
|
||||||
|
|
||||||
|
if(v > 0) {
|
||||||
|
// low phase of SOF too short (< 9 etu). Note: spec is >= 10, but FPGA tends to "smear" edges
|
||||||
|
if(Demod.posCount < 10*2) {
|
||||||
|
Demod.state = DEMOD_UNSYNCD;
|
||||||
|
} else {
|
||||||
|
LED_C_ON(); // Got SOF
|
||||||
|
Demod.state = DEMOD_AWAITING_START_BIT;
|
||||||
|
Demod.posCount = 0;
|
||||||
|
Demod.len = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// low phase of SOF too long (> 12 etu)
|
||||||
|
if(Demod.posCount > 13*2) {
|
||||||
|
Demod.state = DEMOD_UNSYNCD;
|
||||||
|
LED_C_OFF();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEMOD_AWAITING_START_BIT:
|
||||||
|
++Demod.posCount;
|
||||||
|
|
||||||
|
MAKE_SOFT_DECISION()
|
||||||
|
|
||||||
|
if(v > 0) {
|
||||||
|
// max 19us between characters = 16 1/fs, max 3 etu after low phase of SOF = 24 1/fs
|
||||||
|
if(Demod.posCount > 3*2) {
|
||||||
|
Demod.state = DEMOD_UNSYNCD;
|
||||||
|
LED_C_OFF();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// start bit detected
|
||||||
|
Demod.bitCount = 0;
|
||||||
|
Demod.posCount = 1; // this was the first half
|
||||||
|
Demod.thisBit = v;
|
||||||
|
Demod.shiftReg = 0;
|
||||||
|
Demod.state = DEMOD_RECEIVING_DATA;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEMOD_RECEIVING_DATA:
|
||||||
|
|
||||||
|
MAKE_SOFT_DECISION()
|
||||||
|
|
||||||
|
if(Demod.posCount == 0) {
|
||||||
|
// first half of bit
|
||||||
|
Demod.thisBit = v;
|
||||||
|
Demod.posCount = 1;
|
||||||
|
} else {
|
||||||
|
// second half of bit
|
||||||
|
Demod.thisBit += v;
|
||||||
|
Demod.shiftReg >>= 1;
|
||||||
|
// logic '1'
|
||||||
|
if(Demod.thisBit > 0)
|
||||||
|
Demod.shiftReg |= 0x200;
|
||||||
|
|
||||||
|
++Demod.bitCount;
|
||||||
|
|
||||||
|
if(Demod.bitCount == 10) {
|
||||||
|
|
||||||
|
uint16_t s = Demod.shiftReg;
|
||||||
|
|
||||||
|
if((s & 0x200) && !(s & 0x001)) {
|
||||||
|
// stop bit == '1', start bit == '0'
|
||||||
|
uint8_t b = (s >> 1);
|
||||||
|
Demod.output[Demod.len] = b;
|
||||||
|
++Demod.len;
|
||||||
|
Demod.state = DEMOD_AWAITING_START_BIT;
|
||||||
|
} else {
|
||||||
|
Demod.state = DEMOD_UNSYNCD;
|
||||||
|
LED_C_OFF();
|
||||||
|
|
||||||
|
if(s == 0x000) {
|
||||||
|
// This is EOF (start, stop and all data bits == '0'
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Demod.posCount = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Demod.state = DEMOD_UNSYNCD;
|
||||||
|
LED_C_OFF();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear out the state of the "UART" that receives from the tag.
|
||||||
|
static void DemodReset() {
|
||||||
|
Demod.len = 0;
|
||||||
|
Demod.state = DEMOD_UNSYNCD;
|
||||||
|
Demod.posCount = 0;
|
||||||
|
Demod.sumI = 0;
|
||||||
|
Demod.sumQ = 0;
|
||||||
|
Demod.bitCount = 0;
|
||||||
|
Demod.thisBit = 0;
|
||||||
|
Demod.shiftReg = 0;
|
||||||
|
memset(Demod.output, 0x00, MAX_FRAME_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DemodInit(uint8_t *data) {
|
||||||
|
Demod.output = data;
|
||||||
|
DemodReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Demodulate the samples we received from the tag, also log to tracebuffer
|
||||||
|
* quiet: set to 'TRUE' to disable debug output
|
||||||
|
*/
|
||||||
|
#define LEGIC_DMA_BUFFER_SIZE 256
|
||||||
|
static void GetSamplesForLegicDemod(int n, bool quiet)
|
||||||
|
{
|
||||||
|
int max = 0;
|
||||||
|
bool gotFrame = FALSE;
|
||||||
|
int lastRxCounter = LEGIC_DMA_BUFFER_SIZE;
|
||||||
|
int ci, cq, samples = 0;
|
||||||
|
|
||||||
|
BigBuf_free();
|
||||||
|
|
||||||
|
// And put the FPGA in the appropriate mode
|
||||||
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_QUARTER_FREQ);
|
||||||
|
|
||||||
|
// The response (tag -> reader) that we're receiving.
|
||||||
|
// Set up the demodulator for tag -> reader responses.
|
||||||
|
DemodInit(BigBuf_malloc(MAX_FRAME_SIZE));
|
||||||
|
|
||||||
|
// The DMA buffer, used to stream samples from the FPGA
|
||||||
|
int8_t *dmaBuf = (int8_t*) BigBuf_malloc(LEGIC_DMA_BUFFER_SIZE);
|
||||||
|
int8_t *upTo = dmaBuf;
|
||||||
|
|
||||||
|
// Setup and start DMA.
|
||||||
|
if ( !FpgaSetupSscDma((uint8_t*) dmaBuf, LEGIC_DMA_BUFFER_SIZE) ){
|
||||||
|
if (MF_DBGLEVEL > 1) Dbprintf("FpgaSetupSscDma failed. Exiting");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signal field is ON with the appropriate LED:
|
||||||
|
LED_D_ON();
|
||||||
|
for(;;) {
|
||||||
|
int behindBy = lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR;
|
||||||
|
if(behindBy > max) max = behindBy;
|
||||||
|
|
||||||
|
while(((lastRxCounter-AT91C_BASE_PDC_SSC->PDC_RCR) & (LEGIC_DMA_BUFFER_SIZE-1)) > 2) {
|
||||||
|
ci = upTo[0];
|
||||||
|
cq = upTo[1];
|
||||||
|
upTo += 2;
|
||||||
|
if(upTo >= dmaBuf + LEGIC_DMA_BUFFER_SIZE) {
|
||||||
|
upTo = dmaBuf;
|
||||||
|
AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) upTo;
|
||||||
|
AT91C_BASE_PDC_SSC->PDC_RNCR = LEGIC_DMA_BUFFER_SIZE;
|
||||||
|
}
|
||||||
|
lastRxCounter -= 2;
|
||||||
|
if(lastRxCounter <= 0)
|
||||||
|
lastRxCounter = LEGIC_DMA_BUFFER_SIZE;
|
||||||
|
|
||||||
|
samples += 2;
|
||||||
|
|
||||||
|
gotFrame = HandleLegicSamplesDemod(ci , cq );
|
||||||
|
if ( gotFrame )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(samples > n || gotFrame)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
FpgaDisableSscDma();
|
||||||
|
|
||||||
|
if (!quiet && Demod.len == 0) {
|
||||||
|
Dbprintf("max behindby = %d, samples = %d, gotFrame = %d, Demod.len = %d, Demod.sumI = %d, Demod.sumQ = %d",
|
||||||
|
max,
|
||||||
|
samples,
|
||||||
|
gotFrame,
|
||||||
|
Demod.len,
|
||||||
|
Demod.sumI,
|
||||||
|
Demod.sumQ
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Tracing
|
||||||
|
if (Demod.len > 0) {
|
||||||
|
uint8_t parity[MAX_PARITY_SIZE] = {0x00};
|
||||||
|
LogTrace(Demod.output, Demod.len, 0, 0, parity, FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Transmit the command (to the tag) that was placed in ToSend[].
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
static void TransmitForLegic(void)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
|
||||||
|
FpgaSetupSsc();
|
||||||
|
|
||||||
|
while(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))
|
||||||
|
AT91C_BASE_SSC->SSC_THR = 0xff;
|
||||||
|
|
||||||
|
// Signal field is ON with the appropriate Red LED
|
||||||
|
LED_D_ON();
|
||||||
|
|
||||||
|
// Signal we are transmitting with the Green LED
|
||||||
|
LED_B_ON();
|
||||||
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD);
|
||||||
|
|
||||||
|
for(c = 0; c < 10;) {
|
||||||
|
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
|
||||||
|
AT91C_BASE_SSC->SSC_THR = 0xff;
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
|
||||||
|
volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR;
|
||||||
|
(void)r;
|
||||||
|
}
|
||||||
|
WDT_HIT();
|
||||||
|
}
|
||||||
|
|
||||||
|
c = 0;
|
||||||
|
for(;;) {
|
||||||
|
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
|
||||||
|
AT91C_BASE_SSC->SSC_THR = ToSend[c];
|
||||||
|
legic_prng_forward(1); // forward the lfsr
|
||||||
|
c++;
|
||||||
|
if(c >= ToSendMax) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
|
||||||
|
volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR;
|
||||||
|
(void)r;
|
||||||
|
}
|
||||||
|
WDT_HIT();
|
||||||
|
}
|
||||||
|
LED_B_OFF();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Code a layer 2 command (string of octets, including CRC) into ToSend[],
|
||||||
|
// so that it is ready to transmit to the tag using TransmitForLegic().
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
static void CodeLegicBitsAsReader(const uint8_t *cmd, int bits)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
uint8_t b;
|
||||||
|
|
||||||
|
ToSendReset();
|
||||||
|
|
||||||
|
// Send SOF
|
||||||
|
for(i = 0; i < 7; i++) {
|
||||||
|
ToSendStuffBit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < bits; i++) {
|
||||||
|
// Start bit
|
||||||
|
ToSendStuffBit(0);
|
||||||
|
|
||||||
|
// Data bits
|
||||||
|
b = cmd[i];
|
||||||
|
for(j = 0; j < 8; j++) {
|
||||||
|
if(b & 1) {
|
||||||
|
ToSendStuffBit(1);
|
||||||
|
} else {
|
||||||
|
ToSendStuffBit(0);
|
||||||
|
}
|
||||||
|
b >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert from last character reference to length
|
||||||
|
++ToSendMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Convenience function to encode, transmit and trace Legic comms
|
||||||
|
**/
|
||||||
|
static void CodeAndTransmitLegicAsReader(const uint8_t *cmd, int bits)
|
||||||
|
{
|
||||||
|
CodeLegicBitsAsReader(cmd, bits);
|
||||||
|
TransmitForLegic();
|
||||||
|
if (tracing) {
|
||||||
|
uint8_t parity[1] = {0x00};
|
||||||
|
LogTrace(cmd, bits, 0, 0, parity, TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ice_legic_select_card()
|
||||||
|
{
|
||||||
|
//int cmd_size=0, card_size=0;
|
||||||
|
uint8_t wakeup[] = { 0x7F};
|
||||||
|
uint8_t getid[] = {0x19};
|
||||||
|
|
||||||
|
legic_prng_init(SESSION_IV);
|
||||||
|
|
||||||
|
// first, wake up the tag, 7bits
|
||||||
|
CodeAndTransmitLegicAsReader(wakeup, 7);
|
||||||
|
|
||||||
|
GetSamplesForLegicDemod(1000, TRUE);
|
||||||
|
|
||||||
|
// frame_clean(¤t_frame);
|
||||||
|
//frame_receive_rwd(¤t_frame, 6, 1);
|
||||||
|
|
||||||
|
legic_prng_forward(1); /* we wait anyways */
|
||||||
|
|
||||||
|
//while(timer->TC_CV < 387) ; /* ~ 258us */
|
||||||
|
//frame_send_rwd(0x19, 6);
|
||||||
|
CodeAndTransmitLegicAsReader(getid, sizeof(getid));
|
||||||
|
GetSamplesForLegicDemod(1000, TRUE);
|
||||||
|
|
||||||
|
//if (Demod.len < 14) return 2;
|
||||||
|
Dbprintf("CARD TYPE: %02x LEN: %d", Demod.output[0], Demod.len);
|
||||||
|
|
||||||
|
switch(Demod.output[0]) {
|
||||||
|
case 0x1d:
|
||||||
|
DbpString("MIM 256 card found");
|
||||||
|
// cmd_size = 9;
|
||||||
|
// card_size = 256;
|
||||||
|
break;
|
||||||
|
case 0x3d:
|
||||||
|
DbpString("MIM 1024 card found");
|
||||||
|
// cmd_size = 11;
|
||||||
|
// card_size = 1024;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if(bytes == -1)
|
||||||
|
// bytes = card_size;
|
||||||
|
|
||||||
|
// if(bytes + offset >= card_size)
|
||||||
|
// bytes = card_size - offset;
|
||||||
|
|
||||||
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||||
|
set_tracing(FALSE);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up LEGIC communication
|
||||||
|
void ice_legic_setup() {
|
||||||
|
|
||||||
|
// standard things.
|
||||||
|
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||||
|
BigBuf_free(); BigBuf_Clear_ext(false);
|
||||||
|
clear_trace();
|
||||||
|
set_tracing(TRUE);
|
||||||
|
DemodReset();
|
||||||
|
UartReset();
|
||||||
|
|
||||||
|
// Set up the synchronous serial port
|
||||||
|
FpgaSetupSsc();
|
||||||
|
|
||||||
|
// connect Demodulated Signal to ADC:
|
||||||
|
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
|
||||||
|
|
||||||
|
// Signal field is on with the appropriate LED
|
||||||
|
LED_D_ON();
|
||||||
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD);
|
||||||
|
SpinDelay(200);
|
||||||
|
// Start the timer
|
||||||
|
//StartCountSspClk();
|
||||||
|
|
||||||
|
// initalize CRC
|
||||||
|
crc_init(&legic_crc, 4, 0x19 >> 1, 0x5, 0);
|
||||||
|
|
||||||
|
// initalize prng
|
||||||
|
legic_prng_init(0);
|
||||||
|
}
|
|
@ -14,5 +14,9 @@
|
||||||
extern void LegicRfSimulate(int phase, int frame, int reqresp);
|
extern void LegicRfSimulate(int phase, int frame, int reqresp);
|
||||||
extern int LegicRfReader(int bytes, int offset);
|
extern int LegicRfReader(int bytes, int offset);
|
||||||
extern void LegicRfWriter(int bytes, int offset);
|
extern void LegicRfWriter(int bytes, int offset);
|
||||||
|
extern void LegicRfRawWriter(int offset, int bytes);
|
||||||
|
|
||||||
|
int ice_legic_select_card();
|
||||||
|
void ice_legic_setup();
|
||||||
|
|
||||||
#endif /* __LEGICRF_H */
|
#endif /* __LEGICRF_H */
|
||||||
|
|
|
@ -14,6 +14,10 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "string.h"
|
||||||
|
#include "apps.h"
|
||||||
|
#include "BigBuf.h"
|
||||||
|
#include "proxmark3.h"
|
||||||
|
|
||||||
#define BYTEx(x, n) (((x) >> (n * 8)) & 0xff )
|
#define BYTEx(x, n) (((x) >> (n * 8)) & 0xff )
|
||||||
|
|
||||||
|
@ -27,9 +31,17 @@
|
||||||
#define BUTTON_DOUBLE_CLICK -2
|
#define BUTTON_DOUBLE_CLICK -2
|
||||||
#define BUTTON_ERROR -99
|
#define BUTTON_ERROR -99
|
||||||
|
|
||||||
|
#ifndef BSWAP_16
|
||||||
|
# define BSWAP_16(x) ((( ((x) & 0xFF00 ) >> 8))| ( (((x) & 0x00FF) << 8)))
|
||||||
|
#endif
|
||||||
|
#ifndef BITMASK
|
||||||
|
# define BITMASK(X) (1 << (X))
|
||||||
|
#endif
|
||||||
|
|
||||||
void print_result(char *name, uint8_t *buf, size_t len);
|
void print_result(char *name, uint8_t *buf, size_t len);
|
||||||
size_t nbytes(size_t nbits);
|
size_t nbytes(size_t nbits);
|
||||||
uint32_t SwapBits(uint32_t value, int nrbits);
|
uint32_t SwapBits(uint32_t value, int nrbits);
|
||||||
|
uint32_t reflect(uint32_t v, int b);
|
||||||
void num_to_bytes(uint64_t n, size_t len, uint8_t* dest);
|
void num_to_bytes(uint64_t n, size_t len, uint8_t* dest);
|
||||||
uint64_t bytes_to_num(uint8_t* src, size_t len);
|
uint64_t bytes_to_num(uint8_t* src, size_t len);
|
||||||
void rol(uint8_t *data, const size_t len);
|
void rol(uint8_t *data, const size_t len);
|
||||||
|
@ -52,6 +64,7 @@ uint32_t RAMFUNC GetCountUS();
|
||||||
//uint32_t RAMFUNC GetDeltaCountUS();
|
//uint32_t RAMFUNC GetDeltaCountUS();
|
||||||
|
|
||||||
void StartCountSspClk();
|
void StartCountSspClk();
|
||||||
|
void ResetSspClk(void);
|
||||||
uint32_t RAMFUNC GetCountSspClk();
|
uint32_t RAMFUNC GetCountSspClk();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -7,27 +7,21 @@
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// High frequency Legic commands
|
// High frequency Legic commands
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "proxmark3.h"
|
|
||||||
#include "data.h"
|
|
||||||
#include "ui.h"
|
|
||||||
#include "cmdparser.h"
|
|
||||||
#include "cmdhflegic.h"
|
#include "cmdhflegic.h"
|
||||||
#include "cmdmain.h"
|
|
||||||
#include "util.h"
|
|
||||||
#include "crc.h"
|
|
||||||
static int CmdHelp(const char *Cmd);
|
static int CmdHelp(const char *Cmd);
|
||||||
|
|
||||||
int usage_legic_calccrc8(void){
|
int usage_legic_calccrc8(void){
|
||||||
PrintAndLog("Calculates the legic crc8 on the input hexbytes.");
|
PrintAndLog("Calculates the legic crc8/crc16 on the input hexbytes.");
|
||||||
PrintAndLog("There must be an even number of hexsymbols as input.");
|
PrintAndLog("There must be an even number of hexsymbols as input.");
|
||||||
PrintAndLog("Usage: hf legic crc8 <hexbytes>");
|
PrintAndLog("Usage: hf legic crc8 [h] b <hexbytes> u <uidcrc>");
|
||||||
PrintAndLog("Options :");
|
PrintAndLog("Options :");
|
||||||
PrintAndLog(" <hexbytes> : hex bytes in a string");
|
PrintAndLog(" b <hexbytes> : hex bytes");
|
||||||
|
PrintAndLog(" u <uidcrc> : MCC hexbyte");
|
||||||
PrintAndLog("");
|
PrintAndLog("");
|
||||||
PrintAndLog("Sample : hf legic crc8 deadbeef1122");
|
PrintAndLog("Samples :");
|
||||||
|
PrintAndLog(" hf legic crc8 b deadbeef1122");
|
||||||
|
PrintAndLog(" hf legic crc8 b deadbeef1122 u 9A");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,8 +58,10 @@ int CmdLegicDecode(const char *Cmd) {
|
||||||
int crc = 0;
|
int crc = 0;
|
||||||
int wrp = 0;
|
int wrp = 0;
|
||||||
int wrc = 0;
|
int wrc = 0;
|
||||||
uint8_t data_buf[1024]; // receiver buffer, should be 1024..
|
uint8_t data_buf[1052]; // receiver buffer, should be 1024..
|
||||||
char token_type[4];
|
char token_type[5];
|
||||||
|
int dcf;
|
||||||
|
int bIsSegmented = 0;
|
||||||
|
|
||||||
// download EML memory, where the "legic read" command puts the data.
|
// download EML memory, where the "legic read" command puts the data.
|
||||||
GetEMLFromBigBuf(data_buf, sizeof(data_buf), 0);
|
GetEMLFromBigBuf(data_buf, sizeof(data_buf), 0);
|
||||||
|
@ -89,71 +85,120 @@ int CmdLegicDecode(const char *Cmd) {
|
||||||
(calc_crc == crc) ? "OK":"Fail"
|
(calc_crc == crc) ? "OK":"Fail"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
token_type[0] = 0;
|
||||||
|
dcf = ((int)data_buf[6] << 8) | (int)data_buf[5];
|
||||||
|
|
||||||
|
// New unwritten media?
|
||||||
|
if(dcf == 0xFFFF) {
|
||||||
|
|
||||||
|
PrintAndLog("DCF: %d (%02x %02x), Token Type=NM (New Media)",
|
||||||
|
dcf,
|
||||||
|
data_buf[5],
|
||||||
|
data_buf[6]
|
||||||
|
);
|
||||||
|
|
||||||
|
} else if(dcf > 60000) { // Master token?
|
||||||
|
|
||||||
|
int fl = 0;
|
||||||
|
|
||||||
|
if(data_buf[6] == 0xec) {
|
||||||
|
strncpy(token_type, "XAM", sizeof(token_type));
|
||||||
|
fl = 1;
|
||||||
|
stamp_len = 0x0c - (data_buf[5] >> 4);
|
||||||
|
} else {
|
||||||
switch (data_buf[5] & 0x7f) {
|
switch (data_buf[5] & 0x7f) {
|
||||||
case 0x00 ... 0x2f:
|
case 0x00 ... 0x2f:
|
||||||
strncpy(token_type, "IAM",sizeof(token_type));
|
strncpy(token_type, "IAM",sizeof(token_type));
|
||||||
|
fl = (0x2f - (data_buf[5] & 0x7f)) + 1;
|
||||||
break;
|
break;
|
||||||
case 0x30 ... 0x6f:
|
case 0x30 ... 0x6f:
|
||||||
strncpy(token_type, "SAM",sizeof(token_type));
|
strncpy(token_type, "SAM",sizeof(token_type));
|
||||||
|
fl = (0x6f - (data_buf[5] & 0x7f)) + 1;
|
||||||
break;
|
break;
|
||||||
case 0x70 ... 0x7f:
|
case 0x70 ... 0x7f:
|
||||||
strncpy(token_type, "GAM",sizeof(token_type));
|
strncpy(token_type, "GAM",sizeof(token_type));
|
||||||
break;
|
fl = (0x7f - (data_buf[5] & 0x7f)) + 1;
|
||||||
default:
|
|
||||||
strncpy(token_type, "???",sizeof(token_type));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
stamp_len = 0xfc - data_buf[6];
|
stamp_len = 0xfc - data_buf[6];
|
||||||
|
}
|
||||||
|
|
||||||
PrintAndLog("DCF: %02x %02x, Token Type=%s (OLE=%01u), Stamp len=%02u",
|
PrintAndLog("DCF: %d (%02x %02x), Token Type=%s (OLE=%01u), OL=%02u, FL=%02u",
|
||||||
|
dcf,
|
||||||
data_buf[5],
|
data_buf[5],
|
||||||
data_buf[6],
|
data_buf[6],
|
||||||
token_type,
|
token_type,
|
||||||
(data_buf[5]&0x80)>>7,
|
(data_buf[5]&0x80)>>7,
|
||||||
stamp_len
|
stamp_len,
|
||||||
|
fl
|
||||||
);
|
);
|
||||||
|
|
||||||
PrintAndLog("WRP=%02u, WRC=%01u, RD=%01u, raw=%02x, SSC=%02x",
|
} else { // Is IM(-S) type of card...
|
||||||
|
|
||||||
|
if(data_buf[7] == 0x9F && data_buf[8] == 0xFF) {
|
||||||
|
bIsSegmented = 1;
|
||||||
|
strncpy(token_type, "IM-S", sizeof(token_type));
|
||||||
|
} else {
|
||||||
|
strncpy(token_type, "IM", sizeof(token_type));
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLog("DCF: %d (%02x %02x), Token Type=%s (OLE=%01u)",
|
||||||
|
dcf,
|
||||||
|
data_buf[5],
|
||||||
|
data_buf[6],
|
||||||
|
token_type,
|
||||||
|
(data_buf[5]&0x80)>>7
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Makes no sence to show this on blank media...
|
||||||
|
if(dcf != 0xFFFF) {
|
||||||
|
|
||||||
|
if(bIsSegmented) {
|
||||||
|
PrintAndLog("WRP=%02u, WRC=%01u, RD=%01u, SSC=%02x",
|
||||||
data_buf[7]&0x0f,
|
data_buf[7]&0x0f,
|
||||||
(data_buf[7]&0x70)>>4,
|
(data_buf[7]&0x70)>>4,
|
||||||
(data_buf[7]&0x80)>>7,
|
(data_buf[7]&0x80)>>7,
|
||||||
data_buf[7],
|
|
||||||
data_buf[8]
|
data_buf[8]
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Header area is only available on IM-S cards, on master tokens this data is the master token data itself
|
||||||
|
if(bIsSegmented || dcf > 60000) {
|
||||||
|
if(dcf > 60000) {
|
||||||
|
PrintAndLog("Master token data");
|
||||||
|
PrintAndLog("%s", sprint_hex(data_buf+8, 14));
|
||||||
|
} else {
|
||||||
PrintAndLog("Remaining Header Area");
|
PrintAndLog("Remaining Header Area");
|
||||||
PrintAndLog("%s", sprint_hex(data_buf+9, 13));
|
PrintAndLog("%s", sprint_hex(data_buf+9, 13));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
uint8_t segCrcBytes[8] = {0x00};
|
uint8_t segCrcBytes[8] = {0x00};
|
||||||
uint32_t segCalcCRC = 0;
|
uint32_t segCalcCRC = 0;
|
||||||
uint32_t segCRC = 0;
|
uint32_t segCRC = 0;
|
||||||
|
|
||||||
// see if user area is xored or just zeros.
|
|
||||||
int numOfZeros = 0;
|
|
||||||
for (int index=22; index < 256; ++index){
|
|
||||||
if ( data_buf[index] == 0x00 )
|
|
||||||
++numOfZeros;
|
|
||||||
}
|
|
||||||
// if possible zeros is less then 60%, lets assume data is xored
|
|
||||||
// 256 - 22 (header) = 234
|
|
||||||
// 1024 - 22 (header) = 1002
|
|
||||||
int isXored = (numOfZeros*100/stamp_len) < 50;
|
|
||||||
PrintAndLog("is data xored? %d ( %d %)", isXored, (numOfZeros*100/stamp_len));
|
|
||||||
|
|
||||||
print_hex_break( data_buf, 33, 16);
|
// Data card?
|
||||||
|
if(dcf <= 60000) {
|
||||||
return 0;
|
|
||||||
|
|
||||||
PrintAndLog("\nADF: User Area");
|
PrintAndLog("\nADF: User Area");
|
||||||
PrintAndLog("------------------------------------------------------");
|
PrintAndLog("------------------------------------------------------");
|
||||||
|
|
||||||
|
if(bIsSegmented) {
|
||||||
|
|
||||||
|
// Data start point on segmented cards
|
||||||
i = 22;
|
i = 22;
|
||||||
// 64 potential segements
|
|
||||||
// how to detect there is no segments?!?
|
// decode segments
|
||||||
for ( segmentNum=0; segmentNum<64; segmentNum++ ) {
|
for (segmentNum=1; segmentNum < 128; segmentNum++ )
|
||||||
|
{
|
||||||
segment_len = ((data_buf[i+1]^crc)&0x0f) * 256 + (data_buf[i]^crc);
|
segment_len = ((data_buf[i+1]^crc)&0x0f) * 256 + (data_buf[i]^crc);
|
||||||
segment_flag = ((data_buf[i+1]^crc)&0xf0)>>4;
|
segment_flag = ((data_buf[i+1]^crc)&0xf0)>>4;
|
||||||
|
|
||||||
wrp = (data_buf[i+2]^crc);
|
wrp = (data_buf[i+2]^crc);
|
||||||
wrc = ((data_buf[i+3]^crc)&0x70)>>4;
|
wrc = ((data_buf[i+3]^crc)&0x70)>>4;
|
||||||
|
|
||||||
|
@ -198,11 +243,10 @@ int CmdLegicDecode(const char *Cmd) {
|
||||||
PrintAndLog("WRC protected area: (I %d | K %d| WRC %d)", i, k, wrc);
|
PrintAndLog("WRC protected area: (I %d | K %d| WRC %d)", i, k, wrc);
|
||||||
PrintAndLog("\nrow | data");
|
PrintAndLog("\nrow | data");
|
||||||
PrintAndLog("-----+------------------------------------------------");
|
PrintAndLog("-----+------------------------------------------------");
|
||||||
// de-xor? if not zero, assume it needs xoring.
|
|
||||||
if ( isXored) {
|
for ( k=i; k < (i+wrc); ++k)
|
||||||
for ( k=i; k < wrc; ++k)
|
|
||||||
data_buf[k] ^= crc;
|
data_buf[k] ^= crc;
|
||||||
}
|
|
||||||
print_hex_break( data_buf+i, wrc, 16);
|
print_hex_break( data_buf+i, wrc, 16);
|
||||||
|
|
||||||
i += wrc;
|
i += wrc;
|
||||||
|
@ -213,16 +257,14 @@ int CmdLegicDecode(const char *Cmd) {
|
||||||
PrintAndLog("\nrow | data");
|
PrintAndLog("\nrow | data");
|
||||||
PrintAndLog("-----+------------------------------------------------");
|
PrintAndLog("-----+------------------------------------------------");
|
||||||
|
|
||||||
if (isXored) {
|
for (k=i; k < (i+wrp_len); ++k)
|
||||||
for (k=i; k < wrp_len; ++k)
|
|
||||||
data_buf[k] ^= crc;
|
data_buf[k] ^= crc;
|
||||||
}
|
|
||||||
|
|
||||||
print_hex_break( data_buf+i, wrp_len, 16);
|
print_hex_break( data_buf+i, wrp_len, 16);
|
||||||
|
|
||||||
i += wrp_len;
|
i += wrp_len;
|
||||||
|
|
||||||
// does this one work?
|
// does this one work? (Answer: Only if KGH/BGH is used with BCD encoded card number! So maybe this will show just garbage...)
|
||||||
if( wrp_len == 8 )
|
if( wrp_len == 8 )
|
||||||
PrintAndLog("Card ID: %2X%02X%02X", data_buf[i-4]^crc, data_buf[i-3]^crc, data_buf[i-2]^crc);
|
PrintAndLog("Card ID: %2X%02X%02X", data_buf[i-4]^crc, data_buf[i-3]^crc, data_buf[i-2]^crc);
|
||||||
}
|
}
|
||||||
|
@ -230,10 +272,9 @@ int CmdLegicDecode(const char *Cmd) {
|
||||||
PrintAndLog("Remaining segment payload: (I %d | K %d | Remain LEN %d)", i, k, remain_seg_payload_len);
|
PrintAndLog("Remaining segment payload: (I %d | K %d | Remain LEN %d)", i, k, remain_seg_payload_len);
|
||||||
PrintAndLog("\nrow | data");
|
PrintAndLog("\nrow | data");
|
||||||
PrintAndLog("-----+------------------------------------------------");
|
PrintAndLog("-----+------------------------------------------------");
|
||||||
if ( isXored ) {
|
|
||||||
for ( k=i; k < remain_seg_payload_len; ++k)
|
for ( k=i; k < (i+remain_seg_payload_len); ++k)
|
||||||
data_buf[k] ^= crc;
|
data_buf[k] ^= crc;
|
||||||
}
|
|
||||||
|
|
||||||
print_hex_break( data_buf+i, remain_seg_payload_len, 16);
|
print_hex_break( data_buf+i, remain_seg_payload_len, 16);
|
||||||
|
|
||||||
|
@ -245,6 +286,56 @@ int CmdLegicDecode(const char *Cmd) {
|
||||||
if (segment_flag & 0x8) return 0;
|
if (segment_flag & 0x8) return 0;
|
||||||
|
|
||||||
} // end for loop
|
} // end for loop
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Data start point on unsegmented cards
|
||||||
|
i = 8;
|
||||||
|
|
||||||
|
wrp = data_buf[7] & 0x0F;
|
||||||
|
wrc = (data_buf[7] & 0x07) >> 4;
|
||||||
|
|
||||||
|
bool hasWRC = (wrc > 0);
|
||||||
|
bool hasWRP = (wrp > wrc);
|
||||||
|
int wrp_len = (wrp - wrc);
|
||||||
|
int remain_seg_payload_len = (1024 - 22 - wrp); // Any chance to get physical card size here!?
|
||||||
|
|
||||||
|
PrintAndLog("Unsegmented card - WRP: %02u, WRC: %02u, RD: %01u",
|
||||||
|
wrp,
|
||||||
|
wrc,
|
||||||
|
(data_buf[7] & 0x80) >> 7
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( hasWRC ) {
|
||||||
|
PrintAndLog("WRC protected area: (I %d | WRC %d)", i, wrc);
|
||||||
|
PrintAndLog("\nrow | data");
|
||||||
|
PrintAndLog("-----+------------------------------------------------");
|
||||||
|
print_hex_break( data_buf+i, wrc, 16);
|
||||||
|
i += wrc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( hasWRP ) {
|
||||||
|
PrintAndLog("Remaining write protected area: (I %d | WRC %d | WRP %d | WRP_LEN %d)", i, wrc, wrp, wrp_len);
|
||||||
|
PrintAndLog("\nrow | data");
|
||||||
|
PrintAndLog("-----+------------------------------------------------");
|
||||||
|
print_hex_break( data_buf+i, wrp_len, 16);
|
||||||
|
i += wrp_len;
|
||||||
|
|
||||||
|
// does this one work? (Answer: Only if KGH/BGH is used with BCD encoded card number! So maybe this will show just garbage...)
|
||||||
|
if( wrp_len == 8 )
|
||||||
|
PrintAndLog("Card ID: %2X%02X%02X", data_buf[i-4], data_buf[i-3], data_buf[i-2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLog("Remaining segment payload: (I %d | Remain LEN %d)", i, remain_seg_payload_len);
|
||||||
|
PrintAndLog("\nrow | data");
|
||||||
|
PrintAndLog("-----+------------------------------------------------");
|
||||||
|
print_hex_break( data_buf+i, remain_seg_payload_len, 16);
|
||||||
|
i += remain_seg_payload_len;
|
||||||
|
|
||||||
|
PrintAndLog("-----+------------------------------------------------\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,8 +508,37 @@ int CmdLegicRfWrite(const char *Cmd) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: write a help text (iceman)
|
||||||
|
int CmdLegicRfRawWrite(const char *Cmd) {
|
||||||
|
char answer;
|
||||||
|
UsbCommand c = { CMD_RAW_WRITER_LEGIC_RF, {0,0,0} };
|
||||||
|
int res = sscanf(Cmd, " 0x%"llx" 0x%"llx, &c.arg[0], &c.arg[1]);
|
||||||
|
if(res != 2) {
|
||||||
|
PrintAndLog("Please specify the offset and value as two hex strings");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c.arg[0] == 0x05 || c.arg[0] == 0x06) {
|
||||||
|
PrintAndLog("############# DANGER !! #############");
|
||||||
|
PrintAndLog("# changing the DCF is irreversible #");
|
||||||
|
PrintAndLog("#####################################");
|
||||||
|
PrintAndLog("do youe really want to continue? y(es) n(o)");
|
||||||
|
scanf(" %c", &answer);
|
||||||
|
if (answer == 'y' || answer == 'Y') {
|
||||||
|
SendCommand(&c);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearCommandBuffer();
|
||||||
|
SendCommand(&c);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: write a help text (iceman)
|
||||||
int CmdLegicRfFill(const char *Cmd) {
|
int CmdLegicRfFill(const char *Cmd) {
|
||||||
UsbCommand cmd = {CMD_WRITER_LEGIC_RF};
|
UsbCommand cmd = {CMD_WRITER_LEGIC_RF, {0,0,0} };
|
||||||
int res = sscanf(Cmd, " 0x%"llx" 0x%"llx" 0x%"llx, &cmd.arg[0], &cmd.arg[1], &cmd.arg[2]);
|
int res = sscanf(Cmd, " 0x%"llx" 0x%"llx" 0x%"llx, &cmd.arg[0], &cmd.arg[1], &cmd.arg[2]);
|
||||||
if(res != 3) {
|
if(res != 3) {
|
||||||
PrintAndLog("Please specify the offset, length and value as two hex strings");
|
PrintAndLog("Please specify the offset, length and value as two hex strings");
|
||||||
|
@ -427,12 +547,12 @@ int CmdLegicRfFill(const char *Cmd) {
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
UsbCommand c = {CMD_DOWNLOADED_SIM_SAMPLES_125K, {0, 0, 0}};
|
UsbCommand c = {CMD_DOWNLOADED_SIM_SAMPLES_125K, {0, 0, 0}};
|
||||||
for(i = 0; i < 48; i++) {
|
memcpy(c.d.asBytes, cmd.arg[2], 48);
|
||||||
c.d.asBytes[i] = cmd.arg[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
for(i = 0; i < 22; i++) {
|
for(i = 0; i < 22; i++) {
|
||||||
c.arg[0] = i*48;
|
c.arg[0] = i*48;
|
||||||
|
|
||||||
|
clearCommandBuffer();
|
||||||
SendCommand(&c);
|
SendCommand(&c);
|
||||||
WaitForResponse(CMD_ACK, NULL);
|
WaitForResponse(CMD_ACK, NULL);
|
||||||
}
|
}
|
||||||
|
@ -443,20 +563,64 @@ int CmdLegicRfFill(const char *Cmd) {
|
||||||
|
|
||||||
int CmdLegicCalcCrc8(const char *Cmd){
|
int CmdLegicCalcCrc8(const char *Cmd){
|
||||||
|
|
||||||
int len = strlen(Cmd);
|
uint8_t *data;
|
||||||
if ( len & 1 ) return usage_legic_calccrc8();
|
uint8_t cmdp = 0, uidcrc = 0, type=0;
|
||||||
|
bool errors = false;
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
// add 1 for null terminator.
|
while(param_getchar(Cmd, cmdp) != 0x00) {
|
||||||
uint8_t *data = malloc(len+1);
|
switch(param_getchar(Cmd, cmdp)) {
|
||||||
if ( data == NULL ) return 1;
|
case 'b':
|
||||||
|
case 'B':
|
||||||
|
data = malloc(len);
|
||||||
|
if ( data == NULL ) {
|
||||||
|
PrintAndLog("Can't allocate memory. exiting");
|
||||||
|
errors = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
param_gethex_ex(Cmd, cmdp+1, data, &len);
|
||||||
|
// if odd symbols, (hexbyte must be two symbols)
|
||||||
|
if ( len & 1 ) errors = true;
|
||||||
|
|
||||||
if (param_gethex(Cmd, 0, data, len )) {
|
len >>= 1;
|
||||||
free(data);
|
cmdp += 2;
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
case 'U':
|
||||||
|
uidcrc = param_get8ex(Cmd, cmdp+1, 0, 16);
|
||||||
|
cmdp += 2;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
case 'C':
|
||||||
|
type = param_get8ex(Cmd, cmdp+1, 0, 10);
|
||||||
|
cmdp += 2;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
case 'H':
|
||||||
|
errors = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||||
|
errors = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (errors) break;
|
||||||
|
}
|
||||||
|
//Validations
|
||||||
|
if (errors){
|
||||||
|
if (data != NULL) free(data);
|
||||||
return usage_legic_calccrc8();
|
return usage_legic_calccrc8();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t checksum = CRC8Legic(data, len/2);
|
switch (type){
|
||||||
PrintAndLog("Bytes: %s || CRC8: %X", sprint_hex(data, len/2), checksum );
|
case 16:
|
||||||
|
PrintAndLog("LEGIC CRC16: %X", CRC16Legic(data, len, uidcrc));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PrintAndLog("LEGIC CRC8: %X", CRC8Legic(data, len) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
free(data);
|
free(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -469,6 +633,7 @@ static command_t CommandTable[] = {
|
||||||
{"load", CmdLegicLoad, 0, "<filename> -- Restore samples"},
|
{"load", CmdLegicLoad, 0, "<filename> -- Restore samples"},
|
||||||
{"sim", CmdLegicRfSim, 0, "[phase drift [frame drift [req/resp drift]]] Start tag simulator (use after load or read)"},
|
{"sim", CmdLegicRfSim, 0, "[phase drift [frame drift [req/resp drift]]] Start tag simulator (use after load or read)"},
|
||||||
{"write", CmdLegicRfWrite,0, "<offset> <length> -- Write sample buffer (user after load or read)"},
|
{"write", CmdLegicRfWrite,0, "<offset> <length> -- Write sample buffer (user after load or read)"},
|
||||||
|
{"writeRaw",CmdLegicRfRawWrite, 0, "<address> <value> -- Write direct to address"},
|
||||||
{"fill", CmdLegicRfFill, 0, "<offset> <length> <value> -- Fill/Write tag with constant value"},
|
{"fill", CmdLegicRfFill, 0, "<offset> <length> <value> -- Fill/Write tag with constant value"},
|
||||||
{"crc8", CmdLegicCalcCrc8, 1, "Calculate Legic CRC8 over given hexbytes"},
|
{"crc8", CmdLegicCalcCrc8, 1, "Calculate Legic CRC8 over given hexbytes"},
|
||||||
{NULL, NULL, 0, NULL}
|
{NULL, NULL, 0, NULL}
|
||||||
|
|
|
@ -11,6 +11,16 @@
|
||||||
#ifndef CMDHFLEGIC_H__
|
#ifndef CMDHFLEGIC_H__
|
||||||
#define CMDHFLEGIC_H__
|
#define CMDHFLEGIC_H__
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "proxmark3.h"
|
||||||
|
#include "data.h"
|
||||||
|
#include "ui.h"
|
||||||
|
#include "cmdparser.h"
|
||||||
|
#include "cmdmain.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "crc.h"
|
||||||
|
|
||||||
int CmdHFLegic(const char *Cmd);
|
int CmdHFLegic(const char *Cmd);
|
||||||
|
|
||||||
int CmdLegicRFRead(const char *Cmd);
|
int CmdLegicRFRead(const char *Cmd);
|
||||||
|
@ -19,9 +29,12 @@ int CmdLegicLoad(const char *Cmd);
|
||||||
int CmdLegicSave(const char *Cmd);
|
int CmdLegicSave(const char *Cmd);
|
||||||
int CmdLegicRfSim(const char *Cmd);
|
int CmdLegicRfSim(const char *Cmd);
|
||||||
int CmdLegicRfWrite(const char *Cmd);
|
int CmdLegicRfWrite(const char *Cmd);
|
||||||
|
int CmdLegicRfRawWrite(const char *Cmd);
|
||||||
int CmdLegicRfFill(const char *Cmd);
|
int CmdLegicRfFill(const char *Cmd);
|
||||||
|
|
||||||
int CmdLegicCalcCrc8(const char *Cmd);
|
int CmdLegicCalcCrc8(const char *Cmd);
|
||||||
|
|
||||||
int usage_legic_calccrc8(void);
|
int usage_legic_calccrc8(void);
|
||||||
|
int usage_legic_load(void);
|
||||||
|
int usage_legic_read(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -9,15 +9,13 @@
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "proxmark3.h"
|
|
||||||
#define MAX_BIN_BREAK_LENGTH (3072+384+1)
|
#define MAX_BIN_BREAK_LENGTH (3072+384+1)
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
int ukbhit(void)
|
int ukbhit(void) {
|
||||||
{
|
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
int error;
|
int error;
|
||||||
static struct termios Otty, Ntty;
|
static struct termios Otty, Ntty;
|
||||||
|
@ -554,3 +552,19 @@ uint32_t SwapBits(uint32_t value, int nrbits) {
|
||||||
}
|
}
|
||||||
return newvalue;
|
return newvalue;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
ref http://www.csm.ornl.gov/~dunigan/crc.html
|
||||||
|
Returns the value v with the bottom b [0,32] bits reflected.
|
||||||
|
Example: reflect(0x3e23L,3) == 0x3e26
|
||||||
|
*/
|
||||||
|
uint32_t reflect(uint32_t v, int b) {
|
||||||
|
uint32_t t = v;
|
||||||
|
for ( int i = 0; i < b; ++i) {
|
||||||
|
if (t & 1)
|
||||||
|
v |= BITMASK((b-1)-i);
|
||||||
|
else
|
||||||
|
v &= ~BITMASK((b-1)-i);
|
||||||
|
t>>=1;
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
|
@ -15,7 +15,11 @@
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "data.h" //for FILE_PATH_SIZE
|
#include "data.h" //for FILE_PATH_SIZE
|
||||||
|
#include "proxmark3.h"
|
||||||
|
|
||||||
|
#ifndef BITMASK
|
||||||
|
# define BITMASK(X) (1 << (X))
|
||||||
|
#endif
|
||||||
#ifndef ROTR
|
#ifndef ROTR
|
||||||
# define ROTR(x,n) (((uintmax_t)(x) >> (n)) | ((uintmax_t)(x) << ((sizeof(x) * 8) - (n))))
|
# define ROTR(x,n) (((uintmax_t)(x) >> (n)) | ((uintmax_t)(x) << ((sizeof(x) * 8) - (n))))
|
||||||
#endif
|
#endif
|
||||||
|
@ -30,6 +34,10 @@
|
||||||
((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
|
((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
|
||||||
(((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
|
(((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef BSWAP_16
|
||||||
|
# define BSWAP_16(x) ((( ((x) & 0xFF00 ) >> 8))| ( (((x) & 0x00FF) << 8)))
|
||||||
|
#endif
|
||||||
|
|
||||||
#define TRUE 1
|
#define TRUE 1
|
||||||
#define FALSE 0
|
#define FALSE 0
|
||||||
#define EVEN 0
|
#define EVEN 0
|
||||||
|
@ -94,3 +102,4 @@ uint32_t le32toh (uint8_t *data);
|
||||||
uint32_t PackBits(uint8_t start, uint8_t len, uint8_t* bits);
|
uint32_t PackBits(uint8_t start, uint8_t len, uint8_t* bits);
|
||||||
void rol(uint8_t *data, const size_t len);
|
void rol(uint8_t *data, const size_t len);
|
||||||
uint32_t SwapBits(uint32_t value, int nrbits);
|
uint32_t SwapBits(uint32_t value, int nrbits);
|
||||||
|
uint32_t reflect(uint32_t v, int b);
|
|
@ -1,6 +1,6 @@
|
||||||
#include "bucketsort.h"
|
#include "bucketsort.h"
|
||||||
|
|
||||||
void bucket_sort_intersect(uint32_t* const estart, uint32_t* const estop,
|
extern void bucket_sort_intersect(uint32_t* const estart, uint32_t* const estop,
|
||||||
uint32_t* const ostart, uint32_t* const ostop,
|
uint32_t* const ostart, uint32_t* const ostop,
|
||||||
bucket_info_t *bucket_info, bucket_array_t bucket)
|
bucket_info_t *bucket_info, bucket_array_t bucket)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
#ifndef BUCKETSORT_H__
|
#ifndef BUCKETSORT_H__
|
||||||
#define BUCKETSORT_H__
|
#define BUCKETSORT_H__
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
typedef struct bucket {
|
typedef struct bucket {
|
||||||
uint32_t *head;
|
uint32_t *head;
|
||||||
uint32_t *bp;
|
uint32_t *bp;
|
||||||
|
|
140
common/crc.c
140
common/crc.c
|
@ -5,66 +5,136 @@
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Generic CRC calculation code.
|
// Generic CRC calculation code.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
// the Check value below in the comments is CRC of the string '123456789'
|
||||||
|
//
|
||||||
#include "crc.h"
|
#include "crc.h"
|
||||||
#include "util.h"
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
void crc_init(crc_t *crc, int order, uint32_t polynom, uint32_t initial_value, uint32_t final_xor)
|
void crc_init_ref(crc_t *crc, int order, uint32_t polynom, uint32_t initial_value, uint32_t final_xor, bool refin, bool refout) {
|
||||||
{
|
crc_init(crc, order, polynom, initial_value, final_xor);
|
||||||
|
crc->refin = refin;
|
||||||
|
crc->refout = refout;
|
||||||
|
crc_clear(crc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void crc_init(crc_t *crc, int order, uint32_t polynom, uint32_t initial_value, uint32_t final_xor) {
|
||||||
crc->order = order;
|
crc->order = order;
|
||||||
|
crc->topbit = BITMASK( order-1 );
|
||||||
crc->polynom = polynom;
|
crc->polynom = polynom;
|
||||||
crc->initial_value = initial_value;
|
crc->initial_value = initial_value;
|
||||||
crc->final_xor = final_xor;
|
crc->final_xor = final_xor;
|
||||||
crc->mask = (1L<<order)-1;
|
crc->mask = (1L<<order)-1;
|
||||||
|
crc->refin = FALSE;
|
||||||
|
crc->refout = FALSE;
|
||||||
crc_clear(crc);
|
crc_clear(crc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void crc_update(crc_t *crc, uint32_t data, int data_width)
|
void crc_clear(crc_t *crc) {
|
||||||
{
|
|
||||||
for( int i=0; i < data_width; i++) {
|
|
||||||
int oldstate = crc->state;
|
|
||||||
crc->state = crc->state >> 1;
|
|
||||||
if( (oldstate^data) & 1 ) {
|
|
||||||
crc->state ^= crc->polynom;
|
|
||||||
}
|
|
||||||
data >>= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void crc_clear(crc_t *crc)
|
|
||||||
{
|
|
||||||
crc->state = crc->initial_value & crc->mask;
|
crc->state = crc->initial_value & crc->mask;
|
||||||
|
if (crc->refin)
|
||||||
|
crc->state = reflect(crc->state, crc->order);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t crc_finish(crc_t *crc)
|
void crc_update(crc_t *crc, uint32_t indata, int data_width){
|
||||||
{
|
|
||||||
return ( crc->state ^ crc->final_xor ) & crc->mask;
|
//reflected
|
||||||
|
if (crc->refin) indata = reflect(indata, data_width);
|
||||||
|
|
||||||
|
// Bring the next byte into the remainder.
|
||||||
|
crc->state ^= indata << (crc->order - data_width);
|
||||||
|
|
||||||
|
for( uint8_t bit = data_width; bit > 0; --bit) {
|
||||||
|
// Try to divide the current data bit.
|
||||||
|
if (crc->state & crc->topbit)
|
||||||
|
crc->state = (crc->state << 1) ^ crc->polynom;
|
||||||
|
else
|
||||||
|
crc->state = (crc->state << 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//credits to iceman
|
uint32_t crc_finish(crc_t *crc) {
|
||||||
|
uint32_t val = crc->state;
|
||||||
|
if (crc->refout) val = reflect(val, crc->order);
|
||||||
|
return ( val ^ crc->final_xor ) & crc->mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
static void print_crc(crc_t *crc) {
|
||||||
|
printf(" Order %d\n Poly %x\n Init %x\n Final %x\n Mask %x\n topbit %x\n RefIn %s\n RefOut %s\n State %x\n",
|
||||||
|
crc->order,
|
||||||
|
crc->polynom,
|
||||||
|
crc->initial_value,
|
||||||
|
crc->final_xor,
|
||||||
|
crc->mask,
|
||||||
|
crc->topbit,
|
||||||
|
(crc->refin) ? "TRUE":"FALSE",
|
||||||
|
(crc->refout) ? "TRUE":"FALSE",
|
||||||
|
crc->state
|
||||||
|
);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// width=8 poly=0x31 init=0x00 refin=true refout=true xorout=0x00 check=0xA1 name="CRC-8/MAXIM"
|
||||||
uint32_t CRC8Maxim(uint8_t *buff, size_t size) {
|
uint32_t CRC8Maxim(uint8_t *buff, size_t size) {
|
||||||
crc_t crc;
|
crc_t crc;
|
||||||
crc_init(&crc, 9, 0x8c, 0x00, 0x00);
|
crc_init_ref(&crc, 8, 0x31, 0, 0, TRUE, TRUE);
|
||||||
crc_clear(&crc);
|
for ( int i=0; i < size; ++i)
|
||||||
|
|
||||||
for (size_t i=0; i < size; ++i)
|
|
||||||
crc_update(&crc, buff[i], 8);
|
crc_update(&crc, buff[i], 8);
|
||||||
|
|
||||||
return crc_finish(&crc);
|
return crc_finish(&crc);
|
||||||
}
|
}
|
||||||
|
|
||||||
//credits to iceman
|
|
||||||
|
// width=4 poly=0xC, reversed poly=0x7 init=0x5 refin=true refout=true xorout=0x0000 check= name="CRC-4/LEGIC"
|
||||||
|
// width=8 poly=0x63, reversed poly=0x8D init=0x55 refin=true refout=true xorout=0x0000 check=0xC6 name="CRC-8/LEGIC"
|
||||||
|
// the CRC needs to be reversed before returned.
|
||||||
uint32_t CRC8Legic(uint8_t *buff, size_t size) {
|
uint32_t CRC8Legic(uint8_t *buff, size_t size) {
|
||||||
|
|
||||||
// Poly 0x63, reversed poly 0xC6, Init 0x55, Final 0x00
|
|
||||||
crc_t crc;
|
crc_t crc;
|
||||||
crc_init(&crc, 8, 0xC6, 0x55, 0);
|
crc_init_ref(&crc, 8, 0x63, 0x55, 0, TRUE, TRUE);
|
||||||
crc_clear(&crc);
|
|
||||||
|
|
||||||
for ( int i = 0; i < size; ++i)
|
for ( int i = 0; i < size; ++i)
|
||||||
crc_update(&crc, buff[i], 8);
|
crc_update(&crc, buff[i], 8);
|
||||||
return SwapBits(crc_finish(&crc), 8);
|
return reflect(crc_finish(&crc), 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// credits to marshmellow
|
||||||
|
// width=8 poly=0xA3, reversed poly=0x8B, init=0xB0 refin=true refout=true xorout=0x00 check=0x28 name="CRC-8/JA"
|
||||||
|
uint32_t CRC8ja(uint8_t *buff, size_t size) {
|
||||||
|
crc_t crc;
|
||||||
|
crc_init_ref(&crc, 8, 0xA3, 0x42, 0x00, TRUE, TRUE);
|
||||||
|
for ( int i=0; i < size; ++i)
|
||||||
|
crc_update(&crc, buff[i], 8);
|
||||||
|
return crc_finish(&crc);
|
||||||
|
//return reflect(crc_finish(&crc), 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This CRC-16 is used in Legic Advant systems.
|
||||||
|
// width=8 poly=0xB400, reversed poly=0x init=depends refin=true refout=true xorout=0x0000 check= name="CRC-16/LEGIC"
|
||||||
|
uint32_t CRC16Legic(uint8_t *buff, size_t size, uint8_t uidcrc) {
|
||||||
|
|
||||||
|
#define CRC16_POLY_LEGIC 0xB400
|
||||||
|
//uint8_t initial = reflect(uidcrc, 8);
|
||||||
|
uint16_t initial = uidcrc;
|
||||||
|
initial |= initial << 8;
|
||||||
|
crc_t crc;
|
||||||
|
crc_init_ref(&crc, 16, CRC16_POLY_LEGIC, initial, 0, TRUE, TRUE);
|
||||||
|
for ( int i=0; i < size; ++i)
|
||||||
|
crc_update(&crc, buff[i], 8);
|
||||||
|
return reflect(crc_finish(&crc), 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
//w=16 poly=0x3d65 init=0x0000 refin=true refout=true xorout=0xffff check=0xea82 name="CRC-16/DNP"
|
||||||
|
uint32_t CRC16_DNP(uint8_t *buff, size_t size) {
|
||||||
|
crc_t crc;
|
||||||
|
crc_init_ref(&crc, 16, 0x3d65, 0, 0xffff, TRUE, TRUE);
|
||||||
|
for ( int i=0; i < size; ++i)
|
||||||
|
crc_update(&crc, buff[i], 8);
|
||||||
|
|
||||||
|
return BSWAP_16(crc_finish(&crc));
|
||||||
|
}
|
||||||
|
|
||||||
|
//width=16 poly=0x1021 init=0x1d0f refin=false refout=false xorout=0x0000 check=0xe5cc name="CRC-16/AUG-CCITT"
|
||||||
|
uint32_t CRC16_CCITT(uint8_t *buff, size_t size) {
|
||||||
|
crc_t crc;
|
||||||
|
crc_init(&crc, 16, 0x1021, 0x1d0f, 0);
|
||||||
|
for ( int i=0; i < size; ++i)
|
||||||
|
crc_update(&crc, buff[i], 8);
|
||||||
|
return crc_finish(&crc);
|
||||||
|
}
|
36
common/crc.h
36
common/crc.h
|
@ -9,8 +9,10 @@
|
||||||
#ifndef __CRC_H
|
#ifndef __CRC_H
|
||||||
#define __CRC_H
|
#define __CRC_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h> //uint32+
|
||||||
|
#include <stdbool.h> //bool
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include "util.h" // reflect, bswap_16
|
||||||
|
|
||||||
typedef struct crc {
|
typedef struct crc {
|
||||||
uint32_t state;
|
uint32_t state;
|
||||||
|
@ -19,13 +21,25 @@ typedef struct crc {
|
||||||
uint32_t initial_value;
|
uint32_t initial_value;
|
||||||
uint32_t final_xor;
|
uint32_t final_xor;
|
||||||
uint32_t mask;
|
uint32_t mask;
|
||||||
|
int topbit;
|
||||||
|
bool refin; /* Parameter: Reflect input bytes? */
|
||||||
|
bool refout; /* Parameter: Reflect output CRC? */
|
||||||
} crc_t;
|
} crc_t;
|
||||||
|
|
||||||
|
/* Initialize a crc structure. order is the order of the polynom, e.g. 32 for a CRC-32
|
||||||
|
* polynom is the CRC polynom. initial_value is the initial value of a clean state.
|
||||||
|
* final_xor is XORed onto the state before returning it from crc_result().
|
||||||
|
* refin is the setting for reversing (bitwise) the bytes during crc
|
||||||
|
* refot is the setting for reversing (bitwise) the crc byte before returning it.
|
||||||
|
*/
|
||||||
|
extern void crc_init_ref(crc_t *crc, int order, uint32_t polynom, uint32_t initial_value, uint32_t final_xor, bool refin, bool refout);
|
||||||
|
|
||||||
/* Initialize a crc structure. order is the order of the polynom, e.g. 32 for a CRC-32
|
/* Initialize a crc structure. order is the order of the polynom, e.g. 32 for a CRC-32
|
||||||
* polynom is the CRC polynom. initial_value is the initial value of a clean state.
|
* polynom is the CRC polynom. initial_value is the initial value of a clean state.
|
||||||
* final_xor is XORed onto the state before returning it from crc_result(). */
|
* final_xor is XORed onto the state before returning it from crc_result(). */
|
||||||
extern void crc_init(crc_t *crc, int order, uint32_t polynom, uint32_t initial_value, uint32_t final_xor);
|
extern void crc_init(crc_t *crc, int order, uint32_t polynom, uint32_t initial_value, uint32_t final_xor);
|
||||||
|
|
||||||
|
|
||||||
/* Update the crc state. data is the data of length data_width bits (only the
|
/* Update the crc state. data is the data of length data_width bits (only the
|
||||||
* data_width lower-most bits are used).
|
* data_width lower-most bits are used).
|
||||||
*/
|
*/
|
||||||
|
@ -40,9 +54,24 @@ extern uint32_t crc_finish(crc_t *crc);
|
||||||
// Calculate CRC-8/Maxim checksum
|
// Calculate CRC-8/Maxim checksum
|
||||||
uint32_t CRC8Maxim(uint8_t *buff, size_t size);
|
uint32_t CRC8Maxim(uint8_t *buff, size_t size);
|
||||||
|
|
||||||
|
// Calculate CRC-4/Legic checksum
|
||||||
|
uint32_t CRC4Legic(uint8_t *buff, size_t size);
|
||||||
|
|
||||||
// Calculate CRC-8/Legic checksum
|
// Calculate CRC-8/Legic checksum
|
||||||
uint32_t CRC8Legic(uint8_t *buff, size_t size);
|
uint32_t CRC8Legic(uint8_t *buff, size_t size);
|
||||||
|
|
||||||
|
// Calculate CRC-16/Legic checksum
|
||||||
|
// the initial_value is based on the previous legic_Crc8 of the UID.
|
||||||
|
// ie: uidcrc = 0x78 then initial_value == 0x7878
|
||||||
|
uint32_t CRC16Legic(uint8_t *buff, size_t size, uint8_t uidcrc);
|
||||||
|
|
||||||
|
// Calculate CRC-8/ja checksum
|
||||||
|
uint32_t CRC8ja(uint8_t *buff, size_t size);
|
||||||
|
|
||||||
|
// test crc 16.
|
||||||
|
uint32_t CRC16_DNP(uint8_t *buff, size_t size);
|
||||||
|
|
||||||
|
|
||||||
/* Static initialization of a crc structure */
|
/* Static initialization of a crc structure */
|
||||||
#define CRC_INITIALIZER(_order, _polynom, _initial_value, _final_xor) { \
|
#define CRC_INITIALIZER(_order, _polynom, _initial_value, _final_xor) { \
|
||||||
.state = ((_initial_value) & ((1L<<(_order))-1)), \
|
.state = ((_initial_value) & ((1L<<(_order))-1)), \
|
||||||
|
@ -50,6 +79,9 @@ uint32_t CRC8Legic(uint8_t *buff, size_t size);
|
||||||
.polynom = (_polynom), \
|
.polynom = (_polynom), \
|
||||||
.initial_value = (_initial_value), \
|
.initial_value = (_initial_value), \
|
||||||
.final_xor = (_final_xor), \
|
.final_xor = (_final_xor), \
|
||||||
.mask = ((1L<<(_order))-1) }
|
.mask = ((1L<<(_order))-1) \
|
||||||
|
.refin = FALSE, \
|
||||||
|
.refout = FALSE \
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* __CRC_H */
|
#endif /* __CRC_H */
|
||||||
|
|
|
@ -9,11 +9,9 @@
|
||||||
#include "crc16.h"
|
#include "crc16.h"
|
||||||
#define CRC16_POLY_CCITT 0x1021
|
#define CRC16_POLY_CCITT 0x1021
|
||||||
#define CRC16_POLY 0x8408
|
#define CRC16_POLY 0x8408
|
||||||
#define CRC16_POLY_LEGIC 0xB400
|
|
||||||
|
|
||||||
unsigned short update_crc16( unsigned short crc, unsigned char c )
|
uint16_t update_crc16( uint16_t crc, unsigned char c ) {
|
||||||
{
|
uint16_t i, v, tcrc = 0;
|
||||||
unsigned short i, v, tcrc = 0;
|
|
||||||
|
|
||||||
v = (crc ^ c) & 0xff;
|
v = (crc ^ c) & 0xff;
|
||||||
for (i = 0; i < 8; i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
|
@ -29,8 +27,8 @@ uint16_t crc16(uint8_t const *message, int length, uint16_t remainder, uint16_t
|
||||||
if (length == 0)
|
if (length == 0)
|
||||||
return (~remainder);
|
return (~remainder);
|
||||||
|
|
||||||
for (int byte = 0; byte < length; ++byte) {
|
for (uint32_t i = 0; i < length; ++i) {
|
||||||
remainder ^= (message[byte] << 8);
|
remainder ^= (message[i] << 8);
|
||||||
for (uint8_t bit = 8; bit > 0; --bit) {
|
for (uint8_t bit = 8; bit > 0; --bit) {
|
||||||
if (remainder & 0x8000) {
|
if (remainder & 0x8000) {
|
||||||
remainder = (remainder << 1) ^ polynomial;
|
remainder = (remainder << 1) ^ polynomial;
|
||||||
|
@ -47,25 +45,6 @@ uint16_t crc16_ccitt(uint8_t const *message, int length) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t crc16_ccitt_kermit(uint8_t const *message, int length) {
|
uint16_t crc16_ccitt_kermit(uint8_t const *message, int length) {
|
||||||
return bit_reverse_uint16(crc16(message, length, 0x0000, CRC16_POLY_CCITT));
|
uint16_t val = crc16(message, length, 0x0000, CRC16_POLY_CCITT);
|
||||||
}
|
return SwapBits(val, 16);
|
||||||
|
|
||||||
//ICEMAN: not working yet,
|
|
||||||
// This CRC-16 is used in Legic Advant systems.
|
|
||||||
uint16_t crc16_legic(uint8_t const *message, int length, uint16_t inital) {
|
|
||||||
return crc16(message, length, inital, CRC16_POLY_LEGIC);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t bit_reverse_uint16 (uint16_t value) {
|
|
||||||
const uint16_t mask0 = 0x5555;
|
|
||||||
const uint16_t mask1 = 0x3333;
|
|
||||||
const uint16_t mask2 = 0x0F0F;
|
|
||||||
const uint16_t mask3 = 0x00FF;
|
|
||||||
|
|
||||||
value = (((~mask0) & value) >> 1) | ((mask0 & value) << 1);
|
|
||||||
value = (((~mask1) & value) >> 2) | ((mask1 & value) << 2);
|
|
||||||
value = (((~mask2) & value) >> 4) | ((mask2 & value) << 4);
|
|
||||||
value = (((~mask3) & value) >> 8) | ((mask3 & value) << 8);
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,14 +5,14 @@
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// CRC16
|
// CRC16
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#ifndef __CRC16_H
|
#ifndef __CRC16_H
|
||||||
#define __CRC16_H
|
#define __CRC16_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
unsigned short update_crc16(unsigned short crc, unsigned char c);
|
unsigned short update_crc16(unsigned short crc, unsigned char c);
|
||||||
uint16_t crc16(uint8_t const *message, int length, uint16_t remainder, uint16_t polynomial);
|
uint16_t crc16(uint8_t const *message, int length, uint16_t remainder, uint16_t polynomial);
|
||||||
uint16_t crc16_ccitt(uint8_t const *message, int length);
|
uint16_t crc16_ccitt(uint8_t const *message, int length);
|
||||||
uint16_t crc16_ccitt_kermit(uint8_t const *message, int length);
|
uint16_t crc16_ccitt_kermit(uint8_t const *message, int length);
|
||||||
uint16_t crc16_legic(uint8_t const *message, int length, uint16_t inital);
|
|
||||||
uint16_t bit_reverse_uint16 (uint16_t value);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -74,9 +74,7 @@ const uint64_t crc64_table[] = {
|
||||||
|
|
||||||
void crc64 (const uint8_t *data, const size_t len, uint64_t *crc) {
|
void crc64 (const uint8_t *data, const size_t len, uint64_t *crc) {
|
||||||
|
|
||||||
for (size_t i = 0; i < len; i++)
|
for (size_t i = 0; i < len; i++) {
|
||||||
{
|
|
||||||
//uint8_t tableIndex = (((uint8_t)(*crc >> 56)) ^ data[i]) & 0xff;
|
|
||||||
uint8_t tableIndex = (((uint8_t)(*crc >> 56)) ^ data[i]) & 0xff;
|
uint8_t tableIndex = (((uint8_t)(*crc >> 56)) ^ data[i]) & 0xff;
|
||||||
*crc = crc64_table[tableIndex] ^ (*crc << 8);
|
*crc = crc64_table[tableIndex] ^ (*crc << 8);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue