Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(45)

Unified Diff: common/monsoon/monsoon/monsoon_wrapper.py

Issue 3018533002: Implementing a Monsoon power monitor trace agent, utilizing the UI infrastructure that the BattOr a…
Patch Set: Updating static methods and fixing test fakes. Created 3 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: common/monsoon/monsoon/monsoon_wrapper.py
diff --git a/common/monsoon/monsoon/monsoon_wrapper.py b/common/monsoon/monsoon/monsoon_wrapper.py
new file mode 100644
index 0000000000000000000000000000000000000000..dbbc76aa429c38147dab5cda8125222170f99b63
--- /dev/null
+++ b/common/monsoon/monsoon/monsoon_wrapper.py
@@ -0,0 +1,124 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import atexit
+import py_utils
+import re
+import subprocess
+import tempfile
+
+USB_PASSTHROUGH_OFF = "off"
+USB_PASSTHROUGH_ON = "on"
+USB_PASSTHROUGH_AUTO = "auto"
+
+UsbModes = [USB_PASSTHROUGH_OFF, USB_PASSTHROUGH_ON, USB_PASSTHROUGH_AUTO]
+
+class MonsoonWrapper(object):
+ def __init__(self, script):
+ self.script = script
+ self._process = None
+ # Register atexit handler to kill any monsoon processes in the case of
+ # abnormal program termination.
+ atexit.register(self.TerminateMonsoonProcess)
+
+ def ReadStatusProperties(self):
+ """ Reads status properties from Monsoon, returning a dictionary of
+ properties.
+ """
+ status_text = self.ExecuteBlocking(["--status"])
+ status = {}
+ for status_line in status_text:
+ # Sometimes transient USB serial errors are reported. Just ignore them
+ # and only use strings with : in them.
+ if ":" in status_line:
+ key, value = status_line.split(':')
+ status[key] = value
+ return status
+
+ def EnableUSB(self):
+ """ Shorthand for SetUSBMode(USB_PASSTHROUGH_ON) """
+ self.SetUSBMode(USB_PASSTHROUGH_ON)
+
+ def DisableUSB(self):
+ """ Shorthand for SetUSBMode(USB_PASSTHROUGH_OFF) """
+ self.SetUSBMode(USB_PASSTHROUGH_OFF)
+
+ def SetUSBMode(self, mode):
+ """ Set the Monsoon USB mode.
+ """
+ if mode not in UsbModes: raise Exception("Invalid USB mode " + mode)
+ # Sometimes Monsoon fails to make USB passthrough mode changes
+ # permanent if there are transient USB serial errors.
+ retry_count = 5
+ while self.GetUSBMode() is not mode:
+ self.ExecuteBlocking(["--usbpassthrough", mode])
+ if retry_count is 0: Exception("Failed to set USB mode!")
+ retry_count -= 1
+
+ def GetUSBMode(self):
+ """ Retrieves the current Monsoon USB mode, returning USB_PASSTHROUGH_OFF
+ if the status could not be retrieved.
+ """
+ properties = self.ReadStatusProperties()
+ if "usbPassthroughMode" in properties:
+ return UsbModes[int(properties["usbPassthroughMode"])]
+ return USB_PASSTHROUGH_OFF
+
+ def ReadPower(self, time, frequency):
+ """ Reads power from the Monsoon device over a specified perdiod while
+ blocking, returning a file containing raw monsoon data. """
+ sample_count = time * frequency
+ args = ["--samples", str(sample_count), "--hz", str(frequency),
+ "--timestamp"]
+ return self.ExecuteBlocking(args)
+
+ def ExecuteBlocking(self, args):
+ """ Executes a blocking operation on the Monsoon device, returning a file
+ containing stdout output. """
+ if self.IsProcessRunning():
+ raise Exception("Monsoon subprocess already running!")
+ result_file = tempfile.TemporaryFile()
+ subprocess.check_call([self.script] + args, stdout=result_file)
+ result_file.seek(0)
+ return result_file
+
+ def BeginReadPower(self, frequency, out=subprocess.PIPE):
+ """ Begins a non-blocking read of power from the Monsoon device, returning
+ the stdout file of the subprocess.
+ """
+ args = ["--samples", "-1", "--hz", str(frequency), "--timestamp"]
+ return self.BeginExecution(args=args, out=out)
+
+ def BeginExecution(self, args = [], out=subprocess.PIPE):
+ """ Begins a non-blocking operation on the Monsoon device, returning the
+ stdout file of the subprocess.
+ """
+ if self.IsProcessRunning():
+ raise Exception("Monsoon subprocess already running!")
+ self._process = subprocess.Popen([self.script] + args, stdout=out)
+ return self._process.stdout
+
+ def EndExecution(self):
+ """ Ends non-blocking execution of the Monsoon subprocess, returning the
+ stdout file of the subprocess. """
+ if self._process is None or self._process.poll() is not None:
+ raise Exception("Monsoon subprocess not running when going to end "
+ + "execution.")
+ self._process.terminate()
+ self._process.wait()
+ result_file = self._process.stdout
+ self._process = None
+ self._result_file = None
+ return result_file
+
+ def IsProcessRunning(self):
+ """ Returns whether or not the Monsoon subprocess is running.
+ """
+ return self._process is not None and self._process.poll() is None
+
+ def TerminateMonsoonProcess(self):
+ """ Terminates the Monsoon subprocess if it is running.
+ """
+ if self._process is not None and self._process.poll() is None:
+ self._process.kill()

Powered by Google App Engine
This is Rietveld 408576698