/* main_reqa - OpenPCD firmware for generating an endless loop of * ISO 14443-A REQA packets. Alternatively we can send WUPA, or * perform a full ISO14443A anti-collision loop. * * If a response is received from the PICC, LED1 (Red) will be switched * on. If no valid response has been received within the timeout of the * receiver, LED1 (Red) will be switched off. * * (C) 2006 by Harald Welte * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include #include "rc632.h" #include #include #include #include #include #include #include #include "../openpcd.h" #ifdef WITH_TC #include "tc.h" #endif #define RAH NULL static struct rfid_reader_handle *rh; static struct rfid_layer2_handle *l2h; void _init_func(void) { trigger_init(); DEBUGPCRF("enabling RC632"); rc632_init(); #ifdef WITH_TC DEBUGPCRF("enabling TC"); tc_cdiv_init(); #endif DEBUGPCRF("turning on RF"); rc632_turn_on_rf(RAH); DEBUGPCRF("initializing 14443A operation"); rh = rfid_reader_open(NULL, RFID_READER_OPENPCD); l2h = rfid_layer2_init(rh, RFID_LAYER2_ISO14443A); } #define MODE_REQA 0x01 #define MODE_WUPA 0x02 #define MODE_ANTICOL 0x03 #define MODE_14443A 0x04 static volatile int mode = MODE_REQA; static const char frame_14443a[] = { 0x00, 0xff, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x00, 0xff, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x00, 0xff, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x00, 0xff, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x00, 0xff, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x00, 0xff, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x00, 0xff, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x00, 0xff, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, }; static void reg_inc(uint8_t reg) { uint8_t val; opcd_rc632_reg_read(RAH, reg, &val); opcd_rc632_reg_write(RAH, reg, val++); DEBUGPCRF("reg 0x%02x = 0x%02x", reg, val); } static void reg_dec(uint8_t reg) { uint8_t val; opcd_rc632_reg_read(RAH, reg, &val); opcd_rc632_reg_write(RAH, reg, val--); DEBUGPCRF("reg 0x%02x = 0x%02x", reg, val); } static uint8_t ana_out_sel; static uint8_t mfout_sel; static uint8_t speed_idx; static void help(void) { DEBUGPCR("r: REQA w: WUPA a: ANTICOL\r\n" "A: 14443A +: inc speed -: dec speed\r\n" "y: inc cw cond x: dec cond c: inc mod cond"); DEBUGPCR("v: dec mod cond o: dec ana_out p: dec ana_out\r\n" "h: trigger high l: trigger low u: dec MFOUT mode"); DEBUGPCR("i: inc MFOUT md <: dec cdiv ph >: inc cdiv phase\r\n" "{: dev cdiv }: inc cdiv"); } static uint16_t cdivs[] = { 128, 64, 32, 16 }; int _main_dbgu(char key) { int ret = 0; static int cdiv_idx = 2; switch (key) { case '?': help(); break; case 'r': mode = MODE_REQA; break; case 'w': mode = MODE_WUPA; break; case 'A': mode = MODE_14443A; break; case 'a': mode = MODE_ANTICOL; break; /* Those below don't work as long as * iso14443a_init() is called before * every cycle */ case 'y': reg_inc(RC632_REG_CW_CONDUCTANCE); break; case 'x': reg_dec(RC632_REG_CW_CONDUCTANCE); break; case 'c': reg_inc(RC632_REG_MOD_CONDUCTANCE); break; case 'v': reg_dec(RC632_REG_MOD_CONDUCTANCE); break; case 'o': if (ana_out_sel > 0) { ana_out_sel--; DEBUGPCR("switching to analog output mode 0x%x\n", ana_out_sel); opcd_rc632_reg_write(RAH, RC632_REG_TEST_ANA_SELECT, ana_out_sel); } ret = 1; break; case 'p': if (ana_out_sel < 0xc) { ana_out_sel++; DEBUGPCR("switching to analog output mode 0x%x\n", ana_out_sel); opcd_rc632_reg_write(RAH, RC632_REG_TEST_ANA_SELECT, ana_out_sel); } ret = 1; break; case 'u': if (mfout_sel > 0) { mfout_sel--; DEBUGPCR("switching to MFOUT mode 0x%x\n", mfout_sel); opcd_rc632_reg_write(RAH, RC632_REG_MFOUT_SELECT, mfout_sel); } ret = 1; break; case 'i': if (mfout_sel < 5) { mfout_sel++; DEBUGPCR("switching to MFOUT mode 0x%x\n", mfout_sel); opcd_rc632_reg_write(RAH, RC632_REG_MFOUT_SELECT, mfout_sel); } ret = 1; break; case 'h': AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPCD_PIO_TRIGGER); break; case 'l': AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPCD_PIO_TRIGGER); break; #ifdef WITH_TC case '<': tc_cdiv_phase_inc(); break; case '>': tc_cdiv_phase_dec(); break; case '{': if (cdiv_idx > 0) cdiv_idx--; tc_cdiv_set_divider(cdivs[cdiv_idx]); break; case '}': if (cdiv_idx < ARRAY_SIZE(cdivs)-1) cdiv_idx++; tc_cdiv_set_divider(cdivs[cdiv_idx]); break; #endif case '-': if (speed_idx > 0) speed_idx--; break; case '+': if (speed_idx < 3) speed_idx++; break; default: return -EINVAL; } return ret; } void _main_func(void) { int status; struct iso14443a_atqa atqa; volatile int i; /* FIXME: why does this only work every second attempt without reset or * power-cycle? */ //rc632_turn_off_rf(); //rc632_reset(); //rc632_turn_on_rf(); opcd_rc632_reg_write(RAH, RC632_REG_TEST_ANA_SELECT, ana_out_sel); opcd_rc632_reg_write(RAH, RC632_REG_MFOUT_SELECT, mfout_sel); for (i = 0; i < 0xfffff; i++) {} //rc632_dump(); #ifdef WITH_TC tc_cdiv_print(); #endif switch (mode) { case MODE_REQA: status = iso14443a_transceive_sf(l2h, ISO14443A_SF_CMD_REQA, &atqa); if (status < 0) DEBUGPCRF("error during transceive_sf REQA"); else DEBUGPCRF("received ATQA: %s", hexdump((char *)&atqa, sizeof(atqa))); break; case MODE_WUPA: status = iso14443a_transceive_sf(l2h, ISO14443A_SF_CMD_WUPA, &atqa); if (status < 0) DEBUGPCRF("error during transceive_sf WUPA"); else DEBUGPCRF("received WUPA: %s", hexdump((char *)&atqa, sizeof(atqa))); break; case MODE_ANTICOL: status = rfid_layer2_open(l2h); if (status < 0) DEBUGPCR("error during anticol"); else DEBUGPCR("Anticol OK"); break; case MODE_14443A: { char rx_buf[4]; int rx_len = sizeof(rx_buf); rfid_layer2_setopt(l2h, RFID_OPT_14443A_SPEED_RX, &speed_idx, sizeof(speed_idx)); rfid_layer2_setopt(l2h, RFID_OPT_14443A_SPEED_TX, &speed_idx, sizeof(speed_idx)); rfid_layer2_transceive(l2h, RFID_14443A_FRAME_REGULAR, &frame_14443a, sizeof(frame_14443a), &rx_buf, &rx_len, 1, 0); } break; } if (status < 0) led_switch(1, 0); else led_switch(1, 1); led_toggle(2); }