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.
This commit is contained in:
whitequark 2018-05-16 14:07:44 +00:00
parent d446a3293e
commit a39f8d6634
4 changed files with 52 additions and 39 deletions

37
artiq/coredevice/comm.py Normal file
View File

@ -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

View File

@ -1,7 +1,5 @@
import struct import struct
import logging import logging
import socket
import sys
import traceback import traceback
import numpy import numpy
from enum import Enum from enum import Enum
@ -9,6 +7,7 @@ from fractions import Fraction
from collections import namedtuple from collections import namedtuple
from artiq.coredevice import exceptions from artiq.coredevice import exceptions
from artiq.coredevice.comm import initialize_connection
from artiq import __version__ as software_version from artiq import __version__ as software_version
@ -85,30 +84,6 @@ class RPCReturnValueError(ValueError):
RPCKeyword = namedtuple('RPCKeyword', ['name', 'value']) 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: class CommKernelDummy:
def __init__(self): def __init__(self):
pass pass
@ -143,10 +118,10 @@ class CommKernel:
self.host = host self.host = host
self.port = port self.port = port
def open(self): def open(self, **kwargs):
if hasattr(self, "socket"): if hasattr(self, "socket"):
return 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") self.socket.sendall(b"ARTIQ coredev\n")
def close(self): def close(self):

View File

@ -3,6 +3,8 @@ import logging
import socket import socket
import struct import struct
from artiq.coredevice.comm import initialize_connection
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -44,22 +46,15 @@ class LogLevel(Enum):
TRACE = 5 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: class CommMgmt:
def __init__(self, host, port=1380): def __init__(self, host, port=1380):
self.host = host self.host = host
self.port = port self.port = port
def open(self): def open(self, **kwargs):
if hasattr(self, "socket"): if hasattr(self, "socket"):
return 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") self.socket.sendall(b"ARTIQ management\n")
def close(self): def close(self):

View File

@ -18,6 +18,7 @@ import shlex
from artiq.tools import verbosity_args, init_logger from artiq.tools import verbosity_args, init_logger
from artiq.remoting import SSHClient from artiq.remoting import SSHClient
from artiq.coredevice.comm_mgmt import CommMgmt
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -264,10 +265,15 @@ def main():
client.run_command(["flterm", serial, "--output-only"]) client.run_command(["flterm", serial, "--output-only"])
elif action == "hotswap": elif action == "hotswap":
lock()
logger.info("Hotswapping firmware") logger.info("Hotswapping firmware")
firmware = build_dir(variant, "software", firmware, firmware + ".bin") 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: else:
logger.error("Unknown action {}".format(action)) logger.error("Unknown action {}".format(action))