1
0
mirror of https://github.com/kalymos/PsNee.git synced 2026-01-11 23:53:07 +00:00

Update PsNee.ino

This commit is contained in:
kalymos 2017-06-03 10:00:51 +02:00 committed by GitHub
parent af2205bc91
commit 3096483027

540
PsNee.ino
View File

@ -1,87 +1,45 @@
//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//||||||MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM|||||
//||||||M*************************************************************M|||||
//||||||M*************************************************************M|||||
//||||||M***QQQQQQQQQ***************Q******Q**************************M|||||
//||||||M***Q********Q**************QQ*****Q**************************M|||||
//||||||M***Q********Q**************QQ*****Q**************************M|||||
//||||||M***Q********Q**************Q*Q****Q**************************M|||||
//||||||M***Q********Q**************Q*Q****Q**************************M|||||
//||||||M***Q********Q**************Q*Q****Q**************************M|||||
//||||||M***Q********Q**************Q**Q***Q**************************M|||||
//||||||M***QQQQQQQQQ***************Q**Q***Q**************************M|||||
//||||||M***Q***********QQQQQQQQ****Q***Q**Q******QQQQ*******QQQQ*****M|||||
//||||||M***Q**********QQ******Q****Q***Q**Q*****QQ**Q******QQ**Q*****M|||||
//||||||M***Q**********Q************Q***Q**Q****QQ***Q*****Q***QQ*****M|||||
//||||||M***Q**********QQQ**********Q****Q*Q***QQ**QQQ****QQQQQQ******M|||||
//||||||M***Q************QQQQQ******Q****Q*Q***QQQQQ******QQ**********M|||||
//||||||M***Q****************QQQ****Q*****QQ**QQ**********Q***********M|||||
//||||||M***Q******************Q****Q*****QQ**Q**********QQ***********M|||||
//||||||M***Q**********Q*******QQ***Q*****QQ**Q******QQ**Q******QQ****M|||||
//||||||M***Q**********QQ******QQ***Q******Q**QQ****QQ***QQ****QQ*****M|||||
//||||||M***Q***********QQQQQQQQ****Q******Q***QQQQQ******QQQQQQ******M|||||
//||||||M*************************************************************M|||||
//||||||M*************************************************************M|||||
//||||||MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM|||||
//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//||||||||||||||||||||||||||||||||||||||||||||||||||| VERSION 2! |||||||||||
//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//BETA BETA BETA BETA BETA BETA BETA BETA BETA BETA BETA BETA BETA BETA BETA
//Updated on September 10, coded by TheFrietMan, as usual.
//
// PPPPPPPPPPPPPPPP P P
// P P PP P
// P P P P P
// P P P P P
// P P P P P
// P P P P P
// P P P P P
// PPPPPPPPPPPPPPPP PPPPPPPPPPP P P P PPPPPPPPPPP PPPPPPPPPPP
// P P P P P P P
// P P P P P P P
// P P P P P P P
// P P P P P P P
// P PPPPPPPPPPPPPP P PP PPPPPPP PPPPPPP
// P P P P P P
// P P P P P P
// P P P P P P
// P P P P P P
// P P P P P P
// P P P P P P
// PPPPPPPPPPPP P P PPPPPPPPPPP PPPPPPPPPPP VERSION 6!
//UPDATED AT MAY 14 2016, CODED BY THE FRIENDLY FRIETMAN :-)
//PsNee, an open source stealth modchip for the Sony Playstation 1, usable on
//all platforms supported by Arduino, preferably ATTiny. Finally something modern!
//
//
/////////// TO DO: /////////////
// - Make SCEx-arrays smaller by commoning up the common parts of the arrays and thus use less flash
// - Tidy everything up by using functions instead of code-knitting
// - Implement what needs to be done when it is detected that PsNee is connected to a PU-22, PU-23 or PSOne
// - Slice the data signal in sync with an internal Playstation clock (there should be one on the gate-pin,
// this is the 7.35kHz WFCK) instead of using a free running clock from the modchip
////////////////////////////////
//
//
/////////// VERSION 2! :D ///////////
//What has changed?
// - Thanks to TriMesh, the gate-pin is now also used to determine in which model of
// Playstation PsNee is installed. The modchip algorithm thus can be optimized for
// optimal performance on specific Playstation revisions. This works by monitoring
// whether a clock signal is present on this pin - when there is one, the modchip is
// installed in a PU-22, PU-23 or PSOne Playstation, else it is installed in an older
// model Playstation. In this version of PsNee, nothing is actually done with this information.
// - Thanks to -again- TriMesh, NTSC support for PAL SCPH-102 Playstations is added! This uses
// the same method the OneChip modchip used for achieving this:
// 1. Monitor the XLAT signal from the CD mechanism controller chip. This requires
// another connection to the Playstation. When this signal is 0, the first CD copy
// protection is passed! After this, there is another one.
// 2. After this, watch the Address18-pin (pin 31) on the BIOS-chip. When this signal
// is high, this means the second CD copy protection is about to run.
// 3. Wait a short time.
// 4. Pull the Data2-pin (pin 15) on the BIOS-chip to 0. This effectively blocks the
// execution of the region check of the inserted disc.
// 5. The Playstation plays the inserted disc and doesn't care whether it's PAL or NTSC!
// 6. Release the 0 of the Data2-pin.
// To correctly output a PAL video color signal for a PAL TV on a PAL PSOne with an NTSC disc
// inserted, Pin 3 of IC502 must be grounded with an external switch. The modchip also could do
// this, although we would need a device with more pins available.
// - The outputted data signal is now "sliced up" to improve (or less distort) the tracking
// signal from the CD mechanism: later Playstations use the CD tracking signal for transmitting
// the SCEx-string to the Playstation instead of using a seperate connection, so when the modchip
// forces a 0 on the data-pin, the tracking signal also is gone temporarily. By slicing the data-
// signal up in little pieces at least some of the tracking signal remains and the Playstation can
// read discs more easily.
// - The two big for-loops are combined into one with an OR-statement describing the two conditions
// modchip should be active: when flagFirstCycle = 0 or when flagFirstCycle = 1 and the lid is opened
// and closed again. This makes code maintenance easier.
// - The pin-out of the modchip is changed slightly to be able to use an interrupt for the PAL=>NTSC
// BIOS-patch for PAL SCPH-102. Please use the revised pin-out found below with this code.
//~TheFrietMan, The Netherlands
/////////////////////////////////////
//
//
//--------------------------------------------------
// TL;DR
//--------------------------------------------------
//Look for the "Arduino selection!" section and verify the target platform. Hook up your target device and hit Upload!
//BEWARE: when using ATTiny45, make sure the proper device is selected (Extra=>Board=>ATTiny45 (internal 8MHz clock))
//and the proper fuses are burnt (use Extra=>Burn bootloader for this), otherwise PsNee will malfunction. A tutorial on
//uploading Arduino code via an Arduino Uno to an ATTiny device: http://highlowtech.org/?p=1695
//Look at the pinout for your device and hook PsNee up to the points on your Playstation.
//--------------------------------------------------
// General info!
//--------------------------------------------------
//PLAYSTATION 1 SECURITY - HOW IT DOES IT'S THING:
//Sony didn't really go through great lenghts to protect it's precious Playstation
//from running unauthorised software; the main security is based on a simple ASCII
@ -92,21 +50,21 @@
//The nifty Sony engineers did not use the pits and stuff to store the security checks for
//Playstation discs but went crazy with the rolled up carrier string. In an ordinary CD, the
//string is rolled up so that the spacing between the tracks is as equal as possible. If that
//namely is not the case, the laser itself needs to move a bit to keep track of the track and
//is not the case, the laser itself needs to move a bit to keep track of the track and
//reliably read the data off the disc.
//If you wonder how the laser knows when it follows the track optimally: four photodiodes, light
//intensity measurement, difference measurements, servo. There.
//To the point: the Sony engineers decidedly "fumbled up" the track of sector 4 on a Playstation
//disc (the track was modulated in nerd-speak) so that the error correction circuit outputs a
//recognisable signal, as the laser needs to be corrected to follow the track optimally.
//This outputted signal actually is a 250bps serial bitstream (with 1 startbit and 2 stopbits) which
//This output signal actually is a 250bps serial bitstream (with 1 start bit and 2 stop bits) which
//in plain ASCII says SCEA (Sony Computer Entertainment of America), SCEE (Sony Computer Entertainment
//of Europe) or SCEI (Sony Computer Entertainment of Japan), depending on the region of the disc inserted.
//The security thus functions not only as copy protection, but also as region protection.
//The text string from the disc is compared with the text string that is embedded in the Playstation
//hardware. When these text strings are the same, the disc is interpreted to be authentic and from
//the correct region. Bingo!
//
//HOW THE MODCHIP TRICKS THE PLAYSTATION:
//The modchip isn't all that of a complicated device: clever reverse engineers found the point on the
//Playstation motherboard that carried the text string from the disc and found a way to temporarily block
@ -115,238 +73,256 @@
//with this after about 25 seconds. Because all the possible valid region options are outputted on the
//motherboard the Playstation gets a bit confused and simply accepts the inserted disc as authentic; after all,
//one of the codes was the same as that of the Playstation hardware...
//Early modchips applied the text strings as long as there was applied power to them, whereby later Playstation
//Early modchips applied the text strings as long as power was applied to them, whereby later Playstation
//software could detect whether a modchip was installed. This is circumvented in this application by idling the
//modchip after about 25 seconds. The text strings are only tranmitted again when the CD lid is opened and closed
//again, to enable playing multi-disc games. This is also called a stealth modchip in marketing-speak.
//
//This code is verified on an ATTiny45 with the 8MHz internal oscillator using a Saleae Logic Analyser, timing is
//reasonable important in this application.
//Version 1 was kindly coded and documented by TheFrietMan, August 20 2015, The Netherlands.
//The Playstation is great but nothing beats our national pride, the Philips CDi! Cheesiness for the win!
//
//
//PINOUT IC:
// ATTiny45, DIP package:
// Pin 1: OUT - PAL SCPH-102 BIOS Data2
// Pin 2: IN - PAL SCPH-102 BIOS Address18
// Pin 3: IN - CD lid
// Pin 4: Ground
// Pin 5: OUT - Data
// Pin 6: OUT - Gate
// Pin 7: IN - XLAT !This is also where INT0 lives on ATTiny45!
// Pin 8: Vcc
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <Flash.h> //Include the Flash library to conveniently store the SCExData-arrays in PROGMEM, see http://arduiniana.org/libraries/flash/
//BLOODY GLOBAL VARIABLES
//Pins for the Arduino Uno
//int data = 0; //The pin that outputs the SCEE SCEA SCEI string
//int gate = 1; //The pin that gets pulled low to enable data injection on the Playstation motherboard
//int xlat = 2; //On Arduino Uno, Arduino pin 2 is connected to INT0
//int lid = 3; //The pin that gets connected to the internal CD lid signal; active high
//int biosA18 = 4; //Only used in SCPH-102 PAL mode
//int biosD2 = 5; //Only used in SCPH-102 PAL mode
//--------------------------------------------------
// New in this version!
//--------------------------------------------------
//A lot!
// - The PAL SCPH-102 NTSC BIOS-patch works flawlessly! For speed reasons this is implemented in bare
// AVR C. It is functionally identical to the OneChip modchip, this modchip firmware was disassembled,
// documented (available on request, but written in Dutch...) and analyzed with a logic analyzer to
// make sure PsNee works just as well.
// - The code now is segmented in functions which make the program a lot more maintable and readable
// - Timing is perfected, all discs (both backups and originals of PAL and NTSC games) now work in the
// PAL SCPH-102 test machine
// - It was found out that the gate signal doesn't havbe to be hooked up to a PAL SCPH-102 Playstation
// to circumvent the copy protection. This is not tested on other Playstation models so the signal still
// is available
// - The /xlat signal is no longer required to time the PAL SCPH-102 NTSC BIOS-patch
// - Only AVR PORTB is used for compatibility reasons (almost all the AVR chips available have PORTB)
//SET THIS TO 1 IF YOU HAVE A PAL SCPH-102 PLAYSTATION AND WANT TO PLAY NTSC DISCS ON A PAL TV WITHOUT A BOOT DISC
//THIS REQUIRES A MODCHIP WITH MORE PINS. I SUGGEST USING AN ATTINY2313. THE PIN-OUT FOR THIS CHIP IS FOUND A BIT UP
boolean PALSCPH102 = 0;
//Arduino pins for ATTiny45
//--------------------------------------------------
// Pinouts!
//--------------------------------------------------
//FOR ARDUINO UNO (WITH ATMEGA328):
// - Arduino pin 8 = data = ATMega pin 14
// - Arduino pin 9 = gate = ATMega pin 15
// - Arduino pin 10 = lid = ATMega pin 16
// - Arduino pin 11 = biosA18 = ATMega pin 17
// - Arduino pin 12 = biosD2 = ATMega pin 18
//FOR ATTINY25/45/85:
// - Arduino pin 0 = data = ATTiny pin 5
// - Arduino pin 1 = gate = ATTiny pin 6
// - Arduino pin 2 = lid = ATTiny pin 7
// - Arduino pin 3 = biosA18 = ATTiny pin 2
// - Arduino pin 4 = biosD2 = ATTiny pin 3
//--------------------------------------------------
// Includes!
//--------------------------------------------------
#include <Flash.h>
//--------------------------------------------------
// Arduino selection!
//--------------------------------------------------
#define ARDUINO_UNO //Make that "#define ARDUINO_UNO" if you want to compile for Arduino Uno instead of ATTiny25/45/85
#ifdef ARDUINO_UNO
//Pins
int data = 8; //The pin that outputs the SCEE SCEA SCEI string
int gate = 9; //The pin that outputs the SCEE SCEA SCEI string
int lid = 10; //The pin that gets connected to the internal CD lid signal; active high
int biosA18 = 11; //Only used in SCPH-102 PAL mode
int biosD2 = 12; //Only used in SCPH-102 PAL mode
int delay_ntsc = 2350;
int delay_between_bits = 4;
int delay_between_injections = 74;
#endif
#ifdef ATTINY
//Pins
int data = 0; //The pin that outputs the SCEE SCEA SCEI string
int gate = 1; //The pin that gets pulled low to enable data injection on the Playstation motherboard
int xlat = 2;
int gate = 1;
int lid = 2; //The pin that gets connected to the internal CD lid signal; active high
int biosA18 = 3; //Only used in SCPH-102 PAL mode
int lid = 4; //The pin that gets connected to the internal CD lid signal; active high
int biosD2 = 5; //Only used in SCPH-102 PAL mode
int biosD2 = 4; //Only used in SCPH-102 PAL mode
int delay_ntsc = 2400;
int delay_between_bits = 4;
int delay_between_injections = 68;
#endif
//--------------------------------------------------
// Global variables!
//--------------------------------------------------
//None, just like it should be!
//Flags
boolean flagFirstCycle = 0; //This flag is 1 when the system completes the first cycle of SCEx-string outputting; this is done to stealth the chip up
boolean flagNewPlaystationModel = 0; //This flag is 1 when it is detected that the modchip is running on PU-22, PU-23 or PSOne hardware
boolean flagBIOSAlreadyFooled = 0; //This flag is 1 when the NTSC=>PAL BIOS-patch for PAL SCPH-102 consoles has been applied. It is reset to 0 when the lid is opened and closed again or when the console is turned off and on again.
//The SCPH102BIOSFooler()-function fools the PAL SCPH-102 into thinking that it also can read NTSC discs
//We execute this code when XLAT goes from high to low, indicating that the first copy protection check has been passed
//delay() doesn't work in an interrupt handler, we use delayMicroseconds() instead, that doesn't rely on using interrupts itself
void SCPH102BIOSFooler()
//--------------------------------------------------
// Seperate functions!
//--------------------------------------------------
void NTSC_fix()
{
boolean biosA18Status = digitalRead(biosA18);
int addressSignalWaitCounter;
//Make sure all pins are inputs
DDRB = 0x00;
if (flagBIOSAlreadyFooled == 0)
//Wait until just before the pulse on BIOS A18 arrives
delay(delay_ntsc);
//...And wait here until it actually happened
while(!(PINB & B00001000))
{
for (addressSignalWaitCounter = 0; addressSignalWaitCounter < 50; addressSignalWaitCounter = addressSignalWaitCounter + 1)
{
if (biosA18Status == 1)
{
delayMicroseconds(50); //Wait a short time
pinMode(biosD2, OUTPUT);
digitalWrite(biosD2, 0); //Pull the Data2-pin low for a millisecond
delayMicroseconds(1000);
pinMode(biosD2, INPUT); //...And release it again
flagBIOSAlreadyFooled = 1;
return;
}
}
}
else
{
return;
; //Wait
}
delayMicroseconds(12);
PORTB = B00000000;
DDRB = B00010000;
delayMicroseconds(5);
DDRB = 0x00;
}
void setup()
void inject_SCEE()
{
pinMode(data, INPUT); //The pins are high-impedance when configured as inputs so they don't interfere with the Playstation mortherboard circuitry
pinMode(gate, INPUT);
pinMode(lid, INPUT);
pinMode(xlat, INPUT);
//SCEE-array // Start Data Stop
FLASH_ARRAY (boolean, SCEEData, 1,0,0,1,1,0,1,0,1,0,0,1,0,0,1,1,1,1,0,1,0,0,1,0,1,0,1,1,1,0,1,0,0,1,0,1,0,1,1,1,0,1,0,0); //SCEE: 1 00110101 00, 1 00111101 00, 1 01011101 00, 1 01011101 00 44 bits total
if (PALSCPH102 != 0)
int bit_counter;
for (bit_counter = 0; bit_counter < 44; bit_counter = bit_counter + 1)
{
pinMode(biosA18, INPUT); //Only activate the BIOS-pins when connected to a PAL SCPH-102
pinMode(biosD2, INPUT);
//We make an interrupt for XLAT, as we need this signal to detect when we can do our BIOS-magic. The function SCPH102BIOSFooler is ran when the XLAT-pin makes
//a transistion from high to low, the other code is temporarily paused. Only use this when the code is used on a PAL SCPH-102
attachInterrupt(0, SCPH102BIOSFooler, FALLING); //Interrupt 0 is pin 7 on ATTiny45
}
//Determine on which Playstation we are working by watching the gate-signal; we are running on a PU-22, PU-23 or PSOne when there is a clock signal present
//We are taking 10 samples of the gate-signal. As we can't really know the frequency of the clock signal that may or may not be present on this signal, we
//simply take ten samples of the signal and store them in an array. When both 0's and 1's are stored in the array, this means that there is a clock signal
//on the gate-pin. When all the elements in the array are the same, there is no clock signal available and PsNee is installed in an older model Playstation.
boolean gateSamples[10];
int gateSamplesCounter;
boolean sampleLowDetected = 0;
boolean sampleHighDetected = 0;
for (gateSamplesCounter = 0; gateSamplesCounter < 10; gateSamplesCounter = gateSamplesCounter + 1)
{
gateSamples[gateSamplesCounter] = digitalRead(gate);
}
for(gateSamplesCounter = 0; gateSamplesCounter < 10; gateSamplesCounter = gateSamplesCounter + 1)
{
if (gateSamples[gateSamplesCounter] == 0)
{
sampleLowDetected = 1;
if (SCEEData[bit_counter] == 0)
{
pinMode(data, OUTPUT);
digitalWrite(data, 0);
delay(delay_between_bits);
}
else
{
sampleHighDetected = 1;
pinMode(data, INPUT); //We make the data pin high-impedance to let the pull-up of the Playstation motherboard make a 1
delay(delay_between_bits);
}
}
if ((sampleLowDetected && sampleHighDetected) == 1)
{
flagNewPlaystationModel = 1;
}
delay(1000); //Wait a second before we're really heading off
pinMode(data, OUTPUT);
digitalWrite(data, 0);
delay(delay_between_injections);
}
void loop()
{ //The bitstreams are reversed (because LSB) and inverted (because the buffer we're injecting our signal after also inverted it's input)
//VARIABLES // Start Data Stop
FLASH_ARRAY (boolean, SCEEData, 1,0,0,1,1,0,1,0,1,0,0,1,0,0,1,1,1,1,0,1,0,0,1,0,1,0,1,1,1,0,1,0,0,1,0,1,0,1,1,1,0,1,0,0); //SCEE: 1 00110101 00, 1 00111101 00, 1 01011101 00, 1 01011101 00 44 bits total
void inject_SCEA()
{
//SCEE-array // Start Data Stop
FLASH_ARRAY (boolean, SCEAData, 1,0,0,1,1,0,1,0,1,0,0,1,0,0,1,1,1,1,0,1,0,0,1,0,1,0,1,1,1,0,1,0,0,1,0,1,1,1,1,1,0,1,0,0); //SCEA: 1 00110101 00, 1 00111101 00, 1 01011101 00, 1 01111101 00
FLASH_ARRAY (boolean, SCEIData, 1,0,0,1,1,0,1,0,1,0,0,1,0,0,1,1,1,1,0,1,0,0,1,0,1,0,1,1,1,0,1,0,0,1,0,1,1,0,1,1,0,1,0,0); //SCEI: 1 00110101 00, 1 00111101 00, 1 01011101 00, 1 01101101 00
int arraycounter;
int datacounter;
int slicercounter;
boolean lidstatus = digitalRead(lid);
if ((flagFirstCycle == 0) || ((flagFirstCycle != 0) && (lidstatus != 0))) //Only execute the modchip code when the Playstation has just booted or when a new disc needs to be inserted on an already running machine
int bit_counter;
for (bit_counter = 0; bit_counter < 44; bit_counter = bit_counter + 1)
{
if ((flagFirstCycle != 0) && (lidstatus != 0))
{
flagBIOSAlreadyFooled == 0; //When this isn't the first time the modchip does it's thing and the lid has been opened, indicate that the PAL=>NTSC BIOS-patch may be applied again
if (SCEAData[bit_counter] == 0)
{
pinMode(data, OUTPUT);
digitalWrite(data, 0);
delay(delay_between_bits);
}
delay(50); //Extra delay to compensate for the state-switching of the CD lid
if (lidstatus == 0) //Only do your thing when the lid is closed again
else
{
delay(50); //Just wait a second until the coast is clear
pinMode(gate, OUTPUT);
digitalWrite(gate, 0); //Pull to ground to enable data injecting
for (datacounter = 0; datacounter < 31; datacounter = datacounter + 1) //One cycle of SCEx-string outputting takes approximately 744 ms; we want to go on for about 25 seconds so we output the cycle 30 times
{
for (arraycounter = 0; arraycounter < 44; arraycounter = arraycounter + 1)
{
if (SCEEData[arraycounter] == 0)
{
for (slicercounter = 0; slicercounter < 15; slicercounter = slicercounter + 1) //This for-loop slices the data signal when it is 0 in small chunks of 130us and do this 14 times; this way, each block of sliced data is about 4ms long, of 250bps
{
pinMode(data, OUTPUT); //We pull the data pin to ground to force a 0
digitalWrite(data, 0);
delayMicroseconds(130);
pinMode(data, INPUT); //We make it high-impedance again to let at least some of the CD tracking signal through
delayMicroseconds(130);
}
}
else
{
pinMode(data, INPUT); //We make the data pin high-impedance to let the pull-up of the Playstation motherboard make a 1
delay(4);
}
}
delay(64); //According to the logic analyser the time between two bitstreams now approximates 72 ms on an ATTiny45 with built-in 8MHz oscillator, just like the doctor ordered
for (arraycounter = 0; arraycounter < 44; arraycounter = arraycounter + 1)
{
if (SCEAData[arraycounter] == 0)
{
for (slicercounter = 0; slicercounter < 15; slicercounter = slicercounter + 1) //This for-loop slices the data signal when it is 0 in small chunks of 130us; this way, each block of sliced data is about 4ms long, of 250bps
{
pinMode(data, OUTPUT); //We pull the data pin to ground to force a 0
digitalWrite(data, 0);
delayMicroseconds(130);
pinMode(data, INPUT); //We make it high-impedance again to let at least some of the CD tracking signal through
delayMicroseconds(130);
}
}
else
{
pinMode(data, INPUT); //We make the data pin high-impedance to let the pull-up of the Playstation motherboard make a 1
delay(4);
}
}
delay(64);
for (arraycounter = 0; arraycounter < 44; arraycounter = arraycounter + 1)
{
if (SCEIData[arraycounter] == 0)
{
for (slicercounter = 0; slicercounter < 15; slicercounter = slicercounter + 1) //This for-loop slices the data signal when it is 0 in small chunks of 130us; this way, each block of sliced data is about 4ms long, of 250bps
{
pinMode(data, OUTPUT); //We pull the data pin to ground to force a 0
digitalWrite(data, 0);
delayMicroseconds(130);
pinMode(data, INPUT); //We make it high-impedance again to let at least some of the CD tracking signal through
delayMicroseconds(130);
}
}
else
{
pinMode(data, INPUT); //We make the data pin high-impedance to let the pull-up of the Playstation motherboard make a 1
delay(4);
}
}
delay(64);
}
pinMode(data, INPUT); //Make all outputting pins high-impedance again when we're finished
pinMode(gate, INPUT);
flagFirstCycle = 1; //We completed the initial round of SCEx-outputting; only do this again when a new CD is inserted while the Playstation is turned on!
pinMode(data, INPUT); //We make the data pin high-impedance to let the pull-up of the Playstation motherboard make a 1
delay(delay_between_bits);
}
}
pinMode(data, OUTPUT);
digitalWrite(data, 0);
delay(delay_between_injections);
}
void inject_SCEI()
{
//SCEE-array // Start Data Stop
FLASH_ARRAY (boolean, SCEIData, 1,0,0,1,1,0,1,0,1,0,0,1,0,0,1,1,1,1,0,1,0,0,1,0,1,0,1,1,1,0,1,0,0,1,0,1,1,0,1,1,0,1,0,0); //SCEI: 1 00110101 00, 1 00111101 00, 1 01011101 00, 1 01101101 00
int bit_counter;
for (bit_counter = 0; bit_counter < 44; bit_counter = bit_counter + 1)
{
if (SCEIData[bit_counter] == 0)
{
pinMode(data, OUTPUT);
digitalWrite(data, 0);
delay(delay_between_bits);
}
else
{
pinMode(data, INPUT); //We make the data pin high-impedance to let the pull-up of the Playstation motherboard make a 1
delay(delay_between_bits);
}
}
pinMode(data, OUTPUT);
digitalWrite(data, 0);
delay(delay_between_injections);
}
void inject_multiple_times(int number_of_injection_cycles)
{
int cycle_counter;
for(cycle_counter = 0; cycle_counter < number_of_injection_cycles; cycle_counter = cycle_counter + 1)
{
inject_SCEE();
inject_SCEA();
inject_SCEI();
}
}
void inject_playstation()
{
//Variables
int loop_counter;
//Code
NTSC_fix();
delay(6900);
digitalWrite(data, 0);
pinMode(data, OUTPUT);
delay(100);
pinMode(gate, OUTPUT);
digitalWrite(gate, 0);
for (loop_counter = 0; loop_counter < 25; loop_counter = loop_counter + 1)
{
inject_SCEE();
}
pinMode(gate, INPUT);
pinMode(data, INPUT);
delay(11000);
pinMode(gate, OUTPUT);
digitalWrite(gate, 0);
for (loop_counter = 0; loop_counter < 60; loop_counter = loop_counter + 1)
{
inject_SCEE();
}
pinMode(gate, INPUT);
pinMode(data, INPUT);
}
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//--------------------------------------------------
// Setup function - execution starts here!
//--------------------------------------------------
void setup()
{
inject_playstation();
}
//----------------------------------------------------------------
// Loop function - executes after the initial injection cycle
//----------------------------------------------------------------
void loop()
{
if(lid == 0)
{
while(lid != 1); //Wait until the lid is closed again (after being opened) to initiate a new injection cycle
inject_playstation();
}
}