1d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu#!/usr/bin/env python 2d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 3d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu# Copyright (c) 2013 The Chromium OS Authors. All rights reserved. 4d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu# Use of this source code is governed by a BSD-style license that can be 5d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu# found in the LICENSE file. 6d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 7d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhuimport argparse 8d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhuimport dbus 9d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhuimport logging 10d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhuimport os 11d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhuimport signal 12d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhuimport sys 13d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhuimport traceback 14d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 15d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhuimport at_transceiver 16d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhuimport global_state 17d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhuimport modem_configuration 18d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhuimport task_loop 19d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhuimport wardmodem_exceptions as wme 20d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 21d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhuimport common 22d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhufrom autotest_lib.client.bin import utils 23d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhufrom autotest_lib.client.common_lib import error 24d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhufrom autotest_lib.client.cros.cellular import net_interface 25d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 26d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh PrabhuSTATE_MACHINE_DIR_NAME = 'state_machines' 27d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 28d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhuclass WardModem(object): 29d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 30d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu The main wardmodem object that replaces a physical modem. 31d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 32d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu What it does: 33d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu - Loads configuration data. 34d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu - Accepts custom state machines from the test. 35d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu - Builds objects and ties them together. 36d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu - Exposes objects for further customization 37d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 38d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu What it does not do: 39d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu - Tweak the different knobs provided by internal objects that it exposes 40d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu for further customization. 41d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu That is the responsibility of the WardModemContext. 42d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu - Care about setting up / tearing down environment. 43d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu Again, see WardModemContext. 44d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 45d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 46d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu def __init__(self, 47d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu replaced_modem = None, 48d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu state_machines = None, 49d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu modem_at_port_dev_name = None): 50d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 51d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu @param replaced_modem: Name of the modem being emulated. If left None, 52d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu the base modem will be emulated. A list of valid modems can be 53d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu found in the module modem_configuration 54d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 55d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu @param state_machines: Objects of subtypes of StateMachine that override 56d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu any state machine defined in the configuration files for the 57d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu same well-known-name. 58d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 59d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu @param modem_at_port_dev_name: The full path to the primary AT port of 60d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu the physical modem. This is needed only if we're running in a 61d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu mode where we pass on modemmanager commands to the modem. This 62d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu should be a string of the form '/dev/XXX' 63d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 64d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 65d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger = logging.getLogger(__name__) 66d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 67d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if not state_machines: 68d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu state_machines = [] 69d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if modem_at_port_dev_name and ( 70d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu type(modem_at_port_dev_name) is not str or 71d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu modem_at_port_dev_name[0:5] != '/dev/'): 72d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu raise wme.WardModemSetupException( 73d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 'Modem device name must be of the form "/dev/XXX", ' 74d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 'where XXX is the udev device.') 75d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 76d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # The modem that wardmodem is intended to replace. 77d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._replaced_modem = replaced_modem 78d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 79d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # Pseudo net interface exported to shill. 80d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._net_interface = net_interface.PseudoNetInterface() 81d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 82d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # The internal task loop object. Readable through a property. 83d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._task_loop = task_loop.TaskLoop() 84d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 85d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # The global state object shared by all state machines. 86d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._state = global_state.GlobalState() 87d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 88d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # The configuration object for the replaced modem. 89d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._modem_conf = modem_configuration.ModemConfiguration( 90d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu replaced_modem) 91d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 92d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._create_transceiver(modem_at_port_dev_name) 93d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._setup_state_machines(state_machines) 94d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 95d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._started = False 96d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 97d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 98d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu def start(self): 99d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 100d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu Turns on the wardmodem. 101d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 102d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu This call is blocking. It will return after |stop| is called. 103d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 104d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 105d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger.info('Starting wardmodem...') 106d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._net_interface.Setup() 107d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._task_loop.start() 108d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 109d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 110d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu def stop(self): 111d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 112d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu Stops wardmodem and cleanup. 113d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 114d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 115d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # We need to delete a bunch of stuff *before* the task_loop can be 116d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # stopped. 117d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger.info('Stopping wardmodem.') 118d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._net_interface.Teardown() 119d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu del self._transceiver 120d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu os.close(self._wm_at_port) 121d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu os.close(self._mm_at_port) 122d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if self._modem_at_port: 123d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu os.close(self._modem_at_port) 124d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self.task_loop.stop() 125d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 126d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 127d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu @property 128d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu def modem(self): 129d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 130d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu The physical modem being replaced [read-only]. 131d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 132d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu @return string representing the replaced modem. 133d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 134d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 135d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu return self._replaced_modem 136d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 137d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 138d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu @property 139d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu def modem_conf(self): 140d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 141d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu The ModemConfiguration object loaded for the replaced modem [read-only]. 142d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 143d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu @return A ModemConfiguration object. 144d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 145d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 146d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu return self._modem_conf 147d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 148d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu @property 149d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu def transceiver(self): 150d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 151d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu The ATTransceiver that will orchestrate communication [read-only]. 152d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 153d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu @return ATTransceiver object. 154d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 155d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 156d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu return self._transceiver 157d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 158d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 159d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu @property 160d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu def task_loop(self): 161d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 162d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu The main loop for asynchronous operations [read-only]. 163d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 164d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu @return TaskLoop object. 165d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 166d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 167d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu return self._task_loop 168d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 169d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 170d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu @property 171d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu def state(self): 172d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 173d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu The global state object that must by shared by all state machines. 174d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 175d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu @return GlobalState object. 176d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 177d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 178d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu return self._state 179d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 180d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 181d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu @property 182d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu def mm_at_port_pts_name(self): 183d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 184d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu Name of the pty terminal to be used by modemmanager. 185d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 186d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu @return A string of the form 'pts/X' where X is the pty number. 187d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 188d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 189d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu fullname = os.ttyname(self._mm_at_port) 190d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # fullname is of the form /dev/pts/X where X is a pts number. 191d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # We want to return just the pts/X part. 192d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu assert fullname[0:5] == '/dev/' 193d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu return fullname[5:] 194d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 195d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 196d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu def _create_transceiver(self, modem_at_port_dev_name): 197d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 198d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu Opens a pty pair and initialize ATTransceiver. 199d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 200d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu @param modem_at_port_dev_name: The device name of the primary port. 201d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 202d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 203d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._modem_at_port = None 204d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if modem_at_port_dev_name: 205d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu try: 206d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._modem_at_port = os.open(modem_at_port_dev_name, 207d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu os.O_RDWR) 208d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu except (TypeError, OSError) as e: 209d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu logging.warning('Could not open modem_port |%s|\nError:\n%s', 210d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu modem_at_port_dev_name, e) 211d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 212d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._wm_at_port, self._mm_at_port = os.openpty() 213d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._transceiver = at_transceiver.ATTransceiver(self._wm_at_port, 214d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._modem_conf, 215d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._modem_at_port) 216d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 217d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu def _setup_state_machines(self, client_machines): 218d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 219d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu Creates the state machines looking at sources in the right order. 220d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 221d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu @param client_machines: The client provided state machine objects. 222d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 223d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 224d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # A local list of state machines created 225d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu state_machines = [] 226d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 227d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # Create the state machines comprising the wardmodem. 228d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # Highest priority is given to the client provided state machines. The 229d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # remaining will be instantiated based on |replaced_modem|. 230d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu for sm in client_machines: 231d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if sm.get_well_known_name() in state_machines: 232d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu raise wme.SetupError('Multiple state machines provided with ' 233d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 'well-known-name |%s|' % 234d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu sm.get_well_known_name) 235d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu state_machines.append(sm.get_well_known_name()) 236d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._transceiver.register_state_machine(sm) 237d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger.debug('Added client specified machine {%s --> %s}', 238d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu sm.get_well_known_name(), 239d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu sm.__class__.__name__) 240d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # Now instantiate modem specific state machines. 241d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu for sm_module in self._modem_conf.plugin_state_machines: 242d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu sm = self._create_state_machine(sm_module) 243d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if sm.get_well_known_name() not in state_machines: 244d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu state_machines.append(sm.get_well_known_name()) 245d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._transceiver.register_state_machine(sm) 246d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger.debug( 247d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 'Added modem specific machine {%s --> %s}', 248d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu sm.get_well_known_name(), 249d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu sm.__class__.__name__) 250d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # Finally instantiate generic state machines. 251d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu for sm_module in self._modem_conf.base_state_machines: 252d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu sm = self._create_state_machine(sm_module) 253d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if sm.get_well_known_name() not in state_machines: 254d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu state_machines.append(sm.get_well_known_name()) 255d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._transceiver.register_state_machine(sm) 256d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger.debug('Added default machine {%s --> %s}', 257d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu sm.get_well_known_name(), 258d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu sm.__class__.__name__) 259d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger.info('Loaded state machines: %s', str(state_machines)) 260d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 261d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # Also setup the fallback state machine 262d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._transceiver.register_fallback_state_machine( 263d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._modem_conf.fallback_machine, 264d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._modem_conf.fallback_function) 265d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 266d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 267d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu def _create_state_machine(self, module_name): 268d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 269d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu Creates a state machine object given the |module_name|. 270d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 271d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu There is a specific naming convention for these state machine 272d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu definitions. If |module_name| is new_and_shiny_machine, the state 273d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu machine class must be named NewAndShinyMachine. 274d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 275d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu @param module_name: The name of the module from which the state machine 276d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu should be created. 277d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 278d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu @returns An object of type new_and_shiny_machine.NewAndShinyMachine, if 279d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu it exists. 280d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 281d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu @raises WardModemSetupError if |module_name| is malformed or the object 282d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu creation fails. 283d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 284d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 285d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # Obtain the name of the state machine class from module_name. 286d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # viz, convert my_module_name --> MyModuleName 287d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu parts = module_name.split('_') 288d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu parts = [x.title() for x in parts] 289d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu class_name = ''.join(parts) 290d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 291d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._import_state_machine_module_as_sm(module_name) 292d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu return getattr(sm, class_name)( 293d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._state, 294d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._transceiver, 295d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._modem_conf) 296d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 297d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 298d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu def _import_state_machine_module_as_sm(self, module_name): 299d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu global sm 300d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if module_name == 'call_machine': 301d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu from state_machines import call_machine as sm 302d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu elif module_name == 'call_machine_e362': 303d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu from state_machines import call_machine_e362 as sm 304d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu elif module_name == 'level_indicators_machine': 305d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu from state_machines import level_indicators_machine as sm 306d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu elif module_name == 'modem_power_level_machine': 307d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu from state_machines import modem_power_level_machine as sm 308d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu elif module_name == 'network_identity_machine': 309d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu from state_machines import network_identity_machine as sm 310d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu elif module_name == 'network_operator_machine': 311d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu from state_machines import network_operator_machine as sm 312d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu elif module_name == 'network_registration_machine': 313d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu from state_machines import network_registration_machine as sm 314d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu elif module_name == 'request_response': 315d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu from state_machines import request_response as sm 316d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu else: 317d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu raise wme.WardModemSetupException('Unknown state machine module: ' 318d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu '%s' % module_name) 319d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 320d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 321d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhuclass WardModemContext(object): 322d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 323d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu Setup wardmodem according to the options provided. 324d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 325d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu This context should be used by everyone to interact with WardModem. 326d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu This context will 327d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu (1) Setup wardmodem, setting the correct options on the internals exposed by 328d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu the wardmodem object. 329d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu (2) Manage the modemmanager instance during the context's lifetime. 330d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 331d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 332d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 333d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu MODEMMANAGER_RESTART_TIMEOUT = 60 334d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 335d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu def __init__(self, use_wardmodem=True, detach=True, args=None): 336d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 337d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu @param use_wardmodem: If False, this context is a no-op. Otherwise, the 338d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu whole wardmodem magic is done. 339d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 340d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu @param detach: A bool flag indicating whether wardmodem should be run in 341d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu its own process. If True, |start| will return immediately, 342d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu starting WardModem in its own process; Otherwise, |start| will 343d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu block until |stop| is called. 344d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 345d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu @param args: Options to setup WardModem. This is a list of string 346d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu command line arguments accepted by the parser defined in 347d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu |get_option_parser|. 348d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu TODO(pprabhu) Also except a dict of options to ease 349d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu customization in tests. 350d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 351d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 352d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger = logging.getLogger(__name__) 353d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger.info('Initializing wardmodem context.') 354d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 355d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._use_wardmodem = use_wardmodem 356d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if not self._use_wardmodem: 357d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger.info('WardModemContext directed to do nothing. ' 358d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 'All wardmodem actions are no-op.') 359d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger.debug('........... Welcome to the real world Neo.') 360d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu return 361d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 362d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger.debug('Wardmodem arguments: detach: %s, args: %s', 363d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu detach, str(args)) 364d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 365d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._started = False 366d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._wardmodem = None 367d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._was_mm_running = False 368d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._detach = detach 369d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu option_parser = self._get_option_parser() 370d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 371d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # XXX:HACK For some reason, parse_args picks up argv when the context is 372d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # created by an autotest test. Workaround: stash away the argv. 373d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu argv_stash = sys.argv 374d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu sys.argv = ['wardmodem'] 375d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._options = option_parser.parse_args(args) 376d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu sys.argv = argv_stash 377d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 378d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 379d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu def __enter__(self): 380d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self.start() 381d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu return self 382d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 383d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 384d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu def __exit__(self, type, value, traceback): 385d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self.stop() 386d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # Don't supress any exceptions raised in the 'with' block 387d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu return False 388d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 389d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 390d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu def start(self): 391d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 392d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu Start the WardModem, setting up the correct environment. 393d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 394d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu If |detach| was True, this call will return immediately, running 395d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu WardModem in its own process; Otherwise, this call will block and only 396d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu return when |stop| is called. 397d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 398d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 399d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if not self._use_wardmodem: 400d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu return 401d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 402d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if self._started: 403d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu raise wme.WardModemSetupException( 404d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 'Attempted to re-enter an already active wardmodem ' 405d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 'context.') 406d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 407d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._started = True 408d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._wardmodem = WardModem( 409d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._options.modem, 410d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu modem_at_port_dev_name=self._options.modem_port) 411d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if not self._prepare_wardmodem(self._options): 412d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu raise wme.WardModemSetupException( 413d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 'Contradictory wardmodem setup options detected.') 414d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 415d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._prepare_mm() 416d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 417d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if not self._detach: 418d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._wardmodem.start() 419d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu return 420d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 421d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger.debug('Will fork wardmodem process.') 422d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._child = os.fork() 423d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if self._child == 0: 424d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # Setup a way to stop the child. 425d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu def _exit_child(signum, frame): 426d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger.info('Signal handler called with signal %s', 427d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu signum) 428d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._cleanup() 429d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu os._exit(0) 430d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu signal.signal(signal.SIGINT, _exit_child) 431d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu signal.signal(signal.SIGTERM, _exit_child) 432d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # In detach mode, all uncaught exceptions raised by wardmodem 433d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # will be thrown here. Since this is a child process, they will 434d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # be lost. 435d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # At least log them before throwing them again, so that we know 436d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # something went wrong in wardmodem. 437d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu try: 438d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._wardmodem.start() 439d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu except Exception as e: 440d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu traceback.print_exc() 441d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu raise 442d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 443d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu else: 444d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # Wait here for the child to start before continuing. 445d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # We will continue once we know that modemmanager process has 446d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # detected the wardmodem device, and has exported it on its dbus 447d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # interface. 448d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu utils.poll_for_condition( 449d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._check_for_modem, 450d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu exception=wme.WardModemSetupException( 451d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 'Could not cleanly restart modemmanager.'), 452d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu timeout=self.MODEMMANAGER_RESTART_TIMEOUT, 453d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu sleep_interval=1) 454d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger.debug('Continuing the main process outside ' 455d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 'wardmodem.') 456d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 457d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 458d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu def stop(self): 459d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 460d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu Stops WardModem, restore environment to its previous state. 461d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 462d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 463d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if not self._use_wardmodem: 464d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu return 465d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 466d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if not self._started: 467d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger.warning('No wardmodem instance running! ' 468d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 'Nothing to stop.') 469d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu return 470d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 471d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if self._detach: 472d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger.debug('Attempting to kill child wardmodem process.') 473d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if self._child != 0: 474d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu os.kill(self._child, signal.SIGINT) 475d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu os.waitpid(self._child, 0) 476d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._child = 0 477d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger.debug('Finished waiting on child wardmodem process ' 478d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 'to finish.') 479d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu else: 480d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._cleanup() 481d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._started = False 482d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 483d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 484d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu def _cleanup(self): 485d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # Restore mm before turning off wardmodem. 486d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._restore_mm() 487d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._wardmodem.stop() 488d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger.info('Bye, Bye!') 489d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 490d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 491d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu def _prepare_wardmodem(self, options): 492d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 493d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu Tweaks the internals exposed by WardModem post-creation according to the 494d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu options provided. 495d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 496d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu @param options: is an object returned by argparse. 497d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 498d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 499d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if options.modem: 500d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if options.pass_through_mode: 501d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger.warning('Ignoring "modem" in pass-through-mode.') 502d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 503d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if options.at_terminator: 504d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._wardmodem.transceiver.at_terminator = options.at_terminator 505d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 506d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if options.pass_through_mode: 507d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._wardmodem.transceiver.mode = \ 508d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu at_transceiver.ATTransceiverMode.PASS_THROUGH 509d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 510d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if options.bridge_mode: 511d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._wardmodem.transceiver.mode = \ 512d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu at_transceiver.ATTransceiverMode.SPLIT_VERIFY 513d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 514d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if options.modem_port: 515d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if not options.pass_through_mode and not options.bridge_mode: 516d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger.warning('Ignoring "modem-port" in normal mode.') 517d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu else: 518d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if options.pass_through_mode or options.bridge_mode: 519d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger.error('"modem-port" needed in %s mode.' % 520d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 'bridge-mode' if options.bridge_mode else 521d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 'pass-through-mode') 522d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu return False 523d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 524d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if options.fast: 525d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if options.pass_through_mode: 526d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger.warning('Ignoring "fast" in pass-through-mode') 527d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu else: 528d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._wardmodem.task_loop.ignore_delays = True 529d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 530d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if options.randomize_delays: 531d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if options.fast: 532d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger.warning('Ignoring option "randomize-delays" ' 533d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu '"fast" overrides "randomize-delays".') 534d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if options.pass_through_mode: 535d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger.warning('Ignoring "randomize-delays" in ' 536d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 'pass-through-mode') 537d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if not options.fast and not options.pass_through_mode: 538d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._wardmodem.task_loop.random_delays = True 539d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 540d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if options.max_randomized_delay: 541d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if (options.fast or not options.randomize_delays or 542d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu options.pass_through_mode): 543d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger.warning('Ignoring "max_randomized_delays"') 544d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu else: 545d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._wardmodem.task_loop.max_random_delay_ms = \ 546d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu options.max_randomized_delay 547d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 548d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu return True 549d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 550d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 551d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu def _prepare_mm(self): 552d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 553d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu Starts modemmanager in test mode listening to the WardModem specified 554d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu pty end-point. 555d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 556d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 557d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._was_mm_running = False 558d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu try: 559d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu result = utils.run('pgrep ModemManager') 560d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if result.stdout: 561d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._was_mm_running = True 562d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu except error.CmdError: 563d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu pass 564d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu try: 565d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu utils.run('initctl stop modemmanager') 566d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu except error.CmdError: 567d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu pass 568d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 569d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu mm_opts = '' 570d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu mm_opts += '--log-level=DEBUG ' 571d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu mm_opts += '--timestamps ' 572d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu mm_opts += '--test ' 573d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu mm_opts += '--debug ' 574d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu mm_opts += '--test-plugin=' + self._wardmodem.modem_conf.mm_plugin + ' ' 575d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu mm_opts += '--test-at-port="' + self._wardmodem.mm_at_port_pts_name + \ 576d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu '" ' 577d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu mm_opts += '--test-net-port=' + \ 578d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu net_interface.PseudoNetInterface.IFACE_NAME + ' ' 579d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu result = utils.run('ModemManager %s &' % mm_opts) 580d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger.debug('ModemManager stderr:\n%s', result.stderr) 581d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 582d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 583d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu def _check_for_modem(self): 584d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu bus = dbus.SystemBus() 585d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu try: 586d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu manager = bus.get_object('org.freedesktop.ModemManager1', 587d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu '/org/freedesktop/ModemManager1') 588d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu imanager = dbus.Interface(manager, 589d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 'org.freedesktop.DBus.ObjectManager') 590d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu modems = imanager.GetManagedObjects() 591d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu except dbus.exceptions.DBusException as e: 592d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # The ObjectManager interface on modemmanager is not up yet. 593d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu return False 594d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # Check if a modem with the test at port has been exported 595d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if self._wardmodem.mm_at_port_pts_name in str(modems): 596d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu return True 597d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu else: 598d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu return False 599d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 600d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 601d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu def _restore_mm(self): 602d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 603d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu Stops the test instance of modemmanager and restore it to previous 604d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu state. 605d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 606d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 607d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu result = None 608d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu try: 609d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu result = utils.run('pgrep ModemManager') 610d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger.warning('ModemManager in test mode still running! ' 611d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 'Killing it ourselves.') 612d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu try: 613d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu utils.run('pkill -9 ModemManager') 614d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu except error.CmdError: 615d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger.warning('Failed to kill test ModemManager.') 616d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu except error.CmdError: 617d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger.debug('As expected: ModemManager in test mode killed.') 618d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if self._was_mm_running: 619d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu try: 620d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu utils.run('initctl start modemmanager') 621d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu except error.CmdError: 622d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu self._logger.warning('Failed to restart modemmanager service.') 623d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 624d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 625d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu def _get_option_parser(self): 626d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 627d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu Build an argparse parser to accept options from the user/test to tweak 628d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu WardModem post-creation. 629d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 630d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 631d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu parser = argparse.ArgumentParser( 632d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu description='Run the wardmodem modem emulator.') 633d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 634d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu modem_group = parser.add_argument_group( 635d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 'Modem', 636d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 'Description of the modem to emulate.') 637d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu modem_group.add_argument( 638d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu '--modem', 639d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu help='The modem to emulate.') 640d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu modem_group.add_argument('--at-terminator', 641d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu help='The string terminator to use.') 642d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 643d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu physical_modem_group = parser.add_argument_group( 644d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 'Physical modem', 645d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 'Interaction with the physical modem on-board.') 646d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu physical_modem_group.add_argument( 647d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu '--pass-through-mode', 648d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu default=False, 649d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu nargs='?', 650d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu const=True, 651d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu help='Act as a transparent channel between the modem manager ' 652d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 'and the physical modem. "--modem-port" option required.') 653d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu physical_modem_group.add_argument( 654d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu '--bridge-mode', 655d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu default=False, 656d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu nargs='?', 657d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu const=True, 658d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu help='Should we also setup a bridge with the real modem? Note ' 659d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 'that the responses generated by wardmodem state machines ' 660d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 'take precedence over those received from the physical ' 661d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 'modem. The bridge is used for a soft-verification: A ' 662d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 'warning is generated if the responses do not match. ' 663d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu '"--modem-port" option required.') 664d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu physical_modem_group.add_argument( 665d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu '--modem-port', 666d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu help='The primary port used by the real modem. ') 667d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 668d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu behaviour_group = parser.add_argument_group( 669d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 'Behaviour', 670d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 'Tweak the behaviour of running wardmodem.') 671d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu behaviour_group.add_argument( 672d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu '--fast', 673d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu default=False, 674d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu nargs='?', 675d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu const=True, 676d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu help='Run the emulator with minimum delay between operations.') 677d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu behaviour_group.add_argument( 678d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu '--randomize-delays', 679d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu default=False, 680d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu nargs='?', 681d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu const=True, 682d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu help='Run emulator with randomized delays between operations.') 683d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu behaviour_group.add_argument( 684d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu '--max-randomized-delay', 685d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu type=int, 686d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu help='The maximum randomized delay added between operations in ' 687d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu '"randomize-delays" mode.') 688d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 689d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu return parser 690d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 691d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 692d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu# ############################################################################## 693d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu# Run WardModem as a script. 694d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu# ############################################################################## 695d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu_wardmodem_context = None 696d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 697d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh PrabhuSIGNAL_TO_NAMES_DICT = \ 698d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu dict((getattr(signal, n), n) 699d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu for n in dir(signal) if n.startswith('SIG') and '_' not in n) 700d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 701d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhudef exit_wardmodem_script(signum, frame): 702d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 703d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu Signal handler to intercept Keyboard interrupt and stop the WardModem. 704d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 705d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu @param signum: The signal that was sent to the script 706d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 707d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu @param frame: Current stack frame [ignored]. 708d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 709d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 710d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu global _wardmodem_context 711d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if signum == signal.SIGINT: 712d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu logging.info('Captured Ctrl-C. Exiting wardmodem.') 713d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu _wardmodem_context.stop() 714d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu else: 715d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu logging.warning('Captured unexpected signal: %s', 716d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu SIGNAL_TO_NAMES_DICT.get(signum, str(signum))) 717d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 718d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 719d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhudef main(): 720d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 721d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu Entry function to wardmodem script. 722d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 723d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu """ 724d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu global _wardmodem_context 725d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # HACK: I should not have logged anything before getting here, but 726d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu # basicConfig wasn't doing anything: So, attempt to clean config. 727d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu root = logging.getLogger() 728d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu if root.handlers: 729d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu for handler in root.handlers: 730d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu root.removeHandler(handler) 731d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu logger_format = ('[%(asctime)-15s][%(filename)s:%(lineno)s:%(levelname)s] ' 732d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu '%(message)s') 733d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu logging.basicConfig(format=logger_format, 734d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu level=logging.DEBUG) 735d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 736d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu _wardmodem_context = WardModemContext(True, False, sys.argv[1:]) 737d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu logging.info('\n####################################################\n' 738d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 'Running wardmodem, hit Ctrl+C to exit.\n' 739d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu '####################################################\n') 740d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 741d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu signal.signal(signal.SIGINT, exit_wardmodem_script) 742d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu _wardmodem_context.start() 743d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 744d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu 745d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhuif __name__ == '__main__': 746d618de7330b3564b76ac22d369cbbe162e4b5753Prathmesh Prabhu main() 747