示例#1
1
class TouchPiano:
    """
    As you touch one of the touch inputs, A1 - A7, a note will be played.
    """

    def __init__(self):
        # 7 musical note frequencies - starting at middle c
        self.the_notes = [440, 493, 523, 587, 659, 698, 784]

        # instantiate pymatacpx
        self.p = PyMataCpx()

        # turn on all touch pads 1-7
        for touch_pad in range(1, 8):
            self.p.cpx_cap_touch_start(touch_pad, self.play_notes)
        # self.p.cpx_cap_touch_start(4, self.play_notes)

        self.max = 0

        print()
        print('Touch one of the touch pads, A1 - A7, and a note will play.')

        while True:
            # just kill time waiting for a light data to arrive
            try:
                time.sleep(.001)
            except KeyboardInterrupt:
                # If you press control-C, cleanly exit
                self.p.cpx_close_and_exit()

    def play_notes(self, data):
        # determine if the pad was touched or released
        if data[2]:
            # get the note
            try:
                note = self.the_notes[data[1] - 1]
            except IndexError:
                print(data[1])
                raise

            # play the note
            self.p.cpx_tone(note, 0)

        else:
            # touch pad released - turn off the note
            self.p.cpx_tone_off()
示例#2
0
class CpxGateway(GatewayBase, threading.Thread):
    """
    This class is the interface class for the Circuit Playground
    Express supporting Scratch 3.
    """
    def __init__(self,
                 *subscriber_list,
                 back_plane_ip_address=None,
                 subscriber_port='43125',
                 publisher_port='43124',
                 process_name='CpxGateway',
                 publisher_topic=None,
                 log=False):
        """
        :param subscriber_list: a tuple or list of subscription topics.
        :param back_plane_ip_address:
        :param subscriber_port:
        :param publisher_port:
        :param process_name:
        """

        # initialize parent
        super(CpxGateway,
              self).__init__(subscriber_list=subscriber_list,
                             back_plane_ip_address=back_plane_ip_address,
                             subscriber_port=subscriber_port,
                             publisher_port=publisher_port,
                             process_name=process_name)
        self.log = log
        if self.log:
            fn = str(pathlib.Path.home()) + "/cpxgw.log"
            self.logger = logging.getLogger(__name__)
            logging.basicConfig(filename=fn, filemode='w', level=logging.DEBUG)
            sys.excepthook = self.my_handler

        self.publisher_topic = publisher_topic
        self.cpx = PyMataCpx()
        atexit.register(self.shutdown)

        # hold the time of the last analog data to be received.
        # use to determine if connectivity is gone.
        self.last_analog_data_time = None

        # start up all the sensors
        self.cpx.cpx_accel_start(self.tilt_callback)
        self.cpx.cpx_button_a_start(self.switch_callback)
        self.cpx.cpx_button_b_start(self.switch_callback)
        self.cpx.cpx_slide_switch_start(self.switch_callback)

        self.cpx.cpx_light_sensor_start(self.analog_callback)
        self.cpx.cpx_microphone_start(self.analog_callback)
        self.cpx.cpx_temperature_start(self.analog_callback)
        for touch_pad in range(1, 8):
            self.cpx.cpx_cap_touch_start(touch_pad, self.touchpad_callback)

        threading.Thread.__init__(self)
        self.daemon = True

        # start the watchdog thread
        self.start()
        # start the banyan receive loop
        try:
            self.receive_loop()
        except:
            pass
        # except KeyboardInterrupt:
        # except KeyboardInterrupt:
        # self.cpx.cpx_close_and_exit()
        # sys.exit(0)
        #     os._exit(1)

    def init_pins_dictionary(self):
        pass

    def play_tone(self, topic, payload):
        """
        This method plays a tone on a piezo device connected to the selected
        pin at the frequency and duration requested.
        Frequency is in hz and duration in milliseconds.

        Call set_mode_tone before using this method.
        :param topic: message topic
        :param payload: {"command": "play_tone", "pin": “PIN”, "tag": "TAG",
                         “freq”: ”FREQUENCY”, duration: “DURATION”}
        """
        self.cpx.cpx_tone(payload['freq'], payload['duration'])

    def additional_banyan_messages(self, topic, payload):
        if payload['command'] == 'pixel':
            self.set_pixel(payload)

    def set_pixel(self, payload):
        self.cpx.cpx_pixel_set(payload['pixel'], payload['red'],
                               payload['green'], payload['blue'])
        self.cpx.cpx_pixels_show()

    def digital_write(self, topic, payload):
        """
        This method performs a digital write to the board LED
        :param topic: message topic
        :param payload: {"command": "digital_write", "pin": “PIN”, "value": “VALUE”}
        """
        if payload['value']:
            self.cpx.cpx_board_light_on()
        else:
            self.cpx.cpx_board_light_off()

    # The CPX sensor callbacks

    def tilt_callback(self, data):
        """
        Report the tilt of the express board

        Take the raw xyz data and transform it to
        positional strings.
        :param data: data [0] = data mode 32 is analog.
                     data[1] = the pin number - this is a pseudo pin number
                     data[2] = x value
                     data[3] = y value
                     data[4] = z value
        """
        x = data[2]
        y = data[3]
        z = data[4]

        # Convert raw Accelerometer values to degrees
        x_angle = int((math.atan2(y, z) + math.pi) * (180 / math.pi))
        y_angle = int((math.atan2(z, x) + math.pi) * (180 / math.pi))

        h = v = -1

        if 175 < x_angle < 185 and 265 < y_angle < 275:
            h = v = 0  # 'flat'

        elif h or v:
            if 180 <= x_angle <= 270:
                v = 1  # up

            elif 90 <= x_angle <= 180:
                v = 2  # down

            if 180 <= y_angle <= 270:
                h = 3  # left

            elif 270 <= y_angle <= 360:
                h = 4  # right

        payload = {'report': 'tilted', 'value': [v, h]}
        self.publish_payload(payload, 'from_cpx_gateway')

    def switch_callback(self, data):
        """
        This handles switches a, b, and slide
        :param data: data[1] - a=4 b=5, slice=7,
        """
        if data[1] == 4:
            switch = 'a'
        elif data[1] == 5:
            switch = 'b'
        else:
            # 0 = right, 1 = left
            switch = 'slide'

        payload = {'report': switch, 'value': data[2]}
        self.publish_payload(payload, 'from_cpx_gateway')

    def analog_callback(self, data):
        """
        This handles the light, temperature and sound sensors.

        It also sets up a "watchdog timer" and if there is no activity
        for > 1 second will exit.


        :param data: data[1] - 8 = light, temp = 9, 10 = sound,
        """

        self.last_analog_data_time = time.time()

        if data[1] == 8:
            sensor = 'light'
        elif data[1] == 9:
            sensor = 'temp'
        else:
            sensor = 'sound'
        payload = {'report': sensor, 'value': round(data[2], 2)}
        self.publish_payload(payload, 'from_cpx_gateway')

    def touchpad_callback(self, data):
        """
        Build and send a banyan message for the pad and value
        :param data: data[1] = touchpad and data[2] = boolean value
        """
        payload = {'report': 'touch' + str(data[1]), 'value': int(data[2])}
        self.publish_payload(payload, 'from_cpx_gateway')

    def shutdown(self):
        try:
            self.cpx.cpx_close_and_exit()
            sys.exit(0)
        except serial.serialutil.SerialException:
            pass

    def my_handler(self, xtype, value, tb):
        """
        for logging uncaught exceptions
        :param xtype:
        :param value:
        :param tb:
        :return:
        """
        self.logger.exception("Uncaught exception: {0}".format(str(value)))

    def run(self):
        if not self.last_analog_data_time:
            self.last_analog_data_time = time.time()
        while True:
            if time.time() - self.last_analog_data_time > 1.0:
                print('Watchdog timed out - exiting.')
                os._exit(1)

            time.sleep(1)