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
{
2017-01-25 15:38:40 -05: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 ;
2013-10-09 00:41:48 -04:00
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 ) ;
}
2013-09-26 13:15:22 -04:00
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 ;
}
2013-09-26 13:15:22 -04:00
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