xref: /aosp_15_r20/external/autotest/server/cros/cellular/abstract_inst.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1*9c5db199SXin Li# Copyright 2021 The Chromium OS Authors. All rights reserved.
2*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be
3*9c5db199SXin Li# found in the LICENSE file.
4*9c5db199SXin Li"""Python module for Abstract Instrument Library."""
5*9c5db199SXin Li
6*9c5db199SXin Liimport logging
7*9c5db199SXin Liimport requests
8*9c5db199SXin Liimport socket
9*9c5db199SXin Li
10*9c5db199SXin Li
11*9c5db199SXin Liclass SocketInstrumentError(Exception):
12*9c5db199SXin Li    """Abstract Instrument Error Class, via Socket and SCPI."""
13*9c5db199SXin Li
14*9c5db199SXin Li    def __init__(self, error, command=None):
15*9c5db199SXin Li        """Init method for Socket Instrument Error.
16*9c5db199SXin Li
17*9c5db199SXin Li        Args:
18*9c5db199SXin Li            error: Exception error.
19*9c5db199SXin Li            command: Additional information on command,
20*9c5db199SXin Li                Type, Str.
21*9c5db199SXin Li        """
22*9c5db199SXin Li        super(SocketInstrumentError, self).__init__(error)
23*9c5db199SXin Li        self._error_code = error
24*9c5db199SXin Li        self._error_message = self._error_code
25*9c5db199SXin Li        if command is not None:
26*9c5db199SXin Li            self._error_message = 'Command {} returned the error: {}.'.format(
27*9c5db199SXin Li                    repr(command), repr(self._error_message))
28*9c5db199SXin Li
29*9c5db199SXin Li    def __str__(self):
30*9c5db199SXin Li        return self._error_message
31*9c5db199SXin Li
32*9c5db199SXin Li
33*9c5db199SXin Liclass SocketInstrument(object):
34*9c5db199SXin Li    """Abstract Instrument Class, via Socket and SCPI."""
35*9c5db199SXin Li
36*9c5db199SXin Li    def __init__(self, ip_addr, ip_port):
37*9c5db199SXin Li        """Init method for Socket Instrument.
38*9c5db199SXin Li
39*9c5db199SXin Li        Args:
40*9c5db199SXin Li            ip_addr: IP Address.
41*9c5db199SXin Li                Type, str.
42*9c5db199SXin Li            ip_port: TCPIP Port.
43*9c5db199SXin Li                Type, str.
44*9c5db199SXin Li        """
45*9c5db199SXin Li        self._logger = logging.getLogger(__name__)
46*9c5db199SXin Li        self._socket_timeout = 120
47*9c5db199SXin Li        self._socket_buffer_size = 1024
48*9c5db199SXin Li
49*9c5db199SXin Li        self._ip_addr = ip_addr
50*9c5db199SXin Li        self._ip_port = ip_port
51*9c5db199SXin Li
52*9c5db199SXin Li        self._escseq = '\n'
53*9c5db199SXin Li        self._codefmt = 'utf-8'
54*9c5db199SXin Li
55*9c5db199SXin Li        self._socket = None
56*9c5db199SXin Li
57*9c5db199SXin Li    def _connect_socket(self):
58*9c5db199SXin Li        """Init and Connect to socket."""
59*9c5db199SXin Li        try:
60*9c5db199SXin Li            self._socket = socket.create_connection(
61*9c5db199SXin Li                    (self._ip_addr, self._ip_port),
62*9c5db199SXin Li                    timeout=self._socket_timeout)
63*9c5db199SXin Li
64*9c5db199SXin Li            infmsg = 'Opened Socket connection to {}:{} with handle {}.'.format(
65*9c5db199SXin Li                    repr(self._ip_addr), repr(self._ip_port),
66*9c5db199SXin Li                    repr(self._socket))
67*9c5db199SXin Li
68*9c5db199SXin Li        except socket.timeout:
69*9c5db199SXin Li            errmsg = 'Socket timeout while connecting to instrument.'
70*9c5db199SXin Li            raise SocketInstrumentError(errmsg)
71*9c5db199SXin Li
72*9c5db199SXin Li        except socket.error:
73*9c5db199SXin Li            errmsg = 'Socket error while connecting to instrument.'
74*9c5db199SXin Li            raise SocketInstrumentError(errmsg)
75*9c5db199SXin Li
76*9c5db199SXin Li    def _send(self, cmd):
77*9c5db199SXin Li        """Send command via Socket.
78*9c5db199SXin Li
79*9c5db199SXin Li        Args:
80*9c5db199SXin Li            cmd: Command to send,
81*9c5db199SXin Li                Type, Str.
82*9c5db199SXin Li        """
83*9c5db199SXin Li        if not self._socket:
84*9c5db199SXin Li            self._connect_socket()
85*9c5db199SXin Li
86*9c5db199SXin Li        cmd_es = cmd + self._escseq
87*9c5db199SXin Li
88*9c5db199SXin Li        try:
89*9c5db199SXin Li            self._socket.sendall(cmd_es.encode(self._codefmt))
90*9c5db199SXin Li
91*9c5db199SXin Li        except socket.timeout:
92*9c5db199SXin Li            errmsg = ('Socket timeout while sending command {} '
93*9c5db199SXin Li                      'to instrument.').format(repr(cmd))
94*9c5db199SXin Li            raise SocketInstrumentError(errmsg)
95*9c5db199SXin Li
96*9c5db199SXin Li        except socket.error:
97*9c5db199SXin Li            errmsg = ('Socket error while sending command {} '
98*9c5db199SXin Li                      'to instrument.').format(repr(cmd))
99*9c5db199SXin Li            raise SocketInstrumentError(errmsg)
100*9c5db199SXin Li
101*9c5db199SXin Li        except Exception as err:
102*9c5db199SXin Li            errmsg = ('Error {} while sending command {} '
103*9c5db199SXin Li                      'to instrument.').format(repr(cmd), repr(err))
104*9c5db199SXin Li            raise SocketInstrumentError(errmsg)
105*9c5db199SXin Li
106*9c5db199SXin Li    def _recv(self):
107*9c5db199SXin Li        """Receive response via Socket.
108*9c5db199SXin Li
109*9c5db199SXin Li        Returns:
110*9c5db199SXin Li            resp: Response from Instrument via Socket,
111*9c5db199SXin Li                Type, Str.
112*9c5db199SXin Li        """
113*9c5db199SXin Li        if not self._socket:
114*9c5db199SXin Li            self._connect_socket()
115*9c5db199SXin Li
116*9c5db199SXin Li        resp = ''
117*9c5db199SXin Li
118*9c5db199SXin Li        try:
119*9c5db199SXin Li            while True:
120*9c5db199SXin Li                resp_tmp = self._socket.recv(self._socket_buffer_size)
121*9c5db199SXin Li                resp_tmp = resp_tmp.decode(self._codefmt)
122*9c5db199SXin Li                resp += resp_tmp
123*9c5db199SXin Li                if len(resp_tmp) < self._socket_buffer_size:
124*9c5db199SXin Li                    break
125*9c5db199SXin Li
126*9c5db199SXin Li        except socket.timeout:
127*9c5db199SXin Li            errmsg = 'Socket timeout while receiving response from instrument.'
128*9c5db199SXin Li            raise SocketInstrumentError(errmsg)
129*9c5db199SXin Li
130*9c5db199SXin Li        except socket.error:
131*9c5db199SXin Li            errmsg = 'Socket error while receiving response from instrument.'
132*9c5db199SXin Li            raise SocketInstrumentError(errmsg)
133*9c5db199SXin Li
134*9c5db199SXin Li        except Exception as err:
135*9c5db199SXin Li            errmsg = ('Error {} while receiving response '
136*9c5db199SXin Li                      'from instrument').format(repr(err))
137*9c5db199SXin Li            raise SocketInstrumentError(errmsg)
138*9c5db199SXin Li
139*9c5db199SXin Li        resp = resp.rstrip(self._escseq)
140*9c5db199SXin Li
141*9c5db199SXin Li        return resp
142*9c5db199SXin Li
143*9c5db199SXin Li    def _close_socket(self):
144*9c5db199SXin Li        """Close Socket Instrument."""
145*9c5db199SXin Li        if not self._socket:
146*9c5db199SXin Li            return
147*9c5db199SXin Li
148*9c5db199SXin Li        try:
149*9c5db199SXin Li            self._socket.shutdown(socket.SHUT_RDWR)
150*9c5db199SXin Li            self._socket.close()
151*9c5db199SXin Li            self._socket = None
152*9c5db199SXin Li
153*9c5db199SXin Li        except Exception as err:
154*9c5db199SXin Li            errmsg = 'Error {} while closing instrument.'.format(repr(err))
155*9c5db199SXin Li            raise SocketInstrumentError(errmsg)
156*9c5db199SXin Li
157*9c5db199SXin Li    def _query(self, cmd):
158*9c5db199SXin Li        """query instrument via Socket.
159*9c5db199SXin Li
160*9c5db199SXin Li        Args:
161*9c5db199SXin Li            cmd: Command to send,
162*9c5db199SXin Li                Type, Str.
163*9c5db199SXin Li
164*9c5db199SXin Li        Returns:
165*9c5db199SXin Li            resp: Response from Instrument via Socket,
166*9c5db199SXin Li                Type, Str.
167*9c5db199SXin Li        """
168*9c5db199SXin Li        self._send(cmd + ';*OPC?')
169*9c5db199SXin Li        resp = self._recv()
170*9c5db199SXin Li        return resp
171*9c5db199SXin Li
172*9c5db199SXin Li
173*9c5db199SXin Liclass RequestInstrument(object):
174*9c5db199SXin Li    """Abstract Instrument Class, via Request."""
175*9c5db199SXin Li
176*9c5db199SXin Li    def __init__(self, ip_addr):
177*9c5db199SXin Li        """Init method for request instrument.
178*9c5db199SXin Li
179*9c5db199SXin Li        Args:
180*9c5db199SXin Li            ip_addr: IP Address.
181*9c5db199SXin Li                Type, Str.
182*9c5db199SXin Li        """
183*9c5db199SXin Li        self._request_timeout = 120
184*9c5db199SXin Li        self._request_protocol = 'http'
185*9c5db199SXin Li        self._ip_addr = ip_addr
186*9c5db199SXin Li        self._escseq = '\r\n'
187*9c5db199SXin Li
188*9c5db199SXin Li    def _query(self, cmd):
189*9c5db199SXin Li        """query instrument via request.
190*9c5db199SXin Li
191*9c5db199SXin Li        Args:
192*9c5db199SXin Li            cmd: Command to send,
193*9c5db199SXin Li                Type, Str.
194*9c5db199SXin Li
195*9c5db199SXin Li        Returns:
196*9c5db199SXin Li            resp: Response from Instrument via request,
197*9c5db199SXin Li                Type, Str.
198*9c5db199SXin Li        """
199*9c5db199SXin Li        request_cmd = '{}://{}/{}'.format(self._request_protocol,
200*9c5db199SXin Li                                          self._ip_addr, cmd)
201*9c5db199SXin Li        resp_raw = requests.get(request_cmd, timeout=self._request_timeout)
202*9c5db199SXin Li
203*9c5db199SXin Li        resp = resp_raw.text
204*9c5db199SXin Li        for char_del in self._escseq:
205*9c5db199SXin Li            resp = resp.replace(char_del, '')
206*9c5db199SXin Li
207*9c5db199SXin Li        return resp
208