diff --git a/PSNee/BIOS_patching.h b/PSNee/BIOS_patching.h deleted file mode 100644 index c40e002..0000000 --- a/PSNee/BIOS_patching.h +++ /dev/null @@ -1,337 +0,0 @@ -#pragma once - -/* - * ====================================================================================== - * FUNCTION : Bios_Patching() - * TARGET : Data Bus (DX) synchronized via Address Bus (AX / AY) - * - * OPERATIONAL LOGIC: - * Intercepts specific memory transactions by monitoring address lines (AX/AY). - * Uses hardware interrupts (ISR) for high-speed pulse counting and cycle-accurate - * delays to inject modified data onto the Data line (DX) in real-time. - * - * KEY PHASES: - * 1. STABILIZATION & ALIGNMENT (AX): Synchronizes execution with a clean rising - * edge of the AX signal to establish a deterministic timing reference. - * - * 2. ADDRESS CALL DETECTION (PHASE 2): Scans the bus for specific address calls - * by validating consecutive polling blocks (SILENCE_THRESHOLD). - * - * 3. SILENCE CONFIRMATION (GATING): Counts the exact number of validated silence - * windows (CONFIRM_COUNTER_TARGET) to reach the correct pre-patching stage. - * - * 4. HARDWARE PULSE COUNTING (ISR): Uses INT0/INT1 to decrement the 'impulse' - * counter on each rising edge with minimal hardware latency. - * - * 5. DATA OVERDRIVE (DX): Upon reaching the target pulse, triggers a calibrated - * delay (BIT_OFFSET) and momentarily forces the DX pin to OUTPUT mode to - * overwrite the BIOS bit for a precise duration (OVERRIDE). - * ====================================================================================== - */ - -#ifdef BIOS_PATCH - -/** - * Shared state variables between ISRs and the main patching loop. - * Declared 'volatile' to prevent compiler optimization during busy-wait loops. - */ -volatile uint8_t impulse = 0; // Down-counter for physical address pulses -volatile uint8_t patch = 0; // Synchronization flag (0: Idle, 1: AX Done, 2: AY Done) - -/** - * PHASE 3: Primary Interrupt Service Routine (AX) - * Triggered on rising edges to perform the real-time bus override. - */ -ISR(PIN_AX_INTERRUPT_VECTOR) { - if (--impulse == 0) { - // Precise bit-alignment delay within the memory cycle - __builtin_avr_delay_cycles(BIT_OFFSET_CYCLES); - - #ifdef PHASE_TWO_PATCH - PIN_DX_SET; // Pre-drive high if required by specific logic - #endif - - // DATA OVERDRIVE: Pull the DX bus to the custom state - PIN_DX_OUTPUT; - __builtin_avr_delay_cycles(OVERRIDE_CYCLES); - - #ifdef PHASE_TWO_PATCH - PIN_DX_CLEAR; - #endif - - // BUS RELEASE: Return DX to High-Z (Input) mode - PIN_DX_INPUT; - - PIN_AX_INTERRUPT_DISABLE; // Stop tracking AX pulses - PIN_LED_OFF; - patch = 1; // Signal Phase 3 completion - } -} - -#ifdef PHASE_TWO_PATCH -/** - * PHASE 5: Secondary Interrupt Service Routine (AY) - * Handles the second injection stage if multi-patching is active. - */ -ISR(PIN_AY_INTERRUPT_VECTOR) { - if (--impulse == 0) { - __builtin_avr_delay_cycles(BIT_OFFSET_2_CYCLES); - - PIN_DX_OUTPUT; - __builtin_avr_delay_cycles(OVERRIDE_2_CYCLES); - PIN_DX_INPUT; - - PIN_AY_INTERRUPT_DISABLE; - PIN_LED_OFF; - patch = 2; // Signal Phase 5 completion - } -} -#endif - -void Bios_Patching(void) { - - // --- HARDWARE BYPASS OPTION (SCPH-7000 specific) --- - #if defined(SCPH_7000) - PIN_SWITCH_INPUT; // Configure Pin D5 as Input - PIN_SWITCH_SET; // Enable internal Pull-up (D5 defaults to HIGH) - __builtin_avr_delay_cycles(10); // Short delay for voltage stabilization - - /** - * Exit immediately if the switch pulls the pin to GND (Logic LOW). - * This allows the user to disable the BIOS patch on-the-fly. - */ - if (PIN_SWITCH_READ == 0) { - return; - } - #endif - - uint8_t current_confirms = 0; - //uint16_t count; - - patch = 0; // Reset sync flag - sei(); // Enable Global Interrupts - PIN_AX_INPUT; // Set AX to monitor mode - - // --- PHASE 1: STABILIZATION & ALIGNMENT --- - // Align execution pointer to a known rising edge state. - if (PIN_AX_READ != 0) { - while (WAIT_AX_FALLING); // Wait if bus is busy - while (WAIT_AX_RISING); // Sync with next pulse start - } else { - while (WAIT_AX_RISING); // Sync with upcoming pulse - } - - // --- PHASE 2: SILENCE DETECTION --- - // Validate the exact number of silence windows to identify the boot stage. - while (current_confirms < CONFIRM_COUNTER_TARGET) { - uint16_t count = SILENCE_THRESHOLD; - while (count > 0) { - if (PIN_AX_READ != 0) { - while (WAIT_AX_FALLING); - break; // Impulse detected: retry current silence block - } - #ifdef IS_32U4_FAMILY - __asm__ __volatile__ ("nop"); - #endif - - count--; - } - if (count == 0) { - current_confirms++; // Validated one silence window - } - } - - // --- PHASE 3: LAUNCH HARDWARE COUNTING (AX) --- - impulse = PULSE_COUNT; - PIN_LED_ON; - PIN_AX_INTERRUPT_CLEAR; - PIN_AX_INTERRUPT_RISING; // Setup rising-edge trigger - PIN_AX_INTERRUPT_ENABLE; // Engage ISR - - while (patch != 1); - - - // --- PHASE 4 & 5: SECONDARY PATCHING SEQUENCE --- - #ifdef PHASE_TWO_PATCH - PIN_AY_INPUT; - current_confirms = 0; - impulse = PULSE_COUNT_2; - // Monitor for the specific silent gap before the second patch window - while (current_confirms < CONFIRM_COUNTER_TARGET_2) { - uint16_t count = SILENCE_THRESHOLD; - while (count > 0) { - if (PIN_AX_READ != 0) { - while (WAIT_AX_FALLING); - break; - } - - #ifdef IS_32U4_FAMILY - __asm__ __volatile__ ("nop"); - #endif - - count--; - } - if (count == 0) { - current_confirms++; - } - } - - PIN_LED_ON; - PIN_AY_INTERRUPT_CLEAR; - PIN_AY_INTERRUPT_FALLING; - PIN_AY_INTERRUPT_ENABLE; - - while (patch != 2); // Busy-wait for secondary ISR completion - - - return; - - #endif - - -} -#endif - - -/* - * Portability Note: The non-ISR (polling-based) version of the code is maintained - * to facilitate porting to other platforms and architectures that may not support - * AVR-specific hardware interrupts. - * - * Stability Limitation: While the polling version is more portable, it was found - * that at 16MHz, achieving consistent DATA OVERDRIVE stability is nearly impossible - * without using a Hardware ISR. The latency and jitter of software polling at this - * frequency are too high to guarantee a sub-microsecond cycle-accurate injection. - * Therefore, for ATmega328P @ 16MHz, the ISR-driven implementation remains the - * tandard. - */ - -// #ifdef BIOS_PATCH - -// volatile uint8_t impulse = 0; -// volatile uint8_t patch = 0; - - -// ISR(PIN_AX_INTERRUPT_VECTOR) { -// //impulse--; -// if (--impulse == 0){ // If impulse reaches the value defined by TRIGGER, the following actions are performed: -// // Precise cycle-accurate delay before triggering -// __builtin_avr_delay_cycles(BIT_OFFSET_CYCLES); - -// #ifdef PHASE_TWO_PATCH -// PIN_DX_SET; -// #endif - -// PIN_DX_OUTPUT; // Pull the line (Override start) -// __builtin_avr_delay_cycles(OVERRIDE_CYCLES); - -// #ifdef PHASE_TWO_PATCH -// PIN_DX_CLEAR; // Release the bus (Override end) -// #endif - -// PIN_DX_INPUT; - -// PIN_LED_OFF; -// PIN_AX_INTERRUPT_DISABLE; -// patch = 1; // patch is set to 1, indicating that the first patch is completed. -// } -// } - -// #ifdef PHASE_TWO_PATCH - - -// ISR(PIN_AY_INTERRUPT_VECTOR){ - -// //impulse--; -// if (--impulse == 0) // If impulse reaches the value defined by TRIGGER2, the following actions are performed: -// { -// __builtin_avr_delay_cycles(BIT_OFFSET_2_CYCLES); - -// PIN_DX_OUTPUT; -// __builtin_avr_delay_cycles(OVERRIDE_2_CYCLES); -// PIN_DX_INPUT; - -// PIN_AY_INTERRUPT_DISABLE; -// PIN_LED_OFF; -// patch = 2; // patch is set to 2, indicating that the second patch is completed. -// } -// } -// #endif - -// // --- BIOS Patching Main Function --- -// void Bios_Patching(void) { - -// uint8_t current_confirms = 0; -// uint8_t count = 0; -// patch = 0; -// sei(); -// PIN_AX_INPUT; -// // --- PHASE 1: Signal Stabilization & Alignment (AX) --- -// if (PIN_AX_READ != 0) { -// while (WAIT_AX_FALLING); // Wait for falling edge -// while (WAIT_AX_RISING); // Wait for next rising edge to sync -// } else { -// while (WAIT_AX_RISING); // Wait for first rising edge -// } - -// // --- PHASE 2: Silence Detection (AX) --- - -// while (current_confirms < CONFIRM_COUNTER_TARGET) { -// uint16_t count = SILENCE_THRESHOLD; - -// // --- Scan for ONE continuous block of silence --- -// while (count > 0) { -// if (PIN_AX_READ != 0) { -// while (WAIT_AX_FALLING); // Pulse detected: wait for bus to clear -// break; // Reset and try a new silence block -// } -// count--; -// } - -// // If count reaches 0, a silent block is validated -// if (count == 0) { -// current_confirms++; -// } -// } -// impulse = PULSE_COUNT; -// PIN_LED_ON; -// PIN_AX_INTERRUPT_RISING; -// PIN_AX_INTERRUPT_ENABLE; -// while (patch != 1); // Wait for the first stage of the patch to complete: - -// //PIN_LED_OFF; -// // -------- Secondary Patch ---------- -// #ifdef PHASE_TWO_PATCH - -// current_confirms = 0; -// while (current_confirms < CONFIRM_COUNTER_TARGET_2) { -// uint16_t count = SILENCE_THRESHOLD; - -// while (count > 0) { -// if (PIN_AX_READ != 0) { - -// while (WAIT_AX_FALLING); -// break; -// } -// count--; -// } - -// if (count == 0) { -// current_confirms++; -// } -// } - -// PIN_LED_ON; -// impulse = PULSE_COUNT_2; -// PIN_AY_INTERRUPT_RISING; -// PIN_AY_INTERRUPT_ENABLE; - -// while (patch != 2); // Wait for the second stage of the patch to complete: - -// #endif - -// cli(); -// } -// #endif - - diff --git a/PSNee/MCU.h b/PSNee/MCU.h index 4c8a172..e88109b 100644 --- a/PSNee/MCU.h +++ b/PSNee/MCU.h @@ -298,7 +298,7 @@ // 3. Digital Input Buffer Disable (DIDR0 & DIDR2) // 32U4 has more analog channels (ADC0-ADC7 and ADC8-ADC13) DIDR0 = 0xFF; // Disable digital buffers on F0-F7 - DIDR2 = 0x3F; // Disable digital buffers on D4, D6, D7, B4, B5, B6 + //DIDR2 = 0x3F; // Disable digital buffers on D4, D6, D7, B4, B5, B6 // 4. GPIO Strategy (Unused pins to Pull-up) // On 32U4, Port C is small (only PC6/PC7). Adjusting to cover most unused pins. @@ -318,7 +318,7 @@ PRR1 = (1 << PRUSB) | // Disable USB Controller (Stops SOF interrupts) (1 << PRTIM3) | // Timer 3 Off (1 << 4) | // Timer 4 Off (High speed timer) - (1 << PRUSART1); // Disable Serial1 (UART) + (0 << PRUSART1); // KEEP SERIAL1 ACTIVE (PD1/TX1) - Must be 0 // 6. Double Security for Timer 0 (Redundancy) TCCR0B = 0; @@ -858,4 +858,146 @@ #endif // BIOS Patching #endif +/* + * Portability Note: The non-ISR (polling-based) version of the code is maintained + * to facilitate porting to other platforms and architectures that may not support + * AVR-specific hardware interrupts. + * + * Stability Limitation: While the polling version is more portable, it was found + * that at 16MHz, achieving consistent DATA OVERDRIVE stability is nearly impossible + * without using a Hardware ISR. The latency and jitter of software polling at this + * frequency are too high to guarantee a sub-microsecond cycle-accurate injection. + * Therefore, for ATmega328P @ 16MHz, the ISR-driven implementation remains the + * tandard. + */ + +// #ifdef BIOS_PATCH + +// volatile uint8_t impulse = 0; +// volatile uint8_t patch = 0; + + +// ISR(PIN_AX_INTERRUPT_VECTOR) { +// //impulse--; +// if (--impulse == 0){ // If impulse reaches the value defined by TRIGGER, the following actions are performed: +// // Precise cycle-accurate delay before triggering +// __builtin_avr_delay_cycles(BIT_OFFSET_CYCLES); + +// #ifdef PHASE_TWO_PATCH +// PIN_DX_SET; +// #endif + +// PIN_DX_OUTPUT; // Pull the line (Override start) +// __builtin_avr_delay_cycles(OVERRIDE_CYCLES); + +// #ifdef PHASE_TWO_PATCH +// PIN_DX_CLEAR; // Release the bus (Override end) +// #endif + +// PIN_DX_INPUT; + +// PIN_LED_OFF; +// PIN_AX_INTERRUPT_DISABLE; +// patch = 1; // patch is set to 1, indicating that the first patch is completed. +// } +// } + +// #ifdef PHASE_TWO_PATCH + + +// ISR(PIN_AY_INTERRUPT_VECTOR){ + +// //impulse--; +// if (--impulse == 0) // If impulse reaches the value defined by TRIGGER2, the following actions are performed: +// { +// __builtin_avr_delay_cycles(BIT_OFFSET_2_CYCLES); + +// PIN_DX_OUTPUT; +// __builtin_avr_delay_cycles(OVERRIDE_2_CYCLES); +// PIN_DX_INPUT; + +// PIN_AY_INTERRUPT_DISABLE; +// PIN_LED_OFF; +// patch = 2; // patch is set to 2, indicating that the second patch is completed. +// } +// } +// #endif + +// // --- BIOS Patching Main Function --- +// void Bios_Patching(void) { + +// uint8_t current_confirms = 0; +// uint8_t count = 0; +// patch = 0; +// sei(); +// PIN_AX_INPUT; +// // --- PHASE 1: Signal Stabilization & Alignment (AX) --- +// if (PIN_AX_READ != 0) { +// while (WAIT_AX_FALLING); // Wait for falling edge +// while (WAIT_AX_RISING); // Wait for next rising edge to sync +// } else { +// while (WAIT_AX_RISING); // Wait for first rising edge +// } + +// // --- PHASE 2: Silence Detection (AX) --- + +// while (current_confirms < CONFIRM_COUNTER_TARGET) { +// uint16_t count = SILENCE_THRESHOLD; + +// // --- Scan for ONE continuous block of silence --- +// while (count > 0) { +// if (PIN_AX_READ != 0) { +// while (WAIT_AX_FALLING); // Pulse detected: wait for bus to clear +// break; // Reset and try a new silence block +// } +// count--; +// } + +// // If count reaches 0, a silent block is validated +// if (count == 0) { +// current_confirms++; +// } +// } +// impulse = PULSE_COUNT; +// PIN_LED_ON; +// PIN_AX_INTERRUPT_RISING; +// PIN_AX_INTERRUPT_ENABLE; +// while (patch != 1); // Wait for the first stage of the patch to complete: + +// //PIN_LED_OFF; +// // -------- Secondary Patch ---------- +// #ifdef PHASE_TWO_PATCH + +// current_confirms = 0; +// while (current_confirms < CONFIRM_COUNTER_TARGET_2) { +// uint16_t count = SILENCE_THRESHOLD; + +// while (count > 0) { +// if (PIN_AX_READ != 0) { + +// while (WAIT_AX_FALLING); +// break; +// } +// count--; +// } + +// if (count == 0) { +// current_confirms++; +// } +// } + +// PIN_LED_ON; +// impulse = PULSE_COUNT_2; +// PIN_AY_INTERRUPT_RISING; +// PIN_AY_INTERRUPT_ENABLE; + +// while (patch != 2); // Wait for the second stage of the patch to complete: + +// #endif + +// cli(); +// } +// #endif + + diff --git a/PSNee/PSNee.ino b/PSNee/PSNee.ino index 5271b82..96965a6 100644 --- a/PSNee/PSNee.ino +++ b/PSNee/PSNee.ino @@ -46,7 +46,7 @@ // D13 for Arduino, ATtiny add a led between PB3 (pin 2) and gnd with a 1k resistor in series, // ATmega32U4 (Pro Micro) add a led between PB6 (pin 10) and gnd with a 1k resistor in series. - #define DEBUG_SERIAL_MONITOR // Enables serial monitor output. +// #define DEBUG_SERIAL_MONITOR // Enables serial monitor output. /****************************************************************************************************************** * Requires compilation with Arduino libs! @@ -105,8 +105,6 @@ #include "MCU.h" #include "settings.h" -#include "BIOS_patching.h" - uint8_t wfck_mode = 0; //Flag initializing for automatic console generation selection 0 = old, 1 = pu-22 end ++ uint8_t SUBQBuffer[12]; // Global buffer to store the 12-byte SUBQ channel data @@ -124,8 +122,202 @@ uint8_t hysteresis = 0; /******************************************************************************************************************* * Code section ********************************************************************************************************************/ +/**************************************************************************************** + * FUNCTION : Bios_Patching() + * ************************************************************************************** + * + * OPERATION : Real-time Data Bus (DX) override via Address Bus (AX / AY) + * + * KEY PHASES: + * 1. STABILIZATION & ALIGNMENT (AX): + * Synchronizes the execution pointer with the AX rising edge to establish + * a deterministic hardware timing reference. + * + * 2. SILENCE DETECTION (BOOT STAGE): + * Validates consecutive silent windows (SILENCE_THRESHOLD) to identify + * the specific boot stage before the target address call. + * + * 3. HARDWARE COUNTING & OVERDRIVE (AX): + * Engages INT0 to count AX pulses. On the final pulse, triggers a + * bit-aligned delay to force a custom state on the DX line. + * + * 4. SECONDARY SILENCE (GAP DETECTION): + * If PHASE_TWO_PATCH is active, monitors for a secondary silent gap + * (CONFIRM_COUNTER_TARGET_2) between patching windows. + * + * 5. SECONDARY OVERDRIVE (AY): + * Engages INT1 (AY) for the final injection stage, synchronizing the + * patch with the secondary memory address cycles. + * + * CRITICAL TIMING & TIMER-LESS ALIGNMENT: + * - DETERMINISTIC SILENCE: Uses cycle-accurate polling to filter boot jitter + * and PS1 initialization noise, replacing unstable hardware timers. + * + * - CYCLE STABILIZATION (16MHz LIMIT): Uses '__builtin_avr_delay_cycles' to + * prevent compiler reordering. At 16MHz, the CPU has zero margin; a single + * instruction displacement would break high-speed bus alignment. + * + **************************************************************************************/ +#ifdef BIOS_PATCH + + /** + * Shared state variables between ISRs and the main patching loop. + * Declared 'volatile' to prevent compiler optimization during busy-wait loops. + */ + volatile uint8_t impulse = 0; // Down-counter for physical address pulses + volatile uint8_t patch = 0; // Synchronization flag (0: Idle, 1: AX Done, 2: AY Done) + + /** + * PHASE 3: Primary Interrupt Service Routine (AX) + * Triggered on rising edges to perform the real-time bus override. + */ + ISR(PIN_AX_INTERRUPT_VECTOR) { + if (--impulse == 0) { + // Precise bit-alignment delay within the memory cycle + __builtin_avr_delay_cycles(BIT_OFFSET_CYCLES); + + #ifdef PHASE_TWO_PATCH + PIN_DX_SET; // Pre-drive high if required by specific logic + #endif + + // DATA OVERDRIVE: Pull the DX bus to the custom state + PIN_DX_OUTPUT; + __builtin_avr_delay_cycles(OVERRIDE_CYCLES); + + #ifdef PHASE_TWO_PATCH + PIN_DX_CLEAR; + #endif + + // BUS RELEASE: Return DX to High-Z (Input) mode + PIN_DX_INPUT; + + PIN_AX_INTERRUPT_DISABLE; // Stop tracking AX pulses + PIN_LED_OFF; + patch = 1; // Signal Phase 3 completion + } + } + + #ifdef PHASE_TWO_PATCH + /** + * PHASE 5: Secondary Interrupt Service Routine (AY) + * Handles the second injection stage if multi-patching is active. + */ + ISR(PIN_AY_INTERRUPT_VECTOR) { + if (--impulse == 0) { + __builtin_avr_delay_cycles(BIT_OFFSET_2_CYCLES); + + PIN_DX_OUTPUT; + __builtin_avr_delay_cycles(OVERRIDE_2_CYCLES); + PIN_DX_INPUT; + + PIN_AY_INTERRUPT_DISABLE; + PIN_LED_OFF; + patch = 2; // Signal Phase 5 completion + } + } + #endif + + void Bios_Patching(void) { + + // --- HARDWARE BYPASS OPTION (SCPH-7000 specific) --- + #if defined(SCPH_7000) + PIN_SWITCH_INPUT; // Configure Pin D5 as Input + PIN_SWITCH_SET; // Enable internal Pull-up (D5 defaults to HIGH) + __builtin_avr_delay_cycles(10); // Short delay for voltage stabilization + + /** + * Exit immediately if the switch pulls the pin to GND (Logic LOW). + * This allows the user to disable the BIOS patch on-the-fly. + */ + if (PIN_SWITCH_READ == 0) { + return; + } + #endif + + uint8_t current_confirms = 0; + //uint16_t count; + + patch = 0; // Reset sync flag + sei(); // Enable Global Interrupts + PIN_AX_INPUT; // Set AX to monitor mode + + // --- PHASE 1: STABILIZATION & ALIGNMENT (AX) --- + // Establish a deterministic hardware timing reference. + if (PIN_AX_READ != 0) { + while (WAIT_AX_FALLING); // Wait if bus is busy + while (WAIT_AX_RISING); // Sync with next pulse start + } else { + while (WAIT_AX_RISING); // Sync with upcoming pulse + } + + // --- PHASE 2: SILENCE DETECTION --- + // Validate the exact number of silence windows to identify the boot stage. + while (current_confirms < CONFIRM_COUNTER_TARGET) { + uint16_t count = SILENCE_THRESHOLD; + while (count > 0) { + if (PIN_AX_READ != 0) { + while (WAIT_AX_FALLING); + break; // Impulse detected: retry current silence block + } + #ifdef IS_32U4_FAMILY + __asm__ __volatile__ ("nop"); + #endif + + count--; + } + if (count == 0) { + current_confirms++; // Validated one silence window + } + } + + // --- PHASE 3: LAUNCH HARDWARE COUNTING (AX) --- + impulse = PULSE_COUNT; + PIN_LED_ON; + PIN_AX_INTERRUPT_CLEAR; + PIN_AX_INTERRUPT_RISING; // Setup rising-edge trigger + PIN_AX_INTERRUPT_ENABLE; // Engage ISR + + while (patch != 1); + + + // --- PHASE 4 & 5: SECONDARY PATCHING SEQUENCE --- + #ifdef PHASE_TWO_PATCH + PIN_AY_INPUT; + current_confirms = 0; + impulse = PULSE_COUNT_2; + // Monitor for the specific silent gap before the second patch window + while (current_confirms < CONFIRM_COUNTER_TARGET_2) { + uint16_t count = SILENCE_THRESHOLD; + while (count > 0) { + if (PIN_AX_READ != 0) { + while (WAIT_AX_FALLING); + break; + } + + #ifdef IS_32U4_FAMILY + __asm__ __volatile__ ("nop"); + #endif + + count--; + } + if (count == 0) { + current_confirms++; + } + } + + PIN_LED_ON; + PIN_AY_INTERRUPT_CLEAR; + PIN_AY_INTERRUPT_FALLING; + PIN_AY_INTERRUPT_ENABLE; + + while (patch != 2); // Busy-wait for secondary ISR completion + return; + #endif + } +#endif + /******************************************************************************************************************* * FUNCTION : BoardDetection * @@ -390,7 +582,7 @@ void PerformInjectionSequence(uint8_t injectSCEx) { const uint16_t BIT_DELAY = 4000; // 4000us is the standard bit timing for SCEx signal (approx. 250 bps) const uint8_t isWfck = wfck_mode; // Cache wfck_mode to save CPU cycles during the bit loop - hysteresis = (HYSTERESIS_MAX - 10); // Reset hysteresis to mid-point after triggering + hysteresis = (HYSTERESIS_MAX - 6); // Reset hysteresis to mid-point after triggering #ifdef LED_RUN PIN_LED_ON; @@ -524,11 +716,15 @@ void Init() { // --- Debug Interface Setup --- #if defined(DEBUG_SERIAL_MONITOR) && defined(IS_ATTINY_FAMILY) pinMode(debugtx, OUTPUT); // software serial tx pin - mySerial.begin(115200); // 13,82 bytes in 12ms, max for softwareserial. (expected data: ~13 bytes / 12ms) // update: this is actually quicker - #elif defined(DEBUG_SERIAL_MONITOR) && !defined(IS_ATTINY_FAMILY) - Serial.begin(500000); // 60 bytes in 12ms (expected data: ~26 bytes / 12ms) // update: this is actually quicker + mySerial.begin(115200); // 13,82 bytes in 12ms, max for softwareserial + #elif defined(DEBUG_SERIAL_MONITOR) && defined(IS_32U4_FAMILY) + // On 32U4, Serial1 is the hardware UART on pins D0 (RX) and D1 (TX) + Serial1.begin(500000); + #elif defined(DEBUG_SERIAL_MONITOR) && defined(IS_328_168_FAMILY) + Serial.begin(500000); // Standard hardware UART for 328/168 #endif + // --- Console Analysis --- // Identify board revision (PU-7 to PU-22+) to set correct injection timings BoardDetection(); diff --git a/PSNee/settings.h b/PSNee/settings.h index c70d995..a03c6af 100644 --- a/PSNee/settings.h +++ b/PSNee/settings.h @@ -217,6 +217,12 @@ #if defined(DEBUG_SERIAL_MONITOR) extern uint8_t hysteresis; + #if defined(IS_32U4_FAMILY) + #define DEBUG_OUT Serial1 + #else + #define DEBUG_OUT Serial + #endif + void BoardDetectionLog (uint16_t window_result, uint8_t Wfck_mode, uint8_t region){ //Information about the MCU, and old or late console mode. #if defined(IS_ATTINY_FAMILY) @@ -228,12 +234,13 @@ void BoardDetectionLog (uint16_t window_result, uint8_t Wfck_mode, uint8_t regio "PAL", // 2 "Universal" // 3 }; - Serial.println(" "); - Serial.print(F(" MCU frequency: ")); Serial.print(F_CPU / 1000000L); Serial.println(F(" MHz")); - Serial.print(F(" Window remaining: ")); Serial.println(window_result); // Real-time diagnostic - Serial.print(" wfck_mode: "); Serial.println(Wfck_mode); - Serial.print(" region: "); Serial.print(regionNames[region]); - Serial.println(" "); + + DEBUG_OUT.println(""); + DEBUG_OUT.print(F(" CPU Speed: ")); DEBUG_OUT.print(F_CPU / 1000000L); DEBUG_OUT.println(F(" MHz")); + DEBUG_OUT.print(F(" Sync Window: ")); DEBUG_OUT.println(window_result); // Real-time diagnostic + DEBUG_OUT.print(F(" WFCK Mode: ")); DEBUG_OUT.println(Wfck_mode); + DEBUG_OUT.print(F(" Region ID: ")); DEBUG_OUT.println(regionNames[region]); + DEBUG_OUT.println(""); #endif } @@ -258,7 +265,7 @@ void CaptureSUBQLog(uint8_t *dataBuffer) { #if defined(IS_ATTINY_FAMILY) mySerial.print(F(" [Err x")); mySerial.print(errorCount); mySerial.println(F("]")); #else - Serial.print(F(" [Missed sectors: ")); Serial.print(errorCount); Serial.println(F("]")); + DEBUG_OUT.print(F(" [Missed sectors: ")); DEBUG_OUT.print(errorCount); DEBUG_OUT.println(F("]")); #endif errorCount = 0; // Reset counter after reporting } @@ -278,13 +285,13 @@ void CaptureSUBQLog(uint8_t *dataBuffer) { // Formatted hex output for ATmega for (uint8_t i = 0; i < 12; i++) { uint8_t val = dataBuffer[i]; - if (val < 0x10) Serial.print("0"); - Serial.print(val, HEX); - Serial.print(" "); + if (val < 0x10) DEBUG_OUT.print("0"); + DEBUG_OUT.print(val, HEX); + DEBUG_OUT.print(" "); } // Append global hysteresis on the same line - Serial.print(F("| Hyst: ")); - Serial.println(hysteresis); + DEBUG_OUT.print(F("| Hyst: ")); + DEBUG_OUT.println(hysteresis); #endif } @@ -295,7 +302,7 @@ void InjectLog(){ #if defined(IS_ATTINY_FAMILY) mySerial.print("!"); // --- MINIMALIST NOTIFICATION (ATtiny) --- #else - Serial.println(" INJECT ! "); + DEBUG_OUT.println(" INJECT ! "); #endif }