xref: /aosp_15_r20/external/autotest/client/cros/cellular/pseudomodem/client.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1*9c5db199SXin Li
2*9c5db199SXin Li# Lint as: python2, python3
3*9c5db199SXin Li# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
4*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be
5*9c5db199SXin Li# found in the LICENSE file.
6*9c5db199SXin Li
7*9c5db199SXin Lifrom __future__ import absolute_import
8*9c5db199SXin Lifrom __future__ import division
9*9c5db199SXin Lifrom __future__ import print_function
10*9c5db199SXin Li
11*9c5db199SXin Liimport cmd
12*9c5db199SXin Liimport dbus
13*9c5db199SXin Liimport dbus.types
14*9c5db199SXin Liimport dbus.exceptions
15*9c5db199SXin Li
16*9c5db199SXin Liimport six
17*9c5db199SXin Li
18*9c5db199SXin Lifrom six.moves import input
19*9c5db199SXin Li
20*9c5db199SXin Liimport common
21*9c5db199SXin Li
22*9c5db199SXin Lifrom autotest_lib.client.cros.cellular.pseudomodem import pm_constants
23*9c5db199SXin Li
24*9c5db199SXin Lifrom autotest_lib.client.cros.cellular import mm1_constants
25*9c5db199SXin Li
26*9c5db199SXin Liclass PseudoModemClient(cmd.Cmd):
27*9c5db199SXin Li    """
28*9c5db199SXin Li    Interactive client for PseudoModemManager.
29*9c5db199SXin Li
30*9c5db199SXin Li    """
31*9c5db199SXin Li    def __init__(self):
32*9c5db199SXin Li        cmd.Cmd.__init__(self)
33*9c5db199SXin Li        self.prompt = '> '
34*9c5db199SXin Li        self._bus = dbus.SystemBus()
35*9c5db199SXin Li
36*9c5db199SXin Li
37*9c5db199SXin Li    def _get_proxy(self, path=pm_constants.TESTING_PATH):
38*9c5db199SXin Li        return self._bus.get_object(mm1_constants.I_MODEM_MANAGER, path)
39*9c5db199SXin Li
40*9c5db199SXin Li
41*9c5db199SXin Li    def _get_ism_proxy(self, state_machine):
42*9c5db199SXin Li        return self._get_proxy('/'.join([pm_constants.TESTING_PATH,
43*9c5db199SXin Li                                         state_machine]))
44*9c5db199SXin Li
45*9c5db199SXin Li
46*9c5db199SXin Li    def Begin(self):
47*9c5db199SXin Li        """
48*9c5db199SXin Li        Starts the interactive shell.
49*9c5db199SXin Li
50*9c5db199SXin Li        """
51*9c5db199SXin Li        print('\nWelcome to the PseudoModemManager shell!\n')
52*9c5db199SXin Li        self.cmdloop()
53*9c5db199SXin Li
54*9c5db199SXin Li
55*9c5db199SXin Li    def can_exit(self):
56*9c5db199SXin Li        """Override"""
57*9c5db199SXin Li        return True
58*9c5db199SXin Li
59*9c5db199SXin Li
60*9c5db199SXin Li    def do_is_alive(self, args):
61*9c5db199SXin Li        """
62*9c5db199SXin Li        Handles the 'is_alive' command.
63*9c5db199SXin Li
64*9c5db199SXin Li        @params args: ignored.
65*9c5db199SXin Li
66*9c5db199SXin Li        """
67*9c5db199SXin Li        if args:
68*9c5db199SXin Li            print('\nCommand "is_alive" expects no arguments.\n')
69*9c5db199SXin Li            return
70*9c5db199SXin Li        print(self._get_proxy().IsAlive(dbus_interface=pm_constants.I_TESTING))
71*9c5db199SXin Li
72*9c5db199SXin Li
73*9c5db199SXin Li    def help_is_alive(self):
74*9c5db199SXin Li        """ Handles the 'help is_alive' command. """
75*9c5db199SXin Li        print('\nChecks that pseudomodem child process is alive.\n')
76*9c5db199SXin Li
77*9c5db199SXin Li
78*9c5db199SXin Li    def do_properties(self, args):
79*9c5db199SXin Li        """
80*9c5db199SXin Li        Handles the 'properties' command.
81*9c5db199SXin Li
82*9c5db199SXin Li        @param args: Arguments to the command. Unused.
83*9c5db199SXin Li
84*9c5db199SXin Li        """
85*9c5db199SXin Li        if args:
86*9c5db199SXin Li            print('\nCommand "properties" expects no arguments.\n')
87*9c5db199SXin Li            return
88*9c5db199SXin Li        try:
89*9c5db199SXin Li            props = self._get_proxy().GetAll(
90*9c5db199SXin Li                            pm_constants.I_TESTING,
91*9c5db199SXin Li                            dbus_interface=mm1_constants.I_PROPERTIES)
92*9c5db199SXin Li            print('\nProperties: ')
93*9c5db199SXin Li            for k, v in six.iteritems(props):
94*9c5db199SXin Li                print('   ' + k + ': ' + str(v))
95*9c5db199SXin Li            print()
96*9c5db199SXin Li        except dbus.exceptions.DBusException as e:
97*9c5db199SXin Li            print(('\nAn error occurred while communicating with '
98*9c5db199SXin Li                   'PseudoModemManager: ' + e.get_dbus_name() + ' - ' +
99*9c5db199SXin Li                   e.message + '\n'))
100*9c5db199SXin Li        return False
101*9c5db199SXin Li
102*9c5db199SXin Li
103*9c5db199SXin Li    def help_properties(self):
104*9c5db199SXin Li        """Handles the 'help properties' command."""
105*9c5db199SXin Li        print('\nReturns the properties under the testing interface.\n')
106*9c5db199SXin Li
107*9c5db199SXin Li
108*9c5db199SXin Li    def do_sms(self, args):
109*9c5db199SXin Li        """
110*9c5db199SXin Li        Simulates a received SMS.
111*9c5db199SXin Li
112*9c5db199SXin Li        @param args: A string containing the sender and the text message
113*9c5db199SXin Li                content, in which everything before the first ' ' character
114*9c5db199SXin Li                belongs to the sender and everything else belongs to the
115*9c5db199SXin Li                message content. For example "Gandalf You shall not pass!"
116*9c5db199SXin Li                will be parsed into:
117*9c5db199SXin Li
118*9c5db199SXin Li                    sender="Gandalf"
119*9c5db199SXin Li                    content="You shall not pass!"
120*9c5db199SXin Li
121*9c5db199SXin Li                Pseudomodem doesn't distinguish between phone numbers and
122*9c5db199SXin Li                strings containing non-numeric characters for the sender field
123*9c5db199SXin Li                so args can contain pretty much anything.
124*9c5db199SXin Li
125*9c5db199SXin Li        """
126*9c5db199SXin Li        arglist = args.split(' ', 1)
127*9c5db199SXin Li        if len(arglist) != 2:
128*9c5db199SXin Li            print('\nMalformed SMS args: ' + args + '\n')
129*9c5db199SXin Li            return
130*9c5db199SXin Li        try:
131*9c5db199SXin Li            self._get_proxy().ReceiveSms(
132*9c5db199SXin Li                    arglist[0], arglist[1],
133*9c5db199SXin Li                    dbus_interface=pm_constants.I_TESTING)
134*9c5db199SXin Li            print('\nSMS sent!\n')
135*9c5db199SXin Li        except dbus.exceptions.DBusException as e:
136*9c5db199SXin Li            print(('\nAn error occurred while communicating with '
137*9c5db199SXin Li                   'PseudoModemManager: ' + e.get_dbus_name() + ' - ' +
138*9c5db199SXin Li                   e.message + '\n'))
139*9c5db199SXin Li        return False
140*9c5db199SXin Li
141*9c5db199SXin Li
142*9c5db199SXin Li    def help_sms(self):
143*9c5db199SXin Li        """Handles the 'help sms' command."""
144*9c5db199SXin Li        print('\nUsage: sms <sender phone #> <message text>\n')
145*9c5db199SXin Li
146*9c5db199SXin Li
147*9c5db199SXin Li    def do_set(self, args):
148*9c5db199SXin Li        """
149*9c5db199SXin Li        Handles various commands that start with 'set'.
150*9c5db199SXin Li
151*9c5db199SXin Li        @param args: Defines the set command to be issued and its
152*9c5db199SXin Li                arguments. Currently supported commands are:
153*9c5db199SXin Li
154*9c5db199SXin Li                  set pco <pco-value>
155*9c5db199SXin Li
156*9c5db199SXin Li        """
157*9c5db199SXin Li        arglist = args.split(' ')
158*9c5db199SXin Li        if len(arglist) < 1:
159*9c5db199SXin Li            print('\nInvalid command: set ' + args + '\n')
160*9c5db199SXin Li            return
161*9c5db199SXin Li        if arglist[0] == 'pco':
162*9c5db199SXin Li            if len(arglist) == 1:
163*9c5db199SXin Li                arglist.append('')
164*9c5db199SXin Li            elif len(arglist) != 2:
165*9c5db199SXin Li                print('\nExpected: pco <pco-value>. Found: ' + args + '\n')
166*9c5db199SXin Li                return
167*9c5db199SXin Li            pco_value = arglist[1]
168*9c5db199SXin Li            try:
169*9c5db199SXin Li                pco_list = [dbus.types.Struct(
170*9c5db199SXin Li                    [dbus.types.UInt32(1),
171*9c5db199SXin Li                        dbus.types.Boolean(True),
172*9c5db199SXin Li                        dbus.types.ByteArray(pco_value)],
173*9c5db199SXin Li                    signature='ubay')]
174*9c5db199SXin Li                self._get_proxy().UpdatePco(
175*9c5db199SXin Li                        pco_list, dbus_interface=pm_constants.I_TESTING)
176*9c5db199SXin Li                print('\nPCO value updated!\n')
177*9c5db199SXin Li            except dbus.exceptions.DBusException as e:
178*9c5db199SXin Li                print(('\nAn error occurred while communicating with '
179*9c5db199SXin Li                       'PseudoModemManager: ' + e.get_dbus_name() + ' - ' +
180*9c5db199SXin Li                       e.message + '\n'))
181*9c5db199SXin Li        else:
182*9c5db199SXin Li            print('\nUnknown command: set ' + args + '\n')
183*9c5db199SXin Li        return False
184*9c5db199SXin Li
185*9c5db199SXin Li
186*9c5db199SXin Li    def help_set(self):
187*9c5db199SXin Li        """Handles the 'help set' command."""
188*9c5db199SXin Li        print ('\nUsage: set pco <pco-value>\n<pco-value> can be empty to set'
189*9c5db199SXin Li               ' the PCO value to an empty list.\n')
190*9c5db199SXin Li
191*9c5db199SXin Li
192*9c5db199SXin Li    def _get_state_machine(self, args):
193*9c5db199SXin Li        arglist = args.split()
194*9c5db199SXin Li        if len(arglist) != 1:
195*9c5db199SXin Li            print('\nExpected one argument: Name of state machine\n')
196*9c5db199SXin Li            return None
197*9c5db199SXin Li        try:
198*9c5db199SXin Li            return self._get_ism_proxy(arglist[0])
199*9c5db199SXin Li        except dbus.exceptions.DBusException as e:
200*9c5db199SXin Li            print('\nNo such interactive state machine.\n')
201*9c5db199SXin Li            print('Error obtained: |%s|\n' % repr(e))
202*9c5db199SXin Li            return None
203*9c5db199SXin Li
204*9c5db199SXin Li
205*9c5db199SXin Li    def do_is_waiting(self, machine):
206*9c5db199SXin Li        """
207*9c5db199SXin Li        Determine if a machine is waiting for an advance call.
208*9c5db199SXin Li
209*9c5db199SXin Li        @param machine: Case sensitive name of the machine.
210*9c5db199SXin Li        @return: True if |machine| is waiting to be advanced by the user.
211*9c5db199SXin Li
212*9c5db199SXin Li        """
213*9c5db199SXin Li        ism = self._get_state_machine(machine)
214*9c5db199SXin Li        if not ism:
215*9c5db199SXin Li            return False
216*9c5db199SXin Li
217*9c5db199SXin Li        try:
218*9c5db199SXin Li            is_waiting = ism.IsWaiting(
219*9c5db199SXin Li                    dbus_interface=pm_constants.I_TESTING_ISM)
220*9c5db199SXin Li            print(('\nState machine is %swaiting.\n' %
221*9c5db199SXin Li                   ('' if is_waiting else 'not ')))
222*9c5db199SXin Li        except dbus.exceptions.DBusException as e:
223*9c5db199SXin Li            print(('\nCould not determine if |%s| is waiting: |%s|\n' %
224*9c5db199SXin Li                   (machine, repr(e))))
225*9c5db199SXin Li        return False
226*9c5db199SXin Li
227*9c5db199SXin Li
228*9c5db199SXin Li    def help_is_waiting(self):
229*9c5db199SXin Li        """Handles the 'help is_waiting' command"""
230*9c5db199SXin Li        print ('\nUsage: is_waiting <state-machine-name>\n'
231*9c5db199SXin Li               'Check whether a state machine is waiting for user action. The '
232*9c5db199SXin Li               'waiting machine can be advanced using the |advance| command.\n'
233*9c5db199SXin Li               'state-machine-name is the case sensitive name of the machine'
234*9c5db199SXin Li               'whose status is to be queried.\n')
235*9c5db199SXin Li
236*9c5db199SXin Li
237*9c5db199SXin Li    def do_advance(self, machine):
238*9c5db199SXin Li        """
239*9c5db199SXin Li        Advance the given state machine.
240*9c5db199SXin Li
241*9c5db199SXin Li        @param machine: Case sensitive name of the state machine to advance.
242*9c5db199SXin Li        @returns: True if |machine| was successfully advanced, False otherwise.
243*9c5db199SXin Li
244*9c5db199SXin Li        """
245*9c5db199SXin Li        ism = self._get_state_machine(machine)
246*9c5db199SXin Li        if not ism:
247*9c5db199SXin Li            return False
248*9c5db199SXin Li
249*9c5db199SXin Li        try:
250*9c5db199SXin Li            success = ism.Advance(dbus_interface=pm_constants.I_TESTING_ISM)
251*9c5db199SXin Li            print(('\nAdvanced!\n' if success else '\nCould not advance.\n'))
252*9c5db199SXin Li        except dbus.exceptions.DBusException as e:
253*9c5db199SXin Li            print('\nError while advancing state machine: |%s|\n' % repr(e))
254*9c5db199SXin Li        return False
255*9c5db199SXin Li
256*9c5db199SXin Li
257*9c5db199SXin Li    def help_advance(self):
258*9c5db199SXin Li        """Handles the 'help advance' command"""
259*9c5db199SXin Li        print ('\nUsage: advance <state-machine-name>\n'
260*9c5db199SXin Li               'Advance a waiting state machine to the next step.\n'
261*9c5db199SXin Li               'state-machine-name is the case sensitive name of the machine'
262*9c5db199SXin Li               'to advance.\n')
263*9c5db199SXin Li
264*9c5db199SXin Li
265*9c5db199SXin Li    def do_exit(self, args):
266*9c5db199SXin Li        """
267*9c5db199SXin Li        Handles the 'exit' command.
268*9c5db199SXin Li
269*9c5db199SXin Li        @param args: Arguments to the command. Unused.
270*9c5db199SXin Li
271*9c5db199SXin Li        """
272*9c5db199SXin Li        if args:
273*9c5db199SXin Li            print('\nCommand "exit" expects no arguments.\n')
274*9c5db199SXin Li            return
275*9c5db199SXin Li        resp = input('Are you sure? (yes/no): ')
276*9c5db199SXin Li        if resp == 'yes':
277*9c5db199SXin Li            print('\nGoodbye!\n')
278*9c5db199SXin Li            return True
279*9c5db199SXin Li        if resp != 'no':
280*9c5db199SXin Li            print('\nDid not understand: ' + resp + '\n')
281*9c5db199SXin Li        return False
282*9c5db199SXin Li
283*9c5db199SXin Li
284*9c5db199SXin Li    def help_exit(self):
285*9c5db199SXin Li        """Handles the 'help exit' command."""
286*9c5db199SXin Li        print ('\nExits the interpreter. Shuts down the pseudo modem manager '
287*9c5db199SXin Li               'if the interpreter was launched by running pseudomodem.py')
288*9c5db199SXin Li
289*9c5db199SXin Li
290*9c5db199SXin Li    do_EOF = do_exit
291*9c5db199SXin Li    help_EOF = help_exit
292*9c5db199SXin Li
293*9c5db199SXin Li
294*9c5db199SXin Lidef main():
295*9c5db199SXin Li    """ main method, run when this module is executed as stand-alone. """
296*9c5db199SXin Li    client = PseudoModemClient()
297*9c5db199SXin Li    client.Begin()
298*9c5db199SXin Li
299*9c5db199SXin Li
300*9c5db199SXin Liif __name__ == '__main__':
301*9c5db199SXin Li    main()
302