Please do not post a support request without first reading and following the advice in https://retropie.org.uk/forum/topic/3/read-this-first

Gamepadblock Sample COM port script



  • I wrote a script for using the com port on the Raspberry pi to change modes based on the emulator used. There are 2 parts to using it. The first is the runcommand-onstart.sh bash script which calls the python script. The second part is the python script itself. This builds off of the instructions found in the blog article. You'll need to make sure to pyserial installed as mentioned in that article.

    Runcommand-onstart.sh script

    location: /opt/retropie/configs/all/runcommand-onstart.sh

    #!/usr/bin/env bash
    
    # system name
    sys=$1
    
    # Write to Runcommand Log
    #echo "ON START" >> $HOME/test.log
    #echo "system: $sys" >> $HOME/test.log
    
    # Pass variable to python
    sudo python /home/pi/gamepadblock/launch-gamepadblock.py "$sys"
    

    Python Script

    The script above looks for this script here: /home/pi/gamepadblock/launch-gamepadblock.py

    #!/usr/bin/env python
    
    ### CONFIGURE ##################################### 
    
    # change to your device's port location 
    port = "/dev/ttyACM0"
    
    # use a supported system's folder name (see switch below for options)
    default_system = "arcade"
    
    # set to True to enable log output. False to disable log
    debug = False
    ###################################################  
    
    import serial
    import sys
    
    serialPort = serial.Serial(port, baudrate=115200, bytesize=8, parity=serial.PARITY_NONE, stopbits=1, timeout=1)  # open serial port
    
    serialPort.write("c".encode())  # send c character to find out current mode
    currentMode = serialPort.read(size=64)  # read up to 64 bytes. Timeout after 1 second as set above.
    
    if debug:
            import logging
            logger = logging.getLogger('gpblock.log')
            hdlr = logging.FileHandler('/home/pi/gamepadblock/gpblock.log')
            formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
            hdlr.setFormatter(formatter)
            logger.addHandler(hdlr)
            logger.setLevel(logging.INFO)
    
            logger.info("last controller mode was " + str(currentMode))
    
    
    system = sys.argv[1]
    
    def zero():
        serialPort.write("0".encode())
    
    def one():
        serialPort.write("1".encode())
    
    def two():
        serialPort.write("2".encode())
    
    def three():
        serialPort.write("3".encode())
    
    switch = {
            "arcade"        : zero,
            "mame"          : zero,
            "mame4all"      : zero,
            "mame-libretro" : zero,
            "mame-advmame"  : zero,
            "fba"           : zero,
            "neogeo"        : zero,
            "snes"          : one,
            "nes"           : two,
            "atari2600"     : three,
            "atari7800"     : three,
            "atari800"      : three,
            "atari5200"     : three,
            "c64"           : three,
            "c128"          : three,
            "genesis"       : three,
            "megadrive"     : three,
            "mastersystem"  : three,
            "amiga"         : three,
            "vc20"          : three,
    }
    
    if system in switch:
         switch[system]()
    else:
        switch[default_system]
    
    
    serialPort.close()  # close serial port
    

    The only issue I had was:

    1. I could not make the script read the current mode AFTER writing a mode. Does the port need to be closed and then opened again to do this? If I tried reading the current mode after setting the mode I got an error like this:

      currentMode = serialPort.read(size=64) # read up to 64 bytes. Timeout after 1 second as set above.
      File "/usr/local/lib/python2.7/dist-packages/serial/serialposix.py", line 501, in read
      'device reports readiness to read but returned no data '
      serial.serialutil.SerialException: device reports readiness to read but returned no data (device disconnected or multiple access on port?)

    2. The other issue I have is with the Gamepadblock itself. When I have both an SNES and a NES controller plugged in at the same time the NES controller is ignored until i unplug the SNES. My original desire with the gamepadblock was to leave a pile of controllers plugged in all at the same time and just switch controllers as needed. Is that not possible with the GamePadBlock? I thought it was possible that it had something to do with my script, but even when I wasn't running the script, I still had issues with this. For instance, If I have it set in NES mode, (101 using the dip switches) it will show in jstest js0 that there are 4 buttons and two axes (like NES mode) but will ignore the NES controller and use the SNES until i unplug the SNES, at which point the NES controller is picked up and starts to work.

    3. Do you plan to support Playstation 1 controllers? Man that would be awesome :-D


  • Global Moderator

    1. I could not make the script read the current mode AFTER writing a mode. Does the port need to be closed and then opened again to do this? If I tried reading the current mode after setting the mode I got an error like this:

    currentMode = serialPort.read(size=64) # read up to 64 bytes. Timeout after 1 second as set above.
    File "/usr/local/lib/python2.7/dist-packages/serial/serialposix.py", line 501, in read
    'device reports readiness to read but returned no data '
    serial.serialutil.SerialException: device reports readiness to read but returned no data (device disconnected or multiple access on port?)

    After setting a new controller mode the USB interface enforces a re-enumeration. This might take 1-3 seconds. Maybe you can circumvent the error above if you wait for about 3 seconds.

    1. The other issue I have is with the Gamepadblock itself. When I have both an SNES and a NES controller plugged in at the same time the NES controller is ignored until i unplug the SNES. My original desire with the gamepadblock was to leave a pile of controllers plugged in all at the same time and just switch controllers as needed. Is that not possible with the GamePadBlock? I thought it was possible that it had something to do with my script, but even when I wasn't running the script, I still had issues with this. For instance, If I have it set in NES mode, (101 using the dip switches) it will show in jstest js0 that there are 4 buttons and two axes (like NES mode) but will ignore the NES controller and use the SNES until i unplug the SNES, at which point the NES controller is picked up and starts to work.

    I guess this is not directly an issue with the GamepadBlock, but with the nature of the SNES and NES controllers. Both controllers have the same polling method. This means, that if both controllers are connected at the same time, the GamepadBlock observes the states of both controllers, where one controller might return "pressed" and the other controller returns "unpressed" for the same button.

    1. Do you plan to support Playstation 1 controllers? Man that would be awesome :-D

    Actually, yes - I am in the middle of the implementation :-)


  • Global Moderator

    Actually, thanks a lot for that!

    May I put that into a Github repository? In that way it will be easier for others to suggest enhancements or so.



  • @petrockblog feel free to do whatever you want with it. Change it as needed too. Sometime in the next few days I’ll plan to add the delay to the script unless you decide to build that out first. In any case I hope some gets some use out of the script.

    Good news about PlayStation. I won’t hold you to it, but it would be very handy.

    Thanks. And I love the Gamepadblock!



  • I updated the script to add debugging. It's now available in a Github repo

    https://github.com/mahuti/GamePadBlock


  • Global Moderator

    Thanks a lot for that!
    I have just announces it in a tweet, see https://twitter.com/petrockblog/status/1000702534674198533 :-)



Contributions to the project are always appreciated, so if you would like to support us with a donation you can do so here.

Hosting provided by Mythic-Beasts. See the Hosting Information page for more information.