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