1b3a65823851f8ad28d214ad005765bf6b9805480David Rochberg#!/usr/bin/python
2b341239ef136bea7884b0d44e70879cd7d8a3d21Byron Kubert# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
3b3a65823851f8ad28d214ad005765bf6b9805480David Rochberg# Use of this source code is governed by a BSD-style license that can be
4b3a65823851f8ad28d214ad005765bf6b9805480David Rochberg# found in the LICENSE file.
5b3a65823851f8ad28d214ad005765bf6b9805480David Rochberg
6d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubertimport cellular_system_error
7d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubertimport cellular_logging
8d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubertimport os
9b341239ef136bea7884b0d44e70879cd7d8a3d21Byron Kubertimport select
10b3a65823851f8ad28d214ad005765bf6b9805480David Rochbergimport socket
11d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubertimport traceback
12b3a65823851f8ad28d214ad005765bf6b9805480David Rochberg
13b3a65823851f8ad28d214ad005765bf6b9805480David Rochberg
14b3a65823851f8ad28d214ad005765bf6b9805480David Rochbergclass PrologixScpiDriver:
15d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan    """Wrapper for a Prologix TCP<->GPIB bridge.
16d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan    http://prologix.biz/gpib-ethernet-controller.html
17d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan    http://prologix.biz/index.php?dispatch=attachments.getfile&attachment_id=1
18d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan
19d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan    Communication is over a plain TCP stream on port 1234.  Commands to
20d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan    the bridge are in-band, prefixed with ++.
21d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan
22d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan    Notable instance variables include:
23d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan
24d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan      self.auto: When 1, the bridge automatically addresses the target
25d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        in listen mode.  When 0, we must issue a ++read after every
26d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        query.  As of Aug '11, something between us and the Agilent 8960
27d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        is wrong such that running in auto=0 mode leaves us hanging if
28d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        we issue '*RST;*OPC?'
29b3a65823851f8ad28d214ad005765bf6b9805480David Rochberg    """
30d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert    all_open_connections = {}
31d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan
32d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan    def __init__(self, hostname, port=1234, gpib_address=14,
33d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan                 read_timeout_seconds=30, connect_timeout_seconds=5):
34d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        """Constructs a wrapper for the Prologix TCP<->GPIB bridge :
35d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        Arguments:
36d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            hostname: hostname of prologix device
37d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            port: port number
38d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            gpib_address: initial GPIB device to connect to
39d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            read_timeout_seconds: the read time out for the socket to the
40d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan                prologix box
41d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            connect_timeout_seconds: the read time out for the socket to the
42d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan                prologix box
43d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        """
44d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert        logger_name = 'prologix'
45d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        s = 'IP:%s GPIB:%s: ' % (hostname, gpib_address)
46d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert        formatter_string = '%(asctime)s %(filename)s %(lineno)d ' + s + \
47d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert                           '- %(message)s'
48d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert        self.scpi_logger = cellular_logging.SetupCellularLogging(
49d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert            logger_name, formatter_string)
50d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert
51d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert        self.connection_key = "%s:%s" % (hostname, port)
52d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert        self.connection_data = {self.connection_key: traceback.format_stack()}
53d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert        if self.connection_key in self.all_open_connections.keys():
54d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert            raise cellular_system_error.BadState(
55d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert              'IP network connection to '
56d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert              'prologix is already in use. : %s ' % self.all_open_connections)
57d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert        self.all_open_connections[self.connection_key] = self.connection_data
58d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        self.socket = connect_to_port(hostname, port, connect_timeout_seconds)
59d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        self.read_timeout_seconds = read_timeout_seconds
60d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        self.socket.setblocking(0)
61d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        self.SetAuto(1)
62d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert        self._AddCarrigeReturnsToResponses()
63d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        self.SetGpibAddress(gpib_address)
64d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        self.scpi_logger.debug('set read_timeout_seconds: %s ' %
65d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan                               self.read_timeout_seconds)
66d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan
67d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan    def __del__(self):
68d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        self.Close()
69d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan
70d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert    def _AddCarrigeReturnsToResponses(self):
71d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert        """
72d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert        Have the prologix box add a line feed to each response.
73d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert        Some instruments may need this.
74d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert        """
75d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert        pass
76d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert        self.Send('++eot_enable 1')
77d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert        self.Send('++eot_char 10')
78d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan
79d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan    def SetAuto(self, auto):
80d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        """Controls Prologix read-after-write (aka 'auto') mode."""
81d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        # Must be an int so we can send it as an arg to ++auto.
82d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        self.auto = int(auto)
83d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        self.Send('++auto %d' % self.auto)
84d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan
85d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan    def Close(self):
86d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        """Closes the socket."""
87d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        try:
88d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert            self.scpi_logger.error('Closing prologix devices at : %s ' %
89d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert                                   self.connection_key)
90d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert            self.all_open_connections.pop(self.connection_key)
91d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert        except KeyError:
92d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert            self.scpi_logger.error('Closed %s more then once' %
93d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert                                   self.connection_key)
94d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert        try:
95d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            self.socket.close()
96d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        except AttributeError:  # Maybe we close before we finish building.
97d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            pass
98d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan
99d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan    def SetGpibAddress(self, gpib_address):
100d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        max_tries = 10
101d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        while max_tries > 0:
102d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            max_tries -= 1
103d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            self.Send('++addr %s' % gpib_address)
104d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            read_back_value = self._DirectQuery('++addr')
105d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            try:
106d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert                if int(read_back_value) == int(gpib_address):
107d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan                    break
108d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            except ValueError:
109d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan                # If we read a string, don't raise, just try again.
110d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan                pass
111d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            self.scpi_logger.error('Set gpib addr to: %s, read back: %s' %
112d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan                                   (gpib_address, read_back_value))
113d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            self.scpi_logger.error('Setting the GPIB address failed. ' +
114d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan                                   'Trying again...')
115d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan
116d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan    def Send(self, command):
117d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        self.scpi_logger.info('] %s', command)
118d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        try:
119d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            self.socket.send(command + '\n')
120d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        except Exception as e:
121d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            self.scpi_logger.error('sending SCPI command %s failed. ' %
122d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan                                   command)
123d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            self.scpi_logger.exception(e)
124d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert            raise SystemError('Sending SCPI command failed. '
125d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert                              'Did the instrument stopped talking?')
126d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan
127d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan    def Reset(self):
128d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        """Sends a standard SCPI reset and waits for it to complete."""
129d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        # There is some misinteraction between the devices such that if we
130d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        # send *RST and *OPC? and then manually query with ++read,
131d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        # occasionally that ++read doesn't come back.  We currently depend
132d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        # on self.Query to turn on Prologix auto mode to avoid this
133d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        self.Send('*RST')
134d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        self.Query('*OPC?')
135d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan
136d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan    def Read(self):
137d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        """Read a response from the bridge."""
138d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        try:
139d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            ready = select.select([self.socket], [], [],
140d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan                                  self.read_timeout_seconds)
141d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        except Exception as e:
142d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            self.scpi_logger.exception(e)
143d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            s = 'Read from the instrument failed. Timeout:%s' % \
144d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan                self.read_timeout_seconds
145d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            self.scpi_logger.error(s)
146d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            raise SystemError(s)
147d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan
148d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        if ready[0]:
149d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            response = self.socket.recv(4096)
150d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            response = response.rstrip()
151d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            self.scpi_logger.info('[ %s', response)
152d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            return response
153d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        else:
154d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            self.Close()
155d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            s = 'Connection to the prologix adapter worked.' \
156d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan                'But there was not data to read from the instrument.' \
157d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan                'Does that command return a result?' \
158d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan                'Bad GPIB port number, or timeout too short?'
159630f29391fabb13a6e6d191fa747e81512bcb726Byron Kubert        raise cellular_system_error.InstrumentTimeout(s)
160d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan
161d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan    def Query(self, command):
162d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        """Send a GPIB command and return the response."""
163d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        #self.SetAuto(1) #maybe useful?
164d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert
165d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert        s = list(self.scpi_logger.findCaller())
166d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert        s[0] = os.path.basename(s[0])
167d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert
168d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert        s = list(self.scpi_logger.findCaller())
169d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert        s[0] = os.path.basename(s[0])
170d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert        self.scpi_logger.debug('caller :' + str(s) + command)
171d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert
172d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        self.Send(command)
173d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        if not self.auto:
174d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            self.Send('++read eoi')
175d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        output = self.Read()
176d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        #self.SetAuto(0) #maybe useful?
177d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        return output
178d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan
179d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan    def _DirectQuery(self, command):
180d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        """Sends a query to the prologix (do not send ++read).
181d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan
182d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        Returns: response of the query.
183d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        """
184d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        self.Send(command)
185d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        return self.Read()
186b3a65823851f8ad28d214ad005765bf6b9805480David Rochberg
187b3a65823851f8ad28d214ad005765bf6b9805480David Rochberg
188b341239ef136bea7884b0d44e70879cd7d8a3d21Byron Kubertdef connect_to_port(hostname, port, connect_timeout_seconds):
189d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan    # Right out of the python documentation,
190d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan    #  http://docs.python.org/library/socket.html
191d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan    for res in socket.getaddrinfo(
192d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan                hostname, port, socket.AF_UNSPEC, socket.SOCK_STREAM):
193d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        af, socktype, proto, _, sa = res
194d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        try:
195d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            s = socket.socket(af, socktype, proto)
196d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        except socket.error as msg:
197d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert            raise cellular_system_error.SocketTimeout(
198d55c96d6bef22b7fc1d815ab83caec4935ba76f2Byron Kubert                'Failed to make a new socket object. ' + str(msg))
199d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        try:
200d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            s.settimeout(connect_timeout_seconds)
201d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            s.connect(sa)
202d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan        except socket.error as msg:
203d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            try:
204d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan                s.close()
205d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            except Exception:
206d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan                pass  # Try to close it, but it may not have been created.
207d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan            temp_string_var = ' Could be bad IP address. Tried: %s : %s' % \
208d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan                              (hostname, port)
209630f29391fabb13a6e6d191fa747e81512bcb726Byron Kubert            raise cellular_system_error.SocketTimeout(str(msg) +
210630f29391fabb13a6e6d191fa747e81512bcb726Byron Kubert                                                      temp_string_var)
211d34edf26ab8171d0ad944293d2a0439fa1f1b1b4Ben Chan    return s
212