/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// NintendoSpy Firmware for Arduino
// v1.0.1
// Written by jaburns
//
// Anti-spazzing, checksum and RaphNet mod by eN-t
// GameCube controller only!

#define PIN_READ (PIND&(1<<(5)))
#define MICROSECOND_NOPS "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"
#define WAIT_FALLING_EDGE while(!PIN_READ); while(PIN_READ);

#define ZERO  '\0'
#define ONE    '1'
#define SPLIT '\n'

unsigned char rawData[128];

void setup() {
  PORTD = 0x00;
  DDRD  = 0x00;
  PORTC = 0xFF;
  DDRC  = 0x00;
  Serial.begin(115200);
}

void read_oneWire() {
  unsigned char *rawDataPtr = rawData;
  unsigned char bits = 123;

read_loop:
  WAIT_FALLING_EDGE;
  asm volatile(MICROSECOND_NOPS MICROSECOND_NOPS);
  *rawDataPtr = PIN_READ;
  ++rawDataPtr;
  if (--bits == 0) return;
  goto read_loop;
}

inline bool checksum(unsigned char rNc) {
  unsigned long GC_chksm = 0;
  for (unsigned char i = 0; i < 25; i++) {
    bitWrite(GC_chksm, 24 - i, rawData[i + rNc]);
  }
  if (GC_chksm >= 8390144 && GC_chksm <= 8390655) return true;
  return false;
}

inline void sendRawData(unsigned char rNm) {
  for (unsigned char i = 25; i < 89; i++) {
    Serial.write(rawData[i + rNm] ? ONE : ZERO);
  }
  Serial.write(SPLIT);
}

void loop() {
  noInterrupts();
  read_oneWire();
  interrupts();
  if (checksum(0)) sendRawData(0);
  else if (checksum(34)) sendRawData(34);
  delay(11);
}
