Major refactor of ACIO Launcher.
Moved debug stuff into Debug.cpp/h. Moved ACIO driver stuff into its own class.
This commit is contained in:
parent
501b54b98e
commit
77a8d517be
|
@ -0,0 +1,554 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include "ACIO.h"
|
||||
#include "Debug.h"
|
||||
|
||||
/* Length of an ACIO packet without payload or checksum */
|
||||
#define HEADER_LENGTH 5
|
||||
|
||||
/* Minimum packet length including header and checksum */
|
||||
#define MINIMUM_PACKET_LENGTH (HEADER_LENGTH + 1)
|
||||
|
||||
/* Start of Message */
|
||||
#define SOM 0xAA
|
||||
|
||||
/* Location of various parts of the protocol */
|
||||
#define ID_LOCATION 0
|
||||
#define COMMAND_HIGH_LOCATION 1
|
||||
#define COMMAND_LOW_LOCATION 2
|
||||
#define LENGTH_HIGH_LOCATION 3
|
||||
#define LENGTH_LOW_LOCATION 4
|
||||
|
||||
/* Number of times to try initializing a reader by sending baud probe */
|
||||
#define INITIALIZATION_TRIES 16
|
||||
|
||||
/* Number of return baud probes to receive before we consider ourselves initialized */
|
||||
#define MIN_PROBES_RECEIVED 5
|
||||
|
||||
#define WAIT() Sleep( 100 )
|
||||
#define LONGWAIT() Sleep( 1000 )
|
||||
|
||||
ACIO::ACIO()
|
||||
{
|
||||
/* Initialize readers first */
|
||||
printf( "Initializing readers" );
|
||||
serial = InitReaders(readerCount);
|
||||
printf( "\n" );
|
||||
|
||||
/* Get version of all readers */
|
||||
for( unsigned int x = 0; x < readerCount; x++ )
|
||||
{
|
||||
/* Print out reader version in debug mode */
|
||||
DEBUG_PRINTF( "Reader %d returned version %s\n", x + 1, getReaderVersion( serial, x ) );
|
||||
|
||||
/* Walk init routine */
|
||||
initReader( serial, x, 0 );
|
||||
initReader( serial, x, 1 );
|
||||
initReader( serial, x, 2 );
|
||||
|
||||
/* Set ready for keys only */
|
||||
setReaderState( serial, x, STATE_EJECT );
|
||||
}
|
||||
|
||||
/* For key input debouncing */
|
||||
old_keypresses = (unsigned int *)malloc(sizeof(unsigned int) * readerCount);
|
||||
}
|
||||
|
||||
ACIO::~ACIO(void)
|
||||
{
|
||||
/* Kill memory used for keypresses */
|
||||
free(old_keypresses);
|
||||
|
||||
/* Close the reader so we can let the game talk to it */
|
||||
for( unsigned int y = 0; y < readerCount; y++ )
|
||||
{
|
||||
setReaderState( serial, y, STATE_EJECT );
|
||||
}
|
||||
CloseHandle( serial );
|
||||
}
|
||||
|
||||
bool ACIO::getCardInserted(int reader)
|
||||
{
|
||||
unsigned int currentpresses;
|
||||
getReaderState( serial, reader, &state, ¤tpresses, cardId );
|
||||
return (state == STATE_READ || state == STATE_INSERTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: For some reason this returns one card read in the past. So, on first
|
||||
* read it returns garbage, on second read it returns the first card, etc. Fix
|
||||
* that at some point.
|
||||
*/
|
||||
void ACIO::getCardID(int reader, unsigned char *outCardId)
|
||||
{
|
||||
while( !getCardInserted(reader) ) { requestCardId( serial, reader ); }
|
||||
while( !getCardInserted(reader) ) { requestCardId( serial, reader ); }
|
||||
memcpy(outCardId, cardId, CARD_LENGTH);
|
||||
}
|
||||
|
||||
reader_keypress_t ACIO::getPressedKey(int reader)
|
||||
{
|
||||
unsigned int currentpresses;
|
||||
getReaderState( serial, reader, &state, ¤tpresses, cardId );
|
||||
unsigned int keypresses = currentpresses & (~old_keypresses[reader]);
|
||||
old_keypresses[reader] = currentpresses;
|
||||
|
||||
if (keypresses & 0x0002 )
|
||||
{
|
||||
return KEY_1;
|
||||
}
|
||||
if (keypresses & 0x0020 )
|
||||
{
|
||||
return KEY_2;
|
||||
}
|
||||
if (keypresses & 0x0200 )
|
||||
{
|
||||
return KEY_3;
|
||||
}
|
||||
if (keypresses & 0x0004 )
|
||||
{
|
||||
return KEY_4;
|
||||
}
|
||||
if (keypresses & 0x0040 )
|
||||
{
|
||||
return KEY_5;
|
||||
}
|
||||
if (keypresses & 0x0400 )
|
||||
{
|
||||
return KEY_6;
|
||||
}
|
||||
if (keypresses & 0x0008 )
|
||||
{
|
||||
return KEY_7;
|
||||
}
|
||||
if (keypresses & 0x0080 )
|
||||
{
|
||||
return KEY_8;
|
||||
}
|
||||
if (keypresses & 0x0800 )
|
||||
{
|
||||
return KEY_9;
|
||||
}
|
||||
if (keypresses & 0x0001 )
|
||||
{
|
||||
return KEY_0;
|
||||
}
|
||||
if (keypresses & 0x0010 )
|
||||
{
|
||||
return KEY_00;
|
||||
}
|
||||
if (keypresses & 0x0100 )
|
||||
{
|
||||
return KEY_BLANK;
|
||||
}
|
||||
|
||||
return KEY_NONE;
|
||||
}
|
||||
|
||||
void ACIO::requestCardInsert(int reader)
|
||||
{
|
||||
setReaderState( serial, reader, STATE_EJECT );
|
||||
|
||||
/* Walk init routine again. For some reason, it reads the same
|
||||
* card ID the second time through, so I just reinit. */
|
||||
initReader( serial, reader, 0 );
|
||||
initReader( serial, reader, 1 );
|
||||
initReader( serial, reader, 2 );
|
||||
|
||||
setReaderState( serial, reader, STATE_NOT_READY );
|
||||
setReaderState( serial, reader, STATE_GET_READY );
|
||||
setReaderState( serial, reader, STATE_READY );
|
||||
}
|
||||
|
||||
void ACIO::requestCardEject(int reader)
|
||||
{
|
||||
setReaderState( serial, reader, STATE_EJECT );
|
||||
}
|
||||
|
||||
HANDLE ACIO::openSerial( const _TCHAR *arg, int baud )
|
||||
{
|
||||
HANDLE hSerial = CreateFile(arg, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
if (hSerial == INVALID_HANDLE_VALUE) { return hSerial; }
|
||||
|
||||
int rate;
|
||||
|
||||
switch( baud )
|
||||
{
|
||||
case 4800:
|
||||
rate = CBR_4800;
|
||||
break;
|
||||
case 9600:
|
||||
rate = CBR_9600;
|
||||
break;
|
||||
case 19200:
|
||||
rate = CBR_19200;
|
||||
break;
|
||||
case 38400:
|
||||
rate = CBR_38400;
|
||||
break;
|
||||
case 57600:
|
||||
rate = CBR_57600;
|
||||
break;
|
||||
case 115200:
|
||||
rate = CBR_115200;
|
||||
break;
|
||||
default:
|
||||
rate = CBR_9600;
|
||||
break;
|
||||
}
|
||||
|
||||
DCB dcbSerialParams = {0};
|
||||
|
||||
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
|
||||
dcbSerialParams.BaudRate = rate;
|
||||
dcbSerialParams.ByteSize = 8;
|
||||
dcbSerialParams.StopBits = ONESTOPBIT;
|
||||
dcbSerialParams.Parity = NOPARITY;
|
||||
dcbSerialParams.fOutxCtsFlow = 0;
|
||||
dcbSerialParams.fOutxDsrFlow = 0;
|
||||
dcbSerialParams.fDtrControl = DTR_CONTROL_DISABLE;
|
||||
dcbSerialParams.fDsrSensitivity = 0;
|
||||
dcbSerialParams.fOutX = 0;
|
||||
dcbSerialParams.fInX = 0;
|
||||
dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE;
|
||||
|
||||
SetCommState(hSerial, &dcbSerialParams);
|
||||
|
||||
COMMTIMEOUTS timeouts = { 0 };
|
||||
|
||||
timeouts.ReadIntervalTimeout = 1;
|
||||
timeouts.ReadTotalTimeoutConstant = 1;
|
||||
timeouts.ReadTotalTimeoutMultiplier = 1;
|
||||
|
||||
SetCommTimeouts(hSerial, &timeouts);
|
||||
return hSerial;
|
||||
}
|
||||
|
||||
const unsigned char * const ACIO::getPacketData(
|
||||
unsigned int *readerId,
|
||||
unsigned int *command,
|
||||
unsigned int *len,
|
||||
unsigned int *checksum,
|
||||
const unsigned char * const packet,
|
||||
unsigned int length
|
||||
) {
|
||||
/* Exit early if we didn't get a good packet */
|
||||
if (length < MINIMUM_PACKET_LENGTH) { return NULL; }
|
||||
|
||||
for( unsigned int i = 0; i <= length - MINIMUM_PACKET_LENGTH; i++ )
|
||||
{
|
||||
const unsigned char * const data = &packet[i];
|
||||
|
||||
if( data[0] != SOM )
|
||||
{
|
||||
/* Get command */
|
||||
*readerId = data[ID_LOCATION];
|
||||
*command = (data[COMMAND_HIGH_LOCATION] << 8) | data[COMMAND_LOW_LOCATION];
|
||||
*len = (data[LENGTH_HIGH_LOCATION] << 8) | data[LENGTH_LOW_LOCATION];
|
||||
*checksum = data[(*len) + HEADER_LENGTH];
|
||||
return data + HEADER_LENGTH;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned char ACIO::calcPacketChecksum( const unsigned char * const data )
|
||||
{
|
||||
unsigned char *packet = (unsigned char *)data;
|
||||
|
||||
/* Dirty */
|
||||
while( 1 )
|
||||
{
|
||||
/* Get to start of packet */
|
||||
if( packet[0] == SOM )
|
||||
{
|
||||
packet++;
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int length = ((packet[LENGTH_HIGH_LOCATION] << 8) | packet[LENGTH_LOW_LOCATION]);
|
||||
unsigned int sum = 0;
|
||||
|
||||
/* Skip SOM, not part of packet CRC */
|
||||
for( unsigned int i = 0; i < length + HEADER_LENGTH; i++ )
|
||||
{
|
||||
sum += packet[i];
|
||||
}
|
||||
|
||||
return sum & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
int ACIO::probeReader( HANDLE serial )
|
||||
{
|
||||
const unsigned char packet_probe[] = { 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, };
|
||||
unsigned char data[1024];
|
||||
DWORD length;
|
||||
|
||||
WriteFile( serial, packet_probe, sizeof( packet_probe ), &length, 0 );
|
||||
ReadFile( serial, data, sizeof( data ), &length, 0 );
|
||||
|
||||
if (length < MIN_PROBES_RECEIVED)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < length; i++)
|
||||
{
|
||||
if (data[i] != 0xAA)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear out any additional init the reader sends */
|
||||
while (true)
|
||||
{
|
||||
ReadFile( serial, data, sizeof( data ), &length, 0 );
|
||||
if (length == 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int ACIO::getReaderCount( HANDLE serial )
|
||||
{
|
||||
const unsigned char count_probe[] = { 0xAA, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, };
|
||||
unsigned char data[1024];
|
||||
DWORD length;
|
||||
|
||||
WriteFile( serial, count_probe, sizeof( count_probe ), &length, 0 );
|
||||
WAIT();
|
||||
ReadFile( serial, data, sizeof( data ), &length, 0 );
|
||||
|
||||
unsigned int readerId;
|
||||
unsigned int command;
|
||||
unsigned int len;
|
||||
unsigned int checksum;
|
||||
const unsigned char * const payload = getPacketData( &readerId, &command, &len, &checksum, data, length );
|
||||
|
||||
if( payload == NULL ) { return 0; }
|
||||
if( len != 1 ) { return 0; }
|
||||
|
||||
return payload[0];
|
||||
}
|
||||
|
||||
void ACIO::initReader( HANDLE serial, unsigned int id, int whichInit )
|
||||
{
|
||||
unsigned int init_length[3] = { 7, 7, 8 };
|
||||
unsigned char init_probe[3][8] = { { 0xAA, (id + 1), 0x00, 0x03, 0x00, 0x00, 0xFF, },
|
||||
{ 0xAA, (id + 1), 0x01, 0x00, 0x00, 0x00, 0xFF, },
|
||||
{ 0xAA, (id + 1), 0x01, 0x30, 0x00, 0x01, 0x00, 0xFF, } };
|
||||
unsigned char data[1024];
|
||||
DWORD length;
|
||||
|
||||
/* Fix up checksum since ID is variable */
|
||||
init_probe[whichInit][init_length[whichInit] - 1] = calcPacketChecksum( init_probe[whichInit] );
|
||||
|
||||
WriteFile( serial, init_probe[whichInit], init_length[whichInit], &length, 0 );
|
||||
WAIT();
|
||||
ReadFile( serial, data, sizeof( data ), &length, 0 );
|
||||
}
|
||||
|
||||
const char * const ACIO::getReaderVersion( HANDLE serial, unsigned int id )
|
||||
{
|
||||
unsigned char version_probe[] = { 0xAA, (id + 1), 0x00, 0x02, 0x00, 0x00, 0xFF, };
|
||||
static char version[33] = { 0x00 };
|
||||
unsigned char data[1024];
|
||||
DWORD length;
|
||||
|
||||
/* Fix up checksum since ID is variable */
|
||||
version_probe[6] = calcPacketChecksum( version_probe );
|
||||
|
||||
WriteFile( serial, version_probe, sizeof( version_probe ), &length, 0 );
|
||||
WAIT();
|
||||
ReadFile( serial, data, sizeof( data ), &length, 0 );
|
||||
|
||||
unsigned int readerId;
|
||||
unsigned int command;
|
||||
unsigned int len;
|
||||
unsigned int checksum;
|
||||
const unsigned char * const payload = getPacketData( &readerId, &command, &len, &checksum, data, length );
|
||||
|
||||
if( payload != NULL && len == 44 )
|
||||
{
|
||||
memcpy( version, &payload[12], 32 );
|
||||
version[32] = 0x00;
|
||||
|
||||
/* Spaces, for display */
|
||||
for( int i = 0; i < 32; i++ )
|
||||
{
|
||||
if( version[i] == 0x00 ) { version[i] = 0x20; }
|
||||
}
|
||||
}
|
||||
|
||||
return (const char * const)version;
|
||||
}
|
||||
|
||||
void ACIO::getReaderState( HANDLE serial, unsigned int id, card_state_t *state, unsigned int *keypresses, unsigned char *cardId )
|
||||
{
|
||||
unsigned char state_probe[] = { 0xAA, (id + 1), 0x01, 0x34, 0x00, 0x01, 0x10, 0xFF, };
|
||||
unsigned char data[1024];
|
||||
DWORD length;
|
||||
|
||||
/* Fix up checksum since ID is variable */
|
||||
state_probe[7] = calcPacketChecksum( state_probe );
|
||||
|
||||
/* Sane return */
|
||||
*keypresses = 0;
|
||||
|
||||
WriteFile( serial, state_probe, sizeof( state_probe ), &length, 0 );
|
||||
WAIT();
|
||||
ReadFile( serial, data, sizeof( data ), &length, 0 );
|
||||
|
||||
unsigned int readerId;
|
||||
unsigned int command;
|
||||
unsigned int len;
|
||||
unsigned int checksum;
|
||||
const unsigned char * const payload = getPacketData( &readerId, &command, &len, &checksum, data, length );
|
||||
|
||||
if( payload != NULL && len == 16 )
|
||||
{
|
||||
*keypresses = (payload[14] << 8) | payload[15];
|
||||
|
||||
*state = STATE_UNKNOWN;
|
||||
switch( payload[1] )
|
||||
{
|
||||
case 0x00:
|
||||
*state = STATE_REMOVED;
|
||||
break;
|
||||
case 0x10:
|
||||
*state = STATE_FRONT_SENSOR;
|
||||
break;
|
||||
case 0x30:
|
||||
*state = STATE_INSERTED;
|
||||
break;
|
||||
default:
|
||||
if( VERBOSE_DEBUG ) fprintf( stderr, "Unknown card state %02X!\n", payload[1] );
|
||||
break;
|
||||
}
|
||||
|
||||
if( payload[0] != 0x00 && payload[11] == 0x00 && *state == STATE_INSERTED )
|
||||
{
|
||||
memcpy( cardId, &payload[2], CARD_LENGTH );
|
||||
*state = STATE_READ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ACIO::setReaderState( HANDLE serial, unsigned int id, reader_state_t state )
|
||||
{
|
||||
unsigned char state_request[] = { 0xAA, (id + 1), 0x01, 0x35, 0x00, 0x02, 0x10, 0xFF, 0xFF, };
|
||||
unsigned char data[1024];
|
||||
DWORD length;
|
||||
|
||||
/* Set state */
|
||||
switch( state )
|
||||
{
|
||||
case STATE_NOT_READY:
|
||||
state_request[7] = 0x00;
|
||||
break;
|
||||
case STATE_GET_READY:
|
||||
state_request[7] = 0x03;
|
||||
break;
|
||||
case STATE_READY:
|
||||
state_request[7] = 0x11;
|
||||
break;
|
||||
case STATE_EJECT:
|
||||
state_request[7] = 0x12;
|
||||
break;
|
||||
default:
|
||||
if( VERBOSE_DEBUG ) fprintf( stderr, "Unknown reader state %02X!\n", state );
|
||||
state_request[7] = 0xFF;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Fix up checksum since ID is variable */
|
||||
state_request[8] = calcPacketChecksum( state_request );
|
||||
|
||||
WriteFile( serial, state_request, sizeof( state_request ), &length, 0 );
|
||||
WAIT();
|
||||
ReadFile( serial, data, sizeof( data ), &length, 0 );
|
||||
}
|
||||
|
||||
void ACIO::requestCardId( HANDLE serial, unsigned int id )
|
||||
{
|
||||
unsigned char id_request[] = { 0xAA, (id + 1), 0x01, 0x31, 0x00, 0x01, 0x10, 0xFF, };
|
||||
unsigned char data[1024];
|
||||
DWORD length;
|
||||
|
||||
/* Fix up checksum since ID is variable */
|
||||
id_request[7] = calcPacketChecksum( id_request );
|
||||
|
||||
WriteFile( serial, id_request, sizeof( id_request ), &length, 0 );
|
||||
WAIT();
|
||||
ReadFile( serial, data, sizeof( data ), &length, 0 );
|
||||
}
|
||||
|
||||
HANDLE ACIO::InitReaders(unsigned int &readerCount)
|
||||
{
|
||||
/* Walk serial chain, finding readers */
|
||||
HANDLE serial = NULL;
|
||||
const _TCHAR *comport[4] = { L"COM1", L"COM2", L"COM3", L"COM4" };
|
||||
const unsigned int baudrate[2] = { 57600, 9600 };
|
||||
const char *pattern[4] = { "\b\b\b ", "\b\b\b.", ".", "." };
|
||||
unsigned int which = 3;
|
||||
unsigned int pno = 0;
|
||||
|
||||
/* Put a space into location where we will be backspacing, for laziness */
|
||||
NON_DEBUG_PRINTF( " " );
|
||||
DEBUG_PRINTF( "...\n" );
|
||||
|
||||
/* Try to open the reader indefinitely */
|
||||
while( 1 )
|
||||
{
|
||||
/* Try next reader */
|
||||
which = (which + 1) % 4;
|
||||
|
||||
for (unsigned int baud = 0; baud < 2; baud++)
|
||||
{
|
||||
NON_DEBUG_PRINTF( "%s", pattern[(pno++) % 4] );
|
||||
DEBUG_PRINTF("Attempting to probe readers on %ls,%d\n", comport[which], baudrate[baud]);
|
||||
serial = openSerial( comport[which], baudrate[baud] );
|
||||
|
||||
if (serial == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DEBUG_PRINTF("Couldn't open com port!\n");
|
||||
serial = NULL;
|
||||
LONGWAIT();
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Ensure we start fresh */
|
||||
PurgeComm( serial, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR );
|
||||
|
||||
/* Init */
|
||||
for (int i = 0; i < INITIALIZATION_TRIES; i++)
|
||||
{
|
||||
if( probeReader( serial ) )
|
||||
{
|
||||
/* Get count */
|
||||
unsigned int count = getReaderCount( serial );
|
||||
if (count > 0)
|
||||
{
|
||||
DEBUG_PRINTF( "Saw %d readers!\n", count );
|
||||
readerCount = count;
|
||||
return serial;
|
||||
}
|
||||
}
|
||||
|
||||
NON_DEBUG_PRINTF( "%s", pattern[(pno++) % 4] );
|
||||
}
|
||||
|
||||
/* Failed, close */
|
||||
CloseHandle( serial );
|
||||
}
|
||||
|
||||
/* Failed to probe this port, try again on next one */
|
||||
DEBUG_PRINTF("Failed to probe readers!\n");
|
||||
serial = NULL;
|
||||
LONGWAIT();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
#pragma once
|
||||
|
||||
#include <tchar.h>
|
||||
#include <windows.h>
|
||||
|
||||
/* Length of the card ID in bytes */
|
||||
#define CARD_LENGTH 8
|
||||
|
||||
typedef enum
|
||||
{
|
||||
STATE_FRONT_SENSOR,
|
||||
STATE_INSERTED,
|
||||
STATE_READ,
|
||||
STATE_REMOVED,
|
||||
STATE_UNKNOWN,
|
||||
} card_state_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
STATE_NOT_READY,
|
||||
STATE_GET_READY,
|
||||
STATE_READY,
|
||||
STATE_EJECT,
|
||||
} reader_state_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
KEY_NONE,
|
||||
KEY_1,
|
||||
KEY_2,
|
||||
KEY_3,
|
||||
KEY_4,
|
||||
KEY_5,
|
||||
KEY_6,
|
||||
KEY_7,
|
||||
KEY_8,
|
||||
KEY_9,
|
||||
KEY_0,
|
||||
KEY_00,
|
||||
KEY_BLANK,
|
||||
} reader_keypress_t;
|
||||
|
||||
class ACIO
|
||||
{
|
||||
public:
|
||||
ACIO(void);
|
||||
~ACIO(void);
|
||||
|
||||
unsigned int getCount() { return readerCount; }
|
||||
reader_keypress_t getPressedKey(int reader);
|
||||
void requestCardInsert(int reader);
|
||||
void requestCardEject(int reader);
|
||||
bool getCardInserted(int reader);
|
||||
void getCardID(int reader, unsigned char *cardId);
|
||||
|
||||
private:
|
||||
unsigned int readerCount;
|
||||
HANDLE serial;
|
||||
unsigned int *old_keypresses;
|
||||
unsigned char cardId[CARD_LENGTH];
|
||||
card_state_t state;
|
||||
|
||||
HANDLE openSerial( const _TCHAR *arg, int baud );
|
||||
const unsigned char * const getPacketData(
|
||||
unsigned int *readerId,
|
||||
unsigned int *command,
|
||||
unsigned int *len,
|
||||
unsigned int *checksum,
|
||||
const unsigned char * const packet,
|
||||
unsigned int length
|
||||
);
|
||||
unsigned char calcPacketChecksum( const unsigned char * const data );
|
||||
int probeReader( HANDLE serial );
|
||||
unsigned int getReaderCount( HANDLE serial );
|
||||
void initReader( HANDLE serial, unsigned int id, int whichInit );
|
||||
const char * const getReaderVersion( HANDLE serial, unsigned int id );
|
||||
void getReaderState( HANDLE serial, unsigned int id, card_state_t *state, unsigned int *keypresses, unsigned char *cardId );
|
||||
void setReaderState( HANDLE serial, unsigned int id, reader_state_t state );
|
||||
void requestCardId( HANDLE serial, unsigned int id );
|
||||
HANDLE InitReaders( unsigned int &readerCount );
|
||||
};
|
631
ACIOLauncher.cpp
631
ACIOLauncher.cpp
|
@ -5,13 +5,9 @@
|
|||
#include <stdio.h>
|
||||
#include <tchar.h>
|
||||
#include <windows.h>
|
||||
#include "ACIO.h"
|
||||
#include "Menu.h"
|
||||
|
||||
#define WAIT() Sleep( 100 )
|
||||
#define LONGWAIT() Sleep( 1000 )
|
||||
|
||||
/* Define to 1 to get verbose debugging */
|
||||
#define VERBOSE_DEBUG 0
|
||||
#include "Debug.h"
|
||||
|
||||
/**
|
||||
* Define to 1 to enable card reader mode, currently only works with
|
||||
|
@ -22,458 +18,6 @@
|
|||
*/
|
||||
#define CARD_READER_MODE 0
|
||||
|
||||
/* Length of an ACIO packet without payload or checksum */
|
||||
#define HEADER_LENGTH 5
|
||||
|
||||
/* Minimum packet length including header and checksum */
|
||||
#define MINIMUM_PACKET_LENGTH (HEADER_LENGTH + 1)
|
||||
|
||||
/* Start of Message */
|
||||
#define SOM 0xAA
|
||||
|
||||
/* Location of various parts of the protocol */
|
||||
#define ID_LOCATION 0
|
||||
#define COMMAND_HIGH_LOCATION 1
|
||||
#define COMMAND_LOW_LOCATION 2
|
||||
#define LENGTH_HIGH_LOCATION 3
|
||||
#define LENGTH_LOW_LOCATION 4
|
||||
|
||||
/* Length of the card ID in bytes */
|
||||
#define CARD_LENGTH 8
|
||||
|
||||
/* Number of times to try initializing a reader by sending baud probe */
|
||||
#define INITIALIZATION_TRIES 16
|
||||
|
||||
/* Number of return baud probes to receive before we consider ourselves initialized */
|
||||
#define MIN_PROBES_RECEIVED 5
|
||||
|
||||
typedef enum
|
||||
{
|
||||
STATE_FRONT_SENSOR,
|
||||
STATE_INSERTED,
|
||||
STATE_READ,
|
||||
STATE_REMOVED,
|
||||
STATE_UNKNOWN,
|
||||
} card_state_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
STATE_NOT_READY,
|
||||
STATE_GET_READY,
|
||||
STATE_READY,
|
||||
STATE_EJECT,
|
||||
} reader_state_t;
|
||||
|
||||
/* Debug global which can be set via command line flag --debug */
|
||||
bool debug = false;
|
||||
|
||||
/* Debug macros that are enabled via the --debug flag */
|
||||
#define DEBUG_PRINTF(...) do { if(debug) { printf(__VA_ARGS__); } } while(0)
|
||||
#define DEBUG_PRINT_HEX(data, length) do { if(debug) { printHex(data, length); } } while(0)
|
||||
|
||||
/* Macros that are enabled when debug is not enabled */
|
||||
#define NON_DEBUG_PRINTF(...) do { if(!debug) { printf(__VA_ARGS__); } } while(0)
|
||||
|
||||
void printHex(const unsigned char * const data, int length )
|
||||
{
|
||||
printf( "Length: %d bytes\n", length );
|
||||
|
||||
for( int x = 0; x < length; x++ )
|
||||
{
|
||||
printf( "%02X ", data[x] );
|
||||
}
|
||||
|
||||
printf( "\n" );
|
||||
}
|
||||
|
||||
HANDLE OpenSerial( const _TCHAR *arg, int baud )
|
||||
{
|
||||
HANDLE hSerial = CreateFile(arg, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
if (hSerial == INVALID_HANDLE_VALUE) { return hSerial; }
|
||||
|
||||
int rate;
|
||||
|
||||
switch( baud )
|
||||
{
|
||||
case 4800:
|
||||
rate = CBR_4800;
|
||||
break;
|
||||
case 9600:
|
||||
rate = CBR_9600;
|
||||
break;
|
||||
case 19200:
|
||||
rate = CBR_19200;
|
||||
break;
|
||||
case 38400:
|
||||
rate = CBR_38400;
|
||||
break;
|
||||
case 57600:
|
||||
rate = CBR_57600;
|
||||
break;
|
||||
case 115200:
|
||||
rate = CBR_115200;
|
||||
break;
|
||||
default:
|
||||
rate = CBR_9600;
|
||||
break;
|
||||
}
|
||||
|
||||
DCB dcbSerialParams = {0};
|
||||
|
||||
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
|
||||
dcbSerialParams.BaudRate = rate;
|
||||
dcbSerialParams.ByteSize = 8;
|
||||
dcbSerialParams.StopBits = ONESTOPBIT;
|
||||
dcbSerialParams.Parity = NOPARITY;
|
||||
dcbSerialParams.fOutxCtsFlow = 0;
|
||||
dcbSerialParams.fOutxDsrFlow = 0;
|
||||
dcbSerialParams.fDtrControl = DTR_CONTROL_DISABLE;
|
||||
dcbSerialParams.fDsrSensitivity = 0;
|
||||
dcbSerialParams.fOutX = 0;
|
||||
dcbSerialParams.fInX = 0;
|
||||
dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE;
|
||||
|
||||
SetCommState(hSerial, &dcbSerialParams);
|
||||
|
||||
COMMTIMEOUTS timeouts = { 0 };
|
||||
|
||||
timeouts.ReadIntervalTimeout = 1;
|
||||
timeouts.ReadTotalTimeoutConstant = 1;
|
||||
timeouts.ReadTotalTimeoutMultiplier = 1;
|
||||
|
||||
SetCommTimeouts(hSerial, &timeouts);
|
||||
return hSerial;
|
||||
}
|
||||
|
||||
const unsigned char * const getPacketData( unsigned int *readerId,
|
||||
unsigned int *command,
|
||||
unsigned int *len,
|
||||
unsigned int *checksum,
|
||||
const unsigned char * const packet,
|
||||
unsigned int length )
|
||||
{
|
||||
/* Exit early if we didn't get a good packet */
|
||||
if (length < MINIMUM_PACKET_LENGTH) { return NULL; }
|
||||
|
||||
for( unsigned int i = 0; i <= length - MINIMUM_PACKET_LENGTH; i++ )
|
||||
{
|
||||
const unsigned char * const data = &packet[i];
|
||||
|
||||
if( data[0] != SOM )
|
||||
{
|
||||
/* Get command */
|
||||
*readerId = data[ID_LOCATION];
|
||||
*command = (data[COMMAND_HIGH_LOCATION] << 8) | data[COMMAND_LOW_LOCATION];
|
||||
*len = (data[LENGTH_HIGH_LOCATION] << 8) | data[LENGTH_LOW_LOCATION];
|
||||
*checksum = data[(*len) + HEADER_LENGTH];
|
||||
return data + HEADER_LENGTH;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static unsigned char calcPacketChecksum( const unsigned char * const data )
|
||||
{
|
||||
unsigned char *packet = (unsigned char *)data;
|
||||
|
||||
/* Dirty */
|
||||
while( 1 )
|
||||
{
|
||||
/* Get to start of packet */
|
||||
if( packet[0] == SOM )
|
||||
{
|
||||
packet++;
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int length = ((packet[LENGTH_HIGH_LOCATION] << 8) | packet[LENGTH_LOW_LOCATION]);
|
||||
unsigned int sum = 0;
|
||||
|
||||
/* Skip SOM, not part of packet CRC */
|
||||
for( unsigned int i = 0; i < length + HEADER_LENGTH; i++ )
|
||||
{
|
||||
sum += packet[i];
|
||||
}
|
||||
|
||||
return sum & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
int probeReader( HANDLE serial )
|
||||
{
|
||||
const unsigned char packet_probe[] = { 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, };
|
||||
unsigned char data[1024];
|
||||
DWORD length;
|
||||
|
||||
WriteFile( serial, packet_probe, sizeof( packet_probe ), &length, 0 );
|
||||
ReadFile( serial, data, sizeof( data ), &length, 0 );
|
||||
|
||||
if (length < MIN_PROBES_RECEIVED)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < length; i++)
|
||||
{
|
||||
if (data[i] != 0xAA)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear out any additional init the reader sends */
|
||||
while (true)
|
||||
{
|
||||
ReadFile( serial, data, sizeof( data ), &length, 0 );
|
||||
if (length == 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int getReaderCount( HANDLE serial )
|
||||
{
|
||||
const unsigned char count_probe[] = { 0xAA, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, };
|
||||
unsigned char data[1024];
|
||||
DWORD length;
|
||||
|
||||
WriteFile( serial, count_probe, sizeof( count_probe ), &length, 0 );
|
||||
WAIT();
|
||||
ReadFile( serial, data, sizeof( data ), &length, 0 );
|
||||
|
||||
unsigned int readerId;
|
||||
unsigned int command;
|
||||
unsigned int len;
|
||||
unsigned int checksum;
|
||||
const unsigned char * const payload = getPacketData( &readerId, &command, &len, &checksum, data, length );
|
||||
|
||||
if( payload == NULL ) { return 0; }
|
||||
if( len != 1 ) { return 0; }
|
||||
|
||||
return payload[0];
|
||||
}
|
||||
|
||||
void initReader( HANDLE serial, unsigned int id, int whichInit )
|
||||
{
|
||||
unsigned int init_length[3] = { 7, 7, 8 };
|
||||
unsigned char init_probe[3][8] = { { 0xAA, (id + 1), 0x00, 0x03, 0x00, 0x00, 0xFF, },
|
||||
{ 0xAA, (id + 1), 0x01, 0x00, 0x00, 0x00, 0xFF, },
|
||||
{ 0xAA, (id + 1), 0x01, 0x30, 0x00, 0x01, 0x00, 0xFF, } };
|
||||
unsigned char data[1024];
|
||||
DWORD length;
|
||||
|
||||
/* Fix up checksum since ID is variable */
|
||||
init_probe[whichInit][init_length[whichInit] - 1] = calcPacketChecksum( init_probe[whichInit] );
|
||||
|
||||
WriteFile( serial, init_probe[whichInit], init_length[whichInit], &length, 0 );
|
||||
WAIT();
|
||||
ReadFile( serial, data, sizeof( data ), &length, 0 );
|
||||
}
|
||||
|
||||
const char * const getReaderVersion( HANDLE serial, unsigned int id )
|
||||
{
|
||||
unsigned char version_probe[] = { 0xAA, (id + 1), 0x00, 0x02, 0x00, 0x00, 0xFF, };
|
||||
static char version[33] = { 0x00 };
|
||||
unsigned char data[1024];
|
||||
DWORD length;
|
||||
|
||||
/* Fix up checksum since ID is variable */
|
||||
version_probe[6] = calcPacketChecksum( version_probe );
|
||||
|
||||
WriteFile( serial, version_probe, sizeof( version_probe ), &length, 0 );
|
||||
WAIT();
|
||||
ReadFile( serial, data, sizeof( data ), &length, 0 );
|
||||
|
||||
unsigned int readerId;
|
||||
unsigned int command;
|
||||
unsigned int len;
|
||||
unsigned int checksum;
|
||||
const unsigned char * const payload = getPacketData( &readerId, &command, &len, &checksum, data, length );
|
||||
|
||||
if( payload != NULL && len == 44 )
|
||||
{
|
||||
memcpy( version, &payload[12], 32 );
|
||||
version[32] = 0x00;
|
||||
|
||||
/* Spaces, for display */
|
||||
for( int i = 0; i < 32; i++ )
|
||||
{
|
||||
if( version[i] == 0x00 ) { version[i] = 0x20; }
|
||||
}
|
||||
}
|
||||
|
||||
return (const char * const)version;
|
||||
}
|
||||
|
||||
void getReaderState( HANDLE serial, unsigned int id, card_state_t *state, unsigned int *keypresses, unsigned char *cardId )
|
||||
{
|
||||
unsigned char state_probe[] = { 0xAA, (id + 1), 0x01, 0x34, 0x00, 0x01, 0x10, 0xFF, };
|
||||
unsigned char data[1024];
|
||||
DWORD length;
|
||||
|
||||
/* Fix up checksum since ID is variable */
|
||||
state_probe[7] = calcPacketChecksum( state_probe );
|
||||
|
||||
/* Sane return */
|
||||
*keypresses = 0;
|
||||
memset( cardId, 0, CARD_LENGTH );
|
||||
|
||||
WriteFile( serial, state_probe, sizeof( state_probe ), &length, 0 );
|
||||
WAIT();
|
||||
ReadFile( serial, data, sizeof( data ), &length, 0 );
|
||||
|
||||
unsigned int readerId;
|
||||
unsigned int command;
|
||||
unsigned int len;
|
||||
unsigned int checksum;
|
||||
const unsigned char * const payload = getPacketData( &readerId, &command, &len, &checksum, data, length );
|
||||
|
||||
if( payload != NULL && len == 16 )
|
||||
{
|
||||
*keypresses = (payload[14] << 8) | payload[15];
|
||||
|
||||
*state = STATE_UNKNOWN;
|
||||
switch( payload[1] )
|
||||
{
|
||||
case 0x00:
|
||||
*state = STATE_REMOVED;
|
||||
break;
|
||||
case 0x10:
|
||||
*state = STATE_FRONT_SENSOR;
|
||||
break;
|
||||
case 0x30:
|
||||
*state = STATE_INSERTED;
|
||||
break;
|
||||
default:
|
||||
if( VERBOSE_DEBUG ) fprintf( stderr, "Unknown card state %02X!\n", payload[1] );
|
||||
break;
|
||||
}
|
||||
|
||||
if( payload[0] != 0x00 && payload[11] == 0x00 && *state == STATE_INSERTED )
|
||||
{
|
||||
memcpy( cardId, &payload[2], CARD_LENGTH );
|
||||
*state = STATE_READ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setReaderState( HANDLE serial, unsigned int id, reader_state_t state )
|
||||
{
|
||||
unsigned char state_request[] = { 0xAA, (id + 1), 0x01, 0x35, 0x00, 0x02, 0x10, 0xFF, 0xFF, };
|
||||
unsigned char data[1024];
|
||||
DWORD length;
|
||||
|
||||
/* Set state */
|
||||
switch( state )
|
||||
{
|
||||
case STATE_NOT_READY:
|
||||
state_request[7] = 0x00;
|
||||
break;
|
||||
case STATE_GET_READY:
|
||||
state_request[7] = 0x03;
|
||||
break;
|
||||
case STATE_READY:
|
||||
state_request[7] = 0x11;
|
||||
break;
|
||||
case STATE_EJECT:
|
||||
state_request[7] = 0x12;
|
||||
break;
|
||||
default:
|
||||
if( VERBOSE_DEBUG ) fprintf( stderr, "Unknown reader state %02X!\n", state );
|
||||
state_request[7] = 0xFF;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Fix up checksum since ID is variable */
|
||||
state_request[8] = calcPacketChecksum( state_request );
|
||||
|
||||
WriteFile( serial, state_request, sizeof( state_request ), &length, 0 );
|
||||
WAIT();
|
||||
ReadFile( serial, data, sizeof( data ), &length, 0 );
|
||||
}
|
||||
|
||||
void requestCardId( HANDLE serial, unsigned int id )
|
||||
{
|
||||
unsigned char id_request[] = { 0xAA, (id + 1), 0x01, 0x31, 0x00, 0x01, 0x10, 0xFF, };
|
||||
unsigned char data[1024];
|
||||
DWORD length;
|
||||
|
||||
/* Fix up checksum since ID is variable */
|
||||
id_request[7] = calcPacketChecksum( id_request );
|
||||
|
||||
WriteFile( serial, id_request, sizeof( id_request ), &length, 0 );
|
||||
WAIT();
|
||||
ReadFile( serial, data, sizeof( data ), &length, 0 );
|
||||
}
|
||||
|
||||
HANDLE InitReaders(unsigned int &readerCount)
|
||||
{
|
||||
/* Walk serial chain, finding readers */
|
||||
HANDLE serial = NULL;
|
||||
const _TCHAR *comport[4] = { L"COM1", L"COM2", L"COM3", L"COM4" };
|
||||
const unsigned int baudrate[2] = { 57600, 9600 };
|
||||
const char *pattern[4] = { "\b\b\b ", "\b\b\b.", ".", "." };
|
||||
unsigned int which = 3;
|
||||
unsigned int pno = 0;
|
||||
|
||||
/* Put a space into location where we will be backspacing, for laziness */
|
||||
NON_DEBUG_PRINTF( " " );
|
||||
DEBUG_PRINTF( "...\n" );
|
||||
|
||||
/* Try to open the reader indefinitely */
|
||||
while( 1 )
|
||||
{
|
||||
/* Try next reader */
|
||||
which = (which + 1) % 4;
|
||||
|
||||
for (unsigned int baud = 0; baud < 2; baud++)
|
||||
{
|
||||
NON_DEBUG_PRINTF( "%s", pattern[(pno++) % 4] );
|
||||
DEBUG_PRINTF("Attempting to probe readers on %ls,%d\n", comport[which], baudrate[baud]);
|
||||
serial = OpenSerial( comport[which], baudrate[baud] );
|
||||
|
||||
if (serial == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DEBUG_PRINTF("Couldn't open com port!\n");
|
||||
serial = NULL;
|
||||
LONGWAIT();
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Ensure we start fresh */
|
||||
PurgeComm( serial, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR );
|
||||
|
||||
/* Init */
|
||||
for (int i = 0; i < INITIALIZATION_TRIES; i++)
|
||||
{
|
||||
if( probeReader( serial ) )
|
||||
{
|
||||
/* Get count */
|
||||
unsigned int count = getReaderCount( serial );
|
||||
if (count > 0)
|
||||
{
|
||||
DEBUG_PRINTF( "Saw %d readers!\n", count );
|
||||
readerCount = count;
|
||||
return serial;
|
||||
}
|
||||
}
|
||||
|
||||
NON_DEBUG_PRINTF( "%s", pattern[(pno++) % 4] );
|
||||
}
|
||||
|
||||
/* Failed, close */
|
||||
CloseHandle( serial );
|
||||
}
|
||||
|
||||
/* Failed to probe this port, try again on next one */
|
||||
DEBUG_PRINTF("Failed to probe readers!\n");
|
||||
serial = NULL;
|
||||
LONGWAIT();
|
||||
}
|
||||
}
|
||||
|
||||
int _tmain(int argc, _TCHAR* argv[])
|
||||
{
|
||||
/* Ensure command is good */
|
||||
|
@ -522,157 +66,118 @@ int _tmain(int argc, _TCHAR* argv[])
|
|||
DEBUG_PRINTF( "Enabling debug mode!\n" );
|
||||
|
||||
/* Initialize menu */
|
||||
Menu menu = Menu(inifile, debug);
|
||||
Menu *menu = new Menu(inifile);
|
||||
|
||||
if( menu.NumberOfEntries() < 1 )
|
||||
if( menu->NumberOfEntries() < 1 )
|
||||
{
|
||||
fprintf( stderr, "No games configured to launch!\n" );
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Walk serial chain, finding readers */
|
||||
unsigned int count = 0;
|
||||
printf( "Initializing readers" );
|
||||
HANDLE serial = InitReaders(count);
|
||||
printf( "\n" );
|
||||
|
||||
/* Get version of all readers */
|
||||
for( unsigned int x = 0; x < count; x++ )
|
||||
{
|
||||
/* Print out reader version in debug mode */
|
||||
DEBUG_PRINTF( "Reader %d returned version %s\n", x + 1, getReaderVersion( serial, x ) );
|
||||
|
||||
/* Walk init routine */
|
||||
initReader( serial, x, 0 );
|
||||
initReader( serial, x, 1 );
|
||||
initReader( serial, x, 2 );
|
||||
|
||||
/* Set ready for keys only */
|
||||
setReaderState( serial, x, STATE_EJECT );
|
||||
}
|
||||
ACIO *readers = new ACIO();
|
||||
|
||||
/* Whether we're in read mode */
|
||||
unsigned int read = 0;
|
||||
|
||||
/* For key input debouncing */
|
||||
unsigned int *old_keypresses = (unsigned int *)malloc(sizeof(unsigned int) * count);
|
||||
|
||||
/* Actual game to load */
|
||||
char *path = NULL;
|
||||
bool selected = false;
|
||||
|
||||
/* It may have taken a long time to init */
|
||||
menu.ResetTimeout();
|
||||
menu->ResetTimeout();
|
||||
|
||||
/* Display user prompts */
|
||||
menu.DisplayPrompt();
|
||||
menu.DisplayGames();
|
||||
menu->DisplayPrompt();
|
||||
menu->DisplayGames();
|
||||
|
||||
/* Loop until time's up, then boot */
|
||||
while( !selected )
|
||||
{
|
||||
menu.Tick();
|
||||
if (menu.ShouldBootDefault())
|
||||
menu->Tick();
|
||||
if (menu->ShouldBootDefault())
|
||||
{
|
||||
printf( "No selection made, booting %s.\n", menu.GetSelectedName() );
|
||||
path = menu.GetSelectedPath();
|
||||
printf( "No selection made, booting %s.\n", menu->GetSelectedName() );
|
||||
path = menu->GetSelectedPath();
|
||||
selected = true;
|
||||
break;
|
||||
}
|
||||
|
||||
for( unsigned int x = 0; x < count; x++ )
|
||||
for( unsigned int x = 0; x < readers->getCount(); x++ )
|
||||
{
|
||||
unsigned int game = 0;
|
||||
unsigned int currentpresses;
|
||||
unsigned char cardId[CARD_LENGTH];
|
||||
card_state_t state;
|
||||
bool request_reader_toggle = false;
|
||||
|
||||
/* Find new presses only */
|
||||
getReaderState( serial, x, &state, ¤tpresses, cardId );
|
||||
unsigned int keypresses = currentpresses & (~old_keypresses[x]);
|
||||
old_keypresses[x] = currentpresses;
|
||||
|
||||
if (keypresses & 0x0002 )
|
||||
{
|
||||
switch(readers->getPressedKey(x)) {
|
||||
case KEY_1:
|
||||
game = 1;
|
||||
}
|
||||
if (keypresses & 0x0020 )
|
||||
{
|
||||
break;
|
||||
case KEY_2:
|
||||
game = 2;
|
||||
}
|
||||
if (keypresses & 0x0200 )
|
||||
{
|
||||
break;
|
||||
case KEY_3:
|
||||
game = 3;
|
||||
}
|
||||
if (keypresses & 0x0004 )
|
||||
{
|
||||
break;
|
||||
case KEY_4:
|
||||
game = 4;
|
||||
}
|
||||
if (keypresses & 0x0040 )
|
||||
{
|
||||
break;
|
||||
case KEY_5:
|
||||
game = 5;
|
||||
}
|
||||
if (keypresses & 0x0400 )
|
||||
{
|
||||
break;
|
||||
case KEY_6:
|
||||
game = 6;
|
||||
}
|
||||
if (keypresses & 0x0008 )
|
||||
{
|
||||
break;
|
||||
case KEY_7:
|
||||
game = 7;
|
||||
}
|
||||
if (keypresses & 0x0080 )
|
||||
{
|
||||
break;
|
||||
case KEY_8:
|
||||
game = 8;
|
||||
}
|
||||
if (keypresses & 0x0800 )
|
||||
{
|
||||
break;
|
||||
case KEY_9:
|
||||
game = 9;
|
||||
}
|
||||
if (keypresses & 0x0001 )
|
||||
{
|
||||
menu.PageUp();
|
||||
}
|
||||
if (keypresses & 0x0010 )
|
||||
{
|
||||
menu.PageDown();
|
||||
break;
|
||||
case KEY_0:
|
||||
menu->PageUp();
|
||||
break;
|
||||
case KEY_00:
|
||||
menu->PageDown();
|
||||
break;
|
||||
case KEY_BLANK:
|
||||
request_reader_toggle = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (game != 0)
|
||||
{
|
||||
/* Chose a game! */
|
||||
if (menu.SelectGame(game))
|
||||
if (menu->SelectGame(game))
|
||||
{
|
||||
/* Time to boot this game! */
|
||||
printf( "Booting %s.\n", menu.GetSelectedName() );
|
||||
path = menu.GetSelectedPath();
|
||||
printf( "Booting %s.\n", menu->GetSelectedName() );
|
||||
path = menu->GetSelectedPath();
|
||||
selected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( CARD_READER_MODE && (keypresses & 0x0100) )
|
||||
if( CARD_READER_MODE && request_reader_toggle )
|
||||
{
|
||||
/* Pressed empty button, go into/out of card read mode */
|
||||
if (!read)
|
||||
{
|
||||
printf( "Entering card read mode, insert card!\n" );
|
||||
for( unsigned int y = 0; y < count; y++ )
|
||||
for( unsigned int y = 0; y < readers->getCount(); y++ )
|
||||
{
|
||||
setReaderState( serial, y, STATE_EJECT );
|
||||
setReaderState( serial, y, STATE_NOT_READY );
|
||||
setReaderState( serial, y, STATE_GET_READY );
|
||||
setReaderState( serial, y, STATE_READY );
|
||||
readers->requestCardInsert(y);
|
||||
}
|
||||
read = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf( "Entering menu mode!\n" );
|
||||
for( unsigned int y = 0; y < count; y++ )
|
||||
for( unsigned int y = 0; y < readers->getCount(); y++ )
|
||||
{
|
||||
setReaderState( serial, y, STATE_EJECT );
|
||||
setReaderState( serial, y, STATE_NOT_READY );
|
||||
setReaderState( serial, y, STATE_GET_READY );
|
||||
readers->requestCardEject(y);
|
||||
}
|
||||
read = 0;
|
||||
}
|
||||
|
@ -683,46 +188,28 @@ int _tmain(int argc, _TCHAR* argv[])
|
|||
if (!read) { continue; }
|
||||
|
||||
/* Reset time, so we stay here forever */
|
||||
menu.ResetTimeout();
|
||||
menu->ResetTimeout();
|
||||
|
||||
if( state == STATE_INSERTED )
|
||||
if( readers->getCardInserted(x) )
|
||||
{
|
||||
/* Ask for card */
|
||||
requestCardId( serial, x );
|
||||
}
|
||||
unsigned char cardId[CARD_LENGTH];
|
||||
readers->getCardID(x, cardId);
|
||||
|
||||
if( state == STATE_READ )
|
||||
{
|
||||
/* Display card */
|
||||
printf( "Card read: %02X%02X%02X%02X%02X%02X%02X%02X\n",
|
||||
cardId[0], cardId[1], cardId[2], cardId[3],
|
||||
cardId[4], cardId[5], cardId[6], cardId[7] );
|
||||
|
||||
LONGWAIT();
|
||||
setReaderState( serial, x, STATE_EJECT );
|
||||
LONGWAIT();
|
||||
|
||||
/* Walk init routine again. For some reason, it reads the same
|
||||
* card ID the second time through, so I just reinit. */
|
||||
initReader( serial, x, 0 );
|
||||
initReader( serial, x, 1 );
|
||||
initReader( serial, x, 2 );
|
||||
|
||||
setReaderState( serial, x, STATE_NOT_READY );
|
||||
setReaderState( serial, x, STATE_GET_READY );
|
||||
setReaderState( serial, x, STATE_READY );
|
||||
readers->requestCardEject(x);
|
||||
readers->requestCardInsert(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Close the reader so we can let the game talk to it */
|
||||
for( unsigned int y = 0; y < count; y++ )
|
||||
{
|
||||
setReaderState( serial, y, STATE_EJECT );
|
||||
setReaderState( serial, y, STATE_NOT_READY );
|
||||
setReaderState( serial, y, STATE_GET_READY );
|
||||
}
|
||||
CloseHandle( serial );
|
||||
/* Kill menu and ACIO connection */
|
||||
delete readers;
|
||||
delete menu;
|
||||
|
||||
if (path != NULL)
|
||||
{
|
||||
|
|
|
@ -170,10 +170,18 @@
|
|||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\ACIO.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\ACIOLauncher.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Debug.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Menu.cpp"
|
||||
>
|
||||
|
@ -184,6 +192,14 @@
|
|||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\ACIO.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Debug.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Menu.h"
|
||||
>
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include "Debug.h"
|
||||
|
||||
/* Debug global which can be set via command line flag --debug */
|
||||
bool debug = false;
|
||||
|
||||
void printHex(const unsigned char * const data, int length )
|
||||
{
|
||||
printf( "Length: %d bytes\n", length );
|
||||
|
||||
for( int x = 0; x < length; x++ )
|
||||
{
|
||||
printf( "%02X ", data[x] );
|
||||
}
|
||||
|
||||
printf( "\n" );
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
/* Define to 1 to get verbose debugging */
|
||||
#define VERBOSE_DEBUG 0
|
||||
|
||||
/* Debug global which can be set via command line flag --debug */
|
||||
extern bool debug;
|
||||
|
||||
/* Debug macros that are enabled via the --debug flag */
|
||||
#define DEBUG_PRINTF(...) do { if(debug) { printf(__VA_ARGS__); } } while(0)
|
||||
#define DEBUG_PRINT_HEX(data, length) do { if(debug) { printHex(data, length); } } while(0)
|
||||
|
||||
/* Macros that are enabled when debug is not enabled */
|
||||
#define NON_DEBUG_PRINTF(...) do { if(!debug) { printf(__VA_ARGS__); } } while(0)
|
||||
|
||||
void printHex(const unsigned char * const data, int length );
|
6
Menu.cpp
6
Menu.cpp
|
@ -2,12 +2,10 @@
|
|||
#include <windows.h>
|
||||
|
||||
#include "Menu.h"
|
||||
#include "Debug.h"
|
||||
|
||||
Menu::Menu(_TCHAR *inifile, bool isDebugEnabled)
|
||||
Menu::Menu(_TCHAR *inifile)
|
||||
{
|
||||
/* Set up debug */
|
||||
debug = isDebugEnabled;
|
||||
|
||||
/* Read settings */
|
||||
settings = LoadSettings( inifile, &num_programs );
|
||||
|
||||
|
|
3
Menu.h
3
Menu.h
|
@ -22,7 +22,7 @@ typedef struct
|
|||
class Menu
|
||||
{
|
||||
public:
|
||||
Menu(_TCHAR *inifile, bool isDebugEnabled);
|
||||
Menu(_TCHAR *inifile);
|
||||
~Menu(void);
|
||||
|
||||
unsigned int NumberOfEntries() { return num_programs; }
|
||||
|
@ -38,7 +38,6 @@ class Menu
|
|||
void ResetTimeout();
|
||||
bool ShouldBootDefault();
|
||||
private:
|
||||
bool debug;
|
||||
unsigned int num_programs;
|
||||
unsigned int start;
|
||||
unsigned int end;
|
||||
|
|
Loading…
Reference in New Issue