From a39f8d663487871d1620a23d4db1d07614042278 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 16 May 2018 14:07:44 +0000 Subject: [PATCH] artiq_devtool: use CommMgmt instead of shelling out to artiq_coremgmt. (Which no longer exists.) This also fixes `artiq_devtool hotswap` to work without an `artiq_devtool connect` running in background. --- artiq/coredevice/comm.py | 37 +++++++++++++++++++++++++++++++++ artiq/coredevice/comm_kernel.py | 31 +++------------------------ artiq/coredevice/comm_mgmt.py | 13 ++++-------- artiq/frontend/artiq_devtool.py | 10 +++++++-- 4 files changed, 52 insertions(+), 39 deletions(-) create mode 100644 artiq/coredevice/comm.py diff --git a/artiq/coredevice/comm.py b/artiq/coredevice/comm.py new file mode 100644 index 000000000..19a104e54 --- /dev/null +++ b/artiq/coredevice/comm.py @@ -0,0 +1,37 @@ +import sys +import socket +import logging + + +logger = logging.getLogger(__name__) + + +def set_keepalive(sock, after_idle, interval, max_fails): + if sys.platform.startswith("linux"): + sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) + sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, after_idle) + sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, interval) + sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, max_fails) + elif sys.platform.startswith("win") or sys.platform.startswith("cygwin"): + # setting max_fails is not supported, typically ends up being 5 or 10 + # depending on Windows version + sock.ioctl(socket.SIO_KEEPALIVE_VALS, + (1, after_idle*1000, interval*1000)) + else: + logger.warning("TCP keepalive not supported on platform '%s', ignored", + sys.platform) + + +def initialize_connection(host, port, ssh_transport=None): + if ssh_transport is None: + sock = socket.create_connection((host, port), 5.0) + sock.settimeout(None) + set_keepalive(sock, 3, 2, 3) + logger.debug("connected to %s:%d", host, port) + else: + sock = ssh_transport.open_channel("direct-tcpip", (host, port), + ("localhost", 9999), timeout=5.0) + ssh_transport.set_keepalive(2) + logger.debug("connected to %s:%d via SSH transport to %s:%d", + host, port, *ssh_transport.getpeername()) + return sock diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index 2a2a7f560..c02f226e7 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -1,7 +1,5 @@ import struct import logging -import socket -import sys import traceback import numpy from enum import Enum @@ -9,6 +7,7 @@ from fractions import Fraction from collections import namedtuple from artiq.coredevice import exceptions +from artiq.coredevice.comm import initialize_connection from artiq import __version__ as software_version @@ -85,30 +84,6 @@ class RPCReturnValueError(ValueError): RPCKeyword = namedtuple('RPCKeyword', ['name', 'value']) -def set_keepalive(sock, after_idle, interval, max_fails): - if sys.platform.startswith("linux"): - sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) - sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, after_idle) - sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, interval) - sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, max_fails) - elif sys.platform.startswith("win") or sys.platform.startswith("cygwin"): - # setting max_fails is not supported, typically ends up being 5 or 10 - # depending on Windows version - sock.ioctl(socket.SIO_KEEPALIVE_VALS, - (1, after_idle*1000, interval*1000)) - else: - logger.warning("TCP keepalive not supported on platform '%s', ignored", - sys.platform) - - -def initialize_connection(host, port): - sock = socket.create_connection((host, port), 5.0) - sock.settimeout(None) - set_keepalive(sock, 3, 2, 3) - logger.debug("connected to host %s on port %d", host, port) - return sock - - class CommKernelDummy: def __init__(self): pass @@ -143,10 +118,10 @@ class CommKernel: self.host = host self.port = port - def open(self): + def open(self, **kwargs): if hasattr(self, "socket"): return - self.socket = initialize_connection(self.host, self.port) + self.socket = initialize_connection(self.host, self.port, **kwargs) self.socket.sendall(b"ARTIQ coredev\n") def close(self): diff --git a/artiq/coredevice/comm_mgmt.py b/artiq/coredevice/comm_mgmt.py index 98ad07e2b..f235c584a 100644 --- a/artiq/coredevice/comm_mgmt.py +++ b/artiq/coredevice/comm_mgmt.py @@ -3,6 +3,8 @@ import logging import socket import struct +from artiq.coredevice.comm import initialize_connection + logger = logging.getLogger(__name__) @@ -44,22 +46,15 @@ class LogLevel(Enum): TRACE = 5 -def initialize_connection(host, port): - sock = socket.create_connection((host, port), 5.0) - sock.settimeout(None) - logger.debug("connected to host %s on port %d", host, port) - return sock - - class CommMgmt: def __init__(self, host, port=1380): self.host = host self.port = port - def open(self): + def open(self, **kwargs): if hasattr(self, "socket"): return - self.socket = initialize_connection(self.host, self.port) + self.socket = initialize_connection(self.host, self.port, **kwargs) self.socket.sendall(b"ARTIQ management\n") def close(self): diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index 3ab31e776..58edba27d 100755 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -18,6 +18,7 @@ import shlex from artiq.tools import verbosity_args, init_logger from artiq.remoting import SSHClient +from artiq.coredevice.comm_mgmt import CommMgmt logger = logging.getLogger(__name__) @@ -264,10 +265,15 @@ def main(): client.run_command(["flterm", serial, "--output-only"]) elif action == "hotswap": + lock() + logger.info("Hotswapping firmware") firmware = build_dir(variant, "software", firmware, firmware + ".bin") - command("artiq_coreboot", "hotswap", firmware, - on_failure="Hotswapping failed") + + mgmt = CommMgmt(device) + mgmt.open(ssh_transport=client.get_transport()) + with open(firmware, "rb") as f: + mgmt.hotswap(f.read()) else: logger.error("Unknown action {}".format(action))