Source code for spynnaker.pyNN.external_devices_models.munich_spinnaker_link_retina_device

# Copyright (c) 2017 The University of Manchester
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import Iterable, List
from spinn_utilities.overrides import overrides
from pacman.model.routing_info import BaseKeyAndMask
from pacman.model.graphs.application import ApplicationSpiNNakerLinkVertex
from spinn_front_end_common.abstract_models import (
    AbstractSendMeMulticastCommandsVertex)
from spinn_front_end_common.utility_models import MultiCastCommand
from spynnaker.pyNN.exceptions import SpynnakerException
from spynnaker.pyNN.models.common import PopulationApplicationVertex

# robot with 7 7 1


def get_x_from_robot_retina(key: int) -> int:
    """
    :param int key:
    :rtype: int
    """
    return (key >> 7) & 0x7f


def get_y_from_robot_retina(key: int) -> int:
    """
    :param int key:
    :rtype: int
    """
    return key & 0x7f


def get_spike_value_from_robot_retina(key: int) -> int:
    """
    :param int key:
    :rtype: int
    """
    return (key >> 14) & 0x1


class MunichRetinaDevice(
        ApplicationSpiNNakerLinkVertex, PopulationApplicationVertex,
        AbstractSendMeMulticastCommandsVertex):
    """
    An Omnibot silicon retina device.
    """
    __slots__ = (
        "__fixed_key",
        "__fixed_mask",
        "__is_right")

    # key codes for the robot retina
    _MANAGEMENT_BIT = 0x400
    _MANAGEMENT_MASK = 0xFFFFF800
    _LEFT_RETINA_ENABLE = 0x45
    _RIGHT_RETINA_ENABLE = 0x46
    _LEFT_RETINA_DISABLE = 0x45
    _RIGHT_RETINA_DISABLE = 0x46
    _LEFT_RETINA_KEY_SET = 0x43
    _RIGHT_RETINA_KEY_SET = 0x44

    UP_POLARITY = "UP"
    DOWN_POLARITY = "DOWN"
    MERGED_POLARITY = "MERGED"

    #: Select the left retina
    LEFT_RETINA = "LEFT"
    #: Select the right retina
    RIGHT_RETINA = "RIGHT"
    _RETINAS = frozenset((LEFT_RETINA, RIGHT_RETINA))

    default_parameters = {
        'label': "MunichRetinaDevice",
        'polarity': None,
        'board_address': None}

    def __init__(
            self, retina_key, spinnaker_link_id, position,
            label=default_parameters['label'],
            polarity=default_parameters['polarity'],
            board_address=default_parameters['board_address']):
        """
        :param int retina_key:
        :param int spinnaker_link_id:
            The SpiNNaker link to which the retina is connected
        :param str position: ``LEFT`` or ``RIGHT``
        :param str label:
        :param str polarity: ``UP``, ``DOWN`` or ``MERGED``
        :param board_address:
        :type board_address: str or None
        """
        # pylint: disable=too-many-arguments
        if polarity is None:
            polarity = MunichRetinaDevice.MERGED_POLARITY

        self.__fixed_key = (retina_key & 0xFFFF) << 16
        self.__fixed_mask = 0xFFFF8000
        if polarity == MunichRetinaDevice.UP_POLARITY:
            self.__fixed_key |= 0x4000

        if polarity == MunichRetinaDevice.MERGED_POLARITY:
            # There are 128 x 128 retina "pixels" x 2 polarities
            fixed_n_neurons = 128 * 128 * 2
        else:
            # There are 128 x 128 retina "pixels"
            fixed_n_neurons = 128 * 128
            self.__fixed_mask = 0xFFFFC000

        if position not in self._RETINAS:
            raise SpynnakerException(
                "The external Retina does not recognise this position")
        self.__is_right = position == self.RIGHT_RETINA

        super().__init__(
            n_atoms=fixed_n_neurons, spinnaker_link_id=spinnaker_link_id,
            label=label, board_address=board_address)

[docs] @overrides(ApplicationSpiNNakerLinkVertex.get_fixed_key_and_mask) def get_fixed_key_and_mask(self, partition_id: str) -> BaseKeyAndMask: return BaseKeyAndMask(self.__fixed_key, self.__fixed_mask)
@property @overrides(AbstractSendMeMulticastCommandsVertex.start_resume_commands) def start_resume_commands(self) -> Iterable[MultiCastCommand]: # change the retina key it transmits with # (based off if its right or left) key_set_command = self._MANAGEMENT_BIT | ( self._RIGHT_RETINA_KEY_SET if self.__is_right else self._LEFT_RETINA_KEY_SET) # to ensure populations receive the correct packets, this needs to be # different based on which retina key_set_payload = self.__fixed_key if self.__is_right else 0 yield MultiCastCommand( key_set_command, key_set_payload, repeat=5, delay_between_repeats=1000) # make retina enabled (dependent on if its a left or right retina enable_command = self._MANAGEMENT_BIT | ( self._RIGHT_RETINA_ENABLE if self.__is_right else self._LEFT_RETINA_ENABLE) yield MultiCastCommand( enable_command, payload=1, repeat=5, delay_between_repeats=1000) @property @overrides(AbstractSendMeMulticastCommandsVertex.pause_stop_commands) def pause_stop_commands(self) -> Iterable[MultiCastCommand]: # disable retina disable_command = self._MANAGEMENT_BIT | ( self._RIGHT_RETINA_DISABLE if self.__is_right else self._LEFT_RETINA_DISABLE) yield MultiCastCommand( disable_command, payload=0, repeat=5, delay_between_repeats=1000) @property @overrides(AbstractSendMeMulticastCommandsVertex.timed_commands) def timed_commands(self) -> List[MultiCastCommand]: return []