Пример #1
0
    def _remove_switch_coil_mapping(self, switch_num, driver: "OPPSolenoid"):
        """Remove mapping between switch and coil."""
        if self.min_version < 0x00020000:
            return

        _, _, coil_num = driver.number.split('-')
        msg = bytearray()
        msg.append(driver.sol_card.addr)
        msg.extend(OppRs232Intf.SET_SOL_INP_CMD)
        msg.append(int(switch_num))
        msg.append(int(coil_num) + ord(OppRs232Intf.CFG_SOL_INP_REMOVE))
        msg.extend(OppRs232Intf.calc_crc8_whole_msg(msg))
        msg.extend(OppRs232Intf.EOM_CMD)
        final_cmd = bytes(msg)

        self.log.debug("Unmapping input %s and coil %s", switch_num, coil_num)
        self.send_to_processor(driver.sol_card.chain_serial, final_cmd)
Пример #2
0
    def vers_resp(self, chain_serial, msg):
        """Process version response.

        Args:
            chain_serial: Serial of the chain which received the message.
            msg: Message to parse.
        """
        # Multiple get version responses can be received at once
        self.log.debug("Received Version Response:%s",
                       "".join(" 0x%02x" % b for b in msg))
        end = False
        curr_index = 0
        while not end:
            # Verify the CRC8 is correct
            crc8 = OppRs232Intf.calc_crc8_part_msg(msg, curr_index, 6)
            if msg[curr_index + 6] != ord(crc8):
                self.badCRC += 1
                hex_string = "".join(" 0x%02x" % b for b in msg)
                self.log.warning("Msg contains bad CRC:%s.", hex_string)
                end = True
            else:
                version = (msg[curr_index + 2] << 24) | \
                    (msg[curr_index + 3] << 16) | \
                    (msg[curr_index + 4] << 8) | \
                    msg[curr_index + 5]
                self.log.debug("Firmware version: %d.%d.%d.%d",
                               msg[curr_index + 2], msg[curr_index + 3],
                               msg[curr_index + 4], msg[curr_index + 5])
                if version < self.minVersion:
                    self.minVersion = version
                if version == BAD_FW_VERSION:
                    raise AssertionError(
                        "Original firmware sent only to Brian before adding "
                        "real version numbers. The firmware must be updated before "
                        "MPF will work.")
            if not end:
                if msg[curr_index + 7] == ord(OppRs232Intf.EOM_CMD):
                    end = True
                elif msg[curr_index + 8] == ord(OppRs232Intf.GET_GET_VERS_CMD):
                    curr_index += 7
                else:
                    hex_string = "".join(" 0x%02x" % b for b in msg)
                    self.log.warning("Malformed GET_VERS_CMD response:%s.",
                                     hex_string)
                    end = True
                    self.opp_connection[chain_serial].lost_synch()
Пример #3
0
    def reconfigure_driver(self, driver, use_hold: bool):
        """Reconfigure a driver.

        Args:
            driver: Driver object.
            use_hold: Whether this driver stays enabled after a trigger or not.
        """
        # If hold is 0, set the auto clear bit
        if not use_hold:
            cmd = ord(OppRs232Intf.CFG_SOL_AUTO_CLR)
            driver.hw_driver.can_be_pulsed = True
            hold = 0
        else:
            cmd = 0
            driver.hw_driver.can_be_pulsed = False
            hold = self.get_hold_value(driver)
            if not hold:
                raise AssertionError("Hold may not be 0")
            if hold >= 16:
                hold = 15
                if self.minVersion >= 0x00020000:
                    # set flag for full power
                    cmd += ord(OppRs232Intf.CFG_SOL_ON_OFF)

        # TODO: implement separate hold power (0-f) and minimum off time (0-7)
        minimum_off = self.get_minimum_off_time(driver)

        if driver.hw_driver.use_switch:
            cmd += ord(OppRs232Intf.CFG_SOL_USE_SWITCH)

        _, solenoid = driver.config['number'].split('-')
        pulse_len = self._get_pulse_ms_value(driver)

        msg = bytearray()
        msg.append(driver.hw_driver.solCard.addr)
        msg.extend(OppRs232Intf.CFG_IND_SOL_CMD)
        msg.append(int(solenoid))
        msg.append(cmd)
        msg.append(pulse_len)
        msg.append(hold + (minimum_off << 4))
        msg.extend(OppRs232Intf.calc_crc8_whole_msg(msg))
        msg.extend(OppRs232Intf.EOM_CMD)
        final_cmd = bytes(msg)

        self.log.debug("Writing individual config: %s", "".join(" 0x%02x" % b for b in final_cmd))
        self.send_to_processor(driver.hw_driver.solCard.chain_serial, final_cmd)
Пример #4
0
    def _parse_gen2_board(self, chain_serial, msg, read_input_msg):
        has_neo = False
        wing_index = 0
        sol_mask = 0
        inp_mask = 0
        incand_mask = 0
        while wing_index < OppRs232Intf.NUM_G2_WING_PER_BRD:
            if msg[2 + wing_index] == ord(OppRs232Intf.WING_SOL):
                sol_mask |= (0x0f << (4 * wing_index))
                inp_mask |= (0x0f << (8 * wing_index))
            elif msg[2 + wing_index] == ord(OppRs232Intf.WING_INP):
                inp_mask |= (0xff << (8 * wing_index))
            elif msg[2 + wing_index] == ord(OppRs232Intf.WING_INCAND):
                incand_mask |= (0xff << (8 * wing_index))
            elif msg[2 + wing_index] == ord(OppRs232Intf.WING_NEO):
                has_neo = True
            wing_index += 1
        if incand_mask != 0:
            self.opp_incands.append(
                OPPIncandCard(chain_serial, msg[0], incand_mask,
                              self.incandDict))
        if sol_mask != 0:
            self.opp_solenoid.append(
                OPPSolenoidCard(chain_serial, msg[0], sol_mask, self.solDict,
                                self))
        if inp_mask != 0:
            # Create the input object, and add to the command to read all inputs
            self.opp_inputs.append(
                OPPInputCard(chain_serial, msg[0], inp_mask, self.inpDict,
                             self.inpAddrDict))

            # Add command to read all inputs to read input message
            inp_msg = bytearray()
            inp_msg.append(msg[0])
            inp_msg.extend(OppRs232Intf.READ_GEN2_INP_CMD)
            inp_msg.append(0)
            inp_msg.append(0)
            inp_msg.append(0)
            inp_msg.append(0)
            inp_msg.extend(OppRs232Intf.calc_crc8_whole_msg(inp_msg))
            read_input_msg.extend(inp_msg)

        if has_neo:
            self.opp_neopixels.append(
                OPPNeopixelCard(chain_serial, msg[0], self.neoCardDict, self))
Пример #5
0
 def _kick_coil(self, sol_int, on):
     mask = 1 << sol_int
     msg = bytearray()
     msg.append(self.solCard.addr)
     msg.extend(OppRs232Intf.KICK_SOL_CMD)
     if on:
         msg.append((mask >> 8) & 0xff)
         msg.append(mask & 0xff)
     else:
         msg.append(0)
         msg.append(0)
     msg.append((mask >> 8) & 0xff)
     msg.append(mask & 0xff)
     msg.extend(OppRs232Intf.calc_crc8_whole_msg(msg))
     cmd = bytes(msg)
     self.log.debug("Triggering solenoid driver: %s",
                    "".join(" 0x%02x" % b for b in cmd))
     self.solCard.platform.send_to_processor(self.solCard.chain_serial, cmd)
Пример #6
0
    def send_vers_cmd(self):
        """Send get firmware version message."""
        whole_msg = bytearray()
        for card_addr in self.platform.gen2_addr_arr[self.chain_serial]:
            msg = bytearray()
            msg.append(card_addr)
            msg.extend(OppRs232Intf.GET_VERS_CMD)
            msg.append(0)
            msg.append(0)
            msg.append(0)
            msg.append(0)
            msg.extend(OppRs232Intf.calc_crc8_whole_msg(msg))
            whole_msg.extend(msg)

        whole_msg.extend(OppRs232Intf.EOM_CMD)
        cmd = bytes(whole_msg)
        self.log.debug("Sending get version command: %s", "".join(" 0x%02x" % b for b in cmd))
        self.send(cmd)
Пример #7
0
    def send_get_gen2_cfg_cmd(self):
        """Send get gen2 configuration message to find populated wing boards."""
        whole_msg = bytearray()
        for card_addr in self.platform.gen2_addr_arr[self.chain_serial]:
            msg = bytearray()
            msg.append(card_addr)
            msg.extend(OppRs232Intf.GET_GEN2_CFG)
            msg.append(0)
            msg.append(0)
            msg.append(0)
            msg.append(0)
            msg.extend(OppRs232Intf.calc_crc8_whole_msg(msg))
            whole_msg.extend(msg)

        whole_msg.extend(OppRs232Intf.EOM_CMD)
        cmd = bytes(whole_msg)
        self.log.debug("Sending get Gen2 Cfg command: %s", "".join(" 0x%02x" % b for b in cmd))
        self.send(cmd)
Пример #8
0
    def get_gen2_cfg_resp(self, chain_serial, msg):
        """Process cfg response.

        Args:
            chain_serial: Serial of the chain which received the message.
            msg: Message to parse.
        """
        # Multiple get gen2 cfg responses can be received at once
        self.log.debug("Received Gen2 Cfg Response:%s",
                       "".join(" 0x%02x" % b for b in msg))
        curr_index = 0
        read_input_msg = bytearray()
        while True:
            # check that message is long enough, must include crc8
            if len(msg) < curr_index + 7:
                self.log.warning("Msg is too short: %s.",
                                 "".join(" 0x%02x" % b for b in msg))
                self.opp_connection[chain_serial].lost_synch()
                break
            # Verify the CRC8 is correct
            crc8 = OppRs232Intf.calc_crc8_part_msg(msg, curr_index, 6)
            if msg[curr_index + 6] != ord(crc8):
                self.badCRC += 1
                self.log.warning("Msg contains bad CRC:%s.",
                                 "".join(" 0x%02x" % b for b in msg))
                break
            self._parse_gen2_board(chain_serial,
                                   msg[curr_index:curr_index + 6],
                                   read_input_msg)

            if (len(msg) > curr_index + 7) and (msg[curr_index + 7] == ord(
                    OppRs232Intf.EOM_CMD)):
                break
            elif (len(msg) > curr_index + 8) and (msg[curr_index + 8] == ord(
                    OppRs232Intf.GET_GEN2_CFG)):
                curr_index += 7
            else:
                self.log.warning("Malformed GET_GEN2_CFG response:%s.",
                                 "".join(" 0x%02x" % b for b in msg))
                self.opp_connection[chain_serial].lost_synch()
                break

        read_input_msg.extend(OppRs232Intf.EOM_CMD)
        self.read_input_msg[chain_serial] = bytes(read_input_msg)
Пример #9
0
    def read_gen2_inp_resp(self, chain_serial, msg):
        """Read switch changes.

        Args:
            chain_serial: Serial of the chain which received the message.
            msg: Message to parse.
        """
        # Single read gen2 input response.  Receive function breaks them down

        # Verify the CRC8 is correct
        if len(msg) < 6:
            self.log.warning("Msg too shortC: %s.", "".join(" 0x%02x" % b for b in msg))
            self.opp_connection[chain_serial].lost_synch()
            return

        crc8 = OppRs232Intf.calc_crc8_part_msg(msg, 0, 6)
        if msg[6] != ord(crc8):
            self.badCRC += 1
            self.log.warning("Msg contains bad CRC:%s.", "".join(" 0x%02x" % b for b in msg))
        else:
            opp_inp = self.inpAddrDict[chain_serial + '-' + str(msg[0])]
            new_state = (msg[2] << 24) | \
                (msg[3] << 16) | \
                (msg[4] << 8) | \
                msg[5]

            # Update the state which holds inputs that are active
            changes = opp_inp.oldState ^ new_state
            if changes != 0:
                curr_bit = 1
                for index in range(0, 32):
                    if (curr_bit & changes) != 0:
                        if (curr_bit & new_state) == 0:
                            self.machine.switch_controller.process_switch_by_num(
                                state=1,
                                num=opp_inp.chain_serial + '-' + opp_inp.cardNum + '-' + str(index),
                                platform=self)
                        else:
                            self.machine.switch_controller.process_switch_by_num(
                                state=0,
                                num=opp_inp.chain_serial + '-' + opp_inp.cardNum + '-' + str(index),
                                platform=self)
                    curr_bit <<= 1
            opp_inp.oldState = new_state
Пример #10
0
    def read_matrix_inp_resp_initial(self, chain_serial, msg):
        """Read initial matrix switch states.

        Args:
            chain_serial: Serial of the chain which received the message.
            msg: Message to parse.
        """
        # Verify the CRC8 is correct
        if len(msg) < 11:
            raise AssertionError("Received too short initial input response: " + "".join(" 0x%02x" % b for b in msg))
        crc8 = OppRs232Intf.calc_crc8_part_msg(msg, 0, 10)
        if msg[10] != ord(crc8):
            self.badCRC += 1
            self.log.warning("Msg contains bad CRC:%s.", "".join(" 0x%02x" % b for b in msg))
        else:
            if chain_serial + '-' + str(msg[0]) not in self.matrixInpAddrDict:
                self.log.warning("Got input response for invalid matrix card at initial request: %s. Msg: %s.", msg[0],
                                 "".join(" 0x%02x" % b for b in msg))
                return
            opp_inp = self.matrixInpAddrDict[chain_serial + '-' + str(msg[0])]
            opp_inp.oldState = ((msg[2] << 56) | (msg[3] << 48) | (msg[4] << 40) | (msg[5] << 32) |
                                (msg[6] << 24) | (msg[7] << 16) | (msg[8] << 8) | msg[9])
Пример #11
0
    def read_gen2_inp_resp_initial(self, chain_serial, msg):
        """Read initial switch states.

        Args:
            chain_serial: Serial of the chain which received the message.
            msg: Message to parse.
        """
        # Verify the CRC8 is correct
        if len(msg) < 6:
            raise AssertionError("Received too short initial input response: " + "".join(" 0x%02x" % b for b in msg))
        crc8 = OppRs232Intf.calc_crc8_part_msg(msg, 0, 6)
        if msg[6] != ord(crc8):
            self.badCRC += 1
            self.log.warning("Msg contains bad CRC:%s.", "".join(" 0x%02x" % b for b in msg))
        else:
            opp_inp = self.inpAddrDict[chain_serial + '-' + str(msg[0])]
            new_state = (msg[2] << 24) | \
                (msg[3] << 16) | \
                (msg[4] << 8) | \
                msg[5]

            opp_inp.oldState = new_state
Пример #12
0
    def update_incand(self):
        """Update all the incandescents connected to OPP hardware.

        This is done once per game loop if changes have been made.

        It is currently assumed that the oversampling will guarantee proper communication
        with the boards.  If this does not end up being the case, this will be changed
        to update all the incandescents each loop.

        Note:  This could be made much more efficient by supporting a command
        that simply sets the state of all 32 of the LEDs as either on or off.
        """
        for incand in self.opp_incands:
            whole_msg = bytearray()
            # Check if any changes have been made
            if (incand.oldState ^ incand.newState) != 0:
                # Update card
                incand.oldState = incand.newState
                msg = bytearray()
                msg.append(incand.addr)
                msg.extend(OppRs232Intf.INCAND_CMD)
                msg.extend(OppRs232Intf.INCAND_SET_ON_OFF)
                msg.append((incand.newState >> 24) & 0xff)
                msg.append((incand.newState >> 16) & 0xff)
                msg.append((incand.newState >> 8) & 0xff)
                msg.append(incand.newState & 0xff)
                msg.extend(OppRs232Intf.calc_crc8_whole_msg(msg))
                whole_msg.extend(msg)

            if len(whole_msg) != 0:
                whole_msg.extend(OppRs232Intf.EOM_CMD)
                send_cmd = bytes(whole_msg)

                self.send_to_processor(incand.chain_serial, send_cmd)
                self.log.debug("Update incand cmd:%s",
                               "".join(" 0x%02x" % b for b in send_cmd))
Пример #13
0
    def reconfigure_driver(self,
                           pulse_settings: PulseSettings,
                           hold_settings: Optional[HoldSettings],
                           recycle: bool = False):
        """Reconfigure a driver."""
        new_config_state = (pulse_settings, hold_settings, recycle,
                            bool(self.switch_rule))

        # if config would not change do nothing
        if new_config_state == self._config_state:
            return

        self._config_state = new_config_state

        # If hold is 0, set the auto clear bit
        if not hold_settings or not hold_settings.power:
            cmd = ord(OppRs232Intf.CFG_SOL_AUTO_CLR)
            hold = 0
        else:
            cmd = 0
            hold = int(hold_settings.power * 16)
            if hold >= 16:
                if self.solCard.platform.minVersion >= 0x00020000:
                    # set flag for full power
                    cmd += ord(OppRs232Intf.CFG_SOL_ON_OFF)
                    hold = 0
                else:
                    hold = 15

        minimum_off = self.get_minimum_off_time(recycle)
        _, _, solenoid = self.number.split('-')

        # Before version 0.2.0.0 set solenoid input wasn't available.
        # CFG_SOL_USE_SWITCH was used to enable/disable a solenoid.  This
        # will work as long as switches are added using _add_switch_coil_mapping
        if self.switch_rule:
            if self.solCard.platform.minVersion < 0x00020000:
                cmd += ord(OppRs232Intf.CFG_SOL_USE_SWITCH)
            elif str(((int(solenoid) & 0x0c) << 1) | (int(solenoid) & 0x03)) in\
                    [switch.split('-')[2] for switch in self.switches]:
                # If driver is using matching switch set CFG_SOL_USE_SWITCH
                # in case config happens after set switch command
                cmd += ord(OppRs232Intf.CFG_SOL_USE_SWITCH)

        pulse_len = pulse_settings.duration

        msg = bytearray()
        msg.append(self.solCard.addr)
        msg.extend(OppRs232Intf.CFG_IND_SOL_CMD)
        msg.append(int(solenoid))
        msg.append(cmd)
        msg.append(pulse_len)
        msg.append(hold + (minimum_off << 4))
        msg.extend(OppRs232Intf.calc_crc8_whole_msg(msg))
        msg.extend(OppRs232Intf.EOM_CMD)
        final_cmd = bytes(msg)

        self.log.debug("Writing individual config: %s",
                       "".join(" 0x%02x" % b for b in final_cmd))
        self.solCard.platform.send_to_processor(self.solCard.chain_serial,
                                                final_cmd)
Пример #14
0
 def _crc_message(self, msg, term=True):
     crc_msg = msg + OppRs232Intf.calc_crc8_part_msg(msg, 0, len(msg))
     if term:
         crc_msg += b'\xff'
     return crc_msg