www.pudn.com > rc500.rar > M500AuC.c
/////////////////////////////////////////////////////////////////////////////// // Copyright (c), Philips Semiconductors Gratkorn // // (C)PHILIPS Electronics N.V.2000 // All rights are reserved. Reproduction in whole or in part is // prohibited without the written consent of the copyright owner. // Philips reserves the right to make changes without notice at any time. // Philips makes no warranty, expressed, implied or statutory, including but // not limited to any implied warranty of merchantibility or fitness for any //particular purpose, or that the use will not infringe any third party patent, // copyright or trademark. Philips must not be liable for any loss or damage // arising from its use. /////////////////////////////////////////////////////////////////////////////// #define DLL_EXPORT // library source module definition #include#include #include #include #include #include #include //////////////////////////////////////////////////////////////////////////////// // M O D U L E D E F I N I T I O N //////////////////////////////////////////////////////////////////////////////// // COMMENT: This library module is modified from the original source code for a // microcontroller C164 CI, to suit the general purpose 8051 mcu. // The source can be ported to other platforms very easily. // The communication channel to the RC500 reader IC is assumed to be // unknown. All data is written with the generic IO functions // of the module ReaderIO.h. In our case the reader module is // connected via memory mapped io at base address 0x7f00. // The interrupt pin of the reader IC is assumed to be connected to // the fast external interrupt pin INT0# (active low) and the reset // pin of the reader IC should be connected to a dedicated port pin // (Port3: Pin: 3). // In this configuration, a reset of the reader module is independend // from the reset of the microcontroller. // In order to generate communication timeouts, // general purpose timer 2 of the microcontroller is used. This // timer need not to be initialised in advance. Before every usage // the timer is completely initialised in each function. // Non of the timers is essential for the functionality of the reader // module, but are helpful furing software development. All protocoll // relevant timing constraints are generated // by the internal timer of the reader module. // // Some explanations to the programming method of this library. // There are three kind of functions coded in this module. // a) internal functions, which have no prototypes in a header // file and are not intended to be used outside of this file // b) commands, which are intended for the reader module itself // c) commands, which are intended for any tag in the rf field. // These commands are send to the reader and the reader module // transmitts the data to the rf interface. // Commands for the reader and for the tag have the appropriate // prefix (PCD for proximity coupled device or reader module // PICC for proximity integrated circuit card or tag) // and their protypes are defined in the header file. // Each command for a PICC consists of a PCD command. Therefore // the function M500PcdCmd is very important for the understanding // of the communication. // // The basic functionality is provided by the interrupt service // routine (ISR), which closely works together with the function // M500PcdCmd. All kinds of interrupts are serviced by the // same ISR. // inline structure in order to reset the communication channel between // function and ISR #define ResetInfo(info) \ info.cmd = 0; \ info.status = MI_OK;\ info.irqSource = 0; \ info.nBytesSent = 0; \ info.nBytesToSend = 0; \ info.nBytesReceived = 0; \ info.nBitsReceived = 0; \ info.collPos = 0; // struct definition for a communication channel between function and ISR typedef struct { unsigned char cmd; //!< command code char status; // communication status unsigned char nBytesSent; // how many bytes already sent unsigned char nBytesToSend; // how many bytes to send unsigned char nBytesReceived;// how many bytes received unsigned short nBitsReceived; // how many bits received unsigned char irqSource; // which interrupts have occured unsigned char collPos; // at which position occured a // collision } MfCmdInfo; // modul variables extern unsigned char xdata *GpBase; static unsigned char idata MFIFOLength = DEF_FIFO_LENGTH; // actual FIFO length static unsigned char xdata MKeys[16][12]; // storage for authentication keys // in order to provide a calling // compatible interface to old libraries // Other reader modules keep several sets // of keys in an E2PROM. In this case, // these keys are stored in the uC and // transfered to the reader module // before authentication // Infomation concerning data processing // send buffer for general use static volatile unsigned char xdata MSndBuffer[SND_BUF_LEN]; // receive buffer for general use static volatile unsigned char xdata MRcvBuffer[RCV_BUF_LEN]; // info struct for general use static volatile MfCmdInfo MInfo; // Interrupt service routine // Variable in order to exchange data between function and ISR static volatile MfCmdInfo *MpIsrInfo = 0; // ISR send buffer static volatile unsigned char *MpIsrOut = 0; // ISR receive buffer static volatile unsigned char *MpIsrIn = 0; // storage of the last selected serial number including check byte. //For multi level serial numbers, only the first 4 bytes are stored. unsigned char MLastSelectedSnr[5]; // Timer 2 bit T2IR = 0; // Timer2 timeout flag unsigned int CountDown = 0; // Timeout counter with 50us resolution sbit RC500RST = P3^5; sbit LED = P3^4; /////////////////////////////////////////////////////////////////////////////// // Prototypes for local functions /////////////////////////////////////////////////////////////////////////////// void start_timeout(unsigned int _50us); void stop_timeout(void); // _____________________________________________________________________________ // // FUNCTION: M500PcdSetTmo // IN: tmoLength 1 ... 1.0 ms timeout periode // 2 ... 1.5 ms timeout periode // 3 ... 6.0 ms timeout periode // 4 ... 9.6 ms timeout period // 5 ... 38.5 ms timeout period // 6 ... 154 ms timeout period // 7 ... 616.2 ms timeout period // OUT: - // RETURN: // COMMENT: Set timeout length of the reader internal timer. // void M500PcdSetTmo(unsigned char tmoLength); // _____________________________________________________________________________ // // FUNCTION: M500PcdCmd // IN: cmd PCD_IDLE // PCD_WRITEE2 // PCD_READE2 // PCD_LOADCONFIG // PCD_LOADKEYE2 // PCD_AUTHENT1 // PCD_CALCCRC // PCD_AUTHENT2 // PCD_RECEIVE // PCD_LOADKEY // PCD_TRANSMIT // PCD_TRANSCEIVE // PCD_RESETPHASE // for a detailed description of the parameter values, please // have a look on the header file of the reader register // definitions. // send byte stream of variable length, which should be send to // the PICC, the length of stream has to be specified // in the info - structure // OUT: rcv byte stream of variable length, which was received // from the PICC or PCD // info communication and status structure // RETURN: // COMMENT: This function provides the central interface to the reader module. // Depending on the "cmd"-value, all necessary interrupts are enabled // and the communication is started. While the processing is done by // the reader module, this function waits for its completion. // It's notable, that the data in the "send byte stream" is written // to the FIFO of the reader module by the ISR. Immediate after // enabling the interrupts, the LoAlert interrupt is activated. // The ISR writes the data to the FIFO. This function is not involved // in writing or fetching data from FIFO, all work is done by the // ISR.After command completion, the error status is evaluated and // returned to the calling function. // char M500PcdCmd(unsigned char cmd, volatile unsigned char* send, volatile unsigned char* rcv, volatile MfCmdInfo *info); // _____________________________________________________________________________ // // FUNCTION: SetBitMask // IN: reg register address // mask bit mask to set // OUT: - // RETURN: // COMMENT: This function performs a read - modify - write sequence // on the specified register. All bits with a 1 in the mask // are set - all other bits keep their original value. // char SetBitMask(unsigned char reg,unsigned char mask); // _____________________________________________________________________________ // // FUNCTION: ClearBitMask // IN: reg register address // mask bit mask to clear // OUT: - // RETURN: // COMMENT: This function performs a read - modify - write sequence // on the specified register. All bits with a 1 in the mask // are cleared - all other bits keep their original value. // char ClearBitMask(unsigned char reg,unsigned char mask); // _____________________________________________________________________________ // // FUNCTION: FlushFIFO // IN: - // OUT: - // RETURN: // COMMENT: All remaining date in the FIFO of the reader module is // erased by this function. Before wrinting new data or // starting a new command, all remaining data from former // commands should be deleted. Please note, that in // normal operation, never data should be left, that means // that a call to this function should not be necessary. // void FlushFIFO(void); // _____________________________________________________________________________ // // FUNCTION: M500PiccAuthState // IN: auth_mode // snr // sector // OUT: - // RETURN: // COMMENT: // char M500PiccAuthState(unsigned char auth_mode,// PICC_AUTHENT1A, PICC_AUTHENT1B unsigned char *snr, // 4 byte serial number unsigned char sector); // 0 <= sector <= 15 // sector address for authentication ////////////////////////////////////////////////////////////////////// // E X C H A N G E B Y T E S T R E A M /////////////////////////////////////////////////////////////////////// char ExchangeByteStream(unsigned char Cmd, unsigned char *send_data, unsigned char send_bytelen, unsigned char *rec_data, unsigned char *rec_bytelen); /////////////////////////////////////////////////////////////////////////////// // Interrupt Handler RC500 /////////////////////////////////////////////////////////////////////////////// void RC500ISR (void) interrupt 0 using 1 //Ext0 interrupt { static unsigned char idata irqBits; static unsigned char idata irqMask; static unsigned char idata nbytes; static unsigned char idata cnt; IE0 = 0; // Clear interrupt request flag if (MpIsrInfo && MpIsrOut && MpIsrIn) // transfer pointers have to be set // correctly { while( ReadRawIO(RegPrimaryStatus) & 0x08) // loop while IRQ pending // Attention: IRQ bit is // inverted when used with // low activ IRQ { irqMask = ReadRawIO(RegInterruptEn); // read enabled interrupts // read pending interrupts irqBits = ReadRawIO(RegInterruptRq) & irqMask; MpIsrInfo->irqSource |= irqBits; // save pending interrupts //************ LoAlertIRQ ****************** if (irqBits & 0x01) // LoAlert { nbytes = MFIFOLength - ReadRawIO(RegFIFOLength); // less bytes to send, than space in FIFO if ((MpIsrInfo->nBytesToSend - MpIsrInfo->nBytesSent) <= nbytes) { nbytes = MpIsrInfo->nBytesToSend - MpIsrInfo->nBytesSent; WriteRawIO(RegInterruptEn,0x01); // disable LoAlert IRQ } // write remaining data to the FIFO for ( cnt = 0;cnt < nbytes;cnt++) { WriteRawIO(RegFIFOData,MpIsrOut[MpIsrInfo->nBytesSent]); MpIsrInfo->nBytesSent++; } WriteRawIO(RegInterruptRq,0x01); // reset IRQ bit } //************* TxIRQ Handling ************** if (irqBits & 0x10) // TxIRQ { WriteRawIO(RegInterruptRq,0x10); // reset IRQ bit WriteRawIO(RegInterruptEn,0x82); // enable HiAlert Irq for // response if (MpIsrInfo->cmd == PICC_ANTICOLL1) // if cmd is anticollision { // switch off parity generation WriteRawIO(RegChannelRedundancy,0x02); // RXCRC and TXCRC disable, parity disable } } //************* HiAlertIRQ or RxIRQ Handling ****************** if (irqBits & 0x0E) // HiAlert, Idle or RxIRQ { // read some bytes ( length of FIFO queue) // into the receive buffer nbytes = ReadRawIO(RegFIFOLength); // read date from the FIFO and store them in the receive buffer for ( cnt = 0; cnt < nbytes; cnt++) { MpIsrIn[MpIsrInfo->nBytesReceived] = ReadRawIO(RegFIFOData); MpIsrInfo->nBytesReceived++; } WriteRawIO(RegInterruptRq,0x0A & irqBits); // reset IRQ bit - idle irq will // be deleted in a seperate section } //************** IdleIRQ Handling *********** if (irqBits & 0x04) // Idle IRQ { WriteRawIO(RegInterruptEn,0x20); // disable Timer IRQ WriteRawIO(RegInterruptRq,0x20); // disable Timer IRQ request irqBits &= ~0x20; // clear Timer IRQ in local var MpIsrInfo->irqSource &= ~0x20; // clear Timer IRQ in info var // when idle received, then cancel // timeout WriteRawIO(RegInterruptRq,0x04); // reset IRQ bit // status should still be MI_OK // no error - only used for wake up } //************* TimerIRQ Handling *********** if (irqBits & 0x20) // timer IRQ { WriteRawIO(RegInterruptRq,0x20); // reset IRQ bit MpIsrInfo->status = MI_NOTAGERR; // timeout error // otherwise ignore the interrupt } } } } /////////////////////////////////////////////////////////////////////// // S e t T i m e o u t L E N G T H /////////////////////////////////////////////////////////////////////// void M500PcdSetTmo(unsigned char tmoLength) { switch(tmoLength) { // timer clock frequency 13,56 MHz case 1: // short timeout (1,0 ms) WriteIO(RegTimerClock,0x07); // TAutoRestart=0,TPrescale=128 WriteIO(RegTimerReload,0x6a);// TReloadVal = 'h6a =106(dec) break; case 2: // medium timeout (1,5 ms) WriteIO(RegTimerClock,0x07); // TAutoRestart=0,TPrescale=128 WriteIO(RegTimerReload,0xa0);// TReloadVal = 'ha0 =160(dec) break; case 3: // medium timeout (6 ms) WriteIO(RegTimerClock,0x09); // TAutoRestart=0,TPrescale=4*128 WriteIO(RegTimerReload,0xa0);// TReloadVal = 'ha0 =160(dec) break; case 4: // long timeout (9.6 ms) WriteIO(RegTimerClock,0x09); // TAutoRestart=0,TPrescale=4*128 WriteIO(RegTimerReload,0xff);// TReloadVal = 'hff =255(dec) break; case 5: // long timeout (38.5 ms) WriteIO(RegTimerClock,0x0b); // TAutoRestart=0,TPrescale=16*128 WriteIO(RegTimerReload,0xff);// TReloadVal = 'hff =255(dec) break; case 6: // long timeout (154 ms) WriteIO(RegTimerClock,0x0d); // TAutoRestart=0,TPrescale=64*128 WriteIO(RegTimerReload,0xff);// TReloadVal = 'hff =255(dec) break; case 7: // long timeout (616.2 ms) WriteIO(RegTimerClock,0x0f); // TAutoRestart=0,TPrescale=256*128 WriteIO(RegTimerReload,0xff);// TReloadVal = 'hff =255(dec) break; default: // WriteIO(RegTimerClock,0x07); // TAutoRestart=0,TPrescale=128 WriteIO(RegTimerReload,tmoLength);// TReloadVal = 'h6a =tmoLength(dec) break; } } ////////////////////////////////////////////////////////////////////// // W R I T E A P C D C O M M A N D /////////////////////////////////////////////////////////////////////// char M500PcdCmd(unsigned char cmd, volatile unsigned char* send, volatile unsigned char* rcv, volatile MfCmdInfo *info) { char idata status = MI_OK; char idata tmpStatus ; unsigned char idata lastBits; unsigned char idata irqEn = 0x00; unsigned char idata waitFor = 0x00; unsigned char idata timerCtl = 0x00; WriteIO(RegInterruptEn,0x7F); // disable all interrupts WriteIO(RegInterruptRq,0x7F); // reset interrupt requests WriteIO(RegCommand,PCD_IDLE); // terminate probably running command FlushFIFO(); // flush FIFO buffer // save info structures to module pointers MpIsrInfo = info; MpIsrOut = send; MpIsrIn = rcv; info->irqSource = 0x0; // reset interrupt flags // depending on the command code, appropriate interrupts are enabled (irqEn) // and the commit interrupt is choosen (waitFor). switch(cmd) { case PCD_IDLE: // nothing else required irqEn = 0x00; waitFor = 0x00; break; case PCD_WRITEE2: // LoAlert and TxIRq irqEn = 0x11; waitFor = 0x10; break; case PCD_READE2: // HiAlert, LoAlert and IdleIRq irqEn = 0x07; waitFor = 0x04; break; case PCD_LOADCONFIG: // IdleIRq case PCD_LOADKEYE2: // IdleIRq case PCD_AUTHENT1: // IdleIRq irqEn = 0x05; waitFor = 0x04; break; case PCD_CALCCRC: // LoAlert and TxIRq irqEn = 0x11; waitFor = 0x10; break; case PCD_AUTHENT2: // IdleIRq irqEn = 0x04; waitFor = 0x04; break; case PCD_RECEIVE: // HiAlert and IdleIRq info->nBitsReceived = -(ReadIO(RegBitFraming) >> 4); irqEn = 0x06; waitFor = 0x04; break; case PCD_LOADKEY: // IdleIRq irqEn = 0x05; waitFor = 0x04; break; case PCD_TRANSMIT: // LoAlert and IdleIRq irqEn = 0x05; waitFor = 0x04; break; case PCD_TRANSCEIVE: // TxIrq, RxIrq, IdleIRq and LoAlert info->nBitsReceived = -(ReadIO(RegBitFraming) >> 4); irqEn = 0x3D; waitFor = 0x04; break; default: status = MI_UNKNOWN_COMMAND; } if (status == MI_OK) { // Initialize uC Timer for global Timeout management irqEn |= 0x20; // always enable timout irq waitFor |= 0x20; // always wait for timeout start_timeout(4000); // initialise and start guard timer for reader // 50us resolution, 200ms WriteIO(RegInterruptEn,irqEn | 0x80); //necessary interrupts are enabled WriteIO(RegCommand,cmd); //start command // wait for commmand completion // a command is completed, if the corresponding interrupt occurs // or a timeout is signaled while (!(MpIsrInfo->irqSource & waitFor || T2IR)); // wait for cmd completion or timeout WriteIO(RegInterruptEn,0x7F); // disable all interrupts WriteIO(RegInterruptRq,0x7F); // clear all interrupt requests SetBitMask(RegControl,0x04); // stop timer now stop_timeout(); // stop timeout for reader WriteIO(RegCommand,PCD_IDLE); // reset command register if (!(MpIsrInfo->irqSource & waitFor)) // reader has not terminated { // timer 2 expired status = MI_ACCESSTIMEOUT; } else status = MpIsrInfo->status; // set status if (status == MI_OK) // no timeout error occured { if (tmpStatus = (ReadIO(RegErrorFlag) & 0x17)) // error occured { if (tmpStatus & 0x01) // collision detected { info->collPos = ReadIO(RegCollpos); // read collision position status = MI_COLLERR; } else { info->collPos = 0; if (tmpStatus & 0x02) // parity error { status = MI_PARITYERR; } } if (tmpStatus & 0x04) // framing error { status = MI_FRAMINGERR; } if (tmpStatus & 0x10) // FIFO overflow { FlushFIFO(); status = MI_OVFLERR; } if (tmpStatus & 0x08) //CRC error { status = MI_CRCERR; } if (status == MI_OK) status = MI_NY_IMPLEMENTED; // key error occures always, because of // missing crypto 1 keys loaded } // if the last command was TRANSCEIVE, the number of // received bits must be calculated - even if an error occured if (cmd == PCD_TRANSCEIVE) { // number of bits in the last byte lastBits = ReadIO(RegSecondaryStatus) & 0x07; if (lastBits) info->nBitsReceived += (info->nBytesReceived-1) * 8 + lastBits; else info->nBitsReceived += info->nBytesReceived * 8; } } else { info->collPos = 0x00; } } MpIsrInfo = 0; // reset interface variables for ISR MpIsrOut = 0; MpIsrIn = 0; return status; } ////////////////////////////////////////////////////////////////////// // S E T A B I T M A S K /////////////////////////////////////////////////////////////////////// char SetBitMask(unsigned char reg,unsigned char mask) // { char idata tmp = 0x0; tmp = ReadIO(reg); WriteIO(reg,tmp | mask); // set bit mask return 0x0; } ////////////////////////////////////////////////////////////////////// // C L E A R A B I T M A S K /////////////////////////////////////////////////////////////////////// char ClearBitMask(unsigned char reg,unsigned char mask) // { char idata tmp = 0x0; tmp = ReadIO(reg); WriteIO(reg,tmp & ~mask); // clear bit mask return 0x0; } /////////////////////////////////////////////////////////////////////// // F L U S H F I F O /////////////////////////////////////////////////////////////////////// void FlushFIFO(void) { SetBitMask(RegControl,0x01); } /////////////////////////////////////////////////////////////////////// // M I F A R E M O D U L E R E S E T /////////////////////////////////////////////////////////////////////// char M500PcdReset(void) { char idata status = MI_OK; RC500RST = 0; // clear reset pin delay_1ms(25); // wait for 25ms RC500RST = 1; // reset RC500 delay_50us(50); // wait for 2.5ms RC500RST = 0; // clear reset pin start_timeout(42000); // count down with a period of 50 us // 42000 * 50 us = 2.1 s // wait until reset command recognized while (((ReadRawIO(RegCommand) & 0x3F) != 0x3F) && !T2IR); // while reset sequence in progress while ((ReadRawIO(RegCommand) & 0x3F) && !T2IR); stop_timeout(); // stop timeout counter if (T2IR) // If reader timeout occurs { status = MI_RESETERR; // respose of reader IC is not correct T2IR = 0; } else { WriteRawIO(RegPage,0x80); // Dummy access in order to determine the bus // configuration // necessary read access // after first write access, the returned value // should be zero ==> interface recognized if (ReadRawIO(RegCommand) != 0x00) { status = MI_INTERFACEERR; } WriteRawIO(RegPage,0x00); // configure to linear address mode } return status; } /////////////////////////////////////////////////////////////////////// // M I F A R E M O D U L E C O N F I G U R A T I O N /////////////////////////////////////////////////////////////////////// char M500PcdConfig(void) { char idata status; char idata i; char idata j; if ((status = M500PcdReset()) == MI_OK) { // test clock Q calibration - value in the range of 0x46 expected WriteIO(RegClockQControl,0x0); WriteIO(RegClockQControl,0x40); delay_50us(2); // wait approximately 100 us - calibration in progress ClearBitMask(RegClockQControl,0x40); // clear bit ClkQCalib for // further calibration // The following values for RegBitPhase and // RegRxThreshold represents an optimal // value for our demo package. For user // implementation some changes could be // necessary // initialize bit phase WriteIO(RegBitPhase,0xAD); // initialize minlevel WriteIO(RegRxThreshold,0xFF); // disable auto power down WriteIO(RegRxControl2,0x01); // Depending on the processing speed of the // operation environment, the waterlevel // can be adapted. (not very critical for // mifare applications) // initialize waterlevel to value 4 WriteIO(RegFIFOLevel,0x04); //Timer configuration WriteIO(RegTimerControl,0x02); // TStopRxEnd=0,TStopRxBeg=0, // TStartTxEnd=1,TStartTxBeg=0 // timer must be stopped manually M500PcdSetTmo(1); // short timeout WriteIO(RegIRqPinConfig,0x03); // interrupt active low enable M500PcdRfReset(1); // Rf - reset and enable output driver // initialize internal key memory for (i = 0; i < 16; i++) for (j = 0; j < 12; j++) MKeys[i][j] = 0xff; } return status; } /////////////////////////////////////////////////////////////////////// // M I F A R E R E M O T E A N T E N N A // Configuration of slave module /////////////////////////////////////////////////////////////////////// char M500PcdMfInOutSlaveConfig(void) { char idata status = MI_OK; FlushFIFO(); // empty FIFO ResetInfo(MInfo); MSndBuffer[0] = 0x10; // addr low byte MSndBuffer[1] = 0x00; // addr high byte MSndBuffer[2] = 0x00; // Page MSndBuffer[3] = 0x7B; // RegTxControl modsource 11,InvTx2,Tx2RFEn,TX1RFEn MSndBuffer[4] = 0x3F; // RegCwConductance MSndBuffer[5] = 0x3F; // RFU13 MSndBuffer[6] = 0x19; // RFU14 MSndBuffer[7] = 0x13; // RegModWidth MSndBuffer[8] = 0x00; // RFU16 MSndBuffer[9] = 0x00; // RFU17 MSndBuffer[10] = 0x00; // Page MSndBuffer[11] = 0x73; // RegRxControl1 MSndBuffer[12] = 0x08; // RegDecoderControl MSndBuffer[13] = 0x6c; // RegBitPhase MSndBuffer[14] = 0xFF; // RegRxThreshold MSndBuffer[15] = 0x00; // RFU1D MSndBuffer[16] = 0x00; // RegRxControl2 MSndBuffer[17] = 0x00; // RegClockQControl MSndBuffer[18] = 0x00; // Page MSndBuffer[19] = 0x06; // RegRxWait MSndBuffer[20] = 0x03; // RegChannelRedundancy MSndBuffer[21] = 0x63; // RegCRCPresetLSB MSndBuffer[22] = 0x63; // RegCRCPresetMSB MSndBuffer[23] = 0x0; // RFU25 MSndBuffer[24] = 0x04; // RegMfOutSelect enable mfout = manchester HT MSndBuffer[25] = 0x00; // RFU27 // PAGE 5 FIFO, Timer and IRQ-Pin Configuration MSndBuffer[26] = 0x00; // Page MSndBuffer[27] = 0x08; // RegFIFOLevel MSndBuffer[28] = 0x07; // RegTimerClock MSndBuffer[29] = 0x06; // RegTimerControl MSndBuffer[30] = 0x0A; // RegTimerReload MSndBuffer[31] = 0x02; // RegIRqPinConfig MSndBuffer[32] = 0x00; // RFU MSndBuffer[33] = 0x00; // RFU MInfo.nBytesToSend = 34; status = M500PcdCmd(PCD_WRITEE2, MSndBuffer, MRcvBuffer, &MInfo); // write e2 return status; } /////////////////////////////////////////////////////////////////////// // M I F A R E R E M O T E A N T E N N A // Configuration of master module /////////////////////////////////////////////////////////////////////// char M500PcdMfInOutMasterConfig(void) { WriteIO(RegRxControl2,0x42); WriteIO(RegTxControl,0x10); WriteIO(RegBitPhase,0x11); return MI_OK; } /////////////////////////////////////////////////////////////////////// // M A S T E R K E Y L O A D /////////////////////////////////////////////////////////////////////// char M500PcdLoadMk(unsigned char auth_mode, // KEYA or KEYB unsigned char key_addr, // 0 <= key_addr <= 15 unsigned char *mk) // 6 bytes uncoded master key { unsigned char idata offset = (auth_mode == PICC_AUTHENT1A) ? 0 : 6; memcpy(MKeys[key_addr] + offset,mk,6); return MI_OK; } /////////////////////////////////////////////////////////////////////// // E E P R O M M A S T E R K E Y L O A D /////////////////////////////////////////////////////////////////////// char M500PcdLoadKeyE2(unsigned char key_type, unsigned char sector, unsigned char *uncoded_keys) { char idata status = MI_OK; // eeprom address calculation // 0x80 ... offset // key_sector ... sector // 0x18 ... 2 * 12 = 24 = 0x18 unsigned short idata e2addr = 0x80 + sector * 0x18; unsigned char idata *e2addrbuf = (unsigned char*)&e2addr; unsigned char idata keycoded[12]; if (key_type == PICC_AUTHENT1B) e2addr += 12; // key B offset FlushFIFO(); // empty FIFO ResetInfo(MInfo); M500HostCodeKey(uncoded_keys,keycoded); memcpy(MSndBuffer,e2addrbuf,2); // write low and high byte of address MSndBuffer[2] = MSndBuffer[0]; // Move the LSB of the 2-bytes MSndBuffer[0] = MSndBuffer[1]; // address to the first byte MSndBuffer[1] = MSndBuffer[2]; memcpy(&MSndBuffer[2],keycoded,12); // write 12 bytes of coded keys MInfo.nBytesToSend = 14; // write load command status = M500PcdCmd(PCD_WRITEE2, MSndBuffer, MRcvBuffer, &MInfo); return status; } /////////////////////////////////////////////////////////////////////// // E E P R O M R E A D /////////////////////////////////////////////////////////////////////// char PcdReadE2(unsigned short startaddr, unsigned char length, unsigned char* _data) { char status = MI_OK; // ************* Cmd Sequence ********************************** ResetInfo(MInfo); MSndBuffer[0] = startaddr & 0xFF; MSndBuffer[1] = (startaddr >> 8) & 0xFF; MSndBuffer[2] = length; MInfo.nBytesToSend = 3; status = M500PcdCmd(PCD_READE2, MSndBuffer, MRcvBuffer, &MInfo); if (status == MI_OK) { memcpy(_data,MRcvBuffer,length); } else // Response Processing { _data[0] = 0; } return status ; } /////////////////////////////////////////////////////////////////////// // E E P R O M W R I T E /////////////////////////////////////////////////////////////////////// char PcdWriteE2(unsigned short startaddr, unsigned char length, unsigned char* _data) { char status = MI_OK; // ************* Cmd Sequence ********************************** ResetInfo(MInfo); MSndBuffer[0] = startaddr & 0xFF; MSndBuffer[1] = (startaddr >> 8) & 0xFF; memcpy(MSndBuffer + 2,_data,length); MInfo.nBytesToSend = length + 2; status = M500PcdCmd(PCD_WRITEE2, MSndBuffer, MRcvBuffer, &MInfo); // write e2 return status; } /////////////////////////////////////////////////////////////////////// // C O N F I G M F O U T S E L E C T /////////////////////////////////////////////////////////////////////// char M500PcdMfOutSelect(unsigned char type) { WriteIO(RegMfOutSelect,type&0x7); return MI_OK; } /////////////////////////////////////////////////////////////////////// // W R I T E R E G I S T E R /////////////////////////////////////////////////////////////////////// char M500PcdWriteRegister(unsigned char Reg, unsigned char value) { WriteIO(Reg,value); return MI_OK; } /////////////////////////////////////////////////////////////////////// // R E A D R E G I S T E R /////////////////////////////////////////////////////////////////////// char M500PcdReadRegister(unsigned char Reg) { char value; value = ReadIO(Reg); return (value); } /////////////////////////////////////////////////////////////////////// // M I F A R E R E Q U E S T /////////////////////////////////////////////////////////////////////// char M500PiccRequest(unsigned char req_code, // request code ALL = 0x52 // or IDLE = 0x26 unsigned char *atq) // answer to request { return M500PiccCommonRequest(req_code,atq); } /////////////////////////////////////////////////////////////////////// // M I F A R E C O M M O N R E Q U E S T /////////////////////////////////////////////////////////////////////// char M500PiccCommonRequest(unsigned char req_code, unsigned char *atq) { char idata status = MI_OK; //************* initialize ****************************** WriteIO(RegChannelRedundancy,0x03); // RxCRC and TxCRC disable, parity enable ClearBitMask(RegControl,0x08); // disable crypto 1 unit WriteIO(RegBitFraming,0x07); // set TxLastBits to 7 SetBitMask(RegTxControl,0x03); // Tx2RF-En, Tx1RF-En enable ResetInfo(MInfo); MSndBuffer[0] = req_code; MInfo.nBytesToSend = 1; status = M500PcdCmd(PCD_TRANSCEIVE, MSndBuffer, MRcvBuffer, &MInfo); if (status) // error occured { *atq = 0; } else { if (MInfo.nBitsReceived != 16) // 2 bytes expected { *atq = 0; status = MI_BITCOUNTERR; } else { status = MI_OK; memcpy(atq,MRcvBuffer,2); } } return status; } /////////////////////////////////////////////////////////////////////// // M I F A R E A N T I C O L L I S I O N // for standard select /////////////////////////////////////////////////////////////////////// char M500PiccAnticoll (unsigned char bcnt, unsigned char *snr) { return M500PiccCascAnticoll(0x93,bcnt,snr); // first cascade level } /////////////////////////////////////////////////////////////////////// // M I F A R E A N T I C O L L I S I O N // for extended serial numbers /////////////////////////////////////////////////////////////////////// char M500PiccCascAnticoll (unsigned char select_code, unsigned char bcnt, unsigned char *snr) { char idata status = MI_OK; char idata snr_in[4]; // copy of the input parameter snr char idata nbytes = 0; char idata nbits = 0; char idata complete = 0; char idata i = 0; char idata byteOffset = 0; unsigned char idata snr_crc; unsigned char idata snr_check; unsigned char dummyShift1; // dummy byte for snr shift unsigned char dummyShift2; // dummy byte for snr shift //************* Initialisation ****************************** M500PcdSetTmo(106); memcpy(snr_in,snr,4); WriteIO(RegDecoderControl,0x28); // ZeroAfterColl aktivieren ClearBitMask(RegControl,0x08); // disable crypto 1 unit //************** Anticollision Loop *************************** complete = 0; // bcnt = 0; // no part of the snr is known while (!complete && (status == MI_OK) ) { ResetInfo(MInfo); WriteIO(RegChannelRedundancy,0x03); // RxCRC and TxCRC disable, parity enable nbits = bcnt % 8; // remaining number of bits if (nbits) { WriteIO(RegBitFraming,nbits << 4 | nbits); // TxLastBits/RxAlign auf nb_bi nbytes = bcnt / 8 + 1; // number of bytes known // in order to solve an inconsistancy in the anticollision sequence // (will be solved soon), the case of 7 bits has to be treated in a // separate way - please note the errata sheet if (nbits == 7) { MInfo.cmd = PICC_ANTICOLL1; // pass command flag to ISR WriteIO(RegBitFraming,nbits); // reset RxAlign to zero } } else { nbytes = bcnt / 8; } MSndBuffer[0] = select_code; MSndBuffer[1] = 0x20 + ((bcnt/8) << 4) + nbits; //number of bytes send for (i = 0; i < nbytes; i++) // Sende Buffer beschreiben { MSndBuffer[i + 2] = snr_in[i]; } MInfo.nBytesToSend = 2 + nbytes; status = M500PcdCmd(PCD_TRANSCEIVE, MSndBuffer, MRcvBuffer, &MInfo); // in order to solve an inconsistancy in the anticollision sequence // (will be solved soon), the case of 7 bits has to be treated in a // separate way if (nbits == 7) { // reorder received bits dummyShift1 = 0x00; for (i = 0; i < MInfo.nBytesReceived; i++) { dummyShift2 = MRcvBuffer[i]; MRcvBuffer[i] = (dummyShift1 >> (i+1)) | (MRcvBuffer[i] << (7-i)); dummyShift1 = dummyShift2; } MInfo.nBitsReceived -= MInfo.nBytesReceived; // subtract received parity bits // recalculation of collision position if ( MInfo.collPos ) MInfo.collPos += 7 - (MInfo.collPos + 6) / 9; } if ( status == MI_OK || status == MI_COLLERR) // no other occured { // R e s p o n s e P r o c e s s i n g if ( MInfo.nBitsReceived != (40 - bcnt) ) // not 5 bytes answered { status = MI_BITCOUNTERR; // Exit with error } else { byteOffset = 0; if( nbits != 0 ) // last byte was not complete { snr_in[nbytes - 1] = snr_in[nbytes - 1] | MRcvBuffer[0]; byteOffset = 1; } for ( i =0; i < (4 - nbytes); i++) { snr_in[nbytes + i] = MRcvBuffer[i + byteOffset]; } if (status != MI_COLLERR ) // no error and no collision { // SerCh check snr_crc = snr_in[0] ^ snr_in[1] ^ snr_in[2] ^ snr_in[3]; snr_check = MRcvBuffer[MInfo.nBytesReceived - 1]; if (snr_crc != snr_check) { status = MI_SERNRERR; } else { complete = 1; } } else // collision occured { bcnt = bcnt + MInfo.collPos - nbits; status = MI_OK; } } } } if (status == MI_OK) { // transfer snr_in to snr memcpy(snr,snr_in,4); } else { memcpy(snr,"0000",4); } //----------------------Einstellungen aus Initialisierung ruecksetzen ClearBitMask(RegDecoderControl,0x20); // ZeroAfterColl disable return status; } /////////////////////////////////////////////////////////////////////// // M I F A R E S E L E C T // for std. select /////////////////////////////////////////////////////////////////////// char M500PiccSelect(unsigned char *snr, unsigned char *sak) { return M500PiccCascSelect(0x93,snr,sak); // first cascade level } /////////////////////////////////////////////////////////////////////// // M I F A R E C A S C A D E D S E L E C T // for extended serial number /////////////////////////////////////////////////////////////////////// char M500PiccCascSelect(unsigned char select_code, unsigned char *snr, unsigned char *sak) { char idata status = MI_OK; M500PcdSetTmo(106); WriteIO(RegChannelRedundancy,0x0F); // RxCRC,TxCRC, Parity enable ClearBitMask(RegControl,0x08); // disable crypto 1 unit //************* Cmd Sequence ********************************** ResetInfo(MInfo); MSndBuffer[0] = select_code; MSndBuffer[1] = 0x70; // number of bytes send memcpy(MSndBuffer + 2,snr,4); MSndBuffer[6] = MSndBuffer[2] ^ MSndBuffer[3] ^ MSndBuffer[4] ^ MSndBuffer[5]; MInfo.nBytesToSend = 7; status = M500PcdCmd(PCD_TRANSCEIVE, MSndBuffer, MRcvBuffer, &MInfo); *sak = 0; if (status == MI_OK) // no timeout occured { if (MInfo.nBitsReceived != 8) // last byte is not complete { status = MI_BITCOUNTERR; } else { *sak = MRcvBuffer[0]; memcpy(MLastSelectedSnr,snr,4); } } return status; } /////////////////////////////////////////////////////////////////////// // M I F A R E A U T H E N T I C A T I O N // calling compatible version /////////////////////////////////////////////////////////////////////// char M500PiccAuth(unsigned char keyAB, // KEYA or KEYB unsigned char *snr, // 4 bytes card serial number unsigned char key_addr, // key address in reader storage unsigned char block) // block number which should be // authenticated { char idata status = MI_OK; unsigned char xdata * key = 0; unsigned char idata keycoded[12]; unsigned char idata offset = (keyAB == PICC_AUTHENT1A) ? 0 : 6; key = MKeys[key_addr] + offset; M500HostCodeKey(key,keycoded); status = M500PiccAuthKey(keyAB, snr, keycoded, block); return status; } /////////////////////////////////////////////////////////////////////// // A U T H E N T I C A T I O N // W I T H K E Y S F R O M E 2 P R O M /////////////////////////////////////////////////////////////////////// char M500PiccAuthE2( unsigned char auth_mode, // KEYA, KEYB unsigned char *snr, // 4 bytes card serial number unsigned char key_sector, // key address in reader storage, // 0 <= key_sector <= 15 unsigned char block) // block number which should be // authenticated // 0 <= block <= 256 { char idata status = MI_OK; // eeprom address calculation // 0x80 ... offset // key_sector ... sector // 0x18 ... 2 * 12 = 24 = 0x18 unsigned short e2addr = 0x80 + key_sector * 0x18; unsigned char *e2addrbuf = (unsigned char*)&e2addr; if (auth_mode == PICC_AUTHENT1B) e2addr += 12; // key B offset FlushFIFO(); // empty FIFO ResetInfo(MInfo); memcpy(MSndBuffer,e2addrbuf,2); // write low and high byte of address MSndBuffer[2] = MSndBuffer[0]; // Move the LSB of the 2-bytes MSndBuffer[0] = MSndBuffer[1]; // address to the first byte MSndBuffer[1] = MSndBuffer[2]; MInfo.nBytesToSend = 2; // write load command if ((status=M500PcdCmd(PCD_LOADKEYE2,MSndBuffer,MRcvBuffer,&MInfo)) == MI_OK) { // execute authentication status = M500PiccAuthState(auth_mode,snr,block); } return status; } /////////////////////////////////////////////////////////////////////// // C O D E K E Y S /////////////////////////////////////////////////////////////////////// char M500HostCodeKey( unsigned char *uncoded, // 6 bytes key value uncoded unsigned char *coded) // 12 bytes key value coded { char idata status = MI_OK; unsigned char idata cnt = 0; unsigned char idata ln = 0; // low nibble unsigned char idata hn = 0; // high nibble for (cnt = 0; cnt < 6; cnt++) { ln = uncoded[cnt] & 0x0F; hn = uncoded[cnt] >> 4; coded[cnt * 2 + 1] = (~ln << 4) | ln; coded[cnt * 2 ] = (~hn << 4) | hn; } return MI_OK; } /////////////////////////////////////////////////////////////////////// // A U T H E N T I C A T I O N // W I T H P R O V I D E D K E Y S /////////////////////////////////////////////////////////////////////// char M500PiccAuthKey( unsigned char auth_mode, unsigned char *snr, unsigned char *keys, unsigned char block) { char idata status = MI_OK; unsigned char idata i = 0; FlushFIFO(); // empty FIFO ResetInfo(MInfo); memcpy(MSndBuffer,keys,12); // write 12 bytes of the key MInfo.nBytesToSend = 12; // write load command if ((status=M500PcdCmd(PCD_LOADKEY,MSndBuffer,MRcvBuffer,&MInfo)) == MI_OK) { // execute authentication status = M500PiccAuthState(auth_mode,snr,block); } return status; } /////////////////////////////////////////////////////////////////////// // A U T H E N T I C A T I O N S T A T E S /////////////////////////////////////////////////////////////////////// char M500PiccAuthState( unsigned char auth_mode, unsigned char *snr, unsigned char block) { char idata status = MI_OK; unsigned char idata i = 0; status = ReadIO(RegErrorFlag); // read error flags of the previous // key load if (status != MI_OK) { if (status & 0x40) // key error flag set status = MI_KEYERR; else status = MI_AUTHERR; // generic authentication error } else { MSndBuffer[0] = auth_mode; // write authentication command MSndBuffer[1] = block; // write block number for authentication memcpy(MSndBuffer + 2,snr,4); // write 4 bytes card serial number ResetInfo(MInfo); MInfo.nBytesToSend = 6; if ((status = M500PcdCmd(PCD_AUTHENT1, MSndBuffer, MRcvBuffer, &MInfo)) == MI_OK) { if (ReadIO(RegSecondaryStatus) & 0x07) // Check RxLastBits for error { status = MI_BITCOUNTERR; } else { ResetInfo(MInfo); MInfo.nBytesToSend = 0; if ((status = M500PcdCmd(PCD_AUTHENT2, MSndBuffer, MRcvBuffer, &MInfo)) == MI_OK) { if ( ReadIO(RegControl) & 0x08 ) // Crypto1 activated { status = MI_OK; } else { status = MI_AUTHERR; } } } } } return status; } /////////////////////////////////////////////////////////////////////// // M I F A R E R E A D /////////////////////////////////////////////////////////////////////// char M500PiccRead( unsigned char addr, unsigned char *_data) { char idata status = MI_OK; char idata tmp = 0; FlushFIFO(); // empty FIFO M500PcdSetTmo(3); // long timeout WriteIO(RegChannelRedundancy,0x0F); // RxCRC, TxCRC, Parity enable // ************* Cmd Sequence ********************************** ResetInfo(MInfo); MSndBuffer[0] = PICC_READ; // read command code MSndBuffer[1] = addr; MInfo.nBytesToSend = 2; status = M500PcdCmd(PCD_TRANSCEIVE, MSndBuffer, MRcvBuffer, &MInfo); if (status != MI_OK) { if (status != MI_NOTAGERR ) // no timeout occured { if (MInfo.nBitsReceived == 4) // NACK { MRcvBuffer[0] &= 0x0f; // mask out upper nibble if ((MRcvBuffer[0] & 0x0a) == 0) { status = MI_NOTAUTHERR; } else { status = MI_CODEERR; } } } memcpy(_data,"0000000000000000",16); // in case of an error initialise // data } else // Response Processing { if (MInfo.nBytesReceived != 16) { status = MI_BYTECOUNTERR; memcpy(_data,"0000000000000000",16); } else { memcpy(_data,MRcvBuffer,16); } } M500PcdSetTmo(1); // short timeout return status; } /////////////////////////////////////////////////////////////////////// // M I F A R E W R I T E /////////////////////////////////////////////////////////////////////// char M500PiccWrite( unsigned char addr, unsigned char *_data) { char idata status = MI_OK; // ************* Cmd Sequence ********************************** ResetInfo(MInfo); MSndBuffer[0] = PICC_WRITE; // Write command code MSndBuffer[1] = addr; MInfo.nBytesToSend = 2; status = M500PcdCmd(PCD_TRANSCEIVE, MSndBuffer, MRcvBuffer, &MInfo); if (status != MI_NOTAGERR) // no timeout error { if (MInfo.nBitsReceived != 4) // 4 bits are necessary { status = MI_BITCOUNTERR; } else // 4 bit received { MRcvBuffer[0] &= 0x0f; // mask out upper nibble if ((MRcvBuffer[0] & 0x0a) == 0) { status = MI_NOTAUTHERR; } else { if (MRcvBuffer[0] == 0x0a) { status = MI_OK; } else { status = MI_CODEERR; } } } } if ( status == MI_OK) { M500PcdSetTmo(3); // long timeout ResetInfo(MInfo); memcpy(MSndBuffer,_data,16); MInfo.nBytesToSend = 16; status = M500PcdCmd(PCD_TRANSCEIVE, MSndBuffer, MRcvBuffer, &MInfo); if (status & 0x80) // timeout occured { status = MI_NOTAGERR; } else { if (MInfo.nBitsReceived != 4) // 4 bits are necessary { status = MI_BITCOUNTERR; } else // 4 bit received { MRcvBuffer[0] &= 0x0f; // mask out upper nibble if ((MRcvBuffer[0] & 0x0a) == 0) { status = MI_WRITEERR; } else { if (MRcvBuffer[0] == 0x0a) { status = MI_OK; } else { status = MI_CODEERR; } } } } M500PcdSetTmo(1); // short timeout } return status; } /////////////////////////////////////////////////////////////////////// // V A L U E M A N I P U L A T I O N /////////////////////////////////////////////////////////////////////// char M500PiccValue(unsigned char dd_mode, unsigned char addr, unsigned char *value, unsigned char trans_addr) { char status = MI_OK; M500PcdSetTmo(1); // short timeout // ************* Cmd Sequence ********************************** ResetInfo(MInfo); MSndBuffer[0] = dd_mode; // Inc,Dec command code MSndBuffer[1] = addr; MInfo.nBytesToSend = 2; status = M500PcdCmd(PCD_TRANSCEIVE, MSndBuffer, MRcvBuffer, &MInfo); if (status != MI_NOTAGERR) // no timeout error { if (MInfo.nBitsReceived != 4) // 4 bits are necessary { status = MI_BITCOUNTERR; } else // 4 bit received { MRcvBuffer[0] &= 0x0f; // mask out upper nibble switch(MRcvBuffer[0]) { case 0x00: status = MI_NOTAUTHERR; break; case 0x0a: status = MI_OK; break; case 0x01: status = MI_VALERR; break; default: status = MI_CODEERR; break; } } } if ( status == MI_OK) { M500PcdSetTmo(3); // long timeout ResetInfo(MInfo); memcpy(MSndBuffer,value,4); MInfo.nBytesToSend = 4; status = M500PcdCmd(PCD_TRANSCEIVE, MSndBuffer, MRcvBuffer, &MInfo); if (status == MI_OK) // no timeout occured { if (MInfo.nBitsReceived != 4) // 4 bits are necessary { status = MI_BITCOUNTERR; } else // 4 bit received { MRcvBuffer[0] &= 0x0f; // mask out upper nibble switch(MRcvBuffer[0]) { case 0x00: status = MI_NOTAUTHERR; break; case 0x01: status = MI_VALERR; break; default: status = MI_CODEERR; break; } } } else if (status == MI_NOTAGERR ) status = MI_OK; // no response after 4 byte value - // transfer command has to follow } if ( status == MI_OK) { ResetInfo(MInfo); MSndBuffer[0] = PICC_TRANSFER; // transfer command code MSndBuffer[1] = trans_addr; MInfo.nBytesToSend = 2; status = M500PcdCmd(PCD_TRANSCEIVE, MSndBuffer, MRcvBuffer, &MInfo); if (status != MI_NOTAGERR) // timeout occured { if (MInfo.nBitsReceived != 4) // 4 bits are necessary { status = MI_BITCOUNTERR; } else // 4 bit received { MRcvBuffer[0] &= 0x0f; // mask out upper nibble switch(MRcvBuffer[0]) { case 0x00: status = MI_NOTAUTHERR; break; case 0x0a: status = MI_OK; break; case 0x01: status = MI_VALERR; break; default: status = MI_CODEERR; break; } } } } return status; } /////////////////////////////////////////////////////////////////////// // V A L U E M A N I P U L A T I O N W I T H B A C K U P /////////////////////////////////////////////////////////////////////// char M500PiccValueDebit(unsigned char dd_mode, unsigned char addr, unsigned char *value) { char status = MI_OK; M500PcdSetTmo(1); // short timeout ResetInfo(MInfo); MSndBuffer[0] = dd_mode; // Inc,Dec command code MSndBuffer[1] = addr; MInfo.nBytesToSend = 2; status = M500PcdCmd(PCD_TRANSCEIVE, MSndBuffer, MRcvBuffer, &MInfo); if (status != MI_NOTAGERR) // no timeout error { if (MInfo.nBitsReceived != 4) // 4 bits are necessary { status = MI_BITCOUNTERR; } else // 4 bit received { MRcvBuffer[0] &= 0x0f; // mask out upper nibble switch(MRcvBuffer[0]) { case 0x00: status = MI_NOTAUTHERR; break; case 0x0a: status = MI_OK; break; case 0x01: status = MI_VALERR; break; default: status = MI_CODEERR; break; } } } if ( status == MI_OK) { M500PcdSetTmo(3); // long timeout ResetInfo(MInfo); memcpy(MSndBuffer,value,4); MInfo.nBytesToSend = 4; status = M500PcdCmd(PCD_TRANSCEIVE, MSndBuffer, MRcvBuffer, &MInfo); if (status == MI_OK) // no timeout occured { if (MInfo.nBitsReceived != 4) // 4 bits are necessary { status = MI_BITCOUNTERR; } else // 4 bit received { MRcvBuffer[0] &= 0x0f; // mask out upper nibble switch(MRcvBuffer[0]) { case 0x00: status = MI_NOTAUTHERR; break; case 0x0a: status = MI_OK; break; case 0x05: case 0x01: status = MI_VALERR; break; default: status = MI_CODEERR; break; } } } } return status; } ////////////////////////////////////////////////////////////////////// // P I C C E X C H A N G E B L O C K /////////////////////////////////////////////////////////////////////// char M500PiccExchangeBlock(unsigned char *send_data, unsigned char send_bytelen, unsigned char *rec_data, unsigned char *rec_bytelen, unsigned char append_crc, unsigned char timeout ) { char status = MI_OK; if (append_crc) { // RxCRC and TxCRC enable, parity enable WriteIO(RegChannelRedundancy,0x0F); send_bytelen -= 2; } else { // RxCRC and TxCRC disable, parity enable WriteIO(RegChannelRedundancy,0x03); } M500PcdSetTmo(timeout); status = ExchangeByteStream(PCD_TRANSCEIVE, send_data, send_bytelen, rec_data, rec_bytelen); if ( status == MI_OK ) { if (append_crc) { *rec_bytelen += 2; // for two CRC bytes rec_data[*rec_bytelen - 2] = 0x00; rec_data[*rec_bytelen - 1] = 0x00; } } else { *rec_bytelen = 0; } return status; } ////////////////////////////////////////////////////////////////////// // E X C H A N G E B Y T E S T R E A M /////////////////////////////////////////////////////////////////////// char ExchangeByteStream(unsigned char Cmd, unsigned char *send_data, unsigned char send_bytelen, unsigned char *rec_data, unsigned char *rec_bytelen) { signed char status = MI_OK; signed char state; FlushFIFO(); // empty FIFO ResetInfo(MInfo); // initialise ISR Info structure if (send_bytelen > 0) { memcpy(MSndBuffer,send_data,send_bytelen); // write n bytes MInfo.nBytesToSend = send_bytelen; // write load command state = status = M500PcdCmd(Cmd, MSndBuffer, MRcvBuffer, &MInfo); if ( status == MI_OK ) { *rec_bytelen = MInfo.nBytesReceived; if (*rec_bytelen) { memcpy(rec_data,MRcvBuffer,MInfo.nBytesReceived); } } } else { status = MI_WRONG_PARAMETER_VALUE; } return status; } /////////////////////////////////////////////////////////////////////// // M I F A R E H A L T /////////////////////////////////////////////////////////////////////// char M500PiccHalt(void) { char idata status = MI_CODEERR; // ************* Cmd Sequence ********************************** ResetInfo(MInfo); MSndBuffer[0] = PICC_HALT ; // Halt command code MSndBuffer[1] = 0x00; // dummy address MInfo.nBytesToSend = 2; status = M500PcdCmd(PCD_TRANSCEIVE, MSndBuffer, MRcvBuffer, &MInfo); if (status) { // timeout error ==> no NAK received ==> OK if (status == MI_NOTAGERR || status == MI_ACCESSTIMEOUT) status = MI_OK; } //reset command register - no response from tag WriteIO(RegCommand,PCD_IDLE); return status; } ////////////////////////////////////////////////////////////////////// // M I F A R E R E S E T /////////////////////////////////////////////////////////////////////// char M500PcdRfReset(unsigned char ms) { char idata status = MI_OK; if(ms) { ClearBitMask(RegTxControl,0x03); // Tx2RF-En, Tx1RF-En disablen delay_1ms(ms); // Delay for 1 ms SetBitMask(RegTxControl,0x03); // Tx2RF-En, Tx1RF-En enable } else ClearBitMask(RegTxControl,0x03); // Tx2RF-En, Tx1RF-En disablen return status; } void idle_request(void) { uchar status, _10ms; auto_baud(); WriteIO(RegChannelRedundancy,0x03); // RxCRC and TxCRC disable, parity enable auto_baud(); ClearBitMask(RegControl,0x08); // disable crypto 1 unit auto_baud(); WriteIO(RegBitFraming,0x07); // set TxLastBits to 7 auto_baud(); SetBitMask(RegTxControl,0x03); // Tx2RF-En, Tx1RF-En enable auto_baud(); ResetInfo(MInfo); auto_baud(); MSndBuffer[0] = PICC_REQALL; auto_baud(); MInfo.nBytesToSend = 1; auto_baud(); status = M500PcdCmd(PCD_TRANSCEIVE, MSndBuffer, MRcvBuffer, &MInfo); auto_baud(); if (status == MI_OK) { auto_baud(); LED = OFF; auto_baud(); } RCAP2LH = RCAP2_10ms; auto_baud(); T2LH = RCAP2_10ms; auto_baud(); T2CON = 0x04; // 16-bit auto-reload, clear TF2, start timer auto_baud(); _10ms = 10; auto_baud(); do { auto_baud(); while (!TF2) { auto_baud(); if (CmdValid) { TR2 = FALSE; TF2 = FALSE; LED = ON; return; } auto_baud(); if (CmdReceived) { TR2 = FALSE; TF2 = FALSE; LED = ON; return; } auto_baud(); } auto_baud(); TF2 = FALSE; auto_baud(); _10ms--; auto_baud(); } while (_10ms); LED = ON; auto_baud(); TR2 = FALSE; auto_baud(); } //---------------------------------------------------------------------------- // // FUNCTION: start_timeout // // IN: _50us // OUT: - // // COMMENT: Using Timer2 to generate timeout with a resolution of 50 us. // Timeout is calculated in the interrupt routine. // Max Timeout = 65535 x 50us = 3.277s // //---------------------------------------------------------------------------- void start_timeout(unsigned int _50us) { ET2 = 0; // Disable Timer2 interrupt TR2 = 0; RCAP2LH = RCAP2_50us; T2LH = RCAP2_50us; CountDown = _50us; T2IR = 0; // Reset timeout state T2CON = 0x04; // 16-bit auto-reload, clear TF2, start timer ET2 = 1; // Enable Timer2 interrupt } //---------------------------------------------------------------------------- // // FUNCTION: stop_timeout // // IN: - // OUT: - // // COMMENT: Stop Timer2 and clear timeout state // //---------------------------------------------------------------------------- void stop_timeout(void) { ET2 = 0; // disable Timer2 interrupt CountDown = 0; T2CON = 0x00; // 16-bit auto-reload, clear TF2, stop timer } /////////////////////////////////////////////////////////////////////////////// // Interrupt Handler TIMER2 /////////////////////////////////////////////////////////////////////////////// void TIMEOUTISR (void) interrupt 5 using 2 //Timer2 interrupt { if(CountDown) CountDown--; // Decrease timeout counter if(!CountDown) { T2IR = 1; // Set timeout state TR2 = 0; } TF2 = 0; }