/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// NintendoSpy Firmware for Arduino
// v1.0.1
// Written by jaburns
//
// Anti-spazzing and checksum mod for Not64 compatibility by eN-t
// Dual Input GC and N64 (untested!) v2 (now without PINC)

#define PIN_READ (PIND&(1<<(2)))
#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 = 89;

read_loop:
  WAIT_FALLING_EDGE;
  asm volatile(MICROSECOND_NOPS MICROSECOND_NOPS);
  *rawDataPtr = PIN_READ;
  ++rawDataPtr;
  if (--bits == 0) return;
  if (bits == 48 && rawData[1] == 0) return;
  goto read_loop;
}

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

inline bool checksumN64() {
  unsigned long N64_chksm = 0;
  for (unsigned char i = 0; i < 9; i++) {
    bitWrite(N64_chksm, 8 - i, rawData[i]);
  }
  if (N64_chksm == 3) return true;
  return false;
}

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

// Main loop function below!
void loop() {
  noInterrupts();
  read_oneWire();
  interrupts();
  if (checksumGC()) sendRawData(25, 89);
  else if (checksumN64()) sendRawData(9, 41);
  delay(11);
}
