necroware/gameport-adapter

Create a How It Works document

Closed this issue · 3 comments

Hello,
I am very interested in knowing how this project works, however interpreting the C++ is my hurdle. I've spent hours following the code, but continue to not understand much of it, particularly the reading/writing of the Arduino pins. Is there appetite in this community for an operational specification which is programming language agnostic? I'm willing to give it a shot to write one, however I will require someone to assist with interpretation of the actual code.
For what it is worth, I believe there is considerable interest in interfacing legacy game port controllers with USB, particularly with electronics enthusiasts like myself. Hours of searching confirms this interest, and this particular project is as close as I've gotten to understanding.
I'm also new to GitHub, and don't know the protocol for direct messaging between participants.
Much appreciated.
Mike

p.s. This is a QUESTION, not an ISSUE. Being new to GitHub, I can't see the option to mark this as a question. Sorry.

Hi Mike,

first of all every joystick in particular works slightly different, that's why there is no one solution, which can be explained. Furthermore, the code IS already the best and most detailed explanation how it works, so there is no way around it. It is a bad idea to write the same stuff again with the same level of details, but in another language (let it be a human language). It is a very bad software development practice to repeat yourself, which leads to a lot of long term confusion and work. Just imagine, that you have to change the implementation for some reason, then you would have a discrepancy between the description in a programming language and the human language.

You would also have a hard time to make this project language agnostic, since it would be nearly impossible to get the required timings using another languages but C/C++ or Assembler. And to be honest, this is out of scope of this project to explain how USB and I/O works with Arduino. You can find a tone of information about that in a more appropriate places on the internet. The same is for C++.

So, long story short, you will not come around the C++ code if you want to understand how this whole thing works in depth. If you just want abstract information, you can read the official documentation or watch my video on youtube.

Cheers!

Hi necroware,
Your response is very respectful - thank you. I have watched your YT video, which is how I found this project. Please note that I already know how USB and IO work with Arduino. What I'm struggling with is how your C++ code manages the specific IO pins to 'talk' to the game controller (joystick). My specific interest is the Logitech support - the ADI protocol. For example, I understand the concept for an ADI device is:

  1. Initialize the joystick (i.e. put into "digital mode")
  2. Poll the joystick for current states of buttons, axes, and hats
  3. Send the corresponding joystick commands to the USB channel
  4. GOTO 2

I haven't got past the 'Initialize' step in your code. Here is the trail I've followed:

  • init() (in the class Logitech)
  • calls: enableDigitalMode(), which iterates through a list{} of ADI specific delays. Before each delay it calls: m_trigger.pulse()
  • the pulse() function calls toggle(), delays for 10u, and calls toggle() again.
  • what toggle() does is "m_output ^= m_pin.mask;" I know that "^=" is XOR, but this is where I get lost with my lack of C++ expertise. I suspect the code it setting one of the digital pins, but I can't follow the trail any further to see which pin, or how it is setting it. I have spent considerable time trying to understand your code. I've also spent time reviewing Vojtech Pavlic's ADI joystick driver code, but the challenge is that his code is talking to a game port with outb(0xff, ...), not directly to a joystick on specific pins.

This is why I'm committed to writing a document which explains the process to control/read an ADI joystick with a microcontroller such as Arduino. I do understand that this isn't actually in scope for your project, but I believe it will add value to others who find your project and wish to fully understand 'electronically' how this thing works - at least on the joystick side of the equation.

If anybody reading this Issue thread does know exactly how the code works (regarding sending and receiving signals to the ADI joystick), I would be very grateful to ask you questions to help me write this "How the ADI protocol works".

With thanks.

I see. Well, the XOR has nothing to do with C++, this part is totally language agnostic and is about to read the MCU ports, as Arduino calls them. The difference between my code is that I'm using Arduino suite to program the MCU and Vojtech probably used a pure C. I went with the Arduino suite, because it is easier to understand for newbies, since you don't need to mess around with compilers and makefiles directly and you can get a lot of help on the Arduino forums, if you need.

If you want to understand what happens in that part, I'd suggest to read about direct port manipulation on Arduino first. Just to understand, what XOR/OR/AND are for in that scope. Once you understand how to read and write from the ports, you will understand this code. The basic idea is to improve the performance of digitalRead() and digitalWrite() functions, which are far too slow for this project. Those functions doing a lot of work trying to map the physical pin IDs to the bits in the registers and calculate the bit masks every time. This whole information doesn't need to be done on every call, since neither the IDs nor the bit masks will change during the runtime, that's why those things can be calculated exactly once in the constructor. This increases the performance dramatically. All the rest should be self explaining I guess.