From: iceman1001 <iceman@iuse.se>
Date: Wed, 21 Sep 2016 17:03:32 +0000 (+0200)
Subject: CHG:  extracted some timers functionality, to get unified access to a timer/clock... 
X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/commitdiff_plain/22f4dca88cc008287b1ef01bb4da0d46cbcf76d1?ds=sidebyside

CHG:  extracted some timers functionality, to get unified access to a timer/clock which counts in ticks.  Moved stuff from util.c
---

diff --git a/armsrc/Makefile b/armsrc/Makefile
index 7986dd7f..bfc5cbf2 100644
--- a/armsrc/Makefile
+++ b/armsrc/Makefile
@@ -50,7 +50,8 @@ THUMBSRC = start.c \
 	util.c \
 	string.c \
 	usb_cdc.c \
-	cmd.c
+	cmd.c \
+	ticks.c
 
 # These are to be compiled in ARM mode
 ARMSRC = fpgaloader.c \
diff --git a/armsrc/legicrf.c b/armsrc/legicrf.c
index 2883bdfc..e8a2e1aa 100644
--- a/armsrc/legicrf.c
+++ b/armsrc/legicrf.c
@@ -7,7 +7,6 @@
 //-----------------------------------------------------------------------------
 // LEGIC RF simulation code
 //-----------------------------------------------------------------------------
-
 #include "legicrf.h"
 
 static struct legic_frame {
@@ -73,7 +72,7 @@ static void setup_timer(void) {
 //#define RWD_TIME_0 90      /* RWD_TIME_PAUSE off, 40us on = 60us */
 //#define RWD_TIME_PAUSE 30  /* 20us */
 
-// testing calculating in ticks instead of (us) microseconds.
+// testing calculating in (us) microseconds.
 #define	RWD_TIME_1 120		// READER_TIME_PAUSE 20us off, 80us on = 100us  80 * 1.5 == 120ticks
 #define RWD_TIME_0 60		// READER_TIME_PAUSE 20us off, 40us on = 60us   40 * 1.5 == 60ticks 
 #define RWD_TIME_PAUSE 30	// 20us == 20 * 1.5 == 30ticks */
@@ -107,36 +106,17 @@ uint32_t sendFrameStop = 0;
 #ifndef COIL_PULSE
 # define COIL_PULSE(x)  { \
 		SHORT_COIL; \
-		Wait(RWD_TIME_PAUSE); \
+		WaitTicks(RWD_TIME_PAUSE); \
 		OPEN_COIL; \
-		Wait((x)); \
+		WaitTicks((x)); \
 	}
 #endif
-#ifndef GET_TICKS
-# define GET_TICKS AT91C_BASE_TC0->TC_CV
-#endif
 
 // ToDo: define a meaningful maximum size for auth_table. The bigger this is, the lower will be the available memory for traces. 
 // Historically it used to be FREE_BUFFER_SIZE, which was 2744.
 #define LEGIC_CARD_MEMSIZE 1024
 static uint8_t* cardmem;
 
-static void Wait(uint32_t time){
-	if ( time == 0 ) return;
-	time += GET_TICKS;	
-	while (GET_TICKS < time);
-}
-// Starts Clock and waits until its reset
-static void Reset(AT91PS_TC clock){
-	clock->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
-	while(clock->TC_CV > 1) ;
-}
-
-// Starts Clock and waits until its reset
-static void ResetClock(void){
-	Reset(timer);
-}
-
 static void frame_append_bit(struct legic_frame * const f, int bit) {
 	// Overflow, won't happen
    if (f->bits >= 31) return;
@@ -166,8 +146,7 @@ static void frame_clean(struct legic_frame * const f) {
 */
 
 /* Generate Keystream */
-static uint32_t get_key_stream(int skip, int count)
-{
+uint32_t get_key_stream(int skip, int count) {
 	uint32_t key = 0;
 	int i;
 
@@ -175,7 +154,7 @@ static uint32_t get_key_stream(int skip, int count)
 	legic_prng_bc += prng_timer->TC_CV;
 
 	// reset the prng timer.
-	Reset(prng_timer);
+	ResetTimer(prng_timer);
 
 	/* If skip == -1, forward prng time based */
 	if(skip == -1) {
@@ -209,7 +188,7 @@ static uint32_t get_key_stream(int skip, int count)
 /* Send a frame in tag mode, the FPGA must have been set up by
  * LegicRfSimulate
  */
-static void frame_send_tag(uint16_t response, uint8_t bits, uint8_t crypt) {
+void frame_send_tag(uint16_t response, uint8_t bits, uint8_t crypt) {
 	/* Bitbang the response */
 	LOW(GPIO_SSC_DOUT);
 	AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
@@ -222,7 +201,7 @@ static void frame_send_tag(uint16_t response, uint8_t bits, uint8_t crypt) {
 	}
 
 	/* Wait for the frame start */
-	Wait( TAG_FRAME_WAIT );
+	WaitUS( TAG_FRAME_WAIT );
 
 	uint8_t bit = 0;
 	for(int i = 0; i < bits; i++) {
@@ -235,7 +214,7 @@ static void frame_send_tag(uint16_t response, uint8_t bits, uint8_t crypt) {
 		else
 			LOW(GPIO_SSC_DOUT);
 		  
-		Wait(100);
+		WaitUS(100);
    }
    LOW(GPIO_SSC_DOUT);
 }
@@ -243,7 +222,7 @@ static void frame_send_tag(uint16_t response, uint8_t bits, uint8_t crypt) {
 /* Send a frame in reader mode, the FPGA must have been set up by
  * LegicRfReader
  */
-static void frame_sendAsReader(uint32_t data, uint8_t bits){
+void frame_sendAsReader(uint32_t data, uint8_t bits){
 
 	uint32_t starttime = GET_TICKS, send = 0;
 	uint16_t mask = 1;
@@ -298,14 +277,13 @@ static void frame_sendAsReader(uint32_t data, uint8_t bits){
 static void frame_receiveAsReader(struct legic_frame * const f, uint8_t bits) {
 
 	frame_clean(f);
+	if ( bits > 32 ) return;
 	
-	uint8_t i = 0, edges = 0;	
+	uint8_t i = bits, edges = 0;	
 	uint16_t lsfr = 0;
 	uint32_t the_bit = 1, next_bit_at = 0, data;
 	int old_level = 0, level = 0;
 
-	if(bits > 32) bits = 32;
-
 	AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_DIN;
 	AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DIN;
 	
@@ -320,14 +298,14 @@ static void frame_receiveAsReader(struct legic_frame * const f, uint8_t bits) {
 	data = lsfr;
 	
 	//FIXED time between sending frame and now listening frame. 330us
-	Wait( TAG_FRAME_WAIT - ( GET_TICKS - sendFrameStop ) );
-	//Wait( TAG_FRAME_WAIT );
+	//WaitTicks( GET_TICKS - sendFrameStop - TAG_FRAME_WAIT);
+	WaitTicks( 490 );
 
 	uint32_t starttime = GET_TICKS;
 	
 	next_bit_at =  GET_TICKS + TAG_BIT_PERIOD;
 	
-	for( i = 0; i < bits; i++) {
+	while ( i-- ){
 		edges = 0;
 		while  ( GET_TICKS < next_bit_at) {
 
@@ -341,7 +319,7 @@ static void frame_receiveAsReader(struct legic_frame * const f, uint8_t bits) {
 		next_bit_at += TAG_BIT_PERIOD;
 		
 		// We expect 42 edges  == ONE
-		if(edges > 20 && edges < 64)
+		if(edges > 30 && edges < 64)
 			data ^= the_bit;
 
 		the_bit <<= 1;	
@@ -370,12 +348,12 @@ static void frame_receiveAsReader(struct legic_frame * const f, uint8_t bits) {
 
 // Setup pm3 as a Legic Reader
 static uint32_t setup_phase_reader(uint8_t iv) {
-
+	
 	// Switch on carrier and let the tag charge for 1ms
 	HIGH(GPIO_SSC_DOUT);
-	SpinDelay(300);
+	WaitUS(300);	
 	
-	ResetUSClock();
+	ResetTicks();
 	
 	// no keystream yet
 	legic_prng_init(0);
@@ -389,8 +367,8 @@ static uint32_t setup_phase_reader(uint8_t iv) {
 	frame_receiveAsReader(&current_frame, 6);
 
 	// fixed delay before sending ack.
-	Wait(360);  // 240us = 360tick
-	legic_prng_forward(2);  //240us / 100 == 2.4 iterations
+	WaitTicks(387);  // 244us
+	legic_prng_forward(3);  //240us / 100 == 2.4 iterations
 	
 	// Send obsfuscated acknowledgment frame.
 	// 0x19 = 0x18 MIM22, 0x01 LSB READCMD 
@@ -402,17 +380,13 @@ static uint32_t setup_phase_reader(uint8_t iv) {
 		default: break;
 	}
 	return current_frame.data;
-
-	// fixed delay after setup phase.
-	Wait(375); // 260us == 375 ticks
-	legic_prng_forward(2);// 260us / 100 == 2.6 iterations
 }
 
-static void LegicCommonInit(void) {	
+static void LegicCommonInit(void) {
+
 	FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
 	FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX);
 	SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
-	FpgaSetupSsc();
 
 	/* Bitbang the transmitter */
 	LOW(GPIO_SSC_DOUT);
@@ -427,14 +401,15 @@ static void LegicCommonInit(void) {
 	set_tracing(TRUE);
 	crc_init(&legic_crc, 4, 0x19 >> 1, 0x5, 0);
 	
-	StartCountUS();
+	StartTicks();
 }
 
 // Switch off carrier, make sure tag is reset
 static void switch_off_tag_rwd(void) {
 	LOW(GPIO_SSC_DOUT);
-	SpinDelay(10);
+	WaitUS(200);
 	WDT_HIT();
+	Dbprintf("Exit Switch_off_tag_rwd");
 }
 
 // calculate crc4 for a legic READ command 
@@ -451,6 +426,15 @@ static uint32_t legic4Crc(uint8_t legicCmd, uint16_t byte_index, uint8_t value,
 
 int legic_read_byte(int byte_index, int cmd_sz) {
 
+	// (us)| ticks
+	// -------------
+	// 330 | 495
+	// 460 | 690
+	// 258 | 387
+	// 244 | 366
+	WaitTicks(332); 
+	legic_prng_forward(2); // 460 / 100 = 4.6  iterations
+
 	uint8_t byte = 0, crc = 0, calcCrc = 0;
 	uint32_t cmd = (byte_index << 1) | LEGIC_READ;
 
@@ -466,9 +450,8 @@ int legic_read_byte(int byte_index, int cmd_sz) {
 		return -1;
 	}
 
-	Wait(690);  // 460us == 690ticks
-	legic_prng_forward(4); // 460 / 100 = 4.6  iterations
-	
+
+//	legic_prng_forward(2); // 460 / 100 = 4.6  iterations
 	return byte;
 }
 
@@ -504,7 +487,7 @@ int legic_write_byte(uint8_t byte, uint16_t addr, uint8_t addr_sz) {
 
     legic_prng_forward(2); /* we wait anyways */
 	
-	Wait(TAG_FRAME_WAIT);
+	WaitUS(TAG_FRAME_WAIT);
 	
 	frame_sendAsReader(cmd, cmd_sz);
   
@@ -516,7 +499,7 @@ int legic_write_byte(uint8_t byte, uint16_t addr, uint8_t addr_sz) {
     int t, old_level = 0, edges = 0;
     int next_bit_at = 0;
 
-	Wait(TAG_FRAME_WAIT);
+	WaitUS(TAG_FRAME_WAIT);
 
     for( t = 0; t < 80; ++t) {
         edges = 0;
@@ -532,13 +515,13 @@ int legic_write_byte(uint8_t byte, uint16_t addr, uint8_t addr_sz) {
 			int t = timer->TC_CV;
 			int c = t / TAG_BIT_PERIOD;
 			
-			ResetClock();
+			ResetTimer(timer);
 			legic_prng_forward(c);
         	return 0;
         }
     }
 
-	ResetClock();
+	ResetTimer(timer);
 	return -1;
 }
 
@@ -802,7 +785,7 @@ static void frame_handle_tag(struct legic_frame const * const f)
         LED_C_ON();
         
 		// Reset prng timer
-		Reset(prng_timer);
+		ResetTimer(prng_timer);
 		
         legic_prng_init(f->data);
         frame_send_tag(0x3d, 6, 1); /* 0x3d^0x26 = 0x1B */
@@ -812,8 +795,8 @@ static void frame_handle_tag(struct legic_frame const * const f)
         legic_prng_iv = f->data;
  
  
-		ResetClock();
-		Wait(280);
+		ResetTimer(timer);
+		WaitUS(280);
         return;
    }
 
@@ -824,8 +807,8 @@ static void frame_handle_tag(struct legic_frame const * const f)
       if((f->bits == 6) && (f->data == xored)) {
          legic_state = STATE_CON;
 
-		 ResetClock();
-		 Wait(200);
+		 ResetTimer(timer);
+		 WaitUS(200);
          return;
 
 	 } else {
@@ -851,9 +834,9 @@ static void frame_handle_tag(struct legic_frame const * const f)
 
          frame_send_tag(hash | data, 12, 1);
 
-		 ResetClock();
+		 ResetTimer(timer);
          legic_prng_forward(2);
-		 Wait(180);
+		 WaitUS(180);
          return;
       }
    }
@@ -1004,10 +987,6 @@ void LegicRfSimulate(int phase, int frame, int reqresp)
 	LEDsoff();
 }
 
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-
 //-----------------------------------------------------------------------------
 // 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
diff --git a/armsrc/legicrf.h b/armsrc/legicrf.h
index 4e3177ee..2008f5b9 100644
--- a/armsrc/legicrf.h
+++ b/armsrc/legicrf.h
@@ -17,6 +17,7 @@
 #include "string.h"		
 #include "legic_prng.h"	// legic PRNG impl
 #include "crc.h"		// legic crc-4
+#include "ticks.h"		// timers
 
 #define LEGIC_READ 0x01
 #define LEGIC_WRITE 0x00
@@ -26,6 +27,10 @@ extern int  LegicRfReader(int offset, int bytes, int iv);
 extern void LegicRfWriter(int offset, int bytes, int iv);
 extern void LegicRfRawWriter(int address, int data, int iv);
 
+uint32_t get_key_stream(int skip, int count);
+void frame_send_tag(uint16_t response, uint8_t bits, uint8_t crypt);
+void frame_sendAsReader(uint32_t data, uint8_t bits);
+
 int ice_legic_select_card();
 void ice_legic_setup();
 
diff --git a/armsrc/ticks.c b/armsrc/ticks.c
new file mode 100644
index 00000000..43b006ff
--- /dev/null
+++ b/armsrc/ticks.c
@@ -0,0 +1,235 @@
+//-----------------------------------------------------------------------------
+// Jonathan Westhues, Sept 2005
+// Iceman, Sept 2016
+//
+// This code is licensed to you under the terms of the GNU GPL, version 2 or,
+// at your option, any later version. See the LICENSE.txt file for the text of
+// the license.
+//-----------------------------------------------------------------------------
+// Timers, Clocks functions used in LF or Legic where you would need detailed time.
+//-----------------------------------------------------------------------------
+
+#include "ticks.h"
+
+// attempt at high resolution microsecond timer
+// beware: timer counts in 21.3uS increments (1024/48Mhz)
+void SpinDelayUs(int us) {
+	int ticks = (48 * us) >> 10;
+
+	// Borrow a PWM unit for my real-time clock
+	AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0);
+	
+	// 48 MHz / 1024 gives 46.875 kHz
+	AT91C_BASE_PWMC_CH0->PWMC_CMR = PWM_CH_MODE_PRESCALER(10);
+	AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0;
+	AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xffff;
+
+	uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
+
+	for(;;) {
+		uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
+		if (now == (uint16_t)(start + ticks))
+			return;
+
+		WDT_HIT();
+	}
+}
+
+void SpinDelay(int ms) {
+  // convert to uS and call microsecond delay function
+	SpinDelayUs(ms*1000);
+}
+//  -------------------------------------------------------------------------
+//  timer lib
+//  -------------------------------------------------------------------------
+//  test procedure:
+//
+//	ti = GetTickCount();
+//	SpinDelay(1000);
+//	ti = GetTickCount() - ti;
+//	Dbprintf("timer(1s): %d t=%d", ti, GetTickCount());
+
+void StartTickCount() {
+	// This timer is based on the slow clock. The slow clock frequency is between 22kHz and 40kHz.
+	// We can determine the actual slow clock frequency by looking at the Main Clock Frequency Register.
+    uint16_t mainf = AT91C_BASE_PMC->PMC_MCFR & 0xffff;		// = 16 * main clock frequency (16MHz) / slow clock frequency
+	// set RealTimeCounter divider to count at 1kHz:
+	AT91C_BASE_RTTC->RTTC_RTMR = AT91C_RTTC_RTTRST | ((256000 + (mainf/2)) / mainf);
+	// note: worst case precision is approx 2.5%
+}
+
+/*
+* Get the current count.
+*/
+uint32_t RAMFUNC GetTickCount(){
+	return AT91C_BASE_RTTC->RTTC_RTVR;// was * 2;
+}
+
+//  -------------------------------------------------------------------------
+//  microseconds timer 
+//  -------------------------------------------------------------------------
+void StartCountUS() {
+	AT91C_BASE_PMC->PMC_PCER |= (1 << 12) | (1 << 13) | (1 << 14);
+	AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE;
+
+	// fast clock
+	// tick=1.5mks
+	AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable
+	AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK | // MCK(48MHz) / 32 
+								AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO | AT91C_TC_ACPA_CLEAR |
+								AT91C_TC_ACPC_SET | AT91C_TC_ASWTRG_SET;
+	AT91C_BASE_TC0->TC_RA = 1;
+	AT91C_BASE_TC0->TC_RC = 0xBFFF + 1; // 0xC000
+	
+	AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // timer disable  
+	AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_XC1; // from timer 0
+	
+	AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
+	AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
+	AT91C_BASE_TCB->TCB_BCR = 1;
+	
+	while (AT91C_BASE_TC1->TC_CV >= 1);
+}
+
+uint32_t RAMFUNC GetCountUS(){
+	//return (AT91C_BASE_TC1->TC_CV * 0x8000) + ((AT91C_BASE_TC0->TC_CV / 15) * 10);
+	//  By suggestion from PwPiwi, http://www.proxmark.org/forum/viewtopic.php?pid=17548#p17548
+	return (AT91C_BASE_TC1->TC_CV * 0x8000) + ((AT91C_BASE_TC0->TC_CV * 2) / 3); 
+}
+void ResetUSClock(void) {	
+	//enable clock of timer and software trigger
+	AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
+	AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
+	while (AT91C_BASE_TC1->TC_CV >= 1);
+}
+// attempt at high resolution microsecond timer
+// beware: timer counts in 21.3uS increments (1024/48Mhz)
+void SpinDelayCountUs(uint32_t us) {
+	if (us < 8) return;
+	us += GetCountUS();	
+	while ( GetCountUS() < us ){}
+}
+// static uint32_t GlobalUsCounter = 0;
+// uint32_t RAMFUNC GetDeltaCountUS(){
+	// uint32_t g_cnt = GetCountUS();
+	// uint32_t g_res = g_cnt - GlobalUsCounter;
+	// GlobalUsCounter = g_cnt;
+	// return g_res;
+// }
+//  -------------------------------------------------------------------------
+//  Timer for iso14443 commands. Uses ssp_clk from FPGA 
+//  -------------------------------------------------------------------------
+void StartCountSspClk() {
+	AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1) | (1 << AT91C_ID_TC2);  // Enable Clock to all timers
+	AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_TIOA1 		// XC0 Clock = TIOA1
+							| AT91C_TCB_TC1XC1S_NONE 		// XC1 Clock = none
+							| AT91C_TCB_TC2XC2S_TIOA0;		// XC2 Clock = TIOA0
+
+	// configure TC1 to create a short pulse on TIOA1 when a rising edge on TIOB1 (= ssp_clk from FPGA) occurs:
+	AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; 				// disable TC1
+	AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK // TC1 Clock = MCK(48MHz)/2 = 24MHz
+							| AT91C_TC_CPCSTOP				// Stop clock on RC compare
+							| AT91C_TC_EEVTEDG_RISING		// Trigger on rising edge of Event
+							| AT91C_TC_EEVT_TIOB			// Event-Source: TIOB1 (= ssp_clk from FPGA = 13,56MHz/16)
+							| AT91C_TC_ENETRG				// Enable external trigger event
+							| AT91C_TC_WAVESEL_UP	 		// Upmode without automatic trigger on RC compare
+							| AT91C_TC_WAVE 				// Waveform Mode
+							| AT91C_TC_AEEVT_SET 			// Set TIOA1 on external event
+							| AT91C_TC_ACPC_CLEAR; 			// Clear TIOA1 on RC Compare
+	AT91C_BASE_TC1->TC_RC = 0x04; 							// RC Compare value = 0x04
+
+	// use TC0 to count TIOA1 pulses
+	AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;				// disable TC0
+	AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_XC0	 			// TC0 clock = XC0 clock = TIOA1
+							| AT91C_TC_WAVE 				// Waveform Mode
+							| AT91C_TC_WAVESEL_UP	 		// just count
+							| AT91C_TC_ACPA_CLEAR 			// Clear TIOA0 on RA Compare
+							| AT91C_TC_ACPC_SET; 			// Set TIOA0 on RC Compare
+	AT91C_BASE_TC0->TC_RA = 1;								// RA Compare value = 1; pulse width to TC2
+	AT91C_BASE_TC0->TC_RC = 0; 								// RC Compare value = 0; increment TC2 on overflow
+
+	// use TC2 to count TIOA0 pulses (giving us a 32bit counter (TC0/TC2) clocked by ssp_clk)
+	AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKDIS; 				// disable TC2  
+	AT91C_BASE_TC2->TC_CMR = AT91C_TC_CLKS_XC2	 			// TC2 clock = XC2 clock = TIOA0
+							| AT91C_TC_WAVE 				// Waveform Mode
+							| AT91C_TC_WAVESEL_UP;	 		// just count
+
+	AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;				// enable and reset TC0
+	AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;				// enable and reset TC1
+	AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;				// enable and reset TC2
+
+	// synchronize the counter with the ssp_frame signal. 
+	// Note: FPGA must be in any iso14443 mode, otherwise the frame signal would not be present 
+	while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME)); 	// wait for ssp_frame to go high (start of frame)
+	while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME); 		// wait for ssp_frame to be low
+	while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); 	// wait for ssp_clk to go high
+
+	// note: up to now two ssp_clk rising edges have passed since the rising edge of ssp_frame
+	// it is now safe to assert a sync signal. This sets all timers to 0 on next active clock edge
+	AT91C_BASE_TCB->TCB_BCR = 1;							// assert Sync (set all timers to 0 on next active clock edge)
+	// at the next (3rd) ssp_clk rising edge, TC1 will be reset (and not generate a clock signal to TC0)
+	// at the next (4th) ssp_clk rising edge, TC0 (the low word of our counter) will be reset. From now on,
+	// whenever the last three bits of our counter go 0, we can be sure to be in the middle of a frame transfer.
+	// (just started with the transfer of the 4th Bit).
+
+	// The high word of the counter (TC2) will not reset until the low word (TC0) overflows. 
+	// Therefore need to wait quite some time before we can use the counter.
+	while (AT91C_BASE_TC2->TC_CV >= 1);
+}
+void ResetSspClk(void) {	
+	//enable clock of timer and software trigger
+	AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
+	AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
+	AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
+}
+
+uint32_t RAMFUNC GetCountSspClk(){
+
+	uint32_t tmp_count = (AT91C_BASE_TC2->TC_CV << 16) | AT91C_BASE_TC0->TC_CV;
+	if ((tmp_count & 0x0000ffff) == 0)  //small chance that we may have missed an increment in TC2
+		return (AT91C_BASE_TC2->TC_CV << 16);
+	return tmp_count;
+}
+
+
+void StartTicks(void){
+	//initialization of the timer
+	AT91C_BASE_PMC->PMC_PCER |= (1 << 12) | (1 << 13) | (1 << 14);
+	AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE;
+
+	// fast clock TC0
+	// tick=1.5mks
+	AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable
+	AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK;  //clock at 48/32 MHz
+	
+	// Enable and reset timer
+	AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
+	AT91C_BASE_TCB->TCB_BCR = 1;
+	// wait until timer becomes zero.
+	while (AT91C_BASE_TC0->TC_CV > 1);
+}
+// Wait - Spindelay in ticks.
+// if called with a high number, this will trigger the WDT...
+void WaitTicks(uint32_t ticks){
+	if ( ticks == 0 ) return;
+	ticks += GET_TICKS;	
+	while (GET_TICKS < ticks);
+}
+// Wait / Spindelay in us (microseconds) 
+// 1us = 1.5ticks.
+void WaitUS(uint16_t us){
+	if ( us == 0 ) return;
+	WaitTicks(  (uint32_t)(us * 1.5) );
+}
+void WaitMS(uint16_t ms){
+	if (ms == 0) return;
+	WaitTicks( (uint32_t)(ms * 1500) );
+}
+// Starts Clock and waits until its reset
+void ResetTicks(){
+	ResetTimer(AT91C_BASE_TC0);
+}
+void ResetTimer(AT91PS_TC timer){
+	timer->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
+	while(timer->TC_CV > 1) ;
+}
diff --git a/armsrc/ticks.h b/armsrc/ticks.h
new file mode 100644
index 00000000..050cb6ae
--- /dev/null
+++ b/armsrc/ticks.h
@@ -0,0 +1,47 @@
+//-----------------------------------------------------------------------------
+// Jonathan Westhues, Aug 2005
+// Iceman, Sept 2016
+//
+// This code is licensed to you under the terms of the GNU GPL, version 2 or,
+// at your option, any later version. See the LICENSE.txt file for the text of
+// the license.
+//-----------------------------------------------------------------------------
+// Timers, Clocks functions used in LF or Legic where you would need detailed time.
+//-----------------------------------------------------------------------------
+
+#ifndef __TICKS_H
+#define __TICKS_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include "common.h"
+#include "apps.h"
+#include "proxmark3.h"
+
+#ifndef GET_TICKS
+# define GET_TICKS AT91C_BASE_TC0->TC_CV
+#endif
+
+void SpinDelay(int ms);
+void SpinDelayUs(int us);
+
+void StartTickCount(void);
+uint32_t RAMFUNC GetTickCount(void);
+
+void StartCountUS(void);
+uint32_t RAMFUNC GetCountUS(void);
+void ResetUSClock(void);
+void SpinDelayCountUs(uint32_t us);
+//uint32_t RAMFUNC GetDeltaCountUS(void);
+
+void StartCountSspClk();
+void ResetSspClk(void);
+uint32_t RAMFUNC GetCountSspClk();
+
+extern void StartTicks(void);
+extern void WaitTicks(uint32_t ticks);
+extern void WaitUS(uint16_t us);
+extern void WaitMS(uint16_t ms);
+extern void ResetTicks();
+extern void ResetTimer(AT91PS_TC timer);
+#endif
\ No newline at end of file
diff --git a/armsrc/util.c b/armsrc/util.c
index be6170d3..1716a113 100644
--- a/armsrc/util.c
+++ b/armsrc/util.c
@@ -233,35 +233,6 @@ int BUTTON_HELD(int ms) {
 	return BUTTON_ERROR;
 }
 
-// attempt at high resolution microsecond timer
-// beware: timer counts in 21.3uS increments (1024/48Mhz)
-void SpinDelayUs(int us) {
-	int ticks = (48 * us) >> 10;
-
-	// Borrow a PWM unit for my real-time clock
-	AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0);
-	
-	// 48 MHz / 1024 gives 46.875 kHz
-	AT91C_BASE_PWMC_CH0->PWMC_CMR = PWM_CH_MODE_PRESCALER(10);
-	AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0;
-	AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xffff;
-
-	uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
-
-	for(;;) {
-		uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
-		if (now == (uint16_t)(start + ticks))
-			return;
-
-		WDT_HIT();
-	}
-}
-
-void SpinDelay(int ms) {
-  // convert to uS and call microsecond delay function
-	SpinDelayUs(ms*1000);
-}
-
 /* Similar to FpgaGatherVersion this formats stored version information
  * into a string representation. It takes a pointer to the struct version_information,
  * verifies the magic properties, then stores a formatted string, prefixed by
@@ -295,158 +266,3 @@ void FormatVersionInformation(char *dst, int len, const char *prefix, void *vers
 	strncat(dst, v->buildtime, len - strlen(dst) - 1);
 	strncat(dst, "\n", len - strlen(dst) - 1);
 }
-
-//  -------------------------------------------------------------------------
-//  timer lib
-//  -------------------------------------------------------------------------
-//  test procedure:
-//
-//	ti = GetTickCount();
-//	SpinDelay(1000);
-//	ti = GetTickCount() - ti;
-//	Dbprintf("timer(1s): %d t=%d", ti, GetTickCount());
-
-void StartTickCount() {
-	// This timer is based on the slow clock. The slow clock frequency is between 22kHz and 40kHz.
-	// We can determine the actual slow clock frequency by looking at the Main Clock Frequency Register.
-    uint16_t mainf = AT91C_BASE_PMC->PMC_MCFR & 0xffff;		// = 16 * main clock frequency (16MHz) / slow clock frequency
-	// set RealTimeCounter divider to count at 1kHz:
-	AT91C_BASE_RTTC->RTTC_RTMR = AT91C_RTTC_RTTRST | ((256000 + (mainf/2)) / mainf);
-	// note: worst case precision is approx 2.5%
-}
-
-/*
-* Get the current count.
-*/
-uint32_t RAMFUNC GetTickCount(){
-	return AT91C_BASE_RTTC->RTTC_RTVR;// was * 2;
-}
-
-//  -------------------------------------------------------------------------
-//  microseconds timer 
-//  -------------------------------------------------------------------------
-void StartCountUS() {
-	AT91C_BASE_PMC->PMC_PCER |= (0x1 << 12) | (0x1 << 13) | (0x1 << 14);
-//	AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC1XC1S_TIOA0;
-	AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE;
-
-	// fast clock
-	AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable
-	AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK | // MCK(48MHz)/32 -- tick=1.5mks
-								AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO | AT91C_TC_ACPA_CLEAR |
-								AT91C_TC_ACPC_SET | AT91C_TC_ASWTRG_SET;
-	AT91C_BASE_TC0->TC_RA = 1;
-	AT91C_BASE_TC0->TC_RC = 0xBFFF + 1; // 0xC000
-	
-	AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // timer disable  
-	AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_XC1; // from timer 0
-	
-	AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
-	AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
-	AT91C_BASE_TCB->TCB_BCR = 1;
-	
-	while (AT91C_BASE_TC1->TC_CV >= 1);
-}
-
-uint32_t RAMFUNC GetCountUS(){
-	//return (AT91C_BASE_TC1->TC_CV * 0x8000) + ((AT91C_BASE_TC0->TC_CV / 15) * 10);
-	//  By suggestion from PwPiwi, http://www.proxmark.org/forum/viewtopic.php?pid=17548#p17548
-	return (AT91C_BASE_TC1->TC_CV * 0x8000) + ((AT91C_BASE_TC0->TC_CV * 2) / 3); 
-}
-void ResetUSClock(void) {	
-	//enable clock of timer and software trigger
-	AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
-	AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
-	while (AT91C_BASE_TC1->TC_CV >= 1);
-}
-// attempt at high resolution microsecond timer
-// beware: timer counts in 21.3uS increments (1024/48Mhz)
-void SpinDelayCountUs(uint32_t us) {
-	if (us < 8) return;
-	us += GetCountUS();	
-	while ( GetCountUS() < us ){}
-}
-// static uint32_t GlobalUsCounter = 0;
-
-// uint32_t RAMFUNC GetDeltaCountUS(){
-	// uint32_t g_cnt = GetCountUS();
-	// uint32_t g_res = g_cnt - GlobalUsCounter;
-	// GlobalUsCounter = g_cnt;
-	// return g_res;
-// }
-
-
-//  -------------------------------------------------------------------------
-//  Timer for iso14443 commands. Uses ssp_clk from FPGA 
-//  -------------------------------------------------------------------------
-void StartCountSspClk() {
-	AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1) | (1 << AT91C_ID_TC2);  // Enable Clock to all timers
-	AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_TIOA1 		// XC0 Clock = TIOA1
-							| AT91C_TCB_TC1XC1S_NONE 		// XC1 Clock = none
-							| AT91C_TCB_TC2XC2S_TIOA0;		// XC2 Clock = TIOA0
-
-	// configure TC1 to create a short pulse on TIOA1 when a rising edge on TIOB1 (= ssp_clk from FPGA) occurs:
-	AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; 				// disable TC1
-	AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK // TC1 Clock = MCK(48MHz)/2 = 24MHz
-							| AT91C_TC_CPCSTOP				// Stop clock on RC compare
-							| AT91C_TC_EEVTEDG_RISING		// Trigger on rising edge of Event
-							| AT91C_TC_EEVT_TIOB			// Event-Source: TIOB1 (= ssp_clk from FPGA = 13,56MHz/16)
-							| AT91C_TC_ENETRG				// Enable external trigger event
-							| AT91C_TC_WAVESEL_UP	 		// Upmode without automatic trigger on RC compare
-							| AT91C_TC_WAVE 				// Waveform Mode
-							| AT91C_TC_AEEVT_SET 			// Set TIOA1 on external event
-							| AT91C_TC_ACPC_CLEAR; 			// Clear TIOA1 on RC Compare
-	AT91C_BASE_TC1->TC_RC = 0x04; 							// RC Compare value = 0x04
-
-	// use TC0 to count TIOA1 pulses
-	AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;				// disable TC0
-	AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_XC0	 			// TC0 clock = XC0 clock = TIOA1
-							| AT91C_TC_WAVE 				// Waveform Mode
-							| AT91C_TC_WAVESEL_UP	 		// just count
-							| AT91C_TC_ACPA_CLEAR 			// Clear TIOA0 on RA Compare
-							| AT91C_TC_ACPC_SET; 			// Set TIOA0 on RC Compare
-	AT91C_BASE_TC0->TC_RA = 1;								// RA Compare value = 1; pulse width to TC2
-	AT91C_BASE_TC0->TC_RC = 0; 								// RC Compare value = 0; increment TC2 on overflow
-
-	// use TC2 to count TIOA0 pulses (giving us a 32bit counter (TC0/TC2) clocked by ssp_clk)
-	AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKDIS; 				// disable TC2  
-	AT91C_BASE_TC2->TC_CMR = AT91C_TC_CLKS_XC2	 			// TC2 clock = XC2 clock = TIOA0
-							| AT91C_TC_WAVE 				// Waveform Mode
-							| AT91C_TC_WAVESEL_UP;	 		// just count
-
-	AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;				// enable and reset TC0
-	AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;				// enable and reset TC1
-	AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;				// enable and reset TC2
-
-	// synchronize the counter with the ssp_frame signal. 
-	// Note: FPGA must be in any iso14443 mode, otherwise the frame signal would not be present 
-	while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME)); 	// wait for ssp_frame to go high (start of frame)
-	while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME); 		// wait for ssp_frame to be low
-	while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); 	// wait for ssp_clk to go high
-
-	// note: up to now two ssp_clk rising edges have passed since the rising edge of ssp_frame
-	// it is now safe to assert a sync signal. This sets all timers to 0 on next active clock edge
-	AT91C_BASE_TCB->TCB_BCR = 1;							// assert Sync (set all timers to 0 on next active clock edge)
-	// at the next (3rd) ssp_clk rising edge, TC1 will be reset (and not generate a clock signal to TC0)
-	// at the next (4th) ssp_clk rising edge, TC0 (the low word of our counter) will be reset. From now on,
-	// whenever the last three bits of our counter go 0, we can be sure to be in the middle of a frame transfer.
-	// (just started with the transfer of the 4th Bit).
-
-	// The high word of the counter (TC2) will not reset until the low word (TC0) overflows. 
-	// Therefore need to wait quite some time before we can use the counter.
-	while (AT91C_BASE_TC2->TC_CV >= 1);
-}
-void ResetSspClk(void) {	
-	//enable clock of timer and software trigger
-	AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
-	AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
-	AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
-}
-
-uint32_t RAMFUNC GetCountSspClk(){
-	uint32_t tmp_count = (AT91C_BASE_TC2->TC_CV << 16) | AT91C_BASE_TC0->TC_CV;
-	if ((tmp_count & 0x0000ffff) == 0)  //small chance that we may have missed an increment in TC2
-		return (AT91C_BASE_TC2->TC_CV << 16);
-	return tmp_count;
-}
-
diff --git a/armsrc/util.h b/armsrc/util.h
index 3ff70dd4..d3235292 100644
--- a/armsrc/util.h
+++ b/armsrc/util.h
@@ -18,6 +18,7 @@
 #include "apps.h"
 #include "BigBuf.h"
 #include "proxmark3.h"
+#include "ticks.h"
 
 #define BYTEx(x, n) (((x) >> (n * 8)) & 0xff )
 
@@ -51,25 +52,10 @@ void rol(uint8_t *data, const size_t len);
 void lsl (uint8_t *data, size_t len);
 int32_t le24toh (uint8_t data[3]);
 
-void SpinDelay(int ms);
-void SpinDelayUs(int us);
 void LED(int led, int ms);
 void LEDsoff();
 int BUTTON_CLICKED(int ms);
 int BUTTON_HELD(int ms);
 void FormatVersionInformation(char *dst, int len, const char *prefix, void *version_information);
 
-void StartTickCount();
-uint32_t RAMFUNC GetTickCount();
-
-void StartCountUS();
-uint32_t RAMFUNC GetCountUS();
-void ResetUSClock(void);
-void SpinDelayCountUs(uint32_t us);
-//uint32_t RAMFUNC GetDeltaCountUS();
-
-void StartCountSspClk();
-void ResetSspClk(void);
-uint32_t RAMFUNC GetCountSspClk();
-
 #endif
diff --git a/client/cmdhflegic.c b/client/cmdhflegic.c
index 2cfb286e..b52034dc 100644
--- a/client/cmdhflegic.c
+++ b/client/cmdhflegic.c
@@ -404,13 +404,15 @@ int CmdLegicRFRead(const char *Cmd) {
 	PrintAndLog("Current IV: 0x%02x", IV);
 	
 	// get some  prng bytes from 
-	uint8_t temp[12];
+	uint8_t temp[32];
 	legic_prng_init(IV);
-	for ( uint8_t j = 0; j < sizeof(temp); ++j)
-		temp[j] = legic_prng_get_bits(8);
-
-	PrintAndLog("PRNG: %s", sprint_hex(temp, sizeof(temp)));
-	
+	for ( uint8_t j = 0; j < sizeof(temp); ++j) {
+		temp[j] = legic_prng_get_bit(1);
+		legic_prng_forward(1);
+		//PrintAndLog("PRNG: %s", sprint_hex(temp, sizeof(temp)));
+	}
+	PrintAndLog("PRNG: %s", sprint_bin(temp, sizeof(temp)));
+		
 	UsbCommand c = {CMD_READER_LEGIC_RF, {offset, len, IV}};
 	clearCommandBuffer();
 	SendCommand(&c);
diff --git a/common/crc.c b/common/crc.c
index 72e6f024..2f11f5f4 100644
--- a/common/crc.c
+++ b/common/crc.c
@@ -43,6 +43,8 @@ void crc_update(crc_t *crc, uint32_t indata, int data_width){
 	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;
@@ -51,6 +53,22 @@ void crc_update(crc_t *crc, uint32_t indata, int data_width){
 	}
 }
 
+void crc_update2(crc_t *crc, uint32_t data, int data_width)
+{
+	if (crc->refin) data = reflect(data, data_width);
+	
+	int i;
+	for(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;
+	}
+}
+
+
 uint32_t crc_finish(crc_t *crc) {
 	uint32_t val = crc->state;
 	if (crc->refout) val = reflect(val, crc->order);
@@ -83,6 +101,14 @@ uint32_t CRC8Maxim(uint8_t *buff, size_t size) {
 }
 
 // width=4  poly=0xC, reversed poly=0x7  init=0x5   refin=true  refout=true  xorout=0x0000  check=  name="CRC-4/LEGIC"
+uint32_t CRC4Legic(uint8_t *cmd, size_t size) {
+ 	crc_t crc;
+ 	crc_init_ref(&crc, 4, 0x19 >> 1, 0x5, 0, TRUE, TRUE);
+	crc_update2(&crc, 1, 1); /* CMD_READ */
+	crc_update2(&crc, cmd[0], 8);
+	crc_update2(&crc, cmd[1], 8);
+	return reflect(crc_finish(&crc), 4);	
+}
 // 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) {
diff --git a/common/crc.h b/common/crc.h
index d7314379..56f04357 100644
--- a/common/crc.h
+++ b/common/crc.h
@@ -44,6 +44,7 @@ extern void crc_init(crc_t *crc, int order, uint32_t polynom, uint32_t initial_v
  * data_width lower-most bits are used).
  */
 extern void crc_update(crc_t *crc, uint32_t data, int data_width);
+extern void crc_update2(crc_t *crc, uint32_t data, int data_width);
 
 /* Clean the crc state, e.g. reset it to initial_value */
 extern void crc_clear(crc_t *crc);