I'm new here, new to Arduino, and relatively new to programming anything other than shell script and a little HTML/CSS and javascript. Looking to see if there is any interest in this project, as well as for someone to review my code and see if I made any major mistakes. It compiles and loads, but I won't have the hardware built to test it out for a couple of weeks (damn cash flow.....). Anways, after digging around, I couldn't find anything else quite like what I wanted, but I found a project that gave me a starting point, at least with the hardware design, and a couple of libraries tht made my life easier. I am attempting to build a dual wireless controller adapter for the old 8-bit consoles. In my case, specifically the SNES, but it could easily be adapted for any of the older Nintendo and Sega consoles, and theoretically could probably handle four controllers instead of two with some tweaking and extra hardware. My design uses an NRF24l01 wireless board on each end, tied to a 328p. The transmitter will have the game port board from a dead SNES (I have a pile of spare parts....), will read in the controller button states using a modified version of the snesPad library, and transmit the 4 byte packet to the reciever (using Maniacbugs NRF24 library). The reciever will take the button states and push them out to the console. The transmitter end is fairly small using the stock libraries. I made a few tweaks to the snesPad library to have it poll both controllers at the same time rather than just one, and then concatonate the two 16bit ints into an unsigned long and return that to be transmitted. The reciever end is where things get a little dicey for me. I couldn't use the snesPad library, as it's designed to read the shift registers from the controllers, not to act as a shift register to be read by the console. I don't know if the solution I came up with will actually work, but it does compile. So.... let me know what you all think, whether I'm on the right track, and if you think it will work.
Here's the transmitter code
/*
Copyright (C) 2012 John Byers <jbyers2@wgu.edu>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 3 as published by the Free Software Foundation
*/
/**
* Dual Wireless Retro Controller Adapter Transmitter
*
* This is the transmitter side code for the adapter set.
*/
#include <SNESpadDual.h>
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <RF24_config.h>
//
// Hardware Configuration
//
RF24 radio(9,10);
SNESpad nintendo = SNESpad(4,3,5,6);
//
// Variable Inits
//
unsigned long state = 0;
const uint64_t pipes = 0xF0F0F0F0E1LL;
void setup()
{
radio.begin();
radio.setRetries(15,15);
Serial.begin(57600);
}
void loop() {
// Get controller button states and write out to serial monitor for debugging
state = nintendo.buttons();
Serial.println(~state, BIN);
// Send button states to reciever and output transmission status for debugging
bool ok = radio.write( &state, sizeof(unsigned long) );
if (ok)
Serial.println("ok...");
else
Serial.println("failed!!");
}
And here is the reciever code
/*
Copyright (C) 2012 John Byers <jbyers2@wgu.edu>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 3 as published by the Free Software Foundation
*/
/**
* Dual Wireless Retro Controller Adapter Transmitter
*
* This is the reciever side code for the adapter set.
*/
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <RF24_config.h>
//
// Hardware Configuration
//
RF24 radio(9,10);
//
// Variable Inits
//
unsigned long state = 0;
const uint64_t pipes = 0xF0F0F0F0E1LL;
int strobe = 4;
int clock = 3;
int data1 = 5;
int data2 = 6;
void setup()
{
radio.begin();
radio.setRetries(15,15);
Serial.begin(57600);
pinMode(strobe, INPUT);
pinMode(clock, INPUT);
pinMode(data1, OUTPUT);
pinMode(data2, OUTPUT);
//
//Open radio pipe for writing
//
radio.openReadingPipe(1,pipes);
//
//Start Listening
//
radio.startListening();
//
//Dump the configuration of the RF unit for debugging
//
radio.printDetails();
}
void loop()
{
// Wait for data
bool get_data = false;
unsigned long state;
bool timeout = false;
if ( radio.available() ) {
unsigned long started_waiting_at = millis();
radio.read( &state, sizeof(unsigned long) );
Serial.println(state, BIN);
// Data captured, now wait for console to trigger latch
while ( ! digitalRead(strobe) && ! timeout ) {
if ( millis() - started_waiting_at > 200 ) {
timeout = true;
}
}
get_data = true;
}
if ( timeout ) {
Serial.write("Console strobe timeout!!!");
}
else if ( ! get_data) {
Serial.write("No data from transmitter!!!!");
}
else {
// Data captured and latch triggered, output button states
int data_bit1;
int data_bit2;
byte i;
digitalWrite(data1,bitRead(state,0));
digitalWrite(data1,bitRead(state,16));
while ( i = 1, i < 16, i++ ) {
while ( ! digitalRead(clock) ) {
delayMicroseconds(1);
}
digitalWrite(data1,bitRead(state,i));
digitalWrite(data2,bitRead(state,(i+16)));
delayMicroseconds(12);
}
Serial.println("sucess!!!");
}
}
I was having a hell of a time trying to figure out how to read out the unsigned long bits to be written out to the console, untill I found the bitRead function. The description in the Arduino docs is pretty minimal though, so I am not sure if I'm applying it correctly. The first 16 bits of the unsigned long is the button states from controller one, the second 16 bits is the button states from the second controller. The first bit read in is the first bit in the int variable, second bit read in is the second bit, etc...
For those unfamiliar with the SNES controller serial protocol, the controllers contrain two 8bit parallel to serial shift registers. The console pulses a latch signal (24us cycle) high, which tells the registers to lock in the current button states (high=inactive). The first bit is read on the falling edge of the latch pulse, and then each successive bit is set by the shift registers on the rising edge of a clock pulse (24us cycle), and read by the console on the falling edge. The whole cycle repeats every 16ms or so.
The delay between read cycles is another problem I'm not sure about. Unfortunately, I don't think I can determine a suitable delay untill I get actual hardware built and measure the read cycle time. I don't want to overload the reciever by generating button states faster than the console requests them.
The only similar project I've found is designed to have a transmitter build into the controller and a seperate reciever for each controller. While this is great for portability, it's not so great for hardware cost. Sadly, the guy who designed it makes the hex files freely available, but not the source code. Plus he writes in machine language, so I wouldn't have a clue what I was looking at anyways....
If I haven't bored you to tears by now, thank you for looking, and thank you in advance for any help!!