#include "Arduino.h" #include "Reader.h" //contructor Reader::Reader() { keypadInitDone = false; new_reader = false; } //cmd61 is used to specify behaviour on command 0x61 void Reader::setrCode(char* rCode, byte cmd61_s) { byte rType[] = {0x03, 0x00, 0x00, 0x00}; byte rVersion[] = {0x01, 0x06, 0x00}; setVersion(rType, 0x00, rVersion, rCode); cmd61 = cmd61_s; } void Reader::init() { acceptcard = false; holdcard = false; keypad = 0x0000; keypad_old = 0x0000; keydown = 0x00; keycpt = 0x08; } //////////////////////// //keypad pinout setting ///////////////////// void Reader::setkeypadpins(int col1, int col2, int col3, int row1, int row2, int row3, int row4) { colPins[0] = col1; // COL 1 brown wire colPins[1] = col2; // COL 2 black wire colPins[2] = col3; // COL 3 blue wire rowPins[0] = row1; // ROW 4 purple wire rowPins[1] = row2; // ROW 3 yellow wire rowPins[2] = row3; // ROW 2 red wire rowPins[3] = row4; // ROW 1 grey wire // init Keypad pins for(int i=0;i<3;i++) { pinMode(colPins[i], INPUT); // High impedance } for(int i=0;i<4;i++) { // set to input with pullup pinMode(rowPins[i], INPUT); digitalWrite(rowPins[i], HIGH); } keypadInitDone = true; } void Reader::setRfidModule(RfidModule* mod) { rfmodule =mod; } ////////////////////// ///// Override update function from Node to update what a reader needs to update ////////////////////// void Reader::update() { readKeypad(); rfmodule->update(); } ////////////////////// ///// update "keypad" with state of physical keys ////////////////////// void Reader::readKeypad() { if(!keypadInitDone) return; keypad = 0x00; for(int i=0;i<3;i++)//for each collumn { //set the collumn we're going to read low pinMode(colPins[i], OUTPUT); digitalWrite(colPins[i], LOW); for(int j=0;j<4;j++)//for each row { if(! digitalRead(rowPins[j])) //if key is down keypad |= ( 0x0001 << (j + i*4) ); } pinMode(colPins[i], INPUT); // after reading collumn put it back to high impedance } //simulate card with unused key // if(keypad & 0x0100) // if unused key is pressed // card = true; // else // { // card = false; // } } // // Return status buffer // void Reader::getStatus(byte* buf) { // manage keypad rising edge (keydown) word rising = ~keypad_old & keypad; if(rising) { keydown = 0x00; for(byte i=0;i<12;i++) // find which key was pressed { if((0x0001 << i) & rising) // for each key, check if it went from low to high { keydown = (keycpt << 4) | i; break; } } keycpt++; keycpt |= 0x08; } else // if no key went from low to high since last read { keydown = 0x00; } keypad_old = keypad; // set status in buffer if(holdcard) //when simulating card holding, use stored uid { memcpy(buf+2,uid,8); } else { // if a card is present, copy its uid if(rfmodule->isCardPresent()){ rfmodule->getUID(buf+2); } else { for(int i=0;i<8;i++) { buf[2+i] = 0x00; } } } //card presence flags (different behaviour on old and new readers) buf[0] = 0x04; // card presence (1 or 4 :no card, 2 :card) buf[1] = 0x00; //sensors for old readers (front 0x10, back 0x20) or card type for new readers (0 : iso15696 1:felica) if(new_reader) { if(rfmodule->isCardPresent()) { buf[0]=0x02; buf[1] = rfmodule->isCardPresent() -1 ; } else { buf[0]=0x04; } } else { // old readers sensors emulation if(acceptcard && rfmodule->isCardPresent() == 1)//if reader is accepting cards and a card is detected, simulate old reader holding card { holdcard = true; //until card is ejected, we'll ignore new cards and simulate this card being hold in the reader rfmodule->getUID(uid); // copy the current card uid } if(holdcard) //when holding card, both sensors are on and card is present { buf[0] = 0x02; buf[1] = 0x30; } else { if(rfmodule->isCardPresent() == 1)//if card is present, but reader is not accepting card, just set the front sensor { buf[0] = 0x02; buf[1] = 0x10; } else{ buf[0] = 0x01; } } } buf[10] = 0x00; buf[11] = 0x03; //0x03 required for new readers, or else will be stuck at gameover screen buf[12] = keydown; buf[13] = 0x00; buf[14] = keypad >> 8; buf[15] = keypad; } short Reader::processRequest(byte* request, byte* answer) { answer[0] = request[0] | 0x80; // reader id answer[1] = request[1]; // ? answer[2] = request[2]; // command answer[3] = request[3]; // paquet id answer[4] = 0; // data length switch (answer[2]) // switch on the command { // // get version case 0x02: answer[4] = 0x2C; memcpy(answer+5, getVersion(), 0x2C); break; // // init? case 0x00: case 0x03: case 0x16: case 0x20: case 0x30: //re-init (if game is changed) new_reader = false; answer[4] = 1; answer[5] = 0x00; break; // // read card uid (old readers) case 0x31: rfmodule->read(); answer[4] = 0x10; // 16 bytes of data getStatus(answer+5); answer[5] = 0x01; break; // // set action (old readers) return same as 0x34 case 0x35: switch(request[6]) { case 0x00: acceptcard = false; break; case 0x11: // accept card mode acceptcard = true; break; case 0x12: // eject card holdcard = false; acceptcard = false; break; } // // get status (all except pop'n music new readers) case 0x34: answer[4] = 0x10; // 16 bytes of data if(!new_reader) //when simulating old slotted readers, rfid need to be read continously to detect card (since games using old readers only send reading command when sensors are activated) rfmodule->read(); getStatus(answer+5); break; // sleep mode case 0x3A: answer[4] = 0x01; answer[5] = 0x00; break; // // key exchange (for popn new wavepass readers) case 0x60: if(request[4] == 4)//check if there is four bytes of data (32bits key) { unsigned long reckey = ((unsigned long) request[5]) <<24 | ((unsigned long) request[6]) <<16 | ((unsigned long) request[7]) <<8 | (unsigned long) request[8]; //send random key answer[4]=4; answer[5]=0x12;//not random yet answer[6]=0xBC;//not random yet answer[7]=0x22;//not random yet answer[8]=0x01;//not random yet unsigned long mykey = ((unsigned long) answer[5]) <<24 | ((unsigned long) answer[6]) <<16 | ((unsigned long) answer[7]) <<8 | (unsigned long) answer[8]; crypt.setKeys(reckey,mykey); } break; // // Rfid read cards UID (for new wave pass readers) case 0x61: new_reader = true; //only new readers issue this command rfmodule->read(); // for pop'n music and DDR, should not return any data, for iidx and sdvx, should return one byte of data with value 0x01 and for jubeat, should return something like a full status (0x31 like) ... wtf konami switch(cmd61) { case 1: answer[4] = 1; answer[5] = 0x01; break; case 2: answer[4] = 0x10;//16 bytes of data answer[5] = 0x00;//no card answer[6] = 0x00; break; default: answer[4] = 0; } break; // // get status (for pop'n new wavepass readers) case 0x64: if(request[4] == 1) { getStatus(answer+5); //append CRC unsigned int CRC = crypt.CRCCCITT(answer+5,16); answer[21] = (unsigned char) (CRC >>8) ; answer[22] = (unsigned char) CRC ; crypt.encrypt(answer+5,18); answer[4]=18; } break; } }