1. Trammell Hudson
  2. rfid

Source

rfid / avrfid2.c

Trammell Hudson 34a1133 























Trammell Hudson 318bd2a 
Trammell Hudson 34a1133 





























Trammell Hudson 318bd2a 

Trammell Hudson 34a1133 














































Trammell Hudson 318bd2a 
Trammell Hudson 3dd0f57 





Trammell Hudson 318bd2a 




Trammell Hudson 3dd0f57 
Trammell Hudson 318bd2a 
Trammell Hudson 3dd0f57 







Trammell Hudson 318bd2a 

Trammell Hudson 97a7d6d 


Trammell Hudson 318bd2a 


Trammell Hudson 3dd0f57 

Trammell Hudson 34a1133 









Trammell Hudson 318bd2a 



Trammell Hudson 34a1133 
Trammell Hudson 14238f8 


Trammell Hudson 318bd2a 

Trammell Hudson 34a1133 





























Trammell Hudson 318bd2a 

Trammell Hudson 3dd0f57 
Trammell Hudson 34a1133 
Trammell Hudson 318bd2a 
Trammell Hudson 34a1133 









Trammell Hudson 318bd2a 


Trammell Hudson 34a1133 





Trammell Hudson 318bd2a 
Trammell Hudson 3dd0f57 
Trammell Hudson 34a1133 
Trammell Hudson 318bd2a 
Trammell Hudson 34a1133 




























Trammell Hudson 318bd2a 


Trammell Hudson 34a1133 





Trammell Hudson 318bd2a 
Trammell Hudson 34a1133 






Trammell Hudson 318bd2a 

Trammell Hudson 34a1133 


Trammell Hudson 318bd2a 



Trammell Hudson 34a1133 
Trammell Hudson 3dd0f57 










Trammell Hudson 34a1133 


















Trammell Hudson 3dd0f57 
Trammell Hudson 318bd2a 
Trammell Hudson 34a1133 
Trammell Hudson 318bd2a 


Trammell Hudson 97a7d6d 
Trammell Hudson 318bd2a 
Trammell Hudson 34a1133 
Trammell Hudson 318bd2a 
/** \file
 * AVR RFID card.
 *
 * Based on avrfrid.S by Beth at Scanlime.
 *
 * Normal C code doesn't really work here since we are limited to
 * very small number of cycles per bit.  The HID Prox cards are
 * FSK modulated with only four or five RF cycles per baseband cycle.
 * Since the AVR RCALL and RET instructions take four clocks each
 * we would miss all of our timing values if we tried to make those calls.
 *
 * Instead a state machine is generated and the IJMP instruction is
 * used.  This only takes two clocks and allows us to avoid RCALL+RET
 * on each bit.
 * In between each FSK toggle we have two, possibly three clocks.
 * Since we can't count on having three, there is always a NOP
 * and then the two user slots.  Since we have up to ten cycles
 * and a guaranteed one/zero or zero/one transition per bit, we
 * can do up to forty instructions during the FSK bits.  We don't
 * need that many.
 *
 * LPM == 3 clocks
 * IJMP == 2 clocks
 */
#include <avr/io.h>
#include <avr/pgmspace.h>

static void _0(void);
static void _1(void);
static void hid_header(void);

#define HID_MFG_CODE        0x01002  // Do not modify
#define HID_SITE_CODE       42
#define HID_UNIQUE_ID       23946     // May be written on the back of the card

static const void * hid_bits[] PROGMEM = {
// HID manufacturer code (20 bits) == 0x01002
_0, _0, _0, _0,
_0, _0, _0, _1, _0, _0, _0, _0,
_0, _0, _0, _0, _0, _0, _1, _0,

// Facility code (8 bits) == 42
_0, _0, _1, _0, _1, _0, _1, _0,

// ID (16 bits) == 23946
_0, _1, _0, _1, _1, _1, _0, _1,
_1, _0, _0, _0, _1, _0, _1, _0,

// Parity
_0,

// And return to the header when we're done
hid_header
};


/* Use r16 and r17 to track the state of the pins */
volatile register uint8_t r16 __asm__("r16"); 
volatile register uint8_t r17 __asm__("r17"); 

/* Which bit are we currently sending? */
volatile register uint8_t bit_num __asm__("r15"); 


/** Load from a flash address pointed to by z_hi:z_lo
 * Z = r31:r30.
 * Duration: 3 clocks.
 */
static inline uint8_t
lpm_z_inc(void)
{
	uint8_t r;
	__asm__ __volatile__(
		"lpm %0, Z+"
		: "=r"(r)
	);
	return r;
}


static inline void
z_lo(
	uint8_t x,
	uint8_t offset
)
{
	__asm__ __volatile__("mov r30, %0" : : "r"(x));

	// Only add the offset if it is not known at compile time
	// or if it is known at compile time and non-zero.
	if (!__builtin_constant_p(offset) || offset != 0)
		__asm__ __volatile__("add r30, %0" : : "r"(offset));
}

static inline void
z_hi(
	uint8_t x
)
{
	__asm__ __volatile__(
		"mov r31, %0" : :  "r"(x)
	);
}


/**
 * Delay a specific number of clock cycles.
 *
 * rjmp is 2 clocks, nop is 1.
 * So do one nop if the delay is an odd value and then rjmp's for n/2.
 */
static inline void
delay(
	const uint8_t n
)
{
	switch (n/2)
	{
	case 8: asm("rjmp .+0");
	case 7: asm("rjmp .+0");
	case 6: asm("rjmp .+0");
	case 5: asm("rjmp .+0");
	case 4: asm("rjmp .+0");
	case 3: asm("rjmp .+0");
	case 2: asm("rjmp .+0");
	case 1: asm("rjmp .+0");
	case 0: break;
	}

	if (n % 2 == 1)
		asm("nop");
}


static void
__attribute__((__always_inline__))
toggle_raw(void)
{
	__asm__ __volatile__(
		"eor r16, r17\n"
		"out 0x17, r16\n"
	);
}

static void
__attribute__((__always_inline__))
toggle(	
	const uint8_t n
)
{
	toggle_raw();

	if (n > 2)
		delay(n-2);
}

#define ZERO_FREQ	4
#define ONE_FREQ	5


/** Send a 0 at the baseband layer.
 *
 * If delay_slot is set, the last FSK slot will not be filled,
 * instead allowing the caller to make use of two extra clock
 * cycles for their own usage.
 */
static void
__attribute__((__always_inline__))
baseband_0(
	uint8_t delay_slot
)
{
	toggle(ZERO_FREQ); // 4
	toggle(ZERO_FREQ); // 8
	toggle(ZERO_FREQ); // 12
	toggle(ZERO_FREQ); // 16
	toggle(ZERO_FREQ); // 20
	toggle(ZERO_FREQ); // 24
	toggle(ZERO_FREQ); // 28
	toggle(ZERO_FREQ); // 32
	toggle(ZERO_FREQ); // 36
	toggle(ZERO_FREQ); // 40
	toggle(ZERO_FREQ); // 44
	toggle(delay_slot ? ZERO_FREQ : 0); // 48
}


static void
__attribute__((__always_inline__))
baseband_1(void)
{
	toggle(ONE_FREQ); //  5
	toggle(ONE_FREQ); // 10
	toggle(ONE_FREQ); // 15
	toggle(ONE_FREQ); // 20
	toggle(ONE_FREQ); // 25
	toggle(ONE_FREQ); // 30
	toggle(ONE_FREQ); // 35
	toggle(ONE_FREQ); // 40
	toggle(ONE_FREQ); // 45
	toggle(ONE_FREQ); // 50
}


/** Send a 1 at the baseband layer.
 *
 * Interleaved with the FSK are the operations to load the next
 * function pointer.  Once the function "returns", the Z register
 * will contain the address of the next function in the state machine.
 */
static void
__attribute__((__always_inline__))
baseband_1_load(void)
{
	toggle(0); //  5
				uint16_t x = (uint16_t) hid_bits;
				uint8_t ptr_lo = x >> 0;
				uint8_t ptr_hi = x >> 8;
				delay(1);

	toggle(0); // 10
				z_lo(ptr_lo, bit_num);
				z_hi(ptr_hi);

	toggle(0); // 15
				uint8_t next_lo = lpm_z_inc();

	toggle(0); // 20
				uint8_t next_hi = lpm_z_inc();

	toggle(0); // 25
				delay(1);
				z_lo(next_lo, 0);
				z_hi(next_hi);

	toggle(0); // 30
				delay(1);
				bit_num += 2; // word indexed, 2 clocks

	toggle(ONE_FREQ); // 35
	toggle(ONE_FREQ); // 40
	toggle(ONE_FREQ); // 45
	toggle(0); // 50
}


/** Send the HID header start bits.
 *
 * The last baseband 1 will load the first bit and off we go.
 */
static void
hid_header(void)
{

	baseband_0(1);
	baseband_0(1);
	baseband_0(0);
				__asm__ __volatile__ ("eor r15, r15");
				delay(1);

	baseband_1();
	baseband_1();
	baseband_1_load();
				delay(1);
				asm("ijmp");
}



#if 0
static void
__attribute__((__noinline__))
//__attribute__((section(".fini8")))
hid_output(void)
{
	header();
	manchester(HID_MFG_CODE, 20);
	manchester(HID_SITE_CODE, 8);
	manchester(HID_UNIQUE_ID, 16);
	manchester(0, 1);
}
#endif

static void
_0(void)
{
	baseband_0(1);
	baseband_1_load();
				delay(1);
				asm("ijmp"); // PC <- Z, 2 clocks
}

static void
_1(void)
{
	baseband_1_load();
				delay(3); // 3 delays slots remain
	baseband_0(0);
				asm("ijmp"); // PC <- Z, 2 clocks
}

int
__attribute__((section(".vectors")))
main(void)
{
	r16 = 0;
	r17 = _BV(PINB3) | _BV(PINB4);

	hid_header();
}