/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// NintendoSpy Firmware for Arduino
// v1.0.1
// Written by jaburns
//
// N64 controller only!

#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 = 41;

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 int 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() {
  for (unsigned char i = 9; i < 41; i++) {
    Serial.write(rawData[i] ? ONE : ZERO);
  }
  Serial.write(SPLIT);
}

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