Example #1
0
    def build_header(self, run_asap=None, statemachine_body_size=0):
        message = [ord(SendMessageHeader.NEW_STATE_MATRIX)]
        message += [0 if run_asap is None else 1]
        message += [1 if self.use_255_back_signal else 0]

        return ArduinoTypes.get_uint8_array(
            message) + ArduinoTypes.get_uint16_array([statemachine_body_size])
Example #2
0
    def set_thresholds(self, thresholds):
        """
        Sets the thresholds values to trigger the events.

        :ivar list(int) thresholds: List, in maximum, of 6 thresholds to trigger events.
        """
        data = ArduinoTypes.get_uint8_array([self.COM_SETTHRESHOLDS, len(thresholds)])
        data += ArduinoTypes.get_uint16_array([self.__degrees_2_pos(thresh) for thresh in thresholds])
        self.arcom.write_array(data)
        return self.arcom.read_uint8() == 1
Example #3
0
    def _bpodcom_read_timestamps(self):

        data = self._arcom.read_bytes_array(12)

        n_hw_timer_cyles = ArduinoTypes.cvt_uint32(b''.join(data[:4]))
        trial_end_micros = ArduinoTypes.cvt_uint64(b''.join(
            data[4:12]))  # / float(self.hardware.DEFAULT_FREQUENCY_DIVIDER)
        trial_end_timestamp = trial_end_micros / float(
            self.hardware.DEFAULT_FREQUENCY_DIVIDER)
        trial_time_from_micros = trial_end_timestamp - self.trial_start_timestamp
        trial_time_from_cycles = n_hw_timer_cyles / self.hardware.cycle_frequency
        discrepancy = abs(trial_time_from_micros -
                          trial_time_from_cycles) * 1000

        return trial_end_timestamp, discrepancy
Example #4
0
    def _bpodcom_enable_ports(self, hardware):
        """
        Enable input ports on Bpod device

        :param list[int] inputs_enabled: list of inputs to be enabled (0 = disabled, 1 = enabled)
        :rtype: bool
        """

        hardware.configure_inputs()

        logger.debug("Requesting ports enabling (%s)",
                     SendMessageHeader.ENABLE_PORTS)
        logger.debug("Inputs enabled (%s): %s", len(hardware.inputs_enabled),
                     hardware.inputs_enabled)

        bytes2send = ArduinoTypes.get_uint8_array(
            [ord(SendMessageHeader.ENABLE_PORTS)] + hardware.inputs_enabled)

        self._arcom.write_array(bytes2send)

        response = self._arcom.read_uint8()  # type: int

        logger.debug("Response: %s", response)

        return True if response == ReceiveMessageHeader.ENABLE_PORTS_OK else False
Example #5
0
    def build_message_32_bits(self):
        """
        Builds a 32 bit message to send to Bpod box

        :rtype: list(float)
        """
        # TODO find how many global timers are used
        """
        thirty_two_bit_message = [i * self.hardware.cycle_frequency for i in self.state_timers] + \
                                 [i * self.hardware.cycle_frequency for i in self.global_timers.timers] + \
                                 [i * self.hardware.cycle_frequency for i in self.global_timers.on_set_delays] + \
                                 [i * self.hardware.cycle_frequency for i in self.global_timers.loop_intervals] + \
                                 self.global_counters.thresholds"""

        used_timers = range(self.highest_used_global_timer)
        used_counters = range(self.highest_used_global_counter)

        thirty_two_bit_message = (
            [t * self.hardware.cycle_frequency for t in self.state_timers] + [
                self.global_timers.timers[i] * self.hardware.cycle_frequency
                for i in used_timers
            ] + [
                self.global_timers.on_set_delays[i] *
                self.hardware.cycle_frequency for i in used_timers
            ] + [
                self.global_timers.loop_intervals[i] *
                self.hardware.cycle_frequency for i in used_timers
            ] + [self.global_counters.thresholds[i] for i in used_counters])

        return ArduinoTypes.get_uint32_array(thirty_two_bit_message)
Example #6
0
 def _bpodcom_resume_trial(self):
     """
     Resumes ongoing trial (We recommend using computer-side pauses between trials, to keep data uniform)
     """
     logger.debug("Resume trial")
     bytes2send = ArduinoTypes.get_uint8_array(
         [ord(SendMessageHeader.PAUSE_TRIAL), 1])
     self._arcom.write_array(bytes2send)
Example #7
0
 def _bpodcom_send_softcode(self, softcode):
     """
     Send soft code
     """
     logger.debug("Send softcode")
     bytes2send = ArduinoTypes.get_uint8_array(
         [ord(SendMessageHeader.TRIGGER_SOFTCODE), softcode])
     self._arcom.write_array(bytes2send)
Example #8
0
    def set_wrappoint(self, wrap_point):
        """
        Sets wrap point (number of tics in a half-rotation)

        :ivar int wrap_point: number of tics in a half-rotation.
        """
        ticks = self.__degrees_2_pos(wrap_point)
        self.arcom.write_array([self.COM_SETWRAPPOINT] + ArduinoTypes.get_uint16_array([ticks]))
        return self.arcom.read_uint8() == 1
Example #9
0
    def build_message_global_timer(self):

        message = []

        for i in range(self.total_states_added):
            message += (self.global_timers.triggers_matrix[i], )

        for i in range(self.total_states_added):
            message += (self.global_timers.cancels_matrix[i], )

        for i in range(self.highest_used_global_timer):
            message += (self.global_timers.onset_matrix[i], )

        if self.hardware.n_global_timers > 16:
            return ArduinoTypes.get_uint32_array(message)
        elif self.hardware.n_global_timers > 8:
            return ArduinoTypes.get_uint16_array(message)
        else:
            return ArduinoTypes.get_uint8_array(message)
Example #10
0
    def _bpodcom_send_byte_to_hardware_serial(self, channel_number, value):
        """
        Send byte to hardware serial channel 1-3

        :param int channel_number:
        :param int value: value to be written
        """
        bytes2send = ArduinoTypes.get_uint8_array(
            [ord(SendMessageHeader.SEND_TO_HW_SERIAL), channel_number, value])
        self._arcom.write_array(bytes2send)
Example #11
0
 def _bpodcom_manual_override_exec_event(self, event_index, event_data):
     """
     Send soft code
     """
     logger.debug("Manual override execute virtual event")
     bytes2send = ArduinoTypes.get_uint8_array([
         ord(SendMessageHeader.MANUAL_OVERRIDE_EXEC_EVENT), event_index,
         event_data
     ])
     self._arcom.write_array(bytes2send)
Example #12
0
    def _bpodcom_echo_softcode(self, softcode):
        """
        Send soft code
        """
        logger.debug("Echo softcode")
        self._arcom.write_char(SendMessageHeader.ECHO_SOFTCODE)
        self._arcom.write_char(softcode)

        bytes2send = ArduinoTypes.get_uint8_array(
            [ord(SendMessageHeader.ECHO_SOFTCODE), softcode])
        self._arcom.write_array(bytes2send)
Example #13
0
    def set_position(self, degrees):
        """
        Sets the current position in degrees.

        :ivar int degrees: current position in degrees.
        """
        ticks = self.__degrees_2_pos(degrees)
        data = ArduinoTypes.get_uint8_array([self.COM_SETPOS])
        data += ticks.to_bytes(2, byteorder='little', signed=True)

        self.arcom.write_array(data)
        return self.arcom.read_uint8() == 1
    def _bpodcom_module_write(self, module_index, message, dtype=None):
        if dtype is None:
            dtype = ArduinoTypes.UINT8

        if isinstance(message, str):
            message = [ord(c) for c in message]
        elif not isinstance(message, (list, np.ndarray)):
            message = [message]
        else:
            message = message

        msg = ArduinoTypes.get_array(message, dtype)

        if len(msg) > 64:
            raise BpodErrorException(
                "Error: module messages must be under 64 bytes per transmission"
            )

        to_send = [ord(SendMessageHeader.WRITE_TO_MODULE), module_index + 1, len(msg)]
        to_send = ArduinoTypes.get_uint8_array(to_send)

        self._arcom.write_array(to_send + msg)
Example #15
0
    def _bpodcom_override_digital_hardware_state(self, channel_number, value):
        """
        Manually set digital value on channel

        :param int channel_number: number of Bpod port
        :param int value: value to be written
        """

        bytes2send = ArduinoTypes.get_uint8_array([
            ord(SendMessageHeader.OVERRIDE_DIGITAL_HW_STATE), channel_number,
            value
        ])
        self._arcom.write_array(bytes2send)
Example #16
0
    def _bpodcom_override_input_state(self, channel_number, value):
        """
        Manually set digital value on channel

        :param int channel_number: number of Bpod port
        :param int value: value to be written
        """
        logger.debug("Override input state")

        bytes2send = ArduinoTypes.get_uint8_array([
            ord(SendMessageHeader.MANUAL_OVERRIDE_EXEC_EVENT), channel_number,
            value
        ])
        self._arcom.write_array(bytes2send)
Example #17
0
    def _bpodcom_load_serial_message(self, serial_channel, message_id,
                                     serial_message, n_messages):
        """
        Load serial message on channel

        :param TODO
        :rtype: bool
        """
        # self.__bpodcom_check_com_ready()

        if isinstance(serial_channel, BpodModule):
            serial_channel = serial_channel.serial_port

        self.msg_id_list[message_id] = True

        if len(serial_message) > 3:
            raise BpodErrorException(
                'Error: Serial messages cannot be more than 3 bytes in length.'
            )

        if not (1 <= message_id <= 255):
            raise BpodErrorException(
                'Error: Bpod can only store 255 serial messages (indexed 1-255). You used the message_id {0}'
                .format(message_id))

        message_container = [
            serial_channel - 1, n_messages, message_id,
            len(serial_message)
        ] + serial_message

        logger.debug("Requesting load serial message (%s)",
                     SendMessageHeader.LOAD_SERIAL_MESSAGE)
        logger.debug("Message: %s", message_container)

        bytes2send = ArduinoTypes.get_uint8_array(
            [ord(SendMessageHeader.LOAD_SERIAL_MESSAGE)] + message_container)

        self._arcom.write_array(bytes2send)

        response = self._arcom.read_uint8()  # type: int

        logger.debug("Confirmation: %s", response)

        return True if response == ReceiveMessageHeader.LOAD_SERIAL_MESSAGE_OK else False
Example #18
0
    def _bpodcom_set_sync_channel_and_mode(self, sync_channel, sync_mode):
        """
        Request sync channel and sync mode configuration

        :param int sync_channel: 255 = no sync, otherwise set to a hardware channel number
        :param int sync_mode: 0 = flip logic every trial, 1 = every state
        :rtype: bool
        """

        logger.debug("Requesting sync channel and mode (%s)",
                     SendMessageHeader.SYNC_CHANNEL_MODE)

        bytes2send = ArduinoTypes.get_uint8_array([
            ord(SendMessageHeader.SYNC_CHANNEL_MODE), sync_channel, sync_mode
        ])

        self._arcom.write_array(bytes2send)

        response = self._arcom.read_uint8()  # type: int

        logger.debug("Response: %s", response)

        return True if response == ReceiveMessageHeader.SYNC_CHANNEL_MODE_OK else False
Example #19
0
    def _bpodcom_enable_ports(self, hardware):
        """
        Enable input ports on Bpod device

        :param list[int] inputs_enabled: list of inputs to be enabled (0 = disabled, 1 = enabled)
        :rtype: bool
        """

        ###### set inputs enabled or disabled #######################################################
        hardware.inputs_enabled = [0] * len(hardware.inputs)

        for j, i in enumerate(hardware.bnc_inputports_indexes):
            hardware.inputs_enabled[i] = settings.BPOD_BNC_PORTS_ENABLED[j]

        for j, i in enumerate(hardware.wired_inputports_indexes):
            hardware.inputs_enabled[i] = settings.BPOD_WIRED_PORTS_ENABLED[j]

        for j, i in enumerate(hardware.behavior_inputports_indexes):
            hardware.inputs_enabled[i] = settings.BPOD_BEHAVIOR_PORTS_ENABLED[
                j]
        #############################################################################################

        logger.debug("Requesting ports enabling (%s)",
                     SendMessageHeader.ENABLE_PORTS)
        logger.debug("Inputs enabled (%s): %s", len(hardware.inputs_enabled),
                     hardware.inputs_enabled)

        bytes2send = ArduinoTypes.get_uint8_array(
            [ord(SendMessageHeader.ENABLE_PORTS)] + hardware.inputs_enabled)

        self._arcom.write_array(bytes2send)

        response = self._arcom.read_uint8()  # type: int

        logger.debug("Response: %s", response)

        return True if response == ReceiveMessageHeader.ENABLE_PORTS_OK else False
    def _bpodcom_get_modules_info(self, hardware):

        bpod_modules = BpodModules(self)  # type: BpodModules

        input_modules = [inp for inp in hardware.inputs if inp == "U"]
        n_modules = len(input_modules)
        n_serial_events = int(hardware.max_serial_events / (n_modules + 1))

        self._arcom.write_char(SendMessageHeader.GET_MODULES)
        time.sleep(0.3)

        modules_requested_events = np.array([0] * n_modules)

        names = {}

        if self._arcom.bytes_available() > 1:
            for i in range(n_modules):
                connected = self._arcom.read_uint8() == 1
                firmware_version = None
                module_name = None
                events_names = []

                if connected:
                    firmware_version = self._arcom.read_uint32()
                    name_length = self._arcom.read_uint8()
                    name_string = self._arcom.read_char_array(name_length)
                    name_string = "".join(name_string)

                    if name_string not in names:
                        names[name_string] = 0
                    names[name_string] += 1

                    module_name = name_string + str(names[name_string])

                    flag = self._arcom.read_uint8()
                    while flag == 1:  # has more info to be read
                        param_type = self._arcom.read_uint8()

                        if param_type == ReceiveMessageHeader.MODULE_REQUESTED_EVENT:
                            modules_requested_events[i] = self._arcom.read_uint8()

                        elif param_type == ReceiveMessageHeader.MODULE_EVENT_NAMES:

                            n_event_names = self._arcom.read_uint8()
                            for _ in range(n_event_names):
                                n_chars = self._arcom.read_uint8()
                                event_name = self._arcom.read_char_array(n_chars)
                                events_names.append("".join(event_name))

                        flag = self._arcom.read_uint8()

                bpod_modules += BpodModules.create_module(
                    connected,
                    module_name,
                    firmware_version,
                    events_names,
                    n_serial_events,
                    serial_port=i + 1,
                )

        if (
            modules_requested_events.sum() + n_serial_events
        ) > hardware.max_serial_events:
            raise BpodErrorException(
                "Error: Connected modules requested too many events."
            )

        for i, module in enumerate(bpod_modules):
            if module.connected:

                if modules_requested_events[i] > module.n_serial_events:
                    n_to_reassign = modules_requested_events[i] - module.n_serial_events
                    module.n_serial_events = modules_requested_events[i]
                else:
                    n_to_reassign = 0

                index = n_modules - 1
                while n_to_reassign > 0:
                    if bpod_modules[index].n_serial_events >= n_to_reassign:
                        bpod_modules[index].n_serial_events = (
                            bpod_modules[index].n_serial_events - n_to_reassign
                        )
                        n_to_reassign = 0
                    else:
                        n_to_reassign = (
                            n_to_reassign - bpod_modules[index].n_serial_events
                        )
                        bpod_modules[index].n_serial_events = 0
                    index -= 1

        n_serial_events_array = [m.n_serial_events for m in bpod_modules]
        n_soft_codes = hardware.max_serial_events - sum(n_serial_events_array)

        bytes2send = ArduinoTypes.get_uint8_array(
            [ord("%")] + n_serial_events_array + [n_soft_codes]
        )

        self._arcom.write_array(bytes2send)
        res = self._arcom.read_uint8()

        if not res:
            raise BpodErrorException(
                "Error: Failed to configure module event assignment."
            )

        return bpod_modules
Example #21
0
    def build_message(self):
        """
        Builds state machine to send to Bpod box

        :rtype: list(int)
        """
        self.highest_used_global_counter = self.global_counters.get_max_index_used(
        )
        self.highest_used_global_timer = self.global_timers.get_max_index_used(
        )
        self.highest_used_global_condition = self.conditions.get_max_index_used(
        )

        self.highest_used_global_counter = (
            0 if self.highest_used_global_counter is None else
            self.highest_used_global_counter + 1)
        self.highest_used_global_timer = (
            0 if self.highest_used_global_timer is None else
            self.highest_used_global_timer + 1)
        self.highest_used_global_condition = (
            0 if self.highest_used_global_condition is None else
            self.highest_used_global_condition + 1)

        message = [
            self.total_states_added,
            self.highest_used_global_timer,
            self.highest_used_global_counter,
            self.highest_used_global_condition,
        ]

        # STATE TIMER MATRIX
        # Send state timer transitions (for all states)
        tmp = []
        for i in range(self.total_states_added):
            tmp += [
                self.total_states_added if math.isnan(
                    self.state_timer_matrix[i]) else self.state_timer_matrix[i]
            ]

        message += tmp
        logger.debug("STATE TIMER MATRIX: %s", tmp)

        # INPUT MATRIX
        # Send event-triggered transitions (where they are different from default)
        tmp = []
        for i in range(self.total_states_added):

            state_transitions = self.input_matrix[i]
            n_transitions = len(state_transitions)
            tmp += [n_transitions]
            for transition in state_transitions:
                tmp += [transition[0]]
                dest_state = transition[1]
                tmp += [
                    self.total_states_added
                    if math.isnan(dest_state) else dest_state
                ]
        message += tmp
        logger.debug("INPUT MATRIX: %s", tmp)

        # OUTPUT MATRIX
        # Send hardware states (where they are different from default)
        tmp = []
        for i in range(self.total_states_added):
            hw_state = self.output_matrix[i]
            hw_state = [
                evt for evt in hw_state if evt[0] <
                self.hardware.channels.events_positions.globalTimerTrigger
            ]
            n_differences = len(hw_state)
            tmp += [n_differences]
            for hw_conf in hw_state:
                tmp += hw_conf[:2]
        message += tmp
        logger.debug("OUTPUT MATRIX: %s", tmp)

        # GLOBAL_TIMER_START_MATRIX
        # Send global timer-start triggered transitions (where they are different from default)
        tmp = []
        for i in range(self.total_states_added):
            state_transitions = self.global_timers.start_matrix[i]
            n_transitions = len(state_transitions)
            tmp += [n_transitions]
            for transition in state_transitions:
                dest_state = transition[1]
                tmp += [
                    transition[0] -
                    self.hardware.channels.events_positions.globalTimerStart
                ]
                tmp += [
                    self.total_states_added
                    if math.isnan(dest_state) else dest_state
                ]
        message += tmp
        logger.debug("GLOBAL_TIMER_START_MATRIX: %s", tmp)

        # GLOBAL_TIMER_END_MATRIX
        # Send global timer-end triggered transitions (where they are different from default)
        tmp = []
        for i in range(self.total_states_added):
            state_transitions = self.global_timers.end_matrix[i]
            n_transitions = len(state_transitions)
            tmp += [n_transitions]
            for transition in state_transitions:
                dest_state = transition[1]
                tmp += [
                    transition[0] -
                    self.hardware.channels.events_positions.globalTimerEnd
                ]
                tmp += [
                    self.total_states_added
                    if math.isnan(dest_state) else dest_state
                ]
        message += tmp
        logger.debug("GLOBAL_TIMER_END_MATRIX: %s", tmp)

        # GLOBAL_COUNTER_MATRIX
        # Send global counter triggered transitions (where they are different from default)
        tmp = []
        for i in range(self.total_states_added):
            state_transitions = self.global_counters.matrix[i]
            n_transitions = len(state_transitions)
            tmp += [n_transitions]
            for transition in state_transitions:
                dest_state = transition[1]
                tmp += [
                    transition[0] -
                    self.hardware.channels.events_positions.globalCounter
                ]
                tmp += [
                    self.total_states_added
                    if math.isnan(dest_state) else dest_state
                ]
        message += tmp
        logger.debug("GLOBAL_COUNTER_MATRIX: %s", tmp)

        # CONDITION_MATRIX
        # Send condition triggered transitions (where they are different from default)
        tmp = []
        for i in range(self.total_states_added):
            state_transitions = self.conditions.matrix[i]
            n_transitions = len(state_transitions)
            tmp += [n_transitions]
            for transition in state_transitions:
                dest_state = transition[1]
                tmp += [
                    transition[0] -
                    self.hardware.channels.events_positions.condition
                ]
                tmp += [
                    self.total_states_added
                    if math.isnan(dest_state) else dest_state
                ]

        message += tmp
        logger.debug("CONDITION_MATRIX: %s", tmp)

        # GLOBAL_TIMER_CHANNELS
        tmp = []
        for i in range(self.highest_used_global_timer):
            tmp += [self.global_timers.channels[i]]
        message += tmp
        logger.debug("GLOBAL_TIMER_CHANNELS: %s", tmp)

        # GLOBAL_TIMER_ON_MESSAGES
        tmp = []
        for i in range(self.highest_used_global_timer):
            v = self.global_timers.on_messages[i]
            tmp += [255 if v == 0 else v]
        message += tmp
        logger.debug("GLOBAL_TIMER_ON_MESSAGES: %s", tmp)

        # GLOBAL_TIMER_OFF_MESSAGES
        tmp = []
        for i in range(self.highest_used_global_timer):
            v = self.global_timers.off_messages[i]
            tmp += [255 if v == 0 else v]
        message += tmp
        logger.debug("GLOBAL_TIMER_OFF_MESSAGES: %s", tmp)

        # GLOBAL_TIMER_LOOP_MODE
        tmp = []
        for i in range(self.highest_used_global_timer):
            tmp += [self.global_timers.loop_mode[i]]
        message += tmp
        logger.debug("GLOBAL_TIMER_LOOP_MODE: %s", tmp)

        # GLOBAL_TIMER_EVENTS
        tmp = []
        for i in range(self.highest_used_global_timer):
            tmp += [self.global_timers.send_events[i]]
        message += tmp
        logger.debug("GLOBAL_TIMER_EVENTS: %s", tmp)

        # GLOBAL_COUNTER_ATTACHED_EVENTS
        tmp = []
        for i in range(self.highest_used_global_counter):
            tmp += [self.global_counters.attached_events[i]]
        message += tmp
        logger.debug("GLOBAL_COUNTER_ATTACHED_EVENTS: %s", tmp)

        # CONDITIONS_CHANNELS
        tmp = []
        for i in range(self.highest_used_global_condition):
            tmp += [self.conditions.channels[i]]
        message += tmp
        logger.debug("CONDITIONS_CHANNELS: %s", tmp)

        # CONDITIONS VALUES
        tmp = []
        for i in range(self.highest_used_global_condition):
            tmp += [self.conditions.values[i]]
        message += tmp
        logger.debug("CONDITIONS VALUES: %s", tmp)

        # GLOBAL_COUNTER_RESETS
        tmp = []
        for i in range(self.total_states_added):
            tmp += [self.global_counters.reset_matrix[i]]
        message += tmp
        logger.debug("GLOBAL_COUNTER_RESETS: %s", tmp)

        self.state_timers = self.state_timers[:self.total_states_added]

        return ArduinoTypes.get_uint8_array(message)
Example #22
0
 def _bpodcom_get_trial_timestamp_start(self):
     data = self._arcom.read_bytes_array(8)
     self.trial_start_micros = ArduinoTypes.cvt_uint64(b''.join(data))
     return self.trial_start_micros / float(
         self.hardware.DEFAULT_FREQUENCY_DIVIDER)