/************************************************************************************************************
AVR code to emulate Playstation game controller protocol
date: October 12, 2009
compiler: gcc-avr compiler
AVR: ATmega324p
clock source: 8 MHz external crystal
*************************************************************************************************************/
#include <avr/io.h>
#include "def.h"
#include "other.h"
#define F_CPU 8000000UL
#include <util/delay.h>
#include <avr/interrupt.h>
#include <string.h>
#include <inttypes.h>
#include <util/twi.h>
int main(void){
uint8_t final_data[18]; // array stores final formatted data that is sent to ps2
uint8_t dsc_data[6]; // array stores raw data acquired from ps controller
uint8_t chuck_data[6]; // array stores raw data acquired from nunchuck
uint8_t command[6]; // array stores commands sent from ps2 in order they are received
uint8_t saturn_data[2]; // array stores raw data acquired from saturn controller
uint8_t nes_data[2]; // array stores raw data acquired from NES controller
uint8_t DSC_mode_ID = 0x00; // mode ID given by controller connected to ps controller port
uint8_t DSC_config_counter = 0x00; // counter used to increment ps controller config sequence
uint8_t remapped_x; // stores nunchuck x-axis tilt value in remapped 8-bit range
uint8_t remapped_y; // stores nunchuck y-axis tilt value in remapped 8-bit range
uint8_t CSR0 = 0x00; // command status register 0
uint8_t MSR0 = 0x00; // macro status register 0
uint8_t TSR0 = 0x00; // turbo status register 0
uint8_t GCSR0 = 0x00; // game controller status register 0
uint8_t display_tracker = 0x00; // keeps track of displayed message on LCD
uint8_t katamari_counter = 0x01; // counter for katamari mode macro
uint8_t turbo_counter = 0x00; // counter for turbo mode macro
uint8_t reader = 0x00;
char welcome[] = "Welcome DSC Emu v2.5";
char date[] = "Compiled 10/12/2009";
char katamari[] = "Katamari";
char racing[] = "Racing";
char arcade[] = "Arcade";
char standard[] = "Default";
char turbo[] = "Turbo";
char serial_in[] = "Serial Input";
char mode[] = " Mode";
final_data[0] = 0xFF; // Initialise data variables with neutral values
final_data[1] = 0xFF;
final_data[2] = 0x80;
final_data[3] = 0x80;
final_data[4] = 0x80;
final_data[5] = 0x80;
command[0] = 0x00;
command[1] = 0x00;
command[2] = 0x00;
command[3] = 0x00;
command[4] = 0x00;
init(); // configure all AVR registers and interrupts
lcd_init(); // initialise LCD
lcd_string_print(welcome); // print top line welcome message
lcd_move_to_address(SECOND_LINE);
lcd_string_print(date);
lcd_instruction_write(RETURN_HOME);
/* Infinite while loop*/
while(1){
/*PS-AVR SPI SECTION*******************************************************************************************/
if(~SPI_PIN & _BV(SS)){ // If attention line (SS/PB2) is brought low, enter transmission mode
reader = SPSR; // Read SPI status register to clear SPIF flag
SPDR = ~0xFF; // Write SPI data register with initial dummy byte
START_TIMER_AT(1); // setup 1ms timer
// loop while timer counts up, SS remains low, and SPI transmission flag not set
while((!(TIFR2 & _BV(TOV2))) && (~SPI_PIN & _BV(SS)) && (!(SPSR & _BV(SPIF))));
// If these two remain true it means SPI hardware has received a byte and communication continues
if((!(TIFR2 & _BV(TOV2))) && (~SPI_PIN &_BV(SS))){
command[0] = SPDR; // Read first command byte from SPI buffer
if(command[0] == 0x01){ // If PS is not addressing controller, abandon communication
_delay_us(4); // delay before ACK necessary for Ps1 compatibility
ACKNOWLEDGE; // ACK pulse sent following every byte except final byte
if((CSR0 & _BV(ANALOG_MODE_BIT)) && (!(CSR0 & _BV(CONFIG_MODE_BIT)))){ // if analog mode is active and config mode is inactive...
PS_AVR_COMM(0x73, command[1]);} // ...send 0x73, analog mode ID
else if((!(CSR0 & _BV(ANALOG_MODE_BIT))) && (!(CSR0 & _BV(CONFIG_MODE_BIT)))){ // if neither config mode nor analog mode active...
PS_AVR_COMM(0x41, command[1]);} // ...send 0x41, digital mode ID
else if(CSR0 & _BV(CONFIG_MODE_BIT)){ // if config mode is active...
PS_AVR_COMM(0xF3, command[1]);} // ...send 0xF3, config mode ID
// tests for known commands which the adapter will reply to, commands not listed will terminate communication for the current packet
// 0x42 = main polling command used to get control data from adapter
// 0x43 = enter/exit config mode command
// 0x44 = switch between analog/digital modes and lock/unlock controller in specified mode
// 0x45 = command to retrieve status/ID info from adapter
// 0x46 = command to retrieve 10 bytes of mystery data from adapter over two packets
// 0x47 = command to retrieve 5 bytes of mystery data from adapter
// 0x4C = command to retrieve 10 bytes of mystery data from adapter over two packets
// 0x4D = maps rumble motor commands to command bytes 3 and 4 in 0x42 polling packet
if((command[1] == 0x42) || (command[1] == 0x43) || (command[1] == 0x44) || (command[1] == 0x45) || (command[1] == 0x46) || (command[1] == 0x47) || (command[1] == 0x4C) || (command[1] == 0x4D)){
_delay_us(4);
ACKNOWLEDGE;
PS_AVR_COMM(0x5A, command[2]); // filler byte, always 0x5A
if((CSR0 & _BV(CONFIG_MODE_BIT)) && (command[1] == 0x45)){ // if adapter is in config mode and 0x45 command is received
final_data[0] = 0x01; // meaning of these bytes is unknown, copied from analysis of a real Ps1 controller response
final_data[1] = 0x02;
(CSR0 & _BV(ANALOG_MODE_BIT)) ? (final_data[2] = 0x01) : (final_data[2] = 0x00); // 1 if in analog mode, otherwise 0
final_data[3] = 0x02;
final_data[4] = 0x01;
final_data[5] = 0x00;
}
// sets up first two data bytes for a 0x4D command, these bytes report the current rumble motor mapping
if((CSR0 & _BV(CONFIG_MODE_BIT)) && (command[1] == 0x4D)){
if(CSR0 & _BV(FIRST_MOTOR_BYTE_SMALL))
final_data[0] = 0x00;
else if(CSR0 & _BV(FIRST_MOTOR_BYTE_LARGE))
final_data[0] = 0x01;
else
final_data[0] = 0xFF;
if(CSR0 & _BV(SECOND_MOTOR_BYTE_SMALL))
final_data[1] = 0x00;
else if(CSR0 & _BV(SECOND_MOTOR_BYTE_LARGE))
final_data[1] = 0x01;
else
final_data[1] = 0xFF;
}
// ps1 will reject data in the 0x46, 0x47, and 0x4C packets if final_data[0] is not 0x00
if((CSR0 & _BV(CONFIG_MODE_BIT)) && ((command[1] == 0x46) || (command[1] == 0x47) || (command[1] == 0x4C))){
final_data[0] = 0x00;
}
_delay_us(4);
ACKNOWLEDGE;
PS_AVR_COMM(final_data[0], command[3]); // first data byte (8 buttons)
if(command[1] == 0x43){
// command[3] tells the adapter to enter or exit config mode when command[1] is 0x43
(command[3] == 0x00) ? (CSR0 &= ~_BV(CONFIG_MODE_BIT)) : (CSR0 |= _BV(CONFIG_MODE_BIT));
}
if((CSR0 & _BV(CONFIG_MODE_BIT)) && (command[1] == 0x46)){
if(command[3] == 0x00){
final_data[1] = 0x00; // meaning of these bytes is unknown, copied from analysis of a real Ps1 controller response
final_data[2] = 0x01;
final_data[3] = 0x02;
final_data[4] = 0x00;
final_data[5] = 0x0A;
}
else if(command[3] == 0x01){
final_data[1] = 0x00;
final_data[2] = 0x01;
final_data[3] = 0x01;
final_data[4] = 0x01;
final_data[5] = 0x14;
}
}
if((CSR0 & _BV(CONFIG_MODE_BIT)) && (command[1] == 0x47)){
final_data[1] = 0x00; // meaning of these bytes is unknown, copied from analysis of a real Ps1 controller response
final_data[2] = 0x02;
final_data[3] = 0x00;
final_data[4] = 0x01;
final_data[5] = 0x00;
}
if((CSR0 & _BV(CONFIG_MODE_BIT)) && (command[1] == 0x4C)){
if(command[3] == 0x00){
final_data[1] = 0x00; // meaning of these bytes is unknown, copied from analysis of a real Ps1 controller response
final_data[2] = 0x00;
final_data[3] = 0x04;
final_data[4] = 0x00;
final_data[5] = 0x00;
}
else if(command[3] == 0x01){
final_data[1] = 0x00;
final_data[2] = 0x00;
final_data[3] = 0x07;
final_data[4] = 0x00;
final_data[5] = 0x00;
}
}
_delay_us(4);
ACKNOWLEDGE;
PS_AVR_COMM(final_data[1], command[4]); // second data byte (8 buttons)
if((CSR0 & _BV(CONFIG_MODE_BIT)) && (command[1] == 0x44)){
// command[3] turns analog mode on or off, command[4] locks controller in specified mode
(command[3] == 0x00) ? (CSR0 &= ~_BV(ANALOG_MODE_BIT)) : (CSR0 |= _BV(ANALOG_MODE_BIT));
(command[4] == 0x03) ? (CSR0 |= _BV(LOCK_BIT)) : (CSR0 &= ~_BV(LOCK_BIT));
}
if((CSR0 & _BV(CONFIG_MODE_BIT)) && (command[1] == 0x4D)){
if(command[3] == 0){
CSR0 |= _BV(FIRST_MOTOR_BYTE_SMALL);
CSR0 &= ~_BV(FIRST_MOTOR_BYTE_LARGE);}
else if(command[3] == 1){
CSR0 |= _BV(FIRST_MOTOR_BYTE_LARGE);
CSR0 &= ~_BV(FIRST_MOTOR_BYTE_SMALL);}
else{
CSR0 &= ~_BV(FIRST_MOTOR_BYTE_SMALL);
CSR0 &= ~_BV(FIRST_MOTOR_BYTE_LARGE);}
if(command[4] == 0){
CSR0 |= _BV(SECOND_MOTOR_BYTE_SMALL);
CSR0 &= ~_BV(SECOND_MOTOR_BYTE_LARGE);}
else if(command[4] == 1){
CSR0 |= _BV(SECOND_MOTOR_BYTE_LARGE);
CSR0 &= ~_BV(SECOND_MOTOR_BYTE_SMALL);}
else{
CSR0 &= ~_BV(SECOND_MOTOR_BYTE_SMALL);
CSR0 &= ~_BV(SECOND_MOTOR_BYTE_LARGE);}
}
START_TIMER_AT(253);
// loop while timer counts up, and SS remains low, timeout skips ACK and remaining bytes if Ps cuts off communication early
while((!(TIFR2 & _BV(TOV2))) && (~SPI_PIN & _BV(SS)));
// continue with transmission of the final 4 bytes if adapter is in analog mode, config mode, or if command[1] is 0x43
if(((CSR0 & _BV(ANALOG_MODE_BIT)) || (CSR0 & _BV(CONFIG_MODE_BIT)) || (command[1] == 0x43)) && (~SPI_PIN & _BV(SS))){
_delay_us(4);
ACKNOWLEDGE;
PS_AVR_COMM(final_data[2], command[5]); // Right analog X data Byte
_delay_us(4);
ACKNOWLEDGE;
PS_AVR_COMM(final_data[3], command[5]); // Right analog Y data byte
_delay_us(4);
ACKNOWLEDGE;
PS_AVR_COMM(final_data[4], command[5]); // Left analog X data byte
_delay_us(4);
ACKNOWLEDGE;
PS_AVR_COMM(final_data[5], command[5]); // Left analog Y data byte
}// if analog mode or config mode
}// if command[1] == one of the recognised commands
}// 0x01 controller address check
else{ SPI_PORT &= ~_BV(MISO); // Clear data output
DISABLE_SPI; // Disable SPI hardware to avoid conflict with mem-card comm
}
}// timer overflow and SS line check
}// if SS is low
SPI_PORT &= ~_BV(MISO); // Clear data output
while(~SPI_PIN & _BV(SS)); // Loop until SS returns high after communication is complete
/*CONTROLLER POLLING SECTION*****************************************************************************************/
ENABLE_TWI; // re-enable TWI hardware
ENABLE_SPI; // re-enable SPI hardware
START_TIMER_AT(64);
while((!(TIFR2 & _BV(TOV2))) && (SPI_PIN & _BV(SS))); // Loop while timer counts up and SS pin remains high
if(SPI_PIN & _BV(SS)){ // if SS line is high, SPI communication is not being requested
final_data[0] = 0xFF; // Clear data bytes before controller polling
final_data[1] = 0xFF;
final_data[2] = 0x80;
final_data[3] = 0x80;
final_data[4] = 0x80;
final_data[5] = 0x80;
chuck_data[0] = 0x80;
chuck_data[1] = 0x80;
chuck_data[2] = 0x80;
chuck_data[3] = 0x80;
chuck_data[4] = 0x80;
chuck_data[5] = 0xFF; // byte containing unused LSBs of accelerometer data and two digital button states
if(!(CONFIG_CYCLE_PIN & _BV(CONFIG_CYCLE))){
if(!(GCSR0 & _BV(BUTTON1_LOW_STATUS_BIT))){ // BUTTON1_LOW_STATUS_BIT indicates whether or not the button is already being pressed
lcd_instruction_write(CLEAR_SCREEN);
_delay_ms(2);
switch(display_tracker){
case STANDARD_MODE: lcd_string_print(katamari); lcd_string_print(mode); display_tracker++; break;
case KATAMARI_MODE: lcd_string_print(racing); lcd_string_print(mode); display_tracker++; break;
case RACING_MODE: lcd_string_print(arcade); lcd_string_print(mode); display_tracker++; break;
case ARCADE_MODE: lcd_string_print(turbo); lcd_string_print(mode); display_tracker++; break;
case TURBO_MODE: lcd_string_print(serial_in); lcd_string_print(mode); display_tracker++; break;
case SERIAL_IN_MODE: lcd_string_print(standard); lcd_string_print(mode); display_tracker = 0;
}
lcd_instruction_write(RETURN_HOME);
GCSR0 |= _BV(BUTTON1_LOW_STATUS_BIT) | _BV(SKIP_POLLING_BIT);// set BUTTON1_LOW_STATUS_BIT and SKIP_POLLING_BIT flags
}
}
if(CONFIG_CYCLE_PIN & _BV(CONFIG_CYCLE)) // if the button is high (default state)...
GCSR0 &= ~_BV(BUTTON1_LOW_STATUS_BIT); // ...reset BUTTON0_LOW_STATUS_BIT to wait for next press
// controller polling and data formatting is skipped to save time for remainder of main loop after strings are written to LCD, may not be necessary
if(!(GCSR0 & _BV(SKIP_POLLING_BIT))){
// if bit is set in game controller status register this means controller is connecteed, configured, and ready for polling
if(GCSR0 & _BV(DSC_CONNECT_STATUS_BIT)){
BB_PORT &= ~_BV(ATTENTION); // Begin communication with DSC
_delay_us(16); // Delay between ATTENTION dropping low and data transmission
ps2_comm(0x01); // byte 0; standard header, packets addressing the controller always start with 0x01
DSC_mode_ID = ps2_comm(0x42); // byte 1; standard header, controller replies with mode ID, 0x41 = digital, 0x73 = analog
if(ps2_comm(0x00) == 0x5A){ // byte 2; standard header, data reply should always be 0x5A, used to test connection status
// checks motor command configuration set by Ps and passes motor commands sent in 0x42 packet to the corresponding small motor in DSC
if((CSR0 & _BV(FIRST_MOTOR_BYTE_SMALL)) && (command[1] == 0x42) && (command[3] != 0x00)){ dsc_data[0] = ps2_comm(command[3]);}
else if((CSR0 & _BV(SECOND_MOTOR_BYTE_SMALL)) && (command[1] == 0x42) && (command[4] != 0x00)){ dsc_data[0] = ps2_comm(command[4]);}
else{ dsc_data[0] = ps2_comm(0x00);}
// checks motor command configuration set by Ps and passes motor commands sent in 0x42 packet to the corresponding large motor in DSC
if((CSR0 & _BV(FIRST_MOTOR_BYTE_LARGE)) && (command[1] == 0x42) && (command[3] != 0x00)){ dsc_data[1] = ps2_comm(command[3]);}
else if((CSR0 & _BV(SECOND_MOTOR_BYTE_LARGE)) && (command[1] == 0x42) && (command[4] != 0x00)){ dsc_data[1] = ps2_comm(command[4]);}
else{ dsc_data[1] = ps2_comm(0x00);}
for(uint8_t x = 2; x < ((DSC_mode_ID & 0x0F) << 1); x++) // Loop loads data array with mode specific byte count
dsc_data[x] = ps2_comm(0x00);
_delay_us(16); // Delay following data transmission before ATTENTION returns high
BB_PORT |= _BV(ATTENTION); // End communication with DSC
LED_PORT &= ~_BV(STATUS_LED_GREEN); // Green status LED on (controller connected)
}
else{
GCSR0 &= ~_BV(DSC_CONNECT_STATUS_BIT); // if 0x5A not received in command byte 2, controller != connected; set status register accordingly
LED_PORT |= _BV(STATUS_LED_GREEN); // Green status LED off
}
}
if(!(GCSR0 & _BV(DSC_CONNECT_STATUS_BIT))){
// this switch handles the configuration commands to send over six main loops when the DSC is first plugged in
switch(DSC_config_counter){
case 0: DSC_mode_ID = config_comm(0x42, 0x00, 0x00, 0x00, 0x00); DSC_config_counter = 1; break; // standard initial polling request, 5 bytes total
case 1: DSC_mode_ID = config_comm(0x43, 0x01, 0x00, 0x00, 0x00); DSC_config_counter = 2; break; // enter config mode, 5 bytes total
case 2: DSC_mode_ID = config_comm(0x44, 0x01, 0x03, 0x00, 0x04); DSC_config_counter = 3; break; // enable analog mode and lock controller, 9 bytes total
case 3: DSC_mode_ID = config_comm(0x4D, 0x00, 0x01, 0xFF, 0x04); DSC_config_counter = 4; break; // vibration motor control byte mapping, command[3] = small motor, command[4] = large motor
case 4: DSC_mode_ID = config_comm(0x43, 0x00, 0x5A, 0x5A, 0x04); DSC_config_counter = 5; break; // exit config mode
case 5: DSC_mode_ID = config_comm(0x42, 0x00, 0x00, 0x00, 0x04); GCSR0 |= _BV(DSC_CONNECT_STATUS_BIT); DSC_config_counter = 0; break;
}
// test will reset configuration switch if a communication error occurs or controller is disconnected before full configuration is complete
if((DSC_mode_ID == 0x00) || (DSC_mode_ID == 0xFF)){ DSC_config_counter = 0; GCSR0 &= ~_BV(DSC_CONNECT_STATUS_BIT);}
}
if(!(GCSR0 & _BV(CHUCK_CONNECT_STATUS_BIT))){ // if no nunchuck is connected (default first time through)
twi_start();
twi_send_slaw(NUNCHUCK_ADDRESS); // send 7 bit slave address (0x52) plus LSB R/W bit (0)
if(TWI_STATUS_CHECK(TW_MT_SLA_ACK)){ // if TWI status register shows that SLA+R was sent and ack'd
GCSR0 |= _BV(CHUCK_CONNECT_STATUS_BIT);
twi_write_data(0x40); // sending 0x40 followed by 0x00 is necessary to initialise nunchuck
twi_write_data(0x00);
SEND_TWI_STOP;
}
else{
GCSR0 &= ~_BV(CHUCK_CONNECT_STATUS_BIT);
SEND_TWI_STOP; // important to send stop condition to recover from bus errors
}
}
_delay_us(10);
if(GCSR0 & _BV(CHUCK_CONNECT_STATUS_BIT)){ // if nunchuck is connected as detected by TWI_STATUS_CHECK
twi_start();
twi_send_slaw(NUNCHUCK_ADDRESS);
if(TWI_STATUS_CHECK(TW_MT_SLA_ACK)){ // TW_MT_SLA_ACK defined in <util/twi.h>
GCSR0 |= _BV(CHUCK_CONNECT_STATUS_BIT);
twi_write_data(0x00); // 0x00 must be sent to nunchuck before each data packet request
SEND_TWI_STOP;
_delay_us(10);
twi_start();
twi_send_slar(NUNCHUCK_ADDRESS);
chuck_data[0] = twi_read_data(1);
chuck_data[1] = twi_read_data(1);
chuck_data[2] = twi_read_data(1);
chuck_data[3] = twi_read_data(1);
chuck_data[4] = twi_read_data(1);
chuck_data[5] = twi_read_data(0);
SEND_TWI_STOP;
}// if(TWI_STATUS_CHECK(TW_MT_SLA_ACK))
else{
GCSR0 &= ~_BV(CHUCK_CONNECT_STATUS_BIT);
SEND_TWI_STOP;
}
}// if(GCSR0 & _BV(CHUCK_CONNECT_STATUS_BIT))
NES_GET_DATA(nes_data[0], nes_data[1]); // get data from player1 and player2 NES ports
saturn_data[0] = saturn_get_first_byte(); // get first byte of button data from saturn controller
saturn_data[1] = saturn_get_second_byte(); // get second byte of data from saturn controller
/*DATA FORMATTING SECTION********************************************************************************************/
if(display_tracker == STANDARD_MODE){
if(GCSR0 & _BV(DSC_CONNECT_STATUS_BIT)){ // if the playstation controller is connected, map the buttons accordingly
OR_map(dsc_data[0], &final_data[0], PS_UP, PS_UP);
OR_map(dsc_data[0], &final_data[0], PS_DOWN, PS_DOWN);
OR_map(dsc_data[0], &final_data[0], PS_LEFT, PS_LEFT);
OR_map(dsc_data[0], &final_data[0], PS_RIGHT, PS_RIGHT);
OR_map(dsc_data[0], &final_data[0], PS_SELECT, PS_SELECT);
OR_map(dsc_data[0], &final_data[0], PS_START, PS_START);
OR_map(dsc_data[0], &final_data[0], PS_L3, PS_L3);
OR_map(dsc_data[0], &final_data[0], PS_R3, PS_R3);
OR_map(dsc_data[1], &final_data[1], PS_CROSS, PS_CROSS);
OR_map(dsc_data[1], &final_data[1], PS_SQUARE, PS_SQUARE);
OR_map(dsc_data[1], &final_data[1], PS_TRIANGLE, PS_TRIANGLE);
OR_map(dsc_data[1], &final_data[1], PS_CIRCLE, PS_CIRCLE);
OR_map(dsc_data[1], &final_data[1], PS_R1, PS_R1);
OR_map(dsc_data[1], &final_data[1], PS_L1, PS_L1);
OR_map(dsc_data[1], &final_data[1], PS_R2, PS_R2);
OR_map(dsc_data[1], &final_data[1], PS_L2, PS_L2);
// if the playstation controller is in analog mode, map the analog sticks as well
if(DSC_mode_ID == 0x73){ FINAL_RJOY_X = DSC_RJOY_X; FINAL_RJOY_Y = DSC_RJOY_Y; FINAL_LJOY_X = DSC_LJOY_X; FINAL_LJOY_Y = DSC_LJOY_Y;}
}
if(GCSR0 & _BV(CHUCK_CONNECT_STATUS_BIT)){ // if the Wii nunchuck is connected, map some more stuff
OR_map(NUNCHUCK_BUTTON_BYTE, &final_data[1], NUNCHUCK_Z, PS_CROSS);
OR_map(NUNCHUCK_BUTTON_BYTE, &final_data[1], NUNCHUCK_C, PS_SQUARE);
remapped_x = range_8bit(NUNCHUCK_TILT_X, 100, 210);
remapped_y = ~range_8bit(NUNCHUCK_TILT_Y, 90, 200);
FINAL_LJOY_X = remapped_x;
FINAL_LJOY_Y = remapped_y;
map_a2d_if_less(NUNCHUCK_JOY_X, &final_data[0], 0x6F, PS_LEFT);
map_a2d_if_greater(NUNCHUCK_JOY_X, &final_data[0], 0xC0, PS_RIGHT);
map_a2d_if_less(NUNCHUCK_JOY_Y, &final_data[0], 0x5F, PS_DOWN);
map_a2d_if_greater(NUNCHUCK_JOY_Y, &final_data[0], 0xC0, PS_UP);
}
OR_map(nes_data[0], &final_data[0], NES_UP, PS_UP);
OR_map(nes_data[0], &final_data[0], NES_DOWN, PS_DOWN);
OR_map(nes_data[0], &final_data[0], NES_LEFT, PS_LEFT);
OR_map(nes_data[0], &final_data[0], NES_RIGHT, PS_RIGHT);
OR_map(nes_data[0], &final_data[0], NES_START, PS_START);
OR_map(nes_data[0], &final_data[0], NES_SELECT, PS_SELECT);
OR_map(nes_data[0], &final_data[1], NES_A, PS_CROSS);
OR_map(nes_data[0], &final_data[1], NES_B, PS_SQUARE);
OR_map(nes_data[1], &final_data[0], NES_UP, PS_UP);
OR_map(nes_data[1], &final_data[0], NES_DOWN, PS_DOWN);
OR_map(nes_data[1], &final_data[0], NES_LEFT, PS_LEFT);
OR_map(nes_data[1], &final_data[0], NES_RIGHT, PS_RIGHT);
OR_map(nes_data[1], &final_data[0], NES_START, PS_R3);
OR_map(nes_data[1], &final_data[1], NES_A, PS_CROSS);
OR_map(nes_data[1], &final_data[1], NES_B, PS_CIRCLE);
OR_map(saturn_data[1], &final_data[0], SAT_UP, PS_UP);
OR_map(saturn_data[1], &final_data[0], SAT_DOWN, PS_DOWN);
OR_map(saturn_data[1], &final_data[0], SAT_LEFT, PS_LEFT);
OR_map(saturn_data[1], &final_data[0], SAT_RIGHT, PS_RIGHT);
OR_map(saturn_data[1], &final_data[1], SAT_L, PS_L2);
OR_map(saturn_data[0], &final_data[0], SAT_START, PS_START);
OR_map(saturn_data[0], &final_data[1], SAT_B, PS_CROSS);
OR_map(saturn_data[0], &final_data[1], SAT_A, PS_SQUARE);
OR_map(saturn_data[0], &final_data[1], SAT_Y, PS_TRIANGLE);
OR_map(saturn_data[0], &final_data[1], SAT_C, PS_CIRCLE);
OR_map(saturn_data[0], &final_data[1], SAT_Z, PS_R1);
OR_map(saturn_data[0], &final_data[1], SAT_X, PS_L1);
OR_map(saturn_data[0], &final_data[1], SAT_R, PS_R2);
// NES pad button combo for player2 port (select + down) to expand controller functionality, simulates PS_R2 button
if((~nes_data[1] & _BV(NES_SELECT)) && (~nes_data[1] & _BV(NES_DOWN))){ final_data[1] &= ~_BV(PS_R2);}
// NES pad button combo for player2 port (select + up) to expand controller functionality, simulates PS_L2 button
if((~nes_data[1] & _BV(NES_SELECT)) && (~nes_data[1] & _BV(NES_UP))){ final_data[1] &= ~_BV(PS_L2);}
}
// special mode for Ps2 game "Katamari Damacy"
else if(display_tracker == KATAMARI_MODE){
if(GCSR0 & _BV(DSC_CONNECT_STATUS_BIT)){ // if the playstation controller is connected, map the buttons accordingly
OR_map(dsc_data[0], &final_data[0], PS_UP, PS_UP);
OR_map(dsc_data[0], &final_data[0], PS_DOWN, PS_DOWN);
OR_map(dsc_data[0], &final_data[0], PS_LEFT, PS_LEFT);
OR_map(dsc_data[0], &final_data[0], PS_RIGHT, PS_RIGHT);
OR_map(dsc_data[0], &final_data[0], PS_SELECT, PS_SELECT);
OR_map(dsc_data[0], &final_data[0], PS_START, PS_START);
OR_map(dsc_data[0], &final_data[0], PS_L3, PS_L3);
OR_map(dsc_data[0], &final_data[0], PS_R3, PS_R3);
OR_map(dsc_data[1], &final_data[1], PS_CROSS, PS_CROSS);
OR_map(dsc_data[1], &final_data[1], PS_SQUARE, PS_SQUARE);
OR_map(dsc_data[1], &final_data[1], PS_TRIANGLE, PS_TRIANGLE);
OR_map(dsc_data[1], &final_data[1], PS_CIRCLE, PS_CIRCLE);
OR_map(dsc_data[1], &final_data[1], PS_R1, PS_R1);
OR_map(dsc_data[1], &final_data[1], PS_L1, PS_L1);
OR_map(dsc_data[1], &final_data[0], PS_R2, PS_R3);
OR_map(dsc_data[1], &final_data[0], PS_R2, PS_L3);
//OR_map(dsc_data[1], &final_data[1], PS_L2, PS_L2);
// if the playstation controller is in analog mode, map the analog sticks as well
if(DSC_mode_ID == 0x73){
FINAL_LJOY_X = DSC_LJOY_X;
FINAL_RJOY_X = DSC_LJOY_X;
FINAL_LJOY_Y = DSC_LJOY_Y;
FINAL_RJOY_Y = DSC_LJOY_Y;
if((DSC_RJOY_X < 0x64) && (DSC_RJOY_X >= 0x3C)){ FINAL_RJOY_Y = 0x00; FINAL_RJOY_X = 0x80; FINAL_LJOY_Y = 0x80; FINAL_LJOY_X = 0x80;}
if(DSC_RJOY_X < 0x3C){ FINAL_RJOY_Y = DSC_RJOY_X; FINAL_RJOY_X = 0x80; FINAL_LJOY_Y = (0xFF - DSC_RJOY_X); FINAL_LJOY_X = 0x80;}
if((DSC_RJOY_X > 0x9C) && (DSC_RJOY_X <= 0xC4)){ FINAL_LJOY_Y = 0x00; FINAL_RJOY_X = 0x80; FINAL_RJOY_Y = 0x80; FINAL_LJOY_X = 0x80;}
if(DSC_RJOY_X > 0xC4){ FINAL_LJOY_Y = (0xFF - DSC_RJOY_X); FINAL_RJOY_X = 0x80; FINAL_RJOY_Y = DSC_RJOY_X; FINAL_LJOY_X = 0x80;}
}
// "katamari roll" macro for L2 button
if(~dsc_data[1] & _BV(PS_L2)){ // if L2 button on controller is pressed
if(!(MSR0 & _BV(MACRO0_ACTIVE))){ // if the macro is not already active
MSR0 |= _BV(MACRO0_ACTIVE) | _BV(MACRO0_TOGGLE); // set the macro active flag
}
else if(MSR0 & _BV(MACRO0_ACTIVE)){
if((MSR0 & _BV(MACRO0_TOGGLE)) && (katamari_counter < 255)){ FINAL_LJOY_Y = katamari_counter; FINAL_RJOY_Y = (~FINAL_LJOY_Y); katamari_counter = (katamari_counter + 51);}
else{ MSR0 &= ~_BV(MACRO0_TOGGLE);}
if((~MSR0 & _BV(MACRO0_TOGGLE)) && (katamari_counter > 0)){ FINAL_LJOY_Y = katamari_counter; FINAL_RJOY_Y = (~FINAL_LJOY_Y); katamari_counter = (katamari_counter - 51);}
else{ MSR0 |= _BV(MACRO0_TOGGLE);}
}
}
if(dsc_data[1] & _BV(PS_L2)){ MSR0 &= ~_BV(MACRO0_ACTIVE); MSR0 &= ~_BV(MACRO0_TOGGLE); katamari_counter = 0x00;}
}
if(GCSR0 & _BV(CHUCK_CONNECT_STATUS_BIT)){ // if the Wii nunchuck is connected, map some more stuff
OR_map(NUNCHUCK_BUTTON_BYTE, &final_data[0], NUNCHUCK_Z, PS_R3);
OR_map(NUNCHUCK_BUTTON_BYTE, &final_data[0], NUNCHUCK_Z, PS_L3);
OR_map(NUNCHUCK_BUTTON_BYTE, &final_data[1], NUNCHUCK_C, PS_R1);
remapped_x = range_8bit(NUNCHUCK_TILT_X, 100, 210);
remapped_y = ~range_8bit(NUNCHUCK_TILT_Y, 90, 200);
FINAL_LJOY_X = remapped_x;
FINAL_RJOY_X = remapped_x;
FINAL_LJOY_Y = remapped_y;
FINAL_RJOY_Y = remapped_y;
if(remapped_y < 100){ FINAL_LJOY_Y = 0x00; FINAL_RJOY_Y = 0x00;}
if(remapped_y > 150){ FINAL_LJOY_Y = 0xFF; FINAL_RJOY_Y = 0xFF;}
if(NUNCHUCK_JOY_X < 0x6F){ FINAL_LJOY_Y = 0xFF; FINAL_RJOY_Y = 0x00;}
if(NUNCHUCK_JOY_X > 0xC0){ FINAL_LJOY_Y = 0x00; FINAL_RJOY_Y = 0xFF;}
}
if(~saturn_data[1] & _BV(SAT_DOWN)){ FINAL_LJOY_Y = 0xFF; FINAL_RJOY_Y = 0xFF;}
if(~saturn_data[1] & _BV(SAT_UP)){ FINAL_LJOY_Y = 0x00; FINAL_RJOY_Y = 0x00;}
if(~saturn_data[1] & _BV(SAT_RIGHT)){ FINAL_LJOY_X = 0xFF; FINAL_RJOY_X = 0xFF;}
if(~saturn_data[1] & _BV(SAT_LEFT)){ FINAL_LJOY_X = 0x00; FINAL_RJOY_X = 0x00;}
if(~saturn_data[0] & _BV(SAT_X)){ FINAL_LJOY_Y = 0xFF; FINAL_RJOY_Y = 0x00;}
if(~saturn_data[0] & _BV(SAT_Z)){ FINAL_LJOY_Y = 0x00; FINAL_RJOY_Y = 0xFF;}
OR_map(saturn_data[1], &final_data[1], SAT_L, PS_L1);
OR_map(saturn_data[0], &final_data[0], SAT_START, PS_START);
OR_map(saturn_data[0], &final_data[1], SAT_B, PS_CROSS);
OR_map(saturn_data[0], &final_data[1], SAT_A, PS_SQUARE);
OR_map(saturn_data[0], &final_data[1], SAT_C, PS_CIRCLE);
OR_map(saturn_data[0], &final_data[1], SAT_R, PS_R1);
OR_map(saturn_data[0], &final_data[0], SAT_Y, PS_L3);
OR_map(saturn_data[0], &final_data[0], SAT_Y, PS_R3);
}
else if(display_tracker == RACING_MODE){
if(GCSR0 & _BV(DSC_CONNECT_STATUS_BIT)){ // if the playstation controller is connected, map the buttons accordingly
OR_map(dsc_data[0], &final_data[0], PS_UP, PS_UP);
OR_map(dsc_data[0], &final_data[0], PS_DOWN, PS_DOWN);
OR_map(dsc_data[0], &final_data[0], PS_LEFT, PS_LEFT);
OR_map(dsc_data[0], &final_data[0], PS_RIGHT, PS_RIGHT);
OR_map(dsc_data[0], &final_data[0], PS_SELECT, PS_SELECT);
OR_map(dsc_data[0], &final_data[0], PS_START, PS_START);
OR_map(dsc_data[0], &final_data[0], PS_L3, PS_L3);
OR_map(dsc_data[0], &final_data[0], PS_R3, PS_R3);
OR_map(dsc_data[1], &final_data[1], PS_CROSS, PS_CROSS);
OR_map(dsc_data[1], &final_data[1], PS_SQUARE, PS_SQUARE);
OR_map(dsc_data[1], &final_data[1], PS_TRIANGLE, PS_TRIANGLE);
OR_map(dsc_data[1], &final_data[1], PS_CIRCLE, PS_CIRCLE);
OR_map(dsc_data[1], &final_data[1], PS_R1, PS_R1);
OR_map(dsc_data[1], &final_data[1], PS_L1, PS_L1);
OR_map(dsc_data[1], &final_data[1], PS_R2, PS_R2);
OR_map(dsc_data[1], &final_data[1], PS_L2, PS_L2);
// if the playstation controller is in analog mode, map the analog sticks as well
if(DSC_mode_ID == 0x73){ FINAL_RJOY_X = DSC_RJOY_X; FINAL_RJOY_Y = DSC_RJOY_Y; FINAL_LJOY_X = DSC_LJOY_X; FINAL_LJOY_Y = DSC_LJOY_Y;}
}
if(GCSR0 & _BV(CHUCK_CONNECT_STATUS_BIT)){ // if the Wii nunchuck is connected, map some more stuff
OR_map(NUNCHUCK_BUTTON_BYTE, &final_data[1], NUNCHUCK_Z, PS_CROSS);
OR_map(NUNCHUCK_BUTTON_BYTE, &final_data[1], NUNCHUCK_C, PS_SQUARE);
remapped_x = range_8bit(NUNCHUCK_TILT_X, 100, 210);
remapped_y = ~range_8bit(NUNCHUCK_TILT_Y, 90, 200);
FINAL_LJOY_X = remapped_x;
FINAL_LJOY_Y = remapped_y;
map_a2d_if_less(NUNCHUCK_JOY_X, &final_data[0], 0x6F, PS_LEFT);
map_a2d_if_greater(NUNCHUCK_JOY_X, &final_data[0], 0xC0, PS_RIGHT);
map_a2d_if_less(NUNCHUCK_JOY_Y, &final_data[0], 0x5F, PS_DOWN);
map_a2d_if_greater(NUNCHUCK_JOY_Y, &final_data[0], 0xC0, PS_UP);
}
OR_map(nes_data[0], &final_data[0], NES_UP, PS_UP);
OR_map(nes_data[0], &final_data[0], NES_DOWN, PS_DOWN);
OR_map(nes_data[0], &final_data[0], NES_LEFT, PS_LEFT);
OR_map(nes_data[0], &final_data[0], NES_RIGHT, PS_RIGHT);
OR_map(nes_data[0], &final_data[0], NES_START, PS_START);
OR_map(nes_data[0], &final_data[0], NES_SELECT, PS_SELECT);
OR_map(nes_data[0], &final_data[1], NES_A, PS_CROSS);
OR_map(nes_data[0], &final_data[1], NES_B, PS_SQUARE);
OR_map(nes_data[1], &final_data[0], NES_UP, PS_UP);
OR_map(nes_data[1], &final_data[0], NES_DOWN, PS_DOWN);
OR_map(nes_data[1], &final_data[0], NES_LEFT, PS_LEFT);
OR_map(nes_data[1], &final_data[0], NES_RIGHT, PS_RIGHT);
OR_map(nes_data[1], &final_data[0], NES_START, PS_R3);
OR_map(nes_data[1], &final_data[1], NES_A, PS_CROSS);
OR_map(nes_data[1], &final_data[1], NES_B, PS_CIRCLE);
OR_map(saturn_data[1], &final_data[0], SAT_UP, PS_UP);
OR_map(saturn_data[1], &final_data[0], SAT_DOWN, PS_DOWN);
OR_map(saturn_data[1], &final_data[0], SAT_LEFT, PS_LEFT);
OR_map(saturn_data[1], &final_data[0], SAT_RIGHT, PS_RIGHT);
OR_map(saturn_data[0], &final_data[1], SAT_X, PS_L2);
OR_map(saturn_data[0], &final_data[0], SAT_START, PS_START);
OR_map(saturn_data[0], &final_data[1], SAT_B, PS_TRIANGLE);
OR_map(saturn_data[0], &final_data[1], SAT_A, PS_SQUARE);
OR_map(saturn_data[0], &final_data[1], SAT_Y, PS_CROSS);
OR_map(saturn_data[0], &final_data[1], SAT_C, PS_CIRCLE);
OR_map(saturn_data[0], &final_data[1], SAT_R, PS_R1);
OR_map(saturn_data[1], &final_data[1], SAT_L, PS_L1);
OR_map(saturn_data[0], &final_data[1], SAT_Z, PS_R2);
// NES pad button combo for player2 port (select + down) to expand controller functionality, simulates PS_R2 button
if((~nes_data[1] & _BV(NES_SELECT)) && (~nes_data[1] & _BV(NES_DOWN))){ final_data[1] &= ~_BV(PS_R2);}
// NES pad button combo for player2 port (select + up) to expand controller functionality, simulates PS_L2 button
if((~nes_data[1] & _BV(NES_SELECT)) && (~nes_data[1] & _BV(NES_UP))){ final_data[1] &= ~_BV(PS_L2);}
}
if(display_tracker == ARCADE_MODE){
if(GCSR0 & _BV(DSC_CONNECT_STATUS_BIT)){ // if the playstation controller is connected, map the buttons accordingly
OR_map(dsc_data[0], &final_data[0], PS_UP, PS_UP);
OR_map(dsc_data[0], &final_data[0], PS_DOWN, PS_DOWN);
OR_map(dsc_data[0], &final_data[0], PS_LEFT, PS_LEFT);
OR_map(dsc_data[0], &final_data[0], PS_RIGHT, PS_RIGHT);
OR_map(dsc_data[0], &final_data[0], PS_SELECT, PS_SELECT);
OR_map(dsc_data[0], &final_data[0], PS_START, PS_START);
OR_map(dsc_data[0], &final_data[0], PS_L3, PS_L3);
OR_map(dsc_data[0], &final_data[0], PS_R3, PS_R3);
OR_map(dsc_data[1], &final_data[1], PS_CROSS, PS_CROSS);
OR_map(dsc_data[1], &final_data[1], PS_SQUARE, PS_SQUARE);
OR_map(dsc_data[1], &final_data[1], PS_TRIANGLE, PS_TRIANGLE);
OR_map(dsc_data[1], &final_data[1], PS_CIRCLE, PS_CIRCLE);
OR_map(dsc_data[1], &final_data[1], PS_R1, PS_R1);
OR_map(dsc_data[1], &final_data[1], PS_L1, PS_L1);
OR_map(dsc_data[1], &final_data[1], PS_R2, PS_R2);
OR_map(dsc_data[1], &final_data[1], PS_L2, PS_L2);
// Ps2 button combo to expand controller functionality simulates PS_R3 button
if((~dsc_data[1] & _BV(PS_L2)) && (~dsc_data[1] & _BV(PS_R2)) && (~dsc_data[1] & _BV(PS_TRIANGLE)) && (~dsc_data[1] & _BV(PS_CIRCLE)) && (~dsc_data[0] & _BV(PS_UP)) && (~dsc_data[0] & _BV(PS_LEFT))){ final_data[0] &= ~_BV(PS_R3);}
// if the playstation controller is in analog mode, map the analog sticks as well
if(DSC_mode_ID == 0x73){ FINAL_RJOY_X = DSC_RJOY_X; FINAL_RJOY_Y = DSC_RJOY_Y; FINAL_LJOY_X = DSC_LJOY_X; FINAL_LJOY_Y = DSC_LJOY_Y;}
}
if(GCSR0 & _BV(CHUCK_CONNECT_STATUS_BIT)){ // if the Wii nunchuck is connected, map some more stuff
OR_map(NUNCHUCK_BUTTON_BYTE, &final_data[1], NUNCHUCK_Z, PS_CROSS);
OR_map(NUNCHUCK_BUTTON_BYTE, &final_data[1], NUNCHUCK_C, PS_SQUARE);
remapped_x = range_8bit(NUNCHUCK_TILT_X, 100, 210);
remapped_y = ~range_8bit(NUNCHUCK_TILT_Y, 90, 200);
FINAL_LJOY_X = remapped_x;
FINAL_LJOY_Y = remapped_y;
map_a2d_if_less(NUNCHUCK_JOY_X, &final_data[0], 0x6F, PS_LEFT);
map_a2d_if_greater(NUNCHUCK_JOY_X, &final_data[0], 0xC0, PS_RIGHT);
map_a2d_if_less(NUNCHUCK_JOY_Y, &final_data[0], 0x5F, PS_DOWN);
map_a2d_if_greater(NUNCHUCK_JOY_Y, &final_data[0], 0xC0, PS_UP);
}
OR_map(nes_data[0], &final_data[0], NES_UP, PS_UP);
OR_map(nes_data[0], &final_data[0], NES_DOWN, PS_DOWN);
OR_map(nes_data[0], &final_data[0], NES_LEFT, PS_LEFT);
OR_map(nes_data[0], &final_data[0], NES_RIGHT, PS_RIGHT);
OR_map(nes_data[0], &final_data[0], NES_START, PS_START);
OR_map(nes_data[0], &final_data[0], NES_SELECT, PS_SELECT);
OR_map(nes_data[0], &final_data[1], NES_A, PS_CROSS);
OR_map(nes_data[0], &final_data[1], NES_B, PS_SQUARE);
OR_map(nes_data[1], &final_data[0], NES_UP, PS_UP);
OR_map(nes_data[1], &final_data[0], NES_DOWN, PS_DOWN);
OR_map(nes_data[1], &final_data[0], NES_LEFT, PS_LEFT);
OR_map(nes_data[1], &final_data[0], NES_RIGHT, PS_RIGHT);
OR_map(nes_data[1], &final_data[0], NES_START, PS_R3);
OR_map(nes_data[1], &final_data[1], NES_A, PS_CROSS);
OR_map(nes_data[1], &final_data[1], NES_B, PS_CIRCLE);
OR_map(saturn_data[1], &final_data[0], SAT_UP, PS_UP);
OR_map(saturn_data[1], &final_data[0], SAT_DOWN, PS_DOWN);
OR_map(saturn_data[1], &final_data[0], SAT_LEFT, PS_LEFT);
OR_map(saturn_data[1], &final_data[0], SAT_RIGHT, PS_RIGHT);
OR_map(saturn_data[1], &final_data[0], SAT_L, PS_SELECT);
OR_map(saturn_data[0], &final_data[0], SAT_START, PS_START);
OR_map(saturn_data[0], &final_data[1], SAT_B, PS_CROSS);
OR_map(saturn_data[0], &final_data[1], SAT_A, PS_SQUARE);
OR_map(saturn_data[0], &final_data[1], SAT_Y, PS_TRIANGLE);
OR_map(saturn_data[0], &final_data[1], SAT_C, PS_CIRCLE);
OR_map(saturn_data[0], &final_data[1], SAT_Z, PS_R1);
OR_map(saturn_data[0], &final_data[1], SAT_X, PS_L1);
OR_map(saturn_data[0], &final_data[0], SAT_R, PS_R3);
// NES pad button combo for player2 port (select + down) to expand controller functionality, simulates PS_R2 button
if((~nes_data[1] & _BV(NES_SELECT)) && (~nes_data[1] & _BV(NES_DOWN))){ final_data[1] &= ~_BV(PS_R2);}
// NES pad button combo for player2 port (select + up) to expand controller functionality, simulates PS_L2 button
if((~nes_data[1] & _BV(NES_SELECT)) && (~nes_data[1] & _BV(NES_UP))){ final_data[1] &= ~_BV(PS_L2);}
// saturn pad button combo to expand controller functionality, simulates PS_R2 button
if((~saturn_data[1] & _BV(SAT_L)) && (~saturn_data[1] & _BV(SAT_DOWN))){ final_data[1] &= ~_BV(PS_R2);}
// saturn pad button combo to expand controller functionality, simulates PS_L2 button
if((~saturn_data[1] & _BV(SAT_L)) && (~saturn_data[1] & _BV(SAT_UP))){ final_data[1] &= ~_BV(PS_L2);}
}
else if(display_tracker == TURBO_MODE){
(turbo_counter < TURBO_RATE) ? (turbo_counter++): (turbo_counter = 0);
if(GCSR0 & _BV(DSC_CONNECT_STATUS_BIT)){ // if the playstation controller is connected, map the buttons accordingly
OR_map(dsc_data[0], &final_data[0], PS_UP, PS_UP);
OR_map(dsc_data[0], &final_data[0], PS_DOWN, PS_DOWN);
OR_map(dsc_data[0], &final_data[0], PS_LEFT, PS_LEFT);
OR_map(dsc_data[0], &final_data[0], PS_RIGHT, PS_RIGHT);
OR_map(dsc_data[0], &final_data[0], PS_SELECT, PS_SELECT);
OR_map(dsc_data[0], &final_data[0], PS_START, PS_START);
OR_map(dsc_data[0], &final_data[0], PS_L3, PS_L3);
OR_map(dsc_data[0], &final_data[0], PS_R3, PS_R3);
OR_map(dsc_data[1], &final_data[1], PS_CROSS, PS_CROSS);
//OR_map(dsc_data[1], &final_data[1], PS_SQUARE, PS_SQUARE);
OR_map(dsc_data[1], &final_data[1], PS_TRIANGLE, PS_TRIANGLE);
OR_map(dsc_data[1], &final_data[1], PS_CIRCLE, PS_CIRCLE);
//OR_map(dsc_data[1], &final_data[1], PS_R1, PS_R1);
OR_map(dsc_data[1], &final_data[1], PS_L1, PS_L1);
OR_map(dsc_data[1], &final_data[1], PS_R2, PS_R2);
OR_map(dsc_data[1], &final_data[1], PS_L2, PS_L2);
TURBO_MAP(dsc_data[1], final_data[1], PS_SQUARE, PS_SQUARE, TSR0, TURBO0_ACTIVE, TURBO0_TOGGLE);
TURBO_MAP(dsc_data[1], final_data[1], PS_R1, PS_R1, TSR0, TURBO1_ACTIVE, TURBO1_TOGGLE);
// if the playstation controller is in analog mode, map the analog sticks as well
if(DSC_mode_ID == 0x73){ FINAL_RJOY_X = DSC_RJOY_X; FINAL_RJOY_Y = DSC_RJOY_Y; FINAL_LJOY_X = DSC_LJOY_X; FINAL_LJOY_Y = DSC_LJOY_Y;}
}
if(GCSR0 & _BV(CHUCK_CONNECT_STATUS_BIT)){ // if the Wii nunchuck is connected, map some more stuff
OR_map(NUNCHUCK_BUTTON_BYTE, &final_data[1], NUNCHUCK_Z, PS_CROSS);
OR_map(NUNCHUCK_BUTTON_BYTE, &final_data[1], NUNCHUCK_C, PS_SQUARE);
remapped_x = range_8bit(NUNCHUCK_TILT_X, 100, 210);
remapped_y = ~range_8bit(NUNCHUCK_TILT_Y, 90, 200);
FINAL_LJOY_X = remapped_x;
FINAL_LJOY_Y = remapped_y;
map_a2d_if_less(NUNCHUCK_JOY_X, &final_data[0], 0x6F, PS_LEFT);
map_a2d_if_greater(NUNCHUCK_JOY_X, &final_data[0], 0xC0, PS_RIGHT);
map_a2d_if_less(NUNCHUCK_JOY_Y, &final_data[0], 0x5F, PS_DOWN);
map_a2d_if_greater(NUNCHUCK_JOY_Y, &final_data[0], 0xC0, PS_UP);
}
}
else if(display_tracker == SERIAL_IN_MODE){ // Serial input is not yet implimented, currently this is a placeholder
}
/*END DATA FORMATTING************************************************************************************************/
}// if skip polling flag is set
GCSR0 &= ~_BV(SKIP_POLLING_BIT); // reset skip polling flag to default 0
// the following checks for a single press of the analog/digital select button and toggles the adapters state accordingly
if(~ANA_DIG_SELECT_PIN & _BV(ANA_DIG_SELECT)){
if(!(GCSR0 & _BV(BUTTON0_LOW_STATUS_BIT))){ // BUTTON0_LOW_STATUS_BIT indicates whether or not the button is already being pressed
if(!(CSR0 & _BV(LOCK_BIT))){ // check if the adapter is already locked in analog mode
if(CSR0 & _BV(ANALOG_MODE_BIT)) // if analog mode is already active...
CSR0 &= ~_BV(ANALOG_MODE_BIT); // ...turn off analog mode
else if(!(CSR0 & _BV(ANALOG_MODE_BIT))) // if analog mode is not active...
CSR0 |= _BV(ANALOG_MODE_BIT); // ...turn on analog mode
}
GCSR0 |= _BV(BUTTON0_LOW_STATUS_BIT); // set BUTTON0_LOW_STATUS_BIT flag so we know the button press has been recognized
}
}
if(ANA_DIG_SELECT_PIN & _BV(ANA_DIG_SELECT)) // if the button is high (default state)...
GCSR0 &= ~_BV(BUTTON0_LOW_STATUS_BIT); // ...reset BUTTON0_LOW_STATUS_BIT to wait for next press
DISABLE_TWI; // disable TWI hardware to restart in case of errors on bus
if(command[1] == 0x42){ // command 0x42 is the main polling command sent continually once the adapter is configured
LED_PORT |= _BV(STATUS_LED_RED2); // Red status LED off
LED_PORT &= ~_BV(STATUS_LED_GREEN2); // Green status LED on to indicate that everything is cool
LED_PORT |= _BV(STATUS_LED_GREEN2); // FOR DEBUGGING
_delay_us(4); // FOR DEBUGGING
LED_PORT &= ~_BV(STATUS_LED_GREEN2); // FOR DEBUGGING
}
else{
LED_PORT |= _BV(STATUS_LED_GREEN2); // Green status LED off
LED_PORT &= ~_BV(STATUS_LED_RED2); // Red status LED on to indicate that something might be wrong
LED_PORT |= _BV(STATUS_LED_RED2); // FOR DEBUGGING
_delay_us(4); // FOR DEBUGGING
LED_PORT &= ~_BV(STATUS_LED_RED2); // FOR DEBUGGING
}
// turns on an LED whenever a command is received to turn on the vibration motors
if((CSR0 & 0xF0) && (command[1] == 0x42) && ((command[3] != 0x00) || (command[4] != 0x00))){ LED_PORT &= ~_BV(STATUS_LED_MOTOR);}
else{ LED_PORT |= _BV(STATUS_LED_MOTOR);}
command[1] = 0x00;
command[3] = 0x00;
command[4] = 0x00;
}// if SS line is still high after timeout
COMM_IS_OK; // set flag in "CSR0" to allow SPI communication
// loop waits for call from spi master, if not called in 20ms loop to top to keep everything else going
for(uint8_t x = 0; ((x < 18) && (SPI_PIN & _BV(SS))); x++){
START_TIMER_AT(1);
while((!(TIFR2 & _BV(TOV2))) && (SPI_PIN & _BV(SS)));
}
}// infinite while(1) loop
return 0;
}// main loop