Advertisement
pidgezero_one

Untitled

Jan 23rd, 2019
161
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.00 KB | None | 0 0
  1. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2. // NintendoSpy Firmware for Arduino
  3. // v1.0.1
  4. // Written by jaburns
  5.  
  6.  
  7. // ---------- Uncomment one of these options to select operation mode --------------
  8. //#define MODE_GC
  9. //#define MODE_N64
  10. //#define MODE_SNES
  11. #define MODE_NES
  12. // Bridge one of ther analog GND to the right analog IN to enable your selected mode
  13. //#define MODE_DETECT
  14. // ---------------------------------------------------------------------------------
  15. // The only reason you'd want to use 2-wire SNES mode is if you built a NintendoSpy
  16. // before the 3-wire firmware was implemented. This mode is for backwards
  17. // compatibility only.
  18. //#define MODE_2WIRE_SNES
  19. // ---------------------------------------------------------------------------------
  20.  
  21.  
  22. #define PIN_READ( pin ) (PIND&(1<<(pin)))
  23. #define PINC_READ( pin ) (PINC&(1<<(pin)))
  24. #define MICROSECOND_NOPS "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"
  25.  
  26. #define WAIT_FALLING_EDGE( pin ) while( !PIN_READ(pin) ); while( PIN_READ(pin) );
  27.  
  28. #define MODEPIN_SNES 0
  29. #define MODEPIN_N64 1
  30. #define MODEPIN_GC 2
  31.  
  32. #define N64_PIN 2
  33. #define N64_PREFIX 9
  34. #define N64_BITCOUNT 32
  35.  
  36. #define SNES_LATCH 3
  37. #define SNES_DATA 4
  38. #define SNES_CLOCK 6
  39. #define SNES_BITCOUNT 16
  40. #define NES_BITCOUNT 8
  41.  
  42. #define GC_PIN 5
  43. #define GC_PREFIX 25
  44. #define GC_BITCOUNT 64
  45.  
  46. #define ZERO '\0' // Use a byte value of 0x00 to represent a bit with value 0.
  47. #define ONE '1' // Use an ASCII one to represent a bit with value 1. This makes Arduino debugging easier.
  48. #define SPLIT '\n' // Use a new-line character to split up the controller state packets.
  49.  
  50.  
  51.  
  52.  
  53. // Declare some space to store the bits we read from a controller.
  54. unsigned char rawData[ 128 ];
  55.  
  56.  
  57. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  58. // General initialization, just sets all pins to input and starts serial communication.
  59. void setup()
  60. {
  61. PORTD = 0x00;
  62. DDRD = 0x00;
  63. PORTC = 0xFF; // Set the pull-ups on the port we use to check operation mode.
  64. DDRC = 0x00;
  65. Serial.begin( 115200 );
  66. }
  67.  
  68. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  69. // Performs a read cycle from one of Nintendo's one-wire interface based controllers.
  70. // This includes the N64 and the Gamecube.
  71. // pin = Pin index on Port D where the data wire is attached.
  72. // bits = Number of bits to read from the line.
  73. template< unsigned char pin >
  74. void read_oneWire( unsigned char bits )
  75. {
  76. unsigned char *rawDataPtr = rawData;
  77.  
  78. read_loop:
  79.  
  80. // Wait for the line to go high then low.
  81. WAIT_FALLING_EDGE( pin );
  82.  
  83. // Wait ~2us between line reads
  84. asm volatile( MICROSECOND_NOPS MICROSECOND_NOPS );
  85.  
  86. // Read a bit from the line and store as a byte in "rawData"
  87. *rawDataPtr = PIN_READ(pin);
  88. ++rawDataPtr;
  89. if( --bits == 0 ) return;
  90.  
  91. goto read_loop;
  92. }
  93.  
  94. // Verifies that the 9 bits prefixing N64 controller data in 'rawData'
  95. // are actually indicative of a controller state signal.
  96. inline bool checkPrefixN64 ()
  97. {
  98. if( rawData[0] != 0 ) return false; // 0
  99. if( rawData[1] != 0 ) return false; // 0
  100. if( rawData[2] != 0 ) return false; // 0
  101. if( rawData[3] != 0 ) return false; // 0
  102. if( rawData[4] != 0 ) return false; // 0
  103. if( rawData[5] != 0 ) return false; // 0
  104. if( rawData[6] != 0 ) return false; // 0
  105. if( rawData[7] == 0 ) return false; // 1
  106. if( rawData[8] == 0 ) return false; // 1
  107. return true;
  108. }
  109.  
  110. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  111. // Performs a read cycle from a shift register based controller (SNES + NES) using only the data and latch
  112. // wires, and waiting a fixed time between reads. This read method is deprecated due to being finicky,
  113. // but still exists here to support older builds.
  114. // latch = Pin index on Port D where the latch wire is attached.
  115. // data = Pin index on Port D where the output data wire is attached.
  116. // bits = Number of bits to read from the controller.
  117. // longWait = The NES takes a bit longer between reads to get valid results back.
  118. template< unsigned char latch, unsigned char data, unsigned char longWait >
  119. void read_shiftRegister_2wire( unsigned char bits )
  120. {
  121. unsigned char *rawDataPtr = rawData;
  122.  
  123. WAIT_FALLING_EDGE( latch );
  124.  
  125. read_loop:
  126.  
  127. // Read the data from the line and store in "rawData"
  128. *rawDataPtr = !PIN_READ(data);
  129. ++rawDataPtr;
  130. if( --bits == 0 ) return;
  131.  
  132. // Wait until the next button value is on the data line. ~12us between each.
  133. asm volatile(
  134. MICROSECOND_NOPS MICROSECOND_NOPS MICROSECOND_NOPS MICROSECOND_NOPS
  135. MICROSECOND_NOPS MICROSECOND_NOPS MICROSECOND_NOPS MICROSECOND_NOPS
  136. MICROSECOND_NOPS MICROSECOND_NOPS
  137. );
  138. if( longWait ) {
  139. asm volatile(
  140. MICROSECOND_NOPS MICROSECOND_NOPS MICROSECOND_NOPS MICROSECOND_NOPS
  141. MICROSECOND_NOPS MICROSECOND_NOPS MICROSECOND_NOPS MICROSECOND_NOPS
  142. MICROSECOND_NOPS MICROSECOND_NOPS
  143. );
  144. }
  145.  
  146. goto read_loop;
  147. }
  148.  
  149. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  150. // Preferred method for reading SNES + NES controller data.
  151. template< unsigned char latch, unsigned char data, unsigned char clock >
  152. void read_shiftRegister( unsigned char bits )
  153. {
  154. unsigned char *rawDataPtr = rawData;
  155.  
  156. WAIT_FALLING_EDGE( latch );
  157.  
  158. do {
  159. WAIT_FALLING_EDGE( clock );
  160. *rawDataPtr = !PIN_READ(data);
  161. ++rawDataPtr;
  162. }
  163. while( --bits > 0 );
  164. }
  165.  
  166. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  167. // Sends a packet of controller data over the Arduino serial interface.
  168. inline void sendRawData( unsigned char first, unsigned char count )
  169. {
  170. for( unsigned char i = first ; i < first + count ; i++ ) {
  171. Serial.write( rawData[i] ? ONE : ZERO );
  172. }
  173. Serial.write( SPLIT );
  174. }
  175.  
  176.  
  177. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  178. // Update loop definitions for the various console modes.
  179.  
  180. inline void loop_GC()
  181. {
  182. noInterrupts();
  183. read_oneWire< GC_PIN >( GC_PREFIX + GC_BITCOUNT );
  184. interrupts();
  185. sendRawData( GC_PREFIX , GC_BITCOUNT );
  186. }
  187.  
  188. inline void loop_N64()
  189. {
  190. noInterrupts();
  191. read_oneWire< N64_PIN >( N64_PREFIX + N64_BITCOUNT );
  192. interrupts();
  193. if( checkPrefixN64() ) {
  194. sendRawData( N64_PREFIX , N64_BITCOUNT );
  195. }
  196. }
  197.  
  198. inline void loop_SNES()
  199. {
  200. noInterrupts();
  201. #ifdef MODE_2WIRE_SNES
  202. read_shiftRegister_2wire< SNES_LATCH , SNES_DATA , false >( SNES_BITCOUNT );
  203. #else
  204. read_shiftRegister< SNES_LATCH , SNES_DATA , SNES_CLOCK >( SNES_BITCOUNT );
  205. #endif
  206. interrupts();
  207. sendRawData( 0 , SNES_BITCOUNT );
  208. }
  209.  
  210. inline void loop_NES()
  211. {
  212. noInterrupts();
  213. #ifdef MODE_2WIRE_SNES
  214. read_shiftRegister< SNES_LATCH , SNES_DATA , true >( NES_BITCOUNT );
  215. #else
  216. read_shiftRegister< SNES_LATCH , SNES_DATA , SNES_CLOCK >( SNES_BITCOUNT );
  217. #endif
  218. interrupts();
  219. sendRawData( 0 , NES_BITCOUNT );
  220. }
  221.  
  222. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  223. // Arduino sketch main loop definition.
  224. void loop()
  225. {
  226. #ifdef MODE_GC
  227. loop_GC();
  228. #elif defined MODE_N64
  229. loop_N64();
  230. #elif defined MODE_SNES
  231. loop_SNES();
  232. #elif defined MODE_NES
  233. loop_NES();
  234. #elif defined MODE_DETECT
  235. if( !PINC_READ( MODEPIN_SNES ) ) {
  236. loop_SNES();
  237. } else if( !PINC_READ( MODEPIN_N64 ) ) {
  238. loop_N64();
  239. } else if( !PINC_READ( MODEPIN_GC ) ) {
  240. loop_GC();
  241. } else {
  242. loop_NES();
  243. }
  244. #endif
  245. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement