// h/w clock ASK emulator - initialise data pointers for ISR and start timer 2 // args: clock pulsewidth (NOT period!), data as array of 0/1, repeat void write_ASK_HW_clock(unsigned int pulse, BYTE *data, unsigned int tpb, unsigned int repeat) { // convert to ticks pulse= CONVERT_TO_TICKS(pulse); // we only need to tick once per bit pulse *= (unsigned long) tpb; // point globals at data for ISR EMU_ThisBit= *data; EMU_Data= data + 1; EMU_Reset_Data= data; EMU_DataBitRate= 1; EMU_SubCarrier_T0= 1; EMU_Repeat= repeat; // if we're manchester or bi-phase encoding, we want to clock twice as fast so we can toggle on half-bit if(RFIDlerConfig.Manchester || RFIDlerConfig.BiPhase) { pulse /= 2; EMU_SubCarrier_T0 *= 2; EMU_DataBitRate *= 2; } // make sure no clock is running stop_HW_clock(); // set mode EmulationMode= MOD_MODE_ASK_OOK; // make sure nobody's using our timer CloseTimer3(); // tri-state on, clock low READER_CLOCK_ENABLE_ON(); CLOCK_COIL= LOW; // emulator mode COIL_MODE_EMULATOR(); // this is also a semaphore so the rest of the code knows we're running mLED_Emulate_On(); // start timer - ISR will send data OpenTimer3( T3_ON | T3_PS_1_1 | T3_SOURCE_INT, pulse - 1L); mT3SetIntPriority(6); mT3ClearIntFlag(); mT3IntEnable(TRUE); }
// this routine accepts either binary arrays or binary strings BOOL rwd_send(unsigned char *command, unsigned int length, BOOL reset, BOOL block, BYTE initial_state, unsigned long fc, unsigned long sleep, unsigned int wake, unsigned int pw0, unsigned int pw1, unsigned int gap, unsigned int post_wait) { unsigned int i; RWD_Fc= fc; // convert FCs to system ticks RWD_Sleep_Period= CONVERT_TO_TICKS(sleep * fc); RWD_Gap_Period= gap * 2; RWD_One_Gap_Period= gap * 2; RWD_Zero_Gap_Period= gap * 2; // convert FCs to OCM ticks RWD_Wake_Period= wake * 2; RWD_Zero_Period= pw0 * 2; RWD_One_Period= pw1 * 2; RWD_Post_Wait= post_wait * 2; if(!RWD_Zero_Period || !RWD_One_Period || !RWD_Gap_Period) return FALSE; // convert ascii string to bin if required if(command[0] == '0' || command[0] == '1') { if(!binstringtobinarray(RWD_Command_Buff, command)) return FALSE; } else memcpy(RWD_Command_Buff, command, length); RWD_Command_Buff[length]= '*'; RWD_Command_ThisBit= RWD_Command_Buff; // start clock and wait for TAG to wake if not already running // this is needed in case a non-resetting RWD command is issued before any other action has woken tag if(mGetLED_Clock() == mLED_OFF) { RWD_State= RWD_STATE_INACTIVE; InitHWReaderClock(OC_TOGGLE_PULSE, RWD_Fc / 2L, RWD_Fc, RWD_State); if(!reset) Delay_us((RFIDlerConfig.FrameClock * RFIDlerConfig.RWD_Wake_Period) / 100); } if(reset) RWD_State= RWD_STATE_GO_TO_SLEEP; else RWD_State= initial_state; // see if ISR has flagged RWD command finished if(block) while(RWD_State != RWD_STATE_ACTIVE) ; return TRUE; }
void read_PSK1_HW_clock(unsigned int period, unsigned int ticks, BYTE *data, unsigned int bits, unsigned int timeout_us, unsigned int min_pulse_us) { // point globals at data for ISR EMU_Data= data; HW_Bits= bits; PSK_Min_Pulse= min_pulse_us; PSK_Read_Error= FALSE; memset(EMU_Data, '\0', bits); // stop USB interfering USBMaskInterrupts(); // start clock if not already running if(!mGetLED_Clock() == mLED_ON) { InitHWReaderClock(OC_TOGGLE_PULSE, period / 2L, period, RWD_STATE_ACTIVE); // give reader time to wake up and settle Delay_us((RFIDlerConfig.FrameClock * RFIDlerConfig.RWD_Wake_Period) / 100); } // reset timer for timeout GetTimer_us(RESET); // align ourselves to reader's bit period by finding start of a pulse while(READER_DATA) if(timeout_us) if (GetTimer_us(NO_RESET) > timeout_us) return; while(!READER_DATA) if(timeout_us) if (GetTimer_us(NO_RESET) > timeout_us) return; // reset timer for external timeouts GetTimer_us(RESET); // start ISR to read PSK data InitHWReaderISR(CONVERT_TO_TICKS(period) * ticks - 1L, TRUE); }
// h/w clock PSK emulator - initialise data pointers for ISR and start timer 2 // args: clock period, data as array of 0/1, fc per bit, sub-carrier ticks, repeat void write_PSK1_HW_clock(unsigned int period, BYTE *data, unsigned int fcpb, unsigned int c0, unsigned int repeat) { // convert to ticks period= CONVERT_TO_TICKS(period); // for psk we want a full clock cycle, not a tick period *= 2; // point globals at data for ISR EMU_ThisBit= *data; EMU_Data= data + 1; EMU_Reset_Data= data; EMU_DataBitRate= fcpb; EMU_SubCarrier_T0= c0; EMU_Repeat= repeat; // set mode EmulationMode= MOD_MODE_PSK1; // make sure no clock is running stop_HW_clock(); // make sure nobody's using our timers CloseTimer3(); // tri-state on, clock low READER_CLOCK_ENABLE_ON(); CLOCK_COIL= LOW; // emulator mode COIL_MODE_EMULATOR(); // this is also a semaphore so the rest of the code knows we're running mLED_Emulate_On(); // start timer - ISR will send data OpenTimer3( T3_ON | T3_PS_1_1 | T3_SOURCE_INT, period / 2L - 1L); mT3SetIntPriority(6); mT3ClearIntFlag(); mT3IntEnable(TRUE); }
// h/w clock FSK emulator - initialise data pointers for ISR and start timer 2 // args: clock pulsewidth (NOT period!), data as array of 0/1, T0 sub-carrier ticks, T1 sub-carrier ticks, repeat void write_FSK_HW_clock(unsigned long pulse, BYTE *data, unsigned int tpb, unsigned int t0, unsigned int t1, unsigned int repeat) { // convert to ticks pulse= CONVERT_TO_TICKS(pulse); // point globals at data for ISR EMU_ThisBit= *data; EMU_Data= data + 1; EMU_Reset_Data= data; EMU_Repeat= repeat; EMU_DataBitRate= tpb; EMU_SubCarrier_T0= t0; EMU_SubCarrier_T1= t1; // set mode EmulationMode= MOD_MODE_FSK; // make sure no clock is running stop_HW_clock(); // make sure nobody's using our timer CloseTimer3(); // emulator mode COIL_MODE_EMULATOR(); // tri-state on, clock low READER_CLOCK_ENABLE_ON(); CLOCK_COIL= LOW; // this is also a semaphore so the rest of the code knows we're running mLED_Emulate_On(); // start timer - ISR will send data OpenTimer3( T3_ON | T3_PS_1_1 | T3_SOURCE_INT, pulse - 1L); mT3SetIntPriority(6); mT3ClearIntFlag(); mT3IntEnable(TRUE); }
// h/w clock reader - initialise data pointers for ISR and start timers // timer2 creates clock output for external reader // timer4 reads data bit values // period_us == clock for reader // ticks == clock periods per bit // bits == number of bits to read // oneshot must be set if we are reading data in response to RWD, so no repeating stream BOOL read_ASK_HW_clock(unsigned int period, unsigned int ticks, BYTE *data, unsigned int bits, unsigned int timeout_us, BOOL oneshot) { unsigned long dwell, time; BYTE count; Manchester_Error= FALSE; // if we're manchester or bi-phase encoding, we want to clock twice as fast so we can read both halves of the bit if(RFIDlerConfig.Manchester || RFIDlerConfig.BiPhase) { ticks /= 2; HW_Bits= (unsigned long) bits * 2; } else HW_Bits= (unsigned long) bits; // point globals at data for ISR EMU_Data= data; memset(EMU_Data, '\0', bits); // stop USB interfering USBMaskInterrupts(); // start clock if not already running if(!mGetLED_Clock() == mLED_ON) { InitHWReaderClock(OC_TOGGLE_PULSE, period / 2L, period, RWD_STATE_ACTIVE); // give reader time to wake up and settle Delay_us((RFIDlerConfig.FrameClock * RFIDlerConfig.RWD_Wake_Period) / 100); } // align ourselves to reader's bit period by waiting until the end of a pulse GetTimer_us(RESET); count= READER_DATA; while(count == READER_DATA) if(GetTimer_us(NO_RESET) > timeout_us) return FALSE; // convert to ticks period= CONVERT_TO_TICKS(period); // biphase cannot auto-align when it detects a half-bit error, so we must align // on a full bit before we start if(!oneshot && RFIDlerConfig.BiPhase) { dwell= period * ticks * 2; count= 0; while((time= get_reader_gap(timeout_us))) { if(!time || count == 255) return; else if(approx(time, dwell, 10)) break; ++count; } } // wait for half the bit period so we sample mid-tick, not just as bit is toggling dwell= ((period * ticks) / 2L); GetTimer_ticks(RESET); //DEBUG_PIN_2= HIGH; while(GetTimer_ticks(NO_RESET) < dwell) ; // reset timer for external timeouts GetTimer_us(RESET); //DEBUG_PIN_2= LOW; // re-start reader ISR to read this bit if required InitHWReaderISR(period * ticks - 1L, TRUE); return TRUE; }
BOOL read_FSK_HW_clock(unsigned int period, unsigned int ticks, BYTE *data, unsigned int bits, unsigned int timeout_us) { unsigned int gaplength; // point globals at data for ISR EMU_Data= data; HW_Bits= bits; memset(EMU_Data, '\0', bits); // stop USB interfering USBMaskInterrupts(); // start clock if not already running if(!mGetLED_Clock() == mLED_ON) { InitHWReaderClock(OC_TOGGLE_PULSE, period / 2L, period, RWD_STATE_ACTIVE); // give reader time to wake up and settle Delay_us((RFIDlerConfig.FrameClock * RFIDlerConfig.RWD_Wake_Period) / 100); } // reset timer for timeout GetTimer_us(RESET); // align ourselves to reader's bit period by finding the end of a pulse train. // we can do this by measuring the gaps. when they become significantly different // sized (more than 25%), we have just switched frequency. // find the start of a pulse while(READER_DATA) if(timeout_us) if (GetTimer_us(NO_RESET) > timeout_us) return FALSE; while(!READER_DATA) if(timeout_us) if (GetTimer_us(NO_RESET) > timeout_us) return FALSE; while(READER_DATA) if(timeout_us) if (GetTimer_us(NO_RESET) > timeout_us) return FALSE; // reset timer so we can meausure gap period GetTimer_us(RESET); while(!READER_DATA) if(timeout_us) if (GetTimer_us(NO_RESET) > timeout_us) return FALSE; gaplength= GetTimer_us(RESET); // now look for a gap that doesn't match while(42) { while(READER_DATA) if(timeout_us) if (GetTimer_us(NO_RESET) > timeout_us) return FALSE; GetTimer_us(TRUE); while(!READER_DATA) if(timeout_us) if (GetTimer_us(NO_RESET) > timeout_us) return FALSE; if(!approx(GetTimer_us(NO_RESET), gaplength, FSK_TOLERANCE)) break; } // reset timer for external timeouts GetTimer_us(RESET); // start ISR to read FSK data InitHWReaderISR(CONVERT_TO_TICKS(period) * ticks - 1L, TRUE); return TRUE; }
// DATA reading ISR void __ISR(_TIMER_4_VECTOR, ipl7auto) HW_read_bit(void) { static unsigned long count= 0L; unsigned int time; static char out, previous= -1; BYTE i, *p; BOOL fskread= FALSE; // show trigger moment (you must also set end of routine debugger statement) //DEBUG_PIN_2= HIGH; // reset interrupt mT4ClearIntFlag(); // toggle bit period flag for analogue sampler ReaderPeriod= !ReaderPeriod; if(FakeRead) return; // don't do anything unless we've got data to read - we may have been left running due to higher level error. if(!HW_Bits) { stop_HW_reader_ISR(); return; } // debugging - monitor with a logic analyser // show data value //DEBUG_PIN_3= READER_DATA; switch(RFIDlerConfig.Modulation) { case MOD_MODE_ASK_OOK: // get current bit value out= READER_DATA; // check for manchester encoding sync/errors if(RFIDlerConfig.Manchester && count) { // the 2nd half bit may not be equal to the 1st // this error is allowed to occur exactly once, in which case we // are out of sync so we slip timing by half a bit if(count % 2 && out == previous) { //DEBUG_PIN_4= !DEBUG_PIN_4; // error LED on mLED_Error_On(); if(Manchester_Error) { //DEBUG_PIN_4= !DEBUG_PIN_4; // 2 strikes and we fail! count= 0L; previous= -1; Manchester_Auto_Correct= FALSE; stop_HW_reader_ISR(); return; } else { //DEBUG_PIN_4= !DEBUG_PIN_4; // 1st error - reset data and start again, now offset by a half bit. Manchester_Error= TRUE; //DEBUG_PIN_2= LOW; // special case - if tag can start with a '0' (i.e. there is no initial '1' as a sync // bit, it will look like a 1/2 bit error, but we may only detect the error later on, // so we must correct all the previous mis-reads, offset the count by 1/2 a bit and // complete this read if(Manchester_Auto_Correct && count != 1) { for(i= 0, p= EMU_Data ; i <= count / 2L ; ++i, --p) *p= !*(p); --count; } else { EMU_Data -= (count / 2L); count= 1L; // successful read resets timeout WriteTimer5(0); return; } } } } // now set data bit // biphase is 1 if mid-bit change or 0 if no mid-bit change if(RFIDlerConfig.BiPhase && count % 2L) { if(previous == out) *(EMU_Data++)= 0x00 ^ RFIDlerConfig.Invert; else *(EMU_Data++)= 0x01 ^ RFIDlerConfig.Invert; //DEBUG_PIN_1= *(EMU_Data - 1); // successful read resets timeout WriteTimer5(0); } // read data direct for normal ASK if(!RFIDlerConfig.Manchester && !RFIDlerConfig.BiPhase) { //DEBUG_PIN_1= out; *(EMU_Data++)= out ^ RFIDlerConfig.Invert; // successful read resets timeout WriteTimer5(0); } // read only 2nd half of bit if manchester if (RFIDlerConfig.Manchester && count % 2L) { //DEBUG_PIN_1= out; // always invert as we are now reading 2nd half bit, so opposite value *(EMU_Data++)= !(out ^ RFIDlerConfig.Invert); // successful read resets timeout WriteTimer5(0); } previous= out; break; case MOD_MODE_FSK1: case MOD_MODE_FSK2: // to read FSK we will measure a pulse width. we must stop before end of bit period so we don't // get caught by the next interrupt. accordingly our time period is shortened by 20%, but // that should be OK as we only need to see a single pulse. //DEBUG_PIN_4= !DEBUG_PIN_4; //time= CONVERT_TO_TICKS(RFIDlerConfig.FrameClock * (RFIDlerConfig.DataRate - (RFIDlerConfig.DataRate / 5))); time= RFIDlerConfig.FrameClock * (RFIDlerConfig.DataRate - (RFIDlerConfig.DataRate / 5)); GetTimer_us(RESET); // measure 2nd pulse while(GetTimer_us(NO_RESET) < time && !fskread) { fskread= TRUE; //DEBUG_PIN_4= !DEBUG_PIN_4; // skip to first pulse while(READER_DATA) if(GetTimer_us(NO_RESET) > time) { fskread= FALSE; break; } while(!READER_DATA) if(GetTimer_us(NO_RESET) > time) { fskread= FALSE; break; } // skip first pulse while(READER_DATA) if(GetTimer_us(NO_RESET) > time) { fskread= FALSE; break; } while(!READER_DATA) if(GetTimer_us(NO_RESET) > time) { fskread= FALSE; break; } // measure second pulse GetTimer_us(RESET); //DEBUG_PIN_4= !DEBUG_PIN_4; while(READER_DATA) if(GetTimer_us(NO_RESET) > time) { fskread= FALSE; break; } } //DEBUG_PIN_4= !DEBUG_PIN_4; // successful read resets timeout if(fskread) *(EMU_Data++)= GetTimer_us(RESET); // get pulsewidth in uS break; // TODO: PSK2, PSK3 case MOD_MODE_PSK1: // READER_DATA goes high when a phase change occurs // we toggle bit value on phase change // data line should go high at start of bit period, but to allow for some lag // we will wait for up to a full frame clock just to be sure time= CONVERT_TO_TICKS(RFIDlerConfig.FrameClock); WriteTimer5(0); while(ReadTimer5() < time) if(READER_DATA) break; // show toggle output //DEBUG_PIN_1 ^= READER_DATA; // get data out ^= (READER_DATA ^ RFIDlerConfig.Invert); // test read quality - pulsewidth wil be short if tag not correctly coupled if(PSK_Min_Pulse && READER_DATA) { // fast reset timer WriteTimer5(0); //DEBUG_PIN_1 ^= 1; while(READER_DATA) ; time= GetTimer_us(NO_RESET); if(time < PSK_Min_Pulse) PSK_Read_Error= 1; //DEBUG_PIN_1 ^= 1; } *(EMU_Data++)= out; // successful read resets timeout WriteTimer5(0); break; default: break; } ++count; // debugging - reset output line //DEBUG_PIN_2= LOW; // finished? if(count == HW_Bits) { HW_Bits= count= 0L; previous= -1; // if only 1 manchester error caught, that's OK Manchester_Error= FALSE; // caller must reset this to use again Manchester_Auto_Correct= FALSE; mLED_Error_Off(); // stop reading, but leave clock running to preserve tag state - higher level will shut down when done stop_HW_reader_ISR(); } }