ac-real-io/acrealio/Reader.cpp

387 lines
8.8 KiB
C++

#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(const 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;
}
}