Train Controller

I'm going to start by giving credit to Zoinkity for doing this research at least several years ago. I've also personally verified his results. The only reason for me to write about the Train Controller is so the documentation is done in a similar style for all devices and accessories.

Zoinkity original:

The N64 Train Controller is used by a single game "Densha de Go! 64" which is a train simulator based on the commuter trains in Japan. This game series had enough fans that it was made for many platforms over many years.

Similar controllers were released for other consoles including Playstation, Playstation 2, Saturn and Dreamcast when a compatible Densha de Go! game was released.

The open space in the middle of the controller is to hold your pocket watch! While any pocket watch would fit, the manufacturer Taito sold special "Densha de Go!" branded pocket watches. Which from online pictures appear to be very nice metal pocket watches.

Supported Commands

The 0xFF and 0x00 commands both return the value 0x05 00 02 which is identical to a standard controller.

This result is different from Zoinkity's original document. After some discussion with Zoinkity it's believed that his original analysis may of been byte swapped data.

The following image appears to be from the original Taito manual to which Zoinkity added the values for each control position, it's a really clear visual representation of the values.

Button Values - 16 bit value

  • 0x0010 - Select
  • 0x1000 - Start
  • 0x4000 - A
  • 0x8000 - B
  • 0x0020 - C

Left Lever - Accelerator

  • 0x2800 - Neutral
  • 0x2100 - 1
  • 0x2000 - 2
  • 0x0900 - 3
  • 0x0800 - 4
  • 0x0100 - 5

Right Lever - Brake (Right to Left)

The value section 0x0001 to 0x0006 has an analog feel to it. It's gradual and not obvious except by lever position what value the game may actually be using.

  • 0x0000 - FULL Stop
    • 0x000F - When between values
  • 0x0001
    • 0x000F - When between values
  • 0x0002
    • 0x000F - When between values
  • 0x0003
    • 0x000F - When between values
  • 0x0004
    • 0x000F - When between values
  • 0x0005
    • 0x000F - When between values
  • 0x0006 Detent (0x0006 to 0x000E each position has a firm feel when the lever is in position)
    • 0x000F - When between values
  • 0x0007
    • 0x000F - When between values
  • 0x0008
    • 0x000F - When between values
  • 0x0009
    • 0x000F - When between values
  • 0x000A
    • 0x000F - When between values
  • 0x000B
    • 0x000F - When between values
  • 0x000C
    • 0x000F - When between values
  • 0x000D
    • 0x000F - When between values
  • 0x000E
    • 0x000F - When between values

A reminder the full data response from the controller is 4 bytes or 8 hex characters.

ex. 0x280F0000

The last 4 hex or 2 bytes are always Zero, these are the Analog bytes for X/Y on a standard controllers joystick.

The left lever is the accelerator (0x0100 - 0x2800). It moves up and down with 6 detents and the max acceleration with the lever fully down with a value of 0x0100.

The right lever is the brake (0x0000 - 0x000F) which moves left to right with 9 detents and a large smooth range that has 6 values, when the lever is between values it will report 0x000F.

Note: The accelerator and brake (0x0000- 0x000E) will always have a value(maybe 0x0), the buttons are only included if they are pressed.

To make the above image a little more clear here are some actual example results.

0x28 00 00 00 = Accelerator 0, Brake = FULL Right

0x09 06 00 00 = Accelerator 3, Brake = first detent

0x38 10 00 00 = Accelerator 0, Brake = FULL Right, SELECT, START

Observations

For reasons of either cost or development time the protocol is identical to a standard controller. This would be convenient for the game developers to use the official SDK api's so they don't have to write their own api.

One of the notes in the image is that the last 2 bytes are always zeros. Comparing this to the controller data the last 2 bytes are analog values for the X and Y axis of the joystick. So it makes sense to avoid the last 2 bytes. From the original 32 bit response value that leaves only 16 bits to communicate all of the different switch and button positions. The image shows 27 different values many that allow multiple combinations with other inputs.

As part of implementing this controller for use in homebrew programs, I studied the inputs and found that there was a way programatically to tell the difference between the train controller and a standard controller, it does require user input but it works.

Present a prompt screen for the user to press START + A on each controller

    • The A button has a different value between the two controllers!
    • DENSHA_BUTTON_A 0x4000
    • BUTTON_A 0x8000
    • Using START+A makes it a purposeful action vs pressing A alone which could be accidental