ac-real-io/acrealio/Reader.cpp

387 lines
8.8 KiB
C++
Raw Permalink Normal View History

2013-09-07 10:46:05 -04:00
#include "Arduino.h"
#include "Reader.h"
//contructor
Reader::Reader()
2017-01-25 15:59:19 -05:00
{
keypadInitDone = false;
new_reader = false;
2013-09-07 10:46:05 -04:00
}
//cmd61 is used to specify behaviour on command 0x61
2017-01-25 16:08:41 -05:00
void Reader::setrCode(const char* rCode, byte cmd61_s)
2013-09-07 10:46:05 -04:00
{
byte rType[] = {0x03, 0x00, 0x00, 0x00};
byte rVersion[] = {0x01, 0x06, 0x00};
setVersion(rType, 0x00, rVersion, rCode);
2013-09-07 10:46:05 -04:00
cmd61 = cmd61_s;
}
void Reader::init()
{
acceptcard = false;
holdcard = false;
keypad = 0x0000;
keypad_old = 0x0000;
keydown = 0x00;
keycpt = 0x08;
2017-01-25 15:59:19 -05:00
2013-09-07 10:46:05 -04:00
}
////////////////////////
//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
2017-01-25 15:59:19 -05:00
2013-09-07 10:46:05 -04:00
// init Keypad pins
2017-01-25 15:59:19 -05:00
for (int i=0;i<3;i++)
2013-09-07 10:46:05 -04:00
{
pinMode(colPins[i], INPUT); // High impedance
}
2017-01-25 15:59:19 -05:00
for (int i=0;i<4;i++)
2013-09-07 10:46:05 -04:00
{
// set to input with pullup
pinMode(rowPins[i], INPUT);
digitalWrite(rowPins[i], HIGH);
}
2017-01-25 15:59:19 -05:00
keypadInitDone = true;
2013-09-07 10:46:05 -04:00
}
void Reader::setRfidModule(RfidModule* mod)
{
2017-01-25 15:59:19 -05:00
rfmodule =mod;
2013-09-07 10:46:05 -04:00
}
//////////////////////
///// Override update function from Node to update what a reader needs to update
//////////////////////
void Reader::update()
{
2017-01-25 15:59:19 -05:00
readKeypad();
rfmodule->update();
2013-09-07 10:46:05 -04:00
}
//////////////////////
///// update "keypad" with state of physical keys
//////////////////////
void Reader::readKeypad()
{
2017-01-25 15:59:19 -05:00
if (!keypadInitDone)
return;
2013-09-07 10:46:05 -04:00
keypad = 0x00;
2017-01-25 15:59:19 -05:00
for (int i=0;i<3;i++)//for each collumn
2013-09-07 10:46:05 -04:00
{
//set the collumn we're going to read low
pinMode(colPins[i], OUTPUT);
digitalWrite(colPins[i], LOW);
2017-01-25 15:59:19 -05:00
for (int j=0;j<4;j++)//for each row
2013-09-07 10:46:05 -04:00
{
2017-01-25 15:59:19 -05:00
if (! digitalRead(rowPins[j])) //if key is down
2013-09-07 10:46:05 -04:00
keypad |= ( 0x0001 << (j + i*4) );
}
pinMode(colPins[i], INPUT); // after reading collumn put it back to high impedance
}
2017-01-25 15:59:19 -05:00
//simulate card with unused key
2013-09-07 10:46:05 -04:00
// if(keypad & 0x0100) // if unused key is pressed
2017-01-25 15:59:19 -05:00
// card = true;
2013-09-07 10:46:05 -04:00
// else
// {
2017-01-25 15:59:19 -05:00
// card = false;
2013-09-07 10:46:05 -04:00
// }
2017-01-25 15:59:19 -05:00
2013-09-07 10:46:05 -04:00
}
//
// Return status buffer
//
void Reader::getStatus(byte* buf)
{
// manage keypad rising edge (keydown)
word rising = ~keypad_old & keypad;
2017-01-25 15:59:19 -05:00
if (rising)
2013-09-07 10:46:05 -04:00
{
keydown = 0x00;
2017-01-25 15:59:19 -05:00
for (byte i=0;i<12;i++) // find which key was pressed
2013-09-07 10:46:05 -04:00
{
2017-01-25 15:59:19 -05:00
if ((0x0001 << i) & rising) // for each key, check if it went from low to high
2013-09-07 10:46:05 -04:00
{
keydown = (keycpt << 4) | i;
break;
}
}
keycpt++;
keycpt |= 0x08;
}
else // if no key went from low to high since last read
{
keydown = 0x00;
}
2017-01-25 15:59:19 -05:00
2013-09-07 10:46:05 -04:00
keypad_old = keypad;
2017-01-25 15:59:19 -05:00
2013-09-07 10:46:05 -04:00
// set status in buffer
2017-01-25 15:59:19 -05:00
if (holdcard) //when simulating card holding, use stored uid
2013-11-07 06:43:23 -05:00
{
2017-01-25 15:59:19 -05:00
memcpy(buf+2,uid,8);
2013-11-07 06:43:23 -05:00
}
else
{
2017-01-25 15:59:19 -05:00
// if a card is present, copy its uid
if (rfmodule->isCardPresent()) {
rfmodule->getUID(buf+2);
2013-11-07 06:43:23 -05:00
} else {
2017-01-25 15:59:19 -05:00
for (int i=0;i<8;i++)
{
buf[2+i] = 0x00;
}
2013-09-07 10:46:05 -04:00
}
2013-11-07 06:43:23 -05:00
}
2017-01-25 15:59:19 -05:00
2013-09-07 10:46:05 -04:00
//card presence flags (different behaviour on old and new readers)
buf[0] = 0x04; // card presence (1 or 4 :no card, 2 :card)
2017-01-25 15:59:19 -05:00
buf[1] = 0x00; //sensors for old readers (front 0x10, back 0x20) or card type for new readers (0 : iso15696 1:felica)
if (new_reader)
2013-09-07 10:46:05 -04:00
{
2017-01-25 15:59:19 -05:00
if (rfmodule->isCardPresent())
{
2013-09-07 10:46:05 -04:00
buf[0]=0x02;
buf[1] = rfmodule->isCardPresent() -1 ;
2017-01-25 15:59:19 -05:00
}
else
{
2013-09-07 10:46:05 -04:00
buf[0]=0x04;
2017-01-25 15:59:19 -05:00
}
2013-09-07 10:46:05 -04:00
}
else
{
2017-01-25 15:59:19 -05:00
// 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
2013-09-07 10:46:05 -04:00
{
2017-01-25 15:59:19 -05:00
buf[0] = 0x02;
buf[1] = 0x30;
2013-09-07 10:46:05 -04:00
}
2017-01-25 15:59:19 -05:00
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;
}
2013-09-07 10:46:05 -04:00
}
2017-01-25 15:59:19 -05:00
}
2013-09-07 10:46:05 -04:00
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;
2017-01-25 15:59:19 -05:00
2013-09-07 10:46:05 -04:00
}
short Reader::processRequest(byte* request, byte* answer)
2017-01-25 15:59:19 -05:00
{
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
2013-09-07 10:46:05 -04:00
case 0x02:
2017-01-25 15:59:19 -05:00
answer[4] = 0x2C;
memcpy(answer+5, getVersion(), 0x2C);
break;
2013-09-07 10:46:05 -04:00
2017-01-25 15:59:19 -05:00
//
// init?
2013-09-07 10:46:05 -04:00
case 0x00:
case 0x03:
case 0x16:
case 0x20:
case 0x30:
2017-01-25 15:59:19 -05:00
//re-init (if game is changed)
new_reader = false;
answer[4] = 1;
answer[5] = 0x00;
break;
//
// read card uid (old readers)
2013-09-07 10:46:05 -04:00
case 0x31:
2017-01-25 15:59:19 -05:00
rfmodule->read();
answer[4] = 0x10; // 16 bytes of data
getStatus(answer+5);
answer[5] = 0x01;
break;
//
// set action (old readers) return same as 0x34
2013-09-07 10:46:05 -04:00
case 0x35:
2017-01-25 15:59:19 -05:00
switch (request[6])
{
case 0x00:
acceptcard = false;
break;
2013-09-07 10:46:05 -04:00
case 0x11: // accept card mode
2017-01-25 15:59:19 -05:00
acceptcard = true;
break;
2013-09-07 10:46:05 -04:00
case 0x12: // eject card
2017-01-25 15:59:19 -05:00
holdcard = false;
acceptcard = false;
break;
}
2013-09-07 10:46:05 -04:00
2017-01-25 15:59:19 -05:00
//
// get status (all except pop'n music new readers)
2013-09-07 10:46:05 -04:00
case 0x34:
2017-01-25 15:59:19 -05:00
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
2013-11-07 06:43:23 -05:00
case 0x3A:
2017-01-25 15:59:19 -05:00
answer[4] = 0x01;
answer[5] = 0x00;
2013-11-07 06:43:23 -05:00
2013-09-07 10:46:05 -04:00
2017-01-25 15:59:19 -05:00
break;
//
// key exchange (for popn new wavepass readers)
2013-09-07 10:46:05 -04:00
case 0x60:
2017-01-25 15:59:19 -05:00
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;
2017-01-25 15:59:19 -05:00
//
// 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;
2017-01-25 15:59:19 -05:00
//
// get status (for pop'n new wavepass readers)
2013-09-07 10:46:05 -04:00
case 0x64:
2017-01-25 15:59:19 -05:00
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;
2013-09-07 10:46:05 -04:00
}
}
2017-01-25 15:59:19 -05:00