diff --git a/PSNee/MCU.h b/PSNee/MCU.h index 2618da0..2238176 100644 --- a/PSNee/MCU.h +++ b/PSNee/MCU.h @@ -114,7 +114,7 @@ // Stop Timer 0 (Stops Arduino millis/micros) // Setting TCCR0B to 0 stops the clock source. Setting TIMSK0 to 0 disables interrupts. #define E TCCR0B = 0; - #define F TIMSK0 = 0; + //#define F TIMSK0 = 0; // Disable the Analog Comparator (Frees up resources on PD6/PD7) // ACD at 1 = Comparator off. @@ -144,7 +144,7 @@ #include // Global interrupt control settings - #define GLOBAL_INTERRUPT_ENABLE SREG |= (1 << 7) // Set the I-bit (bit 7) in the Status Register to enable global interrupts + //#define GLOBAL_INTERRUPT_ENABLE SREG |= (1 << 7) // Set the I-bit (bit 7) in the Status Register to enable global interrupts #define GLOBAL_INTERRUPT_DISABLE SREG &= ~(1 << 7) // Clear the I-bit (bit 7) in the Status Register to disable global interrupts // Enable/Disable timer interrupts @@ -246,11 +246,11 @@ #ifdef ATmega32U4_16U4 #define F_CPU 16000000L - #define TIMER_TCNT_CLEAR TCNT0 = 0x00; - #define SET_OCROA_DIV OCR0A = 159; - #define SET_TIMER_TCCROA TCCR0A |= (1 << WGM01); - #define SET_TIMER_TCCROB TCCR0B |= (1 << CS00); - #define CTC_TIMER_VECTOR TIMER0_COMPA_vect + // #define TIMER_TCNT_CLEAR TCNT0 = 0x00; + // #define SET_OCROA_DIV OCR0A = 159; + // #define SET_TIMER_TCCROA TCCR0A |= (1 << WGM01); + // #define SET_TIMER_TCCROB TCCR0B |= (1 << CS00); + // #define CTC_TIMER_VECTOR TIMER0_COMPA_vect #include #include @@ -260,11 +260,11 @@ #include // Globale interrupt seting - #define GLOBAL_INTERRUPT_ENABLE SREG |= (1 << 7) + // #define GLOBAL_INTERRUPT_ENABLE SREG |= (1 << 7) #define GLOBAL_INTERRUPT_DISABLE SREG &= ~(1 << 7) - #define TIMER_INTERRUPT_ENABLE TIMSK0 |= (1 << OCIE0A) - #define TIMER_INTERRUPT_DISABLE TIMSK0 &= ~(1 << OCIE0A) + // #define TIMER_INTERRUPT_ENABLE TIMSK0 |= (1 << OCIE0A) + // #define TIMER_INTERRUPT_DISABLE TIMSK0 &= ~(1 << OCIE0A) // Handling the main pins diff --git a/PSNee/PSNee.ino b/PSNee/PSNee.ino index 64d1f02..d9d279e 100644 --- a/PSNee/PSNee.ino +++ b/PSNee/PSNee.ino @@ -6,8 +6,8 @@ // MCU // Arduino //------------------------------------------------------------------------------------------------ -#define ATmega328_168 // Nano, Pro Mini, Uno -//#define ATmega32U4_16U4 // Micro, Pro Micro +//#define ATmega328_168 // Nano, Pro Mini, Uno +#define ATmega32U4_16U4 // Micro, Pro Micro //#define ATtiny85_45_25 // ATtiny /*------------------------------------------------------------------------------------------------ @@ -22,7 +22,7 @@ //#define SCPH_xxx1 // NTSC U/C | America. //#define SCPH_xxx2 // PAL | Europ. //#define SCPH_xxx3 // NTSC J | Asia. -//#define SCPH_5903 // NTSC J | Asia VCD: +#define SCPH_5903 // NTSC J | Asia VCD: // Models that require a BIOS patch. @@ -44,7 +44,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX SCPH model number // Data pin | 32-pin BIOS | 40-pin BIOS | BIOS version -------------------------------------------------------------------------------------------------*/ //#define SCPH_102 // DX - D0 | AX - A7 | | 4.4e - CRC 0BAD7EA9, 4.5e -CRC 76B880E5 -#define SCPH_100 // DX - D0 | AX - A7 | | 4.3j - CRC F2AF798B +//#define SCPH_100 // DX - D0 | AX - A7 | | 4.3j - CRC F2AF798B //#define SCPH_7500_9000 // DX - D0 | AX - A7 | | 4.0j - CRC EC541CD0 //#define SCPH_7000 // DX - D0 | AX - A7 | | 4.0j - CRC EC541CD0 Enables hardware support for disabling BIOS patching. //#define SCPH_5500 // DX - D0 | AX - A5 | | 3.0j - CRC FF3EEB8C @@ -129,15 +129,23 @@ volatile bool wfck_mode = 0; volatile bool Flag_Switch = 0; -// Définition du type pour le pointeur de fonction -typedef void (*ConsoleLogicPtr)(uint8_t, uint8_t*); -////ConsoleLogicPtr currentLogic = logic_Standard; // Default +// --- Prototypes (Forward declarations) --- +// These tell the compiler that the functions exist later in the code. +void logic_Standard(uint8_t isDataSector); +void logic_SCPH_5903(uint8_t isDataSector); -// Variables de contrôle globales -volatile ConsoleLogicPtr currentLogic; +// Function pointer type definition for the console detection logic. +// This allows switching between 'Standard' and 'SCPH-5903' heuristics dynamically. +typedef void (*ConsoleLogicPtr)(uint8_t isDataSector); + +// Global pointer holding the currently active logic function. +// Using a function pointer eliminates the need for repetitive 'if/else' checks in the main loop. +volatile ConsoleLogicPtr currentLogic = logic_Standard; + +// Variables de contrôle globales uint8_t scbuf[12] = { 0 }; uint8_t hysteresis = 0; -uint16_t timeout_clock_counter = 0; + //Initializing values ​​for region code injection timing #define DELAY_BETWEEN_BITS 4000 // 250 bits/s (microseconds) (ATtiny 8Mhz works from 3950 to 4100) PU-23 PU-22 MAX 4250 MIN 3850 #define DELAY_BETWEEN_INJECTIONS 90 // The sweet spot is around 80~100. For all observed models, the worst minimum time seen is 72, and it works well up to 250. @@ -202,54 +210,31 @@ void board_detection(){ - - - //****************************************************************************************************************** // Reads a complete 12-byte SUBQ transmission from the CD drive. // Uses clock-edge synchronization and includes a safety timeout for malformatted streams. //****************************************************************************************************************** void captureSubQ(void) { - //uint8_t bitpos = 0; - uint8_t scpos = 0; - uint8_t bitbuf = 0; + //uint8_t bitpos = 0; + uint8_t scpos = 0; + uint8_t bitbuf = 0; - GLOBAL_INTERRUPT_DISABLE; // Start critical section + do { + bitbuf = 0; + for (uint8_t i = 0; i < 8; i++) { + // Wait for Clock to go LOW then HIGH (Sampling on Rising Edge) + while (PIN_SQCK_READ != 0); + while (PIN_SQCK_READ == 0); + + // Shift buffer and sample the SUBQ pin + bitbuf >>= 1; + if (PIN_SUBQ_READ) { + bitbuf |= 0x80; + } + } + scbuf[scpos++] = bitbuf; + } while (scpos < 12); - do { - bitbuf = 0; - for (uint8_t i = 0; i < 8; i++) { - while (PIN_SQCK_READ != 0); // Wait for clock LOWE - while (PIN_SQCK_READ == 0); // Wait for clock HIGH - - bitbuf >>= 1; // Décale d'abord - if (PIN_SUBQ_READ) bitbuf |= 0x80; // Insère le bit par le haut - } - scbuf[scpos++] = bitbuf; - } while (scpos < 12); - - // do { - // for (bitpos = 0; bitpos < 8; bitpos++) { - // while (PIN_SQCK_READ != 0) { // Wait for clock LOW - // timeout_clock_counter++; - // if (timeout_clock_counter > 1000) { - // scpos = 0; timeout_clock_counter = 0; bitbuf = 0; bitpos = 0; - // continue; - // } - // } - // while (PIN_SQCK_READ == 0); // Wait for clock HIGH - - // if (PIN_SUBQ_READ) { - // bitbuf |= (1 << bitpos); - // } - // timeout_clock_counter = 0; - // } - // scbuf[scpos] = bitbuf; - // scpos++; - // bitbuf = 0; - // } while (scpos < 12); - - GLOBAL_INTERRUPT_ENABLE; // End critical section } @@ -319,54 +304,16 @@ void logic_Standard(uint8_t isDataSector) { } -//****************************************************************************************************************** -// Triggers the region code injection if the hysteresis threshold is reached. -//****************************************************************************************************************** +/** + * Executes the SCEX injection sequence once the confidence threshold (hysteresis) is met. + * Supports both legacy boards (Gate logic) and newer boards (WFCK synchronization). + */ void performInjectionSequence() { - if (hysteresis >= HYSTERESIS_MAX) { - hysteresis = 11; // Reset to 11 for faster re-injection if head stays in TOC - -#ifdef LED_RUN - PIN_LED_ON; -#endif - PIN_DATA_OUTPUT; PIN_DATA_CLEAR; - if (!wfck_mode) { PIN_WFCK_OUTPUT; PIN_WFCK_CLEAR; } - - _delay_ms(DELAY_BETWEEN_INJECTIONS); - - for (uint8_t scex = 0; scex < 2; scex++) { - inject_SCEX(region[scex]); - } - - if (!wfck_mode) { PIN_WFCK_INPUT; } - PIN_DATA_INPUT; - -#ifdef LED_RUN - PIN_LED_OFF; -#endif - -#if defined(PSNEE_DEBUG_SERIAL_MONITOR) - Debug_Inject(); -#endif - } -} - -/***************************************************************************************** - Function: inject_SCEX - - Injects SCEX data corresponding to a given region ('e' for Europe, 'a' for America, - 'i' for Japan). This function is used for modulating the SCEX signal to bypass - region-locking mechanisms. - - Parameters: - - region: A character ('e', 'a', or 'i') representing the target region. - -*****************************************************************************************/ -void inject_SCEX(const char region) { // SCEX data patterns for different regions (SCEE: Europe, SCEA: America, SCEI: Japan) // Each array contains the specific bit sequence required to bypass region locking. - static const uint8_t SCEEData[] = { + #if (REGION_SETTING == 2) + static const uint8_t SCEData[] = { // NTSC U/C | America. 0b01011001, 0b11001001, 0b01001011, @@ -374,8 +321,8 @@ void inject_SCEX(const char region) { 0b11101010, 0b00000010 }; - - static const uint8_t SCEAData[] = { + #elif (REGION_SETTING == 1) + static const uint8_t SCEData[] = { // PAL | Europ. 0b01011001, 0b11001001, 0b01001011, @@ -383,8 +330,8 @@ void inject_SCEX(const char region) { 0b11111010, 0b00000010 }; - - static const uint8_t SCEIData[] = { + #else + static const uint8_t SCEData[] = { // NTSC J | Asia. 0b01011001, 0b11001001, 0b01001011, @@ -392,90 +339,129 @@ void inject_SCEX(const char region) { 0b11011010, 0b00000010 }; - - // Select the appropriate data pointer based on the region character to avoid - // repetitive conditional checks inside the high-timing-sensitive loop. - const uint8_t* ByteSet = (region == 'e') ? SCEEData : (region == 'a') ? SCEAData : SCEIData; + #endif + // Use 'SCEData' directly in your loops + const uint8_t* ByteSet = SCEData; +// Select the appropriate data pointer based on the region character. + // Using a single char variable avoids pointer-to-integer comparison errors. +// const uint8_t* ByteSet = (region == '1') ? SCEEData : (region == '2') ? SCEAData : SCEIData; +// Select the bitstream based on the first character of the region string. +// We access region[0] to avoid pointer-to-integer comparison warnings. +//const uint8_t* ByteSet = (region[0] == 'e') ? SCEEData : (region[0] == 'a') ? SCEAData : SCEIData; - // for (uint8_t bit_counter = 0; bit_counter < 44; bit_counter++) { - // // Check if the current bit is 0 - // if (readBit(bit_counter, region == 'e' ? SCEEData : region == 'a' ? SCEAData : SCEIData) == 0) { - - // Iterate through the 44 bits of the SCEX sequence - for (uint8_t bit_counter = 0; bit_counter < 44; bit_counter++) { + if (hysteresis >= HYSTERESIS_MAX) { + hysteresis = 11; // Reset to 11 for faster re-injection if head stays in TOC - // Extraction of the current bit (Inlined readBit logic) - bool currentBit = (ByteSet[bit_counter / 8] & (1 << (bit_counter % 8))); +#ifdef LED_RUN + PIN_LED_ON; +#endif - // ------------------------------------------------------------------------- - // MODE: OLDER BOARDS (PU-7 to PU-20) - Standard Gate Logic - // ------------------------------------------------------------------------- - if (!wfck_mode) { - if (currentBit == 0) { - // For OLD boards, bit 0 is a forced LOW signal - PIN_DATA_OUTPUT; - PIN_DATA_CLEAR; - _delay_us(DELAY_BETWEEN_BITS); - } - else { - // For OLD boards, bit 1 is High-Z (Pin set as input) - PIN_DATA_INPUT; - _delay_us(DELAY_BETWEEN_BITS); - } - } + // Initialize pins for injection + PIN_DATA_OUTPUT; + PIN_DATA_CLEAR; + if (!wfck_mode) { PIN_WFCK_OUTPUT; PIN_WFCK_CLEAR; } - // ------------------------------------------------------------------------- - // MODE: NEWER BOARDS (PU-22 or newer) - WFCK Clock Synchronization - // ------------------------------------------------------------------------- - else if (wfck_mode) { - if (currentBit == 0) { - // For NEW boards, bit 0 is also a forced LOW signal - PIN_DATA_OUTPUT; - PIN_DATA_CLEAR; - _delay_us(DELAY_BETWEEN_BITS); - } - else { - // For NEW boards, bit 1 must be modulated with the WFCK clock signal - PIN_DATA_OUTPUT; - uint8_t count = 30; - uint8_t last_wfck = PIN_WFCK_READ; + _delay_ms(DELAY_BETWEEN_INJECTIONS); - while (count > 0) { - uint8_t current_wfck = PIN_WFCK_READ; - if (current_wfck) { + // Perform 2 injection cycles for reliability + for (uint8_t scei = 0; scei < 2; scei++) { + + // Iterate through the 44 bits of the SCEX sequence + for (uint8_t bit_counter = 0; bit_counter < 44; bit_counter++) { - PIN_DATA_SET; - } else { - PIN_DATA_CLEAR; + // Extract bit using bitwise shift + bool currentBit = (ByteSet[bit_counter / 8] & (1 << (bit_counter % 8))); + + if (!wfck_mode) { + // MODE: OLDER BOARDS (PU-7 to PU-20) - Standard Gate Logic + if (currentBit == 0) { + // For OLD boards, bit 0 is a forced LOW signal + PIN_DATA_OUTPUT; + PIN_DATA_CLEAR; + } + else { + // For OLD boards, bit 1 is High-Z (Pin set as input) + PIN_DATA_INPUT; } + _delay_us(DELAY_BETWEEN_BITS); + } + else if (wfck_mode) { + // MODE: NEWER BOARDS (PU-22+) - WFCK Clock Synchronization + PIN_DATA_OUTPUT; + + if (currentBit == 0) { + // Bit 0: Constant LOW signal + PIN_DATA_CLEAR; + _delay_us(DELAY_BETWEEN_BITS); + } + else { + // Bit 1: High-speed modulation synchronized with WFCK clock + uint8_t count = 30; + uint8_t last_wfck = PIN_WFCK_READ; - if (current_wfck && !last_wfck) { - count--; + // Optimized loop: Data line only toggles on WFCK edge detection + while (count > 0) { + uint8_t current_wfck = PIN_WFCK_READ; + + if (current_wfck != last_wfck) { + // Only update DATA if WFCK state changed + if (current_wfck) { + PIN_DATA_SET; + } else { + PIN_DATA_CLEAR; + } + + // Count rising edges to track bit duration + if (current_wfck) { + count--; + } + last_wfck = current_wfck; + } + } } - last_wfck = current_wfck; } } + // After injecting SCEX data, set DATA pin as output and clear (low) + PIN_DATA_OUTPUT; + PIN_DATA_CLEAR; + _delay_ms(DELAY_BETWEEN_INJECTIONS); } + // Cleanup: Release the bus + if (!wfck_mode) { + PIN_WFCK_INPUT; + } + PIN_DATA_INPUT; + +#ifdef LED_RUN + PIN_LED_OFF; +#endif + +#if defined(PSNEE_DEBUG_SERIAL_MONITOR) + Debug_Inject(); +#endif } - // After injecting SCEX data, set DATA pin as output and clear (low) - PIN_DATA_OUTPUT; - PIN_DATA_CLEAR; - _delay_ms(DELAY_BETWEEN_INJECTIONS); } + void Init() { -#if defined(ATmega328_168) || defined(ATmega32U4_16U4) || defined(ATtiny85_45_25) +#if defined(ATmega328_168) // Optimization test in progress... A; B; D; E; - F; + //F; G; #endif +#ifdef SCPH_5903 + currentLogic = logic_SCPH_5903; +#else + currentLogic = logic_Standard; +#endif + #if defined(PATCH_SWITCH) && defined(BIOS_PATCH) PIN_SWITCH_INPUT; @@ -489,7 +475,7 @@ void Init() { PIN_LED_OUTPUT; #endif - GLOBAL_INTERRUPT_ENABLE; + GLOBAL_INTERRUPT_DISABLE; PIN_SQCK_INPUT; PIN_SUBQ_INPUT; @@ -528,22 +514,12 @@ int main() { Debug_Log(lows, wfck_mode); #endif - -#ifdef SCPH_5903 - currentLogic = logic_SCPH_5903; -#else - currentLogic = logic_Standard; -#endif - while (1) { _delay_ms(1); /* Start with a small delay, which can be necessary in cases where the MCU loops too quickly and picks up the laster SUBQ trailing end*/ - - captureSubQ(); - #if defined(PSNEE_DEBUG_SERIAL_MONITOR) Debug_Scbuf(scbuf); #endif @@ -557,24 +533,18 @@ int main() { While the laser lens moves to correct for the error, they can pick up a few TOC sectors. -------------------------------------------------------------------------------*/ - //This variable initialization macro is to replace (0x41) with a filter that will check that only the three most significant bits are correct. 0x001xxxxx - uint8_t isDataSector = (((scbuf[0] & 0x40) == 0x40) && (((scbuf[0] & 0x10) == 0) && ((scbuf[0] & 0x80) == 0))); - - - // 2. Execute selected logic through function pointer - currentLogic(isDataSector, scbuf); - - - - - + //This variable initialization macro is to replace (0x41) with a filter that will check that only the three most significant bits are correct. 0x001xxxxx + uint8_t isDataSector = (((scbuf[0] & 0x40) == 0x40) && (((scbuf[0] & 0x10) == 0) && ((scbuf[0] & 0x80) == 0))); + + // 2. Execute selected logic through function pointer + currentLogic(isDataSector); #ifdef LED_RUN PIN_LED_ON; #endif - // 3. Check hysteresis and inject if necessary - performInjectionSequence(); + // 3. Check hysteresis and inject if necessary + performInjectionSequence(); #ifdef LED_RUN PIN_LED_OFF; @@ -584,6 +554,5 @@ int main() { Debug_Inject(); #endif - //} } } diff --git a/PSNee/settings.h b/PSNee/settings.h index c98c77f..445070b 100644 --- a/PSNee/settings.h +++ b/PSNee/settings.h @@ -117,17 +117,17 @@ ------------------------------------------------------------------------------------------------*/ #if defined(SCPH_xxx1) // NTSC U/C | America. -const char region[3] = {'a', 'a', 'a'}; +#define REGION_SETTING 1 #endif #if defined(SCPH_102) || defined(SCPH_xxx2) // PAL | Europ. -const char region[3] = {'e', 'e', 'e'}; +#define REGION_SETTING 2 #endif #if defined(SCPH_100) || defined(SCPH_7500_9000) || defined(SCPH_7000) || \ defined(SCPH_5500) || defined(SCPH_3500_5000) || defined(SCPH_3000) || \ defined(SCPH_1000) || defined(SCPH_xxx3) || defined(SCPH_5903) // NTSC J | Asia. -const char region[3] = {'i', 'i', 'i'}; +#define REGION_SETTING 0 #endif