コード例 #1
0
ファイル: game.py プロジェクト: tchapi/pianette
def reapply_character_mappings(cmd, config, player_config):
    global FORWARDING_DIRECTION
    global SELECTED_CHARACTER

    if SELECTED_CHARACTER is None:
        Debug.println("FAIL", "You must select a character first")
        return

    if FORWARDING_DIRECTION is None:
        FORWARDING_DIRECTION = player_config.get('default-character-forwarding')
        
    # Get all the config
    game_mappings = config.get("Mappings")
    player_mappings = player_config.get("Mappings")
    character_mappings = game_mappings.get(SELECTED_CHARACTER)

    Debug.println("NOTICE", "Applying forwarding direction: %s" % FORWARDING_DIRECTION)
    forwarded_character_mappings = { n: PianetteCmd.unpack_console_args_string(c, FORWARDING_DIRECTION)
                                     for n, c in character_mappings.items() }

    # Merge the three dictionaries of keys
    full_mappings = dict(game_mappings, **player_mappings)
    full_mappings.update(forwarded_character_mappings)

    # Re-init the mappings following the character change
    cmd.pianette.init_mappings(full_mappings)
コード例 #2
0
    def do_game(self, args):
        'The `game` namespace contains all game-defined commands.'
        try:
            method = args[0]
        except IndexError:
            Debug.println("WARNING", "You must specify a command")
            return
        config = self.pianette.get_selected_game_config()
        player_config = self.pianette.get_selected_player_config()

        # Is there a command defined in the configuration for this method ?
        commands = player_config.get("Commands").get(method)
        if commands is not None:
            for command in commands.split("\n"):
                if command.strip():
                    self.onecmd(command)
            return

        # In this case, let's ask the game module
        module = self.pianette.get_selected_game_module()
        game = self.pianette.get_selected_game()
        try:
            # Call the relevant game method from the loaded module
            getattr(module, method)(args[1:],
                                    cmd=self,
                                    config=config,
                                    player_config=player_config)
        except AttributeError:
            # Method does not exist, gracefully fail
            Debug.println(
                "WARNING", "Command %s (%s) does not exist for the game '%s'" %
                (method, args[1:], game))
コード例 #3
0
ファイル: gpio.py プロジェクト: tchapi/pianette
    def poll(self):
        channel_inputs = {}
        channels_with_events = []

        for channel in self.last_polled_gpio_inputs.keys():
            polled_gpio_input = RPi.GPIO.input(channel)
            channel_inputs[channel] = polled_gpio_input

            if self.last_polled_gpio_inputs[channel] is not None:
                matching_polling_event = GPIOConfigUtil.get_matching_polling_event(self.last_polled_gpio_inputs[channel], polled_gpio_input)
                if (matching_polling_event is not None
                    and channel in self.polling_event_callbacks
                    and matching_polling_event in self.polling_event_callbacks[channel]
                   ):
                    channels_with_events.append(channel)
                    Debug.println('INFO', 'Invoking polling event callback for channel %d, input %d, event %s' % (channel, polled_gpio_input, matching_polling_event))
                    self.polling_event_callbacks[channel][matching_polling_event](channel)

            self.last_polled_gpio_inputs[channel] = polled_gpio_input

            if (channel not in channels_with_events
                and channel in self.polling_status_callbacks
                and polled_gpio_input in self.polling_status_callbacks[channel]
               ):
                Debug.println('INFO', 'Invoking polling callback for channel %d, input %d' % (channel, polled_gpio_input))
                self.polling_status_callbacks[channel][polled_gpio_input](channel)
コード例 #4
0
    def poll(self):
        channel_inputs = {}
        channels_with_events = []

        for channel in self.last_polled_gpio_inputs.keys():
            polled_gpio_input = RPi.GPIO.input(channel)
            channel_inputs[channel] = polled_gpio_input

            if self.last_polled_gpio_inputs[channel] is not None:
                matching_polling_event = GPIOConfigUtil.get_matching_polling_event(
                    self.last_polled_gpio_inputs[channel], polled_gpio_input)
                if (matching_polling_event is not None
                        and channel in self.polling_event_callbacks
                        and matching_polling_event
                        in self.polling_event_callbacks[channel]):
                    channels_with_events.append(channel)
                    Debug.println(
                        'INFO',
                        'Invoking polling event callback for channel %d, input %d, event %s'
                        % (channel, polled_gpio_input, matching_polling_event))
                    self.polling_event_callbacks[channel][
                        matching_polling_event](channel)

            self.last_polled_gpio_inputs[channel] = polled_gpio_input

            if (channel not in channels_with_events
                    and channel in self.polling_status_callbacks
                    and polled_gpio_input
                    in self.polling_status_callbacks[channel]):
                Debug.println(
                    'INFO',
                    'Invoking polling callback for channel %d, input %d' %
                    (channel, polled_gpio_input))
                self.polling_status_callbacks[channel][polled_gpio_input](
                    channel)
コード例 #5
0
 def disable_source(self, source):
     Debug.println("INFO", "Disabling Source '%s'" % (source))
     if source in self.sources:
         self.sources[source]['enabled'] = False
     else:
         raise PianetteConfigError("Source '%s' is not loaded yet" %
                                   (source))
コード例 #6
0
ファイル: PianetteCmd.py プロジェクト: tchapi/pianette
    def do_game(self, args):
        'The `game` namespace contains all game-defined commands.'
        try:
            method = args[0]
        except IndexError:
            Debug.println("WARNING", "You must specify a command")
            return
        config = self.pianette.get_selected_game_config()
        player_config = self.pianette.get_selected_player_config()
        
        # Is there a command defined in the configuration for this method ?
        commands = player_config.get("Commands").get(method)
        if commands is not None:
            for command in commands.split("\n"):
                if command.strip():
                    self.onecmd(command)
            return

        # In this case, let's ask the game module
        module = self.pianette.get_selected_game_module()
        game = self.pianette.get_selected_game()
        try:
            # Call the relevant game method from the loaded module
            getattr(module, method)(args[1:], cmd=self, config=config, player_config=player_config)
        except AttributeError:
            # Method does not exist, gracefully fail
            Debug.println("WARNING", "Command %s (%s) does not exist for the game '%s'" % (method, args[1:], game))
コード例 #7
0
ファイル: Pianette.py プロジェクト: tchapi/pianette
 def inputcmds(self, commands, source=None):
     if source is not None and self.is_source_enabled(source):
         Debug.println("INFO", "Running commands from source '%s'" % (source))
         for command in commands.split("\n"):
             if command.strip():
                 self.cmd.onecmd(command)
     else:
         Debug.println("WARNING", "Ignoring commands from source '%s'" % (source))
コード例 #8
0
 def cmdloop(self):
     try:
         cmd.Cmd.cmdloop(self)
     except KeyboardInterrupt as e:
         print()
         Debug.println("NOTICE", "Exiting, bye bye!")
         self.pianette.stop_timer()
         return True
コード例 #9
0
ファイル: PianetteCmd.py プロジェクト: tchapi/pianette
 def cmdloop(self):
     try:
         cmd.Cmd.cmdloop(self)
     except KeyboardInterrupt as e:
         print()
         Debug.println("NOTICE", "Exiting, bye bye!")
         self.pianette.stop_timer()
         return True
コード例 #10
0
 def enable_source(self, source):
     Debug.println("INFO", "Enabling Source '%s'" % (source))
     if source in self.sources and self.sources[source][
             'instance'] is not None:
         self.sources[source]['enabled'] = True
     else:
         raise PianetteConfigError("Source '%s' is not loaded yet" %
                                   (source))
コード例 #11
0
ファイル: game.py プロジェクト: tchapi/pianette
def select_fighting_handicap(*args, **kwargs):
    cmd = kwargs['cmd']
    try:
        handicap = args[0][0]
    except IndexError:
        Debug.println("WARNING", "You must define a handicap (between ▶ and ▶▶▶▶▶▶▶▶)")
        return
    
    cmd.onecmd("console.play ← ; ← ; ← ; ← ; ← ; ← ; ← ; ← ; " + ((max(1, min(8, len(handicap))) - 1) * "→ ; ") + "✕")
コード例 #12
0
ファイル: config.py プロジェクト: tchapi/pianette
def get_all_configobj():
    configobj = ConfigObj()

    for root, dirs, files in os.walk(PIANETTE_CONFIG_PATH):
        for file in files:
            if file.endswith(".ini"):
                Debug.println("INFO", "Reading configuration file %s/%s ..." % (os.path.basename(root), file))
                configobj.merge(ConfigObj(os.path.join(root, file)))

    return configobj
コード例 #13
0
 def inputcmds(self, commands, source=None):
     if source is not None and self.is_source_enabled(source):
         Debug.println("INFO",
                       "Running commands from source '%s'" % (source))
         for command in commands.split("\n"):
             if command.strip():
                 self.cmd.onecmd(command)
     else:
         Debug.println("WARNING",
                       "Ignoring commands from source '%s'" % (source))
コード例 #14
0
 def unload_source(self, source):
     Debug.println("INFO", "Unloading Source '%s'" % (source))
     # Gives a chance for the source to disable itself
     if source in self.sources and 'instance' in self.sources[source]:
         try:
             self.sources[source]['instance'].disable()
         except AttributeError:
             pass
     self.sources[source] = {
         'enabled': False,
     }
コード例 #15
0
ファイル: Pianette.py プロジェクト: tchapi/pianette
 def unload_source(self, source):
     Debug.println("INFO", "Unloading Source '%s'" % (source))
     # Gives a chance for the source to disable itself
     if source in self.sources and 'instance' in self.sources[source]:
         try:
             self.sources[source]['instance'].disable()
         except AttributeError:
             pass
     self.sources[source] = {
         'enabled': False,
     }
コード例 #16
0
ファイル: Piano.py プロジェクト: tchapi/pianette
    def __init_pedal_states(self):
        try:
            supported_pedals = self.configobj['Piano']['supported-pedals']
        except KeyError:
            raise PianetteConfigError('Piano config must define supported-pedals')

        self.pedal_states = {}
        for pedal in supported_pedals:
            self.__set_pedal_state(pedal, False)

        Debug.println('SUCCESS', 'Piano pedal states initialized')
コード例 #17
0
ファイル: Piano.py プロジェクト: tchapi/pianette
    def __init_note_states(self):
        try:
            supported_notes = self.configobj['Piano']['supported-notes']
        except KeyError:
            raise PianetteConfigError('Piano config must define supported-notes')

        self.note_states = {}
        for note in supported_notes:
            self.__set_note_state(note, False)

        Debug.println('SUCCESS', 'Piano note states initialized')
コード例 #18
0
def get_all_configobj():
    configobj = ConfigObj()

    for root, dirs, files in os.walk(PIANETTE_CONFIG_PATH):
        for file in files:
            if file.endswith(".ini"):
                Debug.println(
                    "INFO", "Reading configuration file %s/%s ..." %
                    (os.path.basename(root), file))
                configobj.merge(ConfigObj(os.path.join(root, file)))

    return configobj
コード例 #19
0
ファイル: game.py プロジェクト: tchapi/pianette
def select_mode(*args, **kwargs):
    cmd = kwargs['cmd']
    try:
        mode = " ".join(args[0])
    except IndexError:
        Debug.println("WARNING", "You must define a mode (Versus or Arcade)")
        return

    if mode == "Versus":
        cmd.onecmd("console.play → ✕")
    else: 
        cmd.onecmd("console.play ✕")
コード例 #20
0
    def __init__(self, configobj=None):
        self.__init_using_configobj(configobj=configobj)

        self.piano = Piano(configobj=self.configobj)
        self.psx_controller_state = ControllerState(configobj=self.configobj)

        self.sources = {}

        self.selected_game = None

        # Instantiate the console controller that is responsible for sendint out the psx constroller state to the console
        self.console_controller = ConsoleController(self.psx_controller_state,
                                                    configobj=self.configobj)

        # Upcoming state cycles for the Piano Notes (input)
        self.piano_buffered_note_states = {
            note: []
            for note in self.piano.get_supported_notes()
        }

        # Upcoming state cycles for the Piano Pedals (input)
        self.piano_buffered_pedal_states = {
            pedal: []
            for pedal in self.piano.get_supported_pedals()
        }

        # Upcoming state cycles for the Console Controls (output)
        self.psx_controller_buffered_states = {}
        try:
            self.psx_controller_buffered_states = {
                k: []
                for k in self.configobj['Console']['supported-controls']
            }
        except KeyError:
            pass

        # Run the Pianette!
        self._timer = None
        self._timer_interval = PIANETTE_CYCLE_PERIOD
        self._timer_is_running = False

        # Start the timer thread that will cycle buffered states at each interval
        self.start_timer()
        Debug.println(
            "INFO",
            "Pianette buffered states timer thread started at %f secs interval"
            % self._timer_interval)

        # Create pianette command interface
        self.cmd = PianetteCmd(configobj=configobj, pianette=self)
コード例 #21
0
    def __init__(self, configobj=None, pianette=None, **kwargs):
        super().__init__(**kwargs)
        app.pianette = pianette
        app.configs = configobj.get("Game").keys()
        app.hosts = configobj.get("Pianette").get('Hosts')
        app.port = configobj.get("Pianette").get('API').get('port')

        for player, ip in app.hosts.iteritems():
            Debug.println("NOTICE", "Adding Player '%s' at %s" % (player, ip))

        Debug.println("INFO", "Starting API thread on port %s" % app.port)
        self.t = Thread(target=self.startApi)
        self.t.daemon = True
        self.t.start()
コード例 #22
0
def select_mode(*args, **kwargs):
    cmd = kwargs['cmd']
    try:
        mode = " ".join(args[0])
    except IndexError:
        Debug.println("WARNING", "You must define a mode (Multiplayer Race, Single Race or Team Race)")
        return

    if mode == "Multiplayer Race":
        cmd.onecmd("console.play ↓ ; ↓ ; ✕ ; ; ; ; ; ; ; ✕ ; ; ; ; ; ; ; ✕ ; ; ; ; ; ; ; ✕ ; ; ; ; ; ; ;")
    elif mode == "Single Race":
        cmd.onecmd("console.play ↓ ; ✕ ; ; ; ; ; ; ; ✕ ; ; ; ; ; ; ; ✕ ; ; ; ; ; ; ;")
    elif mode == "Team Race":
        cmd.onecmd("console.play ↓ ; ✕ ; ; ; ; ; ; ; ↓ ; ✕ ; ; ; ; ; ; ; ✕ ; ; ; ; ; ; ;")
    else: 
        cmd.onecmd("console.play ↓ ; ↓ ; ✕ ; ; ; ; ; ; ; ✕ ; ; ; ; ; ; ; ✕ ; ; ; ; ; ; ; ✕ ; ; ; ; ; ; ;") # default to multiplayer
コード例 #23
0
ファイル: game.py プロジェクト: tchapi/pianette
def select_fighting_style(*args, **kwargs):
    cmd = kwargs['cmd']
    try:
        style = " ".join(args[0])
    except IndexError:
        Debug.println("WARNING", "You must define a style (A-ISM, X-ISM or V-ISM)")
        return

    if style == "V-ISM":
        cmd.onecmd("console.play ↓")
    elif style == "X-ISM":
        cmd.onecmd("console.play ↑")
    elif style == "A-ISM":
        pass
    else:
        Debug.println("WARNING", "%s is not an available fighting style" % style)
        return

    cmd.onecmd("console.play ✕")
コード例 #24
0
ファイル: game.py プロジェクト: tchapi/pianette
def select_character(*args, **kwargs):
    global SELECTED_CHARACTER
    global FORWARDING_DIRECTION

    cmd = kwargs['cmd']
    config = kwargs['config']
    player_config = kwargs['player_config']

    try:
        character = " ".join(args[0])
    except IndexError:
        Debug.println("WARNING", "You must define a character or pass {random}")
        return

    if (character == "{random}"):
        # Select a random character in supported-characters
        character = random.choice(config.get('supported-characters'))
    elif not character in config.get('supported-characters'):
        Debug.println("WARNING", "This character is not supported")
        return

    Debug.println("NOTICE", "Choosing character %s" % character)
    # Process list of commands to obtain this character
    cmd.onecmd("console.play %s ✕" % player_config.get("Positions").get(character))

    SELECTED_CHARACTER = character
    # When selecting a character, we revert to its default forwarding direction
    FORWARDING_DIRECTION = player_config.get('default-character-forwarding')
    
    reapply_character_mappings(cmd, config, player_config)
コード例 #25
0
ファイル: Pianette.py プロジェクト: tchapi/pianette
    def select_game(self, game=None):
        if game is None:
            return self.unselect_game()
        Debug.println("INFO", "Selecting Game '%s'" % (game))
        module_name = "config.games.%s.game" % game

        # Let's import the game module, if not previously done
        if module_name not in sys.modules:
            try:
                self.selected_game_module = importlib.import_module(module_name)
            except ImportError:
                Debug.println("FAIL", "Game '%s' doesn't have a module in the games folder" % game)
                return
        else:
            self.selected_game_module = sys.modules[module_name]
        self.selected_game = game
        
        # We have to re-init with the game's mappings
        # instead of the general mappings :
        if not self.configobj.get("Game").get(game):
            raise PianetteConfigError("Undefined Game '%s' section in configobj" % game)
        if not self.selected_player:
            raise PianetteConfigError("You must select a player first")

        self.selected_game_config = self.configobj.get("Game").get(game)
        self.selected_player_config = self.selected_game_config.get("Player %s" % self.selected_player)

        # Retrieve the mappings
        game_mappings = self.selected_game_config.get("Mappings")
        player_mappings = self.selected_player_config.get("Mappings")

        # Merge the two dictionaries of keys
        if player_mappings is not None:
            full_mappings = dict(game_mappings, **player_mappings);
        else:
            full_mappings = game_mappings

        # Finally, override PIANETTE_CYCLE_PERIOD
        global PIANETTE_CYCLE_PERIOD
        if self.selected_game_config.get('cycle-period') is not None:
            PIANETTE_CYCLE_PERIOD = float(self.selected_game_config.get('cycle-period'))
            Debug.println("NOTICE", "The selected game overrides the cycle period : %f seconds" % PIANETTE_CYCLE_PERIOD)
        else:
            PIANETTE_CYCLE_PERIOD = float(self.configobj.get("Console").get('default-cycle-period'))
            Debug.println("NOTICE", "Resetting the default cycle period : %f seconds" % PIANETTE_CYCLE_PERIOD)

        # Re-init the mappings
        self.init_mappings(full_mappings)
コード例 #26
0
ファイル: Pianette.py プロジェクト: tchapi/pianette
    def __init__(self, configobj=None):
        self.__init_using_configobj(configobj=configobj)

        self.piano = Piano(configobj=self.configobj)
        self.psx_controller_state = ControllerState(configobj=self.configobj)

        self.sources = {}

        self.selected_game = None

        # Instantiate the console controller that is responsible for sendint out the psx constroller state to the console
        self.console_controller = ConsoleController(self.psx_controller_state, configobj=self.configobj)

        # Upcoming state cycles for the Piano Notes (input)
        self.piano_buffered_note_states = { note: [] for note in self.piano.get_supported_notes() }

        # Upcoming state cycles for the Piano Pedals (input)
        self.piano_buffered_pedal_states = { pedal: [] for pedal in self.piano.get_supported_pedals() }

        # Upcoming state cycles for the Console Controls (output)
        self.psx_controller_buffered_states = {}
        try:
            self.psx_controller_buffered_states = { k: [] for k in self.configobj['Console']['supported-controls'] }
        except KeyError:
            pass

        # Run the Pianette!
        self._timer = None
        self._timer_interval = PIANETTE_CYCLE_PERIOD
        self._timer_is_running = False

        # Start the timer thread that will cycle buffered states at each interval
        self.start_timer()
        Debug.println("INFO", "Pianette buffered states timer thread started at %f secs interval" % self._timer_interval)

        # Create pianette command interface
        self.cmd = PianetteCmd(configobj=configobj, pianette=self)
コード例 #27
0
ファイル: PianetteCmd.py プロジェクト: tchapi/pianette
 def do_time__sleep(self, args):
     'Block the exeuction for a certain amount of Pianette cycles'
     Debug.println("INFO", "running command: time.sleep" + " " + args)
     args_list = args.split()
     sleep_time = float(args_list[0]) * self.pianette.get_cycle_period()
     if args_list:
         Debug.println("NOTICE", 'sleeping for {:.3f} seconds'.format(sleep_time))
         time.sleep(sleep_time)
         Debug.println("NOTICE", 'done sleeping for {:.3f} seconds'.format(sleep_time))
     else:
         raise pianette.errors.PianetteCmdError("No argument provided for time.sleep")
コード例 #28
0
 def do_time__sleep(self, args):
     'Block the exeuction for a certain amount of Pianette cycles'
     Debug.println("INFO", "running command: time.sleep" + " " + args)
     args_list = args.split()
     sleep_time = float(args_list[0]) * self.pianette.get_cycle_period()
     if args_list:
         Debug.println("NOTICE",
                       'sleeping for {:.3f} seconds'.format(sleep_time))
         time.sleep(sleep_time)
         Debug.println(
             "NOTICE",
             'done sleeping for {:.3f} seconds'.format(sleep_time))
     else:
         raise pianette.errors.PianetteCmdError(
             "No argument provided for time.sleep")
コード例 #29
0
ファイル: ConsoleController.py プロジェクト: tchapi/pianette
  def __init__(self, psx_controller_state, configobj=None):
    self.configobj = configobj

    self.psx_controller_state = psx_controller_state
    # Tries to find correct Serial port
    open_ports = self.getSerialPorts()

    # Opens first port available
    try:
      self.serialConnection = serial.Serial(open_ports[0], 38400)
      Debug.println("INFO", "SPI Slave detected at %s, waiting for the port to initialize." % open_ports[0])
      time.sleep(3) # DIRTY but apparently required for the serial port to get fully ready
      Debug.println("SUCCESS", "SPI Slave initialized.")
    except Exception:
      self.serialConnection = None
      Debug.println("WARNING", "No ConsoleController SPI Slave detected.")
コード例 #30
0
ファイル: Pianette.py プロジェクト: tchapi/pianette
    def load_source(self, source):
        if source in self.sources and 'instance' in self.sources[source]:
            Debug.println("WARNING", "Source '%s' is already enabled" % (source))
            return

        try:
            source_module = importlib.import_module('pianette.sources.' + source)
        except ImportError:
            Debug.println("FAIL", "Unsupported source '%s'" % (source))
            return
        source_class = getattr(source_module, source)
        instance = source_class(configobj=self.configobj, pianette=self)

        Debug.println("INFO", "Loading Source '%s'" % (source))
        self.sources[source] = {
            'enabled': True,
            'instance': instance,
        }
コード例 #31
0
ファイル: game.py プロジェクト: tchapi/pianette
def select_stage(*args, **kwargs):
    cmd = kwargs['cmd']
    config = kwargs['config']
    try:
        stage = " ".join(args[0])
    except IndexError:
        Debug.println("WARNING", "You must define a stage")
        return

    if (stage == "{random}"):
        # Select a random stage in supported-stages
        stage = random.choice(config.get('supported-stages'))
    elif not stage in config.get('supported-stages'):
        Debug.println("WARNING", "This stage is not supported")
        return

    Debug.println("NOTICE", "Choosing stage '%s'" % stage)

    cmd.onecmd("console.play %s ; ✕" % config.get("Stages").get(stage))
コード例 #32
0
def select_track(*args, **kwargs):
    cmd = kwargs['cmd']
    config = kwargs['config']

    try:
        track = " ".join(args[0])
    except IndexError:
        Debug.println("WARNING", "You must define a track")
        return

    if (track == "{random}"):
        # Select a random track in supported-tracks
        track = random.choice(config.get('supported-tracks'))
    elif not track in config.get('supported-tracks'):
        Debug.println("WARNING", "This track '%s' is not supported" % track)
        return

    Debug.println("NOTICE", "Choosing track '%s'" % track)

    cmd.onecmd("console.play ; ; ; %s ; ; ; ; ; ; ; ; ; ; ✕ " % config.get("Tracks").get(track))
コード例 #33
0
    def load_source(self, source):
        if source in self.sources and 'instance' in self.sources[source]:
            Debug.println("WARNING",
                          "Source '%s' is already enabled" % (source))
            return

        try:
            source_module = importlib.import_module('pianette.sources.' +
                                                    source)
        except ImportError:
            Debug.println("FAIL", "Unsupported source '%s'" % (source))
            return
        source_class = getattr(source_module, source)
        instance = source_class(configobj=self.configobj, pianette=self)

        Debug.println("INFO", "Loading Source '%s'" % (source))
        self.sources[source] = {
            'enabled': True,
            'instance': instance,
        }
コード例 #34
0
    def __init__(self, psx_controller_state, configobj=None):
        self.configobj = configobj

        self.psx_controller_state = psx_controller_state
        # Tries to find correct Serial port
        open_ports = self.getSerialPorts()

        # Opens first port available
        try:
            self.serialConnection = serial.Serial(open_ports[0], 38400)
            Debug.println(
                "INFO",
                "SPI Slave detected at %s, waiting for the port to initialize."
                % open_ports[0])
            time.sleep(
                3
            )  # DIRTY but apparently required for the serial port to get fully ready
            Debug.println("SUCCESS", "SPI Slave initialized.")
        except Exception:
            self.serialConnection = None
            Debug.println("WARNING",
                          "No ConsoleController SPI Slave detected.")
コード例 #35
0
def select_character(*args, **kwargs):
    cmd = kwargs['cmd']
    config = kwargs['config']
    player_config = kwargs['player_config']

    try:
        character = " ".join(args[0])
    except IndexError:
        Debug.println("WARNING", "You must define a character or pass {random}")
        return

    if (character == "{random}"):
        # Select a random character in supported-characters
        character = random.choice(config.get('supported-characters'))
    elif not character in config.get('supported-characters'):
        Debug.println("WARNING", "This character '%s' is not supported" % character)
        return

    # Choosing a deterministic character will only work for the first player to choose
    Debug.println("NOTICE", "_Probably_ choosing character %s" % character)
    # Process list of commands to obtain this character
    cmd.onecmd("console.play START ; ; ; ; ; %s ; ; ; ; ; ✕" % config.get("Positions").get(character))
コード例 #36
0
ファイル: PianetteCmd.py プロジェクト: tchapi/pianette
    def do_pianette__dump_state(self, args):
        'Dump a full state of the Pianette configuration'
        Debug.println("INFO", "running command: pianette.dump_state")

        # Dump general info on the pianette instance
        Debug.println("NOTICE", "Enabled sources: %s" % self.pianette.get_selected_player())

        # Dump general game configuration
        Debug.println("NOTICE", "Currently selected game: '%s'" % self.pianette.get_selected_game())
        Debug.println("NOTICE", "Current game config:")
        print(json.dumps(self.pianette.get_selected_game_config(), sort_keys=True, indent=4))
        
        # Dump player specific configuration for this game
        Debug.println("NOTICE", "Currently selected player: %s" % self.pianette.get_selected_player())
        Debug.println("NOTICE", "Current player config:")
        print(json.dumps(self.pianette.get_selected_player_config(), sort_keys=True, indent=4))

        # Dumps the buffered mappings
        Debug.println("NOTICE", "Current buffered mappings:")
        print(json.dumps(self.pianette.get_buffered_states_mappings(), sort_keys=True, indent=4))
コード例 #37
0
ファイル: PianetteCmd.py プロジェクト: tchapi/pianette
 def do_pianette__enable_source(self, args):
     'Enable an input source'
     Debug.println("INFO", "running command: pianette.enable_source" + " " + args)
     self.pianette.enable_source(args)
コード例 #38
0
ファイル: PianetteCmd.py プロジェクト: tchapi/pianette
 def do_pianette__select_game(self, args):
     'Select a game and load its configuration'
     Debug.println("INFO", "running command: pianette.select_game" + " " + args)
     self.pianette.select_game(args)
コード例 #39
0
 def select_player(self, player=None):
     Debug.println("INFO", "Selecting Player %s" % (player))
     self.selected_player = player
コード例 #40
0
ファイル: PianetteCmd.py プロジェクト: tchapi/pianette
 def do_pianette__disable_source(self, args):
     'Disable a previously enabled source'
     Debug.println("INFO", "running command: pianette.disable_source" + " " + args)
     self.pianette.disable_source(args)
コード例 #41
0
ファイル: PianetteCmd.py プロジェクト: tchapi/pianette
 def do_piano__release(self, args):
     'Release a sequence of notes, chords and pedals'
     Debug.println("INFO", "running command: piano.release" + " " + args)
     self.pianette.release_piano_pedals(args)
コード例 #42
0
 def do_pianette__select_game(self, args):
     'Select a game and load its configuration'
     Debug.println("INFO",
                   "running command: pianette.select_game" + " " + args)
     self.pianette.select_game(args)
コード例 #43
0
 def do_piano__play(self, args):
     'Play a sequence of notes, chords and pedals'
     Debug.println("INFO", "running command: piano.play" + " " + args)
     self.pianette.push_piano_notes(args)
コード例 #44
0
# A command-line emulator of a PS2 Game Pad Controller
# that asynchronously listens to GPIO EDGE_RISING
# inputs from sensors and sends Serial commands to
# an ATMEGA328P acting as a fake SPI Slave for the Console.

# Written in Python 3.

import importlib
import pianette.config
import sys

from pianette.Pianette import Pianette
from pianette.PianetteArgumentParser import PianetteArgumentParser
from pianette.utils import Debug

Debug.println("INFO", " ")
Debug.println("INFO", " ################################## ")
Debug.println("INFO", " |            PIANETTE            | ")
Debug.println("INFO", " ################################## ")
Debug.println("INFO", " ")

configobj = pianette.config.get_all_configobj()

parser = PianetteArgumentParser(configobj=configobj)
args = parser.parse_args()

# Instanciate the global Pianette
# Its responsibility is to translate Piano actions to Console actions
pianette = Pianette(configobj=configobj)

# We MUST select a player before we select a game.
コード例 #45
0
    def select_game(self, game=None):
        if game is None:
            return self.unselect_game()
        Debug.println("INFO", "Selecting Game '%s'" % (game))
        module_name = "config.games.%s.game" % game

        # Let's import the game module, if not previously done
        if module_name not in sys.modules:
            try:
                self.selected_game_module = importlib.import_module(
                    module_name)
            except ImportError:
                Debug.println(
                    "FAIL",
                    "Game '%s' doesn't have a module in the games folder" %
                    game)
                return
        else:
            self.selected_game_module = sys.modules[module_name]
        self.selected_game = game

        # We have to re-init with the game's mappings
        # instead of the general mappings :
        if not self.configobj.get("Game").get(game):
            raise PianetteConfigError(
                "Undefined Game '%s' section in configobj" % game)
        if not self.selected_player:
            raise PianetteConfigError("You must select a player first")

        self.selected_game_config = self.configobj.get("Game").get(game)
        self.selected_player_config = self.selected_game_config.get(
            "Player %s" % self.selected_player)

        # Retrieve the mappings
        game_mappings = self.selected_game_config.get("Mappings")
        player_mappings = self.selected_player_config.get("Mappings")

        # Merge the two dictionaries of keys
        if player_mappings is not None:
            full_mappings = dict(game_mappings, **player_mappings)
        else:
            full_mappings = game_mappings

        # Finally, override PIANETTE_CYCLE_PERIOD
        global PIANETTE_CYCLE_PERIOD
        if self.selected_game_config.get('cycle-period') is not None:
            PIANETTE_CYCLE_PERIOD = float(
                self.selected_game_config.get('cycle-period'))
            Debug.println(
                "NOTICE",
                "The selected game overrides the cycle period : %f seconds" %
                PIANETTE_CYCLE_PERIOD)
        else:
            PIANETTE_CYCLE_PERIOD = float(
                self.configobj.get("Console").get('default-cycle-period'))
            Debug.println(
                "NOTICE", "Resetting the default cycle period : %f seconds" %
                PIANETTE_CYCLE_PERIOD)

        # Re-init the mappings
        self.init_mappings(full_mappings)
コード例 #46
0
    def cycle_buffered_states(self):
        self.poll_enabled_sources()

        # Input Piano Notes to Piano Buffered States
        for piano_note in self.piano.get_supported_notes():
            if self.piano.is_note_on(piano_note):
                Debug.println("INFO", "Buffering Piano Note %s" % (piano_note))
                self.piano_buffered_note_states[piano_note].append(
                    {"cycles_remaining": PIANETTE_PROCESSING_CYCLES})
                self.piano.switch_note_off(piano_note)

        # Input Piano Pedals to Piano Buffered States
        for piano_pedal in self.piano.get_supported_pedals():
            if self.piano.is_pedal_on(piano_pedal):
                if not self.piano_buffered_pedal_states[piano_pedal]:
                    Debug.println(
                        "INFO", "Indefinitely buffering Piano Pedal %s" %
                        (piano_pedal))
                self.piano_buffered_pedal_states[piano_pedal] = [{
                    "cycles_remaining":
                    "∞"
                }]
            else:
                if self.piano_buffered_pedal_states[piano_pedal]:
                    Debug.println(
                        "INFO", "Indefinitely unbuffering Piano Pedal %s" %
                        (piano_pedal))
                self.piano_buffered_pedal_states[piano_pedal] = []

        # Process Buffered States: Determine piano note or chord
        # Notes that have reached their last cycle "lead" the chord determination
        # Other notes may be used to "complement" lead notes.
        # If a winning chord is found, push corresponding combo to PSX Controller buffer
        # If complementary notes are actually used, they are discarded from buffer.
        lead_notes = []
        complementary_notes = []
        for piano_note in self.piano_buffered_note_states.keys():
            processed_buffered_states = []
            for buffered_state in self.piano_buffered_note_states[piano_note]:
                if buffered_state["cycles_remaining"] == 0:
                    lead_notes.append(piano_note)
                else:
                    complementary_notes.append(piano_note)
                    buffered_state["cycles_remaining"] -= 1
                    processed_buffered_states.append(buffered_state)
            self.piano_buffered_note_states[
                piano_note] = processed_buffered_states

        if lead_notes:
            Debug.println(
                "INFO", "Processing Piano Notes: lead=%s, complementary=%s" %
                (lead_notes, complementary_notes))
            ranked_chord_bitids = self.get_ranked_chord_bitids_including_at_least_one_of_notes(
                lead_notes)

            all_notes_chord_bitid = self.get_notes_chord_bitid(
                lead_notes + complementary_notes)
            ranked_winning_chord_bitids = [
                chord_bitid for chord_bitid in ranked_chord_bitids
                if not ((all_notes_chord_bitid & chord_bitid) ^ chord_bitid)
            ]

            if ranked_winning_chord_bitids:
                winning_chord_bitid = ranked_winning_chord_bitids[0]
                winning_states_mapping = deepcopy(
                    self._buffered_states_mapping_for_chord_bitid[
                        winning_chord_bitid])

                # Push piano command to PSX Controller buffer, clearing any pending combo
                for control in self.psx_controller_buffered_states.keys():
                    self.psx_controller_buffered_states[
                        control] = winning_states_mapping[
                            "psx_controller"].get(control, [])

                # Clear winning chord notes from the piano buffer
                for piano_note in self.piano_buffered_note_states.keys():
                    if piano_note in self._note_bitids:
                        if self._note_bitids[piano_note] & winning_chord_bitid:
                            if self.piano_buffered_note_states[piano_note]:
                                self.piano_buffered_note_states[
                                    piano_note] = self.piano_buffered_note_states[
                                        piano_note][1:]

        # Pedals buffer their own PSX controls in parallel of chord resolution
        for piano_pedal in self.piano_buffered_pedal_states.keys():
            for buffered_state in self.piano_buffered_pedal_states[
                    piano_pedal]:
                if buffered_state["cycles_remaining"] == "∞":
                    if piano_pedal in self._pedal_bitids:
                        # Unshift pedal command to PSX Controller buffer, merging with any pending combo
                        psx_controller_states_for_pedal = self._buffered_states_mapping_for_pedal_bitid[
                            self._pedal_bitids[piano_pedal]]["psx_controller"]
                        for control, single_cycles_count in psx_controller_states_for_pedal.items(
                        ):
                            cycles_count = single_cycles_count[0]
                            if not self.psx_controller_buffered_states[control]:
                                self.psx_controller_buffered_states[
                                    control] = [cycles_count]
                            elif self.psx_controller_buffered_states[control][
                                    0] < cycles_count:
                                self.psx_controller_buffered_states[control][
                                    0] = cycles_count

        # Output PSX Controller Buffered states to PSX Controller
        triggered_controls = ""
        cleared_controls = ""
        for psx_control, buffered_state in self.psx_controller_buffered_states.items(
        ):
            if buffered_state:
                cyclesCount = buffered_state.pop(0)
                if cyclesCount > 0:
                    triggered_controls += "(%s, %d) " % (psx_control,
                                                         cyclesCount)
                    self.psx_controller_state.raiseFlag(psx_control)
                    cyclesCount -= 1
                    # If we're decrementing a cycle count, we don't
                    # want to insert 0 to avoid 'missing a step'.
                    if cyclesCount > 0:
                        buffered_state.insert(0, cyclesCount)
                elif cyclesCount < 0:
                    cleared_controls += "(%s, %d) " % (psx_control,
                                                       -cyclesCount)
                    self.psx_controller_state.clearFlag(psx_control)
                    cyclesCount += 1
                    # If we're incrementing a cycle count, we don't
                    # want to insert 0 to avoid 'missing a step'.
                    if cyclesCount < 0:
                        buffered_state.insert(0, cyclesCount)
                else:
                    cleared_controls += "(%s, %d) " % (psx_control, 1)
                    self.psx_controller_state.clearFlag(psx_control)
            else:
                self.psx_controller_state.clearFlag(psx_control)

        if len(triggered_controls) > 0:
            Debug.println(
                "INFO",
                "Keeping PSX Controls %sTriggered" % triggered_controls)
        if len(cleared_controls) > 0 and len(triggered_controls) == 0:
            Debug.println("INFO", "General pause for 1 cycle")
        elif len(cleared_controls) > 0:
            Debug.println("DEBUG",
                          "Keeping PSX Control %sCleared" % cleared_controls)

        self.console_controller.sendStateBytes()
コード例 #47
0
 def do_piano__release(self, args):
     'Release a sequence of notes, chords and pedals'
     Debug.println("INFO", "running command: piano.release" + " " + args)
     self.pianette.release_piano_pedals(args)
コード例 #48
0
    def do_pianette__dump_state(self, args):
        'Dump a full state of the Pianette configuration'
        Debug.println("INFO", "running command: pianette.dump_state")

        # Dump general info on the pianette instance
        Debug.println(
            "NOTICE",
            "Enabled sources: %s" % self.pianette.get_selected_player())

        # Dump general game configuration
        Debug.println(
            "NOTICE", "Currently selected game: '%s'" %
            self.pianette.get_selected_game())
        Debug.println("NOTICE", "Current game config:")
        print(
            json.dumps(self.pianette.get_selected_game_config(),
                       sort_keys=True,
                       indent=4))

        # Dump player specific configuration for this game
        Debug.println(
            "NOTICE", "Currently selected player: %s" %
            self.pianette.get_selected_player())
        Debug.println("NOTICE", "Current player config:")
        print(
            json.dumps(self.pianette.get_selected_player_config(),
                       sort_keys=True,
                       indent=4))

        # Dumps the buffered mappings
        Debug.println("NOTICE", "Current buffered mappings:")
        print(
            json.dumps(self.pianette.get_buffered_states_mappings(),
                       sort_keys=True,
                       indent=4))
コード例 #49
0
 def do_pianette__enable_source(self, args):
     'Enable an input source'
     Debug.println("INFO",
                   "running command: pianette.enable_source" + " " + args)
     self.pianette.enable_source(args)
コード例 #50
0
ファイル: PianetteCmd.py プロジェクト: tchapi/pianette
 def do_piano__play(self, args):
     'Play a sequence of notes, chords and pedals'
     Debug.println("INFO", "running command: piano.play" + " " + args)
     self.pianette.push_piano_notes(args)
コード例 #51
0
 def do_piano__hold(self, args):
     'Hold a sequence of notes, chords and pedals'
     Debug.println("INFO", "running command: piano.hold" + " " + args)
     self.pianette.hold_piano_pedals(args)
コード例 #52
0
ファイル: PianetteCmd.py プロジェクト: tchapi/pianette
 def do_piano__hold(self, args):
     'Hold a sequence of notes, chords and pedals'
     Debug.println("INFO", "running command: piano.hold" + " " + args)
     self.pianette.hold_piano_pedals(args)
コード例 #53
0
ファイル: PianetteCmd.py プロジェクト: tchapi/pianette
 def do_console__play(self, args):
     'Play a sequence of buttons in a definite order for a full Pianette cycle'
     Debug.println("INFO", "running command: console.play" + " " + args)
     self.pianette.push_console_controls(args)
コード例 #54
0
 def do_pianette__disable_source(self, args):
     'Disable a previously enabled source'
     Debug.println("INFO",
                   "running command: pianette.disable_source" + " " + args)
     self.pianette.disable_source(args)
コード例 #55
0
 def unselect_game(self):
     Debug.println("INFO", "Unselecting Game")
     self.selected_game_module = None
     self.selected_game = None
     self.selected_game_config = None
     self.selected_player_config = None
コード例 #56
0
    def get_buffered_states_for_controls_string(self,
                                                controls_string,
                                                force_duration_cycles=None):
        # Initial state and time
        controls_buffered_states = {}
        time_index = 0

        # Combo loop variables
        in_combo = False
        combo_controls = []
        previous_control = None

        # By default, no duration cycle is set to detect malformed controls_string starting with `+`
        duration_cycles = None

        for control in controls_string.split():
            # '+' should not be at the start of the string, fail gracefully
            if control == "+" and duration_cycles is None:
                Debug.println(
                    "FAIL",
                    "Control string is not grammatically correct (starting with a +)"
                )
                return controls_buffered_states
            elif control == "+":
                time_index -= duration_cycles
                in_combo = True
            elif control == ";" and in_combo == False:  # During a combo, a semi-colon (;) is not grammatically correct.
                # We add a "0" cycle count for every possible state, to be sure
                # that it will add an offset even for future added controls
                # that are not yet present in self.controls_buffered_states
                for c in self.psx_controller_buffered_states:
                    if c in controls_buffered_states:
                        controls_buffered_states[c].extend(
                            [0] * PIANETTE_CONSOLE_PLAY_DURATION_CYCLES)
                    else:
                        controls_buffered_states[c] = [
                            0
                        ] * PIANETTE_CONSOLE_PLAY_DURATION_CYCLES
            else:
                if in_combo:
                    combo_controls.append(
                        previous_control)  # Next control will be in a combo
                else:
                    combo_controls = []
                control, duration_cycles = self.extract(
                    control, combo_controls, force_duration_cycles)

                if control in controls_buffered_states:
                    buffer_duration = 0
                    for duration in controls_buffered_states[control]:
                        buffer_duration += abs(duration)

                    if time_index - buffer_duration > 0:
                        controls_buffered_states[control].append(
                            -time_index + buffer_duration)
                        controls_buffered_states[control].append(
                            duration_cycles)
                    elif not in_combo or time_index == buffer_duration:
                        controls_buffered_states[control].append(
                            duration_cycles)

                # If we've got an unknown control, it will be ignored and the string will
                # be parsed as if the control was not there, still modifying the time index
                # if needed and not breaking combos, leading to generally correct and expected
                # results. No exception should be raised.
                elif control in self.psx_controller_buffered_states:
                    controls_buffered_states[control] = []

                    if time_index > 0:
                        controls_buffered_states[control].append(-time_index)

                    controls_buffered_states[control].append(duration_cycles)

                time_index += duration_cycles
                in_combo = False  # Always assume that we're the last control in the combo

                previous_control = control

        return controls_buffered_states
コード例 #57
0
 def do_console__play(self, args):
     'Play a sequence of buttons in a definite order for a full Pianette cycle'
     Debug.println("INFO", "running command: console.play" + " " + args)
     self.pianette.push_console_controls(args)