Skip to content

Commit

Permalink
Merge pull request #356 from SpiNNakerManchester/power_on_during_init
Browse files Browse the repository at this point in the history
Power on during init
  • Loading branch information
rowleya authored Oct 4, 2023
2 parents 8c40423 + a86497a commit ba79621
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 45 deletions.
2 changes: 1 addition & 1 deletion quick_tests/quick_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ def __exit__(self, *_ignored):
def print_transceiver_tests(transceiver):

with Section("Version Information"):
version_info = transceiver.ensure_board_is_ready()
version_info = transceiver._get_scamp_version()
print(version_info)

app_id = SpiNNManDataView().get_new_id()
Expand Down
87 changes: 43 additions & 44 deletions spinnman/transceiver.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
UDP_BOOT_CONNECTION_DEFAULT_PORT, NO_ROUTER_DIAGNOSTIC_FILTERS,
ROUTER_REGISTER_BASE_ADDRESS, ROUTER_DEFAULT_FILTERS_MAX_POSITION,
ROUTER_FILTER_CONTROLS_OFFSET, ROUTER_DIAGNOSTIC_FILTER_SIZE, N_RETRIES,
BOOT_RETRIES)
BOOT_RETRIES, POWER_CYCLE_WAIT_TIME_IN_SECONDS)
from spinnman.data import SpiNNManDataView
from spinnman.exceptions import (
SpinnmanInvalidParameterException, SpinnmanException, SpinnmanIOException,
Expand Down Expand Up @@ -88,10 +88,27 @@
_ONE_LONG = struct.Struct("<Q")
_EXECUTABLE_ADDRESS = 0x67800000

_POWER_CYCLE_WARNING = (
"When power-cycling a board, it is recommended that you wait for 30 "
"seconds before attempting a reboot. Therefore, the tools will now "
"wait for 30 seconds. If you wish to avoid this wait, please set "
"reset_machine_on_startup = False in the [Machine] section of the "
"relevant configuration (cfg) file.")

_POWER_CYCLE_FAILURE_WARNING = (
"The end user requested the power-cycling of the board. But the "
"tools did not have the required BMP connection to facilitate a "
"power-cycling, and therefore will not do so. please set the "
"bmp_names accordingly in the [Machine] section of the relevant "
"configuration (cfg) file. Or use a machine assess process which "
"provides the BMP data (such as a spalloc system) or finally set "
"reset_machine_on_startup = False in the [Machine] section of the "
"relevant configuration (cfg) file to avoid this warning in future.")


def create_transceiver_from_hostname(
hostname, version, bmp_connection_data=None, number_of_boards=None,
auto_detect_bmp=False):
auto_detect_bmp=False, power_cycle=False):
"""
Create a Transceiver by creating a :py:class:`~.UDPConnection` to the
given hostname on port 17893 (the default SCAMP port), and a
Expand All @@ -116,6 +133,7 @@ def create_transceiver_from_hostname(
automatically determined from the board IP address
:param scamp_connections:
the list of connections used for SCAMP communications
:param bool power_cycle: If True will power cycle the machine:
:return: The created transceiver
:rtype: Transceiver
:raise SpinnmanIOException:
Expand Down Expand Up @@ -151,7 +169,8 @@ def create_transceiver_from_hostname(
# handle the boot connection
connections.append(BootConnection(remote_host=hostname))

return Transceiver(version, connections=connections)
return Transceiver(version, connections=connections,
power_cycle=power_cycle)


class Transceiver(AbstractContextManager):
Expand Down Expand Up @@ -188,12 +207,13 @@ class Transceiver(AbstractContextManager):
"_width"]

def __init__(
self, version, connections=None):
self, version, connections=None, power_cycle=False):
"""
:param int version: The version of the board being connected to
:param list(Connection) connections:
An iterable of connections to the board. If not specified, no
communication will be possible until connections are found.
:param bool power_cycle: If True will power cycle the machine:
:raise SpinnmanIOException:
If there is an error communicating with the board, or if no
connections to the board can be found (if connections is ``None``)
Expand Down Expand Up @@ -253,6 +273,10 @@ def __init__(

self._machine_off = False

if power_cycle:
self._power_off_machine()
self._ensure_board_is_ready()

def _where_is_xy(self, x, y):
"""
Attempts to get where_is_x_y info from the machine
Expand Down Expand Up @@ -641,7 +665,7 @@ def _is_scamp_version_compabible(version):
# version is irrelevant
return version[1] > _SCAMP_VERSION[1]

def ensure_board_is_ready(self, n_retries=5, extra_boot_values=None):
def _ensure_board_is_ready(self, n_retries=5, extra_boot_values=None):
"""
Ensure that the board is ready to interact with this version of the
transceiver. Boots the board if not already booted and verifies that
Expand All @@ -653,7 +677,6 @@ def ensure_board_is_ready(self, n_retries=5, extra_boot_values=None):
This should only be used for values which are not standard
based on the board version.
:return: The version identifier
:rtype: VersionInfo
:raise SpinnmanIOException:
* If there is a problem booting the board
* If the version of software on the board is not compatible with
Expand Down Expand Up @@ -716,8 +739,6 @@ def ensure_board_is_ready(self, n_retries=5, extra_boot_values=None):
self._scamp_connection_selector = MostDirectConnectionSelector(
self._scamp_connections)

return version_info

def __is_default_destination(self, version_info):
return (version_info.x == AbstractSCPRequest.DEFAULT_DEST_X_COORD
and version_info.y == AbstractSCPRequest.DEFAULT_DEST_Y_COORD)
Expand Down Expand Up @@ -1048,66 +1069,44 @@ def _power_on_machine(self):
"""
Power on the whole machine.
:rtype bool
:return success of failure to power on machine
"""
if self._bmp_connection is None:
logger.warning("No BMP connections, so can't power on")
return False
self.power_on(self._bmp_connection)
return True

def power_on(self, boards=0):
"""
Power on a set of boards in the machine.
self._power(PowerCommand.POWER_ON)
self._machine_off = True
# Sleep for 5 seconds as the machine has just been powered on
time.sleep(BMP_POST_POWER_ON_SLEEP_TIME)

:param int boards: The board or boards to power on
"""
self._power(PowerCommand.POWER_ON, boards)

def power_off_machine(self):
def _power_off_machine(self):
"""
Power off the whole machine.
:rtype bool
:return success or failure to power off the machine
"""
if self._bmp_connection is None:
logger.warning("No BMP connections, so can't power off")
return False
logger.info("Turning off machine")
self.power_off(self._bmp_connection)
return True

def power_off(self, boards=0):
"""
Power off a set of boards in the machine.
logger.warning(_POWER_CYCLE_FAILURE_WARNING)
self._power(PowerCommand.POWER_OFF)
logger.warning(_POWER_CYCLE_WARNING)
time.sleep(POWER_CYCLE_WAIT_TIME_IN_SECONDS)
logger.warning("Power cycle wait complete")

:param int boards: The board or boards to power off
"""
self._power(PowerCommand.POWER_OFF, boards)

def _power(self, power_command, boards=0):
def _power(self, power_command):
"""
Send a power request to the machine.
:param PowerCommand power_command: The power command to send
:param boards: The board or boards to send the command to
"""
connection_selector = self._bmp_selector
timeout = (
BMP_POWER_ON_TIMEOUT
if power_command == PowerCommand.POWER_ON
else BMP_TIMEOUT)
process = SendSingleCommandProcess(
connection_selector, timeout=timeout, n_retries=0)
process.execute(SetPower(power_command, boards))
self._bmp_selector, timeout=timeout, n_retries=0)
process.execute(SetPower(power_command, self._bmp_connection.boards))
self._machine_off = power_command == PowerCommand.POWER_OFF

# Sleep for 5 seconds if the machine has just been powered on
if not self._machine_off:
time.sleep(BMP_POST_POWER_ON_SLEEP_TIME)

def read_fpga_register(
self, fpga_num, register, board=0):
"""
Expand Down Expand Up @@ -1937,7 +1936,7 @@ def close(self):
"""
if self._bmp_connection is not None:
if get_config_bool("Machine", "turn_off_machine"):
self.power_off_machine()
self._power_off_machine()

for connection in self._all_connections:
connection.close()
Expand Down
3 changes: 3 additions & 0 deletions unittests/test_transceiver.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ def write_memory(
def close(self):
pass

def _ensure_board_is_ready(self, n_retries=5, extra_boot_values=None):
pass


class MockExtendedTransceiver(MockWriteTransceiver, ExtendedTransceiver):
pass
Expand Down

0 comments on commit ba79621

Please sign in to comment.