def receive_sa(self, msg): self.log.debug("Received SA: %s", msg) hw_states = dict() num_local, local_states, num_nw, nw_states = msg.split(',') for offset, byte in enumerate(bytearray.fromhex(nw_states)): for i in range(8): num = Config.int_to_hex_string((offset * 8) + i) if byte & (2**i): hw_states[(num, 1)] = 1 else: hw_states[(num, 1)] = 0 for offset, byte in enumerate(bytearray.fromhex(local_states)): for i in range(8): num = Config.int_to_hex_string((offset * 8) + i) if byte & (2**i): hw_states[(num, 0)] = 1 else: hw_states[(num, 0)] = 0 self.hw_switch_data = hw_states
def configure_led(self, config): if not self.rgb_connection: self.log.critical("A request was made to configure a FAST LED, " "but no connection to an LED processor is " "available") sys.exit() if not self.flag_led_tick_registered: self.machine.events.add_handler('timer_tick', self.update_leds) self.flag_led_tick_registered = True # if the LED number is in <channel> - <led> format, convert it to a # FAST hardware number if '-' in config['number_str']: num = config['number_str'].split('-') config['number'] = int((num[0] * 64) + num[1]) self.config['config_number_format'] = 'int' else: config['number'] = str(config['number']) if self.config['config_number_format'] == 'int': config['number'] = Config.int_to_hex_string(config['number']) else: config['number'] = Config.normalize_hex_string(config['number']) this_fast_led = FASTDirectLED(config['number']) self.fast_leds.add(this_fast_led) return this_fast_led
def configure_matrixlight(self, config): if not self.net_connection: self.log.critical("A request was made to configure a FAST matrix " "light, but no connection to a NET processor is " "available") sys.exit() if self.machine_type == 'wpc': # translate number to FAST light num config['number'] = self.wpc_light_map.get( config['number_str'].upper()) elif self.config['config_number_format'] == 'int': config['number'] = Config.int_to_hex_string(config['number']) else: config['number'] = Config.normalize_hex_string(config['number']) return (FASTMatrixLight(config['number'], self.net_connection.send), config['number'])
def configure_driver(self, config, device_type='coil'): if not self.net_connection: self.log.critical("A request was made to configure a FAST driver, " "but no connection to a NET processor is " "available") sys.exit() # If we have WPC driver boards, look up the driver number if self.machine_type == 'wpc': config['number'] = self.wpc_driver_map.get( config['number_str'].upper()) if ('connection' in config and config['connection'].lower() == 'network'): config['connection'] = 1 else: config['connection'] = 0 # local driver (default for WPC) # If we have fast driver boards, we need to make sure we have hex strs elif self.machine_type == 'fast': if self.config['config_number_format'] == 'int': config['number'] = Config.int_to_hex_string(config['number']) else: config['number'] = Config.normalize_hex_string(config['number']) # Now figure out the connection type if ('connection' in config and config['connection'].lower() == 'local'): config['connection'] = 0 else: config['connection'] = 1 # network driver (default for FAST) else: self.log.critical("Invalid machine type: {0{}}".format( self.machine_type)) sys.exit() return (FASTDriver(config, self.net_connection.send), (config['number'], config['connection']))
def write_hw_rule(self, sw, sw_activity, coil_action_ms, coil=None, pulse_ms=0, pwm_on=8, pwm_off=8, delay=0, recycle_time=0, debounced=True, drive_now=False): """Used to write (or update) a hardware rule to the FAST controller. *Hardware Rules* are used to configure the hardware controller to automatically change driver states based on switch changes. These rules are completely handled by the hardware (i.e. with no interaction from the Python game code). They're used for things that you want to happen fast, like firing coils when flipper buttons are pushed, slingshots, pop bumpers, etc. You can overwrite existing hardware rules at any time to change or remove them. Args: sw: Which switch you're creating this rule for. The parameter is a reference to the switch object itsef. sw_activity: Int which specifies whether this coil should fire when the switch becomes active (1) or inactive (0) coil_action_ms: Int of the total time (in ms) that this coil action should take place. A value of -1 means it's forever. A value of 0 means the coil disables itself when this switch goes into the state specified. coil: The coil object this rule is for. pulse_ms: How long should the coil be pulsed (ms) pwm_on: Integer 0 (off) through 8 (100% on) for the initial pwm power of this coil pwm_off: pwm level 0-8 of the power of this coil during the hold phase (after the initial kick). delay: Not currently implemented recycle_time: How long (in ms) should this switch rule wait before firing again. Put another way, what's the "fastest" this rule can fire? This is used to prevent "machine gunning" of slingshots and pop bumpers. Do not use it with flippers. debounced: Should the hardware fire this coil after the switch has been debounced? drive_now: Should the hardware check the state of the switches when this rule is firts applied, and fire the coils if they should be? Typically this is True, especially with flippers because you want them to fire if the player is holding in the buttons when the machine enables the flippers (which is done via several calls to this method.) """ if not coil_action_ms: return # with fast this is built into the main coil rule self.log.debug("Setting HW Rule. Switch:%s, Action ms:%s, Coil:%s, " "Pulse:%s, pwm1:%s, pwm2:%s, Delay:%s, Recycle:%s," "Debounced:%s, Now:%s", sw.name, coil_action_ms, coil.name, pulse_ms, pwm_on, pwm_off, delay, recycle_time, debounced, drive_now) if not pwm_on: pwm_on = 8 if not pwm_off: pwm_off = 8 pwm_on = self.pwm8_to_int[pwm_on] pwm_off = self.pwm8_to_int[pwm_off] control = 0x01 # Driver enabled if drive_now: control += 0x08 if sw_activity == 0: control += 0x10 control = Config.int_to_hex_string(int(control)) mode = '00' param1 = 0 param2 = 0 param3 = 0 param4 = 0 param5 = 0 # First figure out if this is pulse (timed) or latched if coil_action_ms == -1: # Latched mode = '18' param1 = pulse_ms # max on time param2 = pwm_on # pwm 1 param3 = pwm_off # pwm 2 param4 = recycle_time #param5 elif coil_action_ms > 0: # Pulsed mode = '10' param1 = pulse_ms # initial pulse param2 = pwm_on # pwm for initial pulse param3 = coil_action_ms - pulse_ms # second on time param4 = pwm_off # pwm for second pulse param5 = recycle_time if coil.number[1] == 1: cmd = 'DN:' else: cmd = 'DL:' param1 = Config.int_to_hex_string(param1) param2 = Config.int_to_hex_string(param2) param3 = Config.int_to_hex_string(param3) param4 = Config.int_to_hex_string(param4) param5 = Config.int_to_hex_string(param5) # hw_rules key = ('05', 1) # all values are strings self.hw_rules[coil] = {'mode': mode, 'param1': param1, 'param2': param2, 'param3': param3, 'param4': param4, 'param5': param5, 'switch': sw.number} cmd = (cmd + coil.number[0] + ',' + control + ',' + sw.number[0] + ',' + mode + ',' + param1 + ',' + param2 + ',' + param3 + ',' + param4 + ',' + param5) # todo change to join() coil.autofire = cmd self.log.debug("Writing hardware rule: %s", cmd) self.net_connection.send(cmd)
def configure_switch(self, config): """Configures the switch object for a FAST Pinball controller. FAST Controllers support two types of switches: `local` and `network`. Local switches are switches that are connected to the FAST controller board itself, and network switches are those connected to a FAST I/O board. MPF needs to know which type of switch is this is. You can specify the switch's connection type in the config file via the ``connection:`` setting (either ``local`` or ``network``). If a connection type is not specified, this method will use some intelligence to try to figure out which default should be used. If the DriverBoard type is ``fast``, then it assumes the default is ``network``. If it's anything else (``wpc``, ``system11``, ``bally``, etc.) then it assumes the connection type is ``local``. Connection types can be mixed and matched in the same machine. """ if not self.net_connection: self.log.critical("A request was made to configure a FAST switch, " "but no connection to a NET processor is " "available") sys.exit() if self.machine_type == 'wpc': # translate switch number to FAST switch config['number'] = self.wpc_switch_map.get( config['number_str'].upper()) if 'connection' not in config: config['connection'] = 0 # local switch (default for WPC) else: config['connection'] = 1 # network switch elif self.machine_type == 'fast': if 'connection' not in config: config['connection'] = 1 # network switch (default for FAST) else: config['connection'] = 0 # local switch if self.config['config_number_format'] == 'int': config['number'] = Config.int_to_hex_string(config['number']) else: config['number'] = Config.normalize_hex_string(config['number']) # convert the switch number into a tuple which is: # (switch number, connection) config['number'] = (config['number'], config['connection']) if 'debounce_open' not in config: config['debounce_open'] = self.config['default_debounce_open'] if 'debounce_close' not in config: config['debounce_close'] = self.config['default_debounce_close'] self.log.debug("FAST Switch hardware tuple: %s", config['number']) switch = FASTSwitch(number=config['number'], debounce_open=config['debounce_open'], debounce_close=config['debounce_close'], sender=self.net_connection.send) return switch, config['number']