| OLD | NEW |
| 1 # Copyright 2013 The Chromium Authors. All rights reserved. | 1 # Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 """Interface for a USB-connected Monsoon power meter. | 5 """Interface for a USB-connected Monsoon power meter. |
| 6 | 6 |
| 7 http://msoon.com/LabEquipment/PowerMonitor/ | 7 http://msoon.com/LabEquipment/PowerMonitor/ |
| 8 Currently Unix-only. Relies on fcntl, /dev, and /tmp. | 8 Currently Unix-only. Relies on fcntl, /dev, and /tmp. |
| 9 """ | 9 """ |
| 10 | 10 |
| 11 import collections | 11 import collections |
| 12 import logging | 12 import logging |
| 13 import os | 13 import os |
| 14 import select | 14 import select |
| 15 import struct | 15 import struct |
| 16 import time | 16 import time |
| 17 | 17 |
| 18 from telemetry.core import util | 18 from telemetry.core import util |
| 19 | 19 |
| 20 util.AddDirToPythonPath(util.GetTelemetryDir(), 'third_party', 'pyserial') | 20 util.AddDirToPythonPath(util.GetTelemetryDir(), 'third_party', 'pyserial') |
| 21 import serial # pylint: disable=F0401 | 21 import serial # pylint: disable=F0401 |
| 22 import serial.tools.list_ports |
| 22 | 23 |
| 23 | 24 |
| 24 Power = collections.namedtuple('Power', ['amps', 'volts']) | 25 Power = collections.namedtuple('Power', ['amps', 'volts']) |
| 25 | 26 |
| 26 | 27 |
| 27 class Monsoon: | 28 class Monsoon: |
| 28 """Provides a simple class to use the power meter. | 29 """Provides a simple class to use the power meter. |
| 29 | 30 |
| 30 mon = monsoon.Monsoon() | 31 mon = monsoon.Monsoon() |
| 31 mon.SetVoltage(3.7) | 32 mon.SetVoltage(3.7) |
| (...skipping 17 matching lines...) Expand all Loading... |
| 49 | 50 |
| 50 self._coarse_ref = self._fine_ref = self._coarse_zero = self._fine_zero = 0 | 51 self._coarse_ref = self._fine_ref = self._coarse_zero = self._fine_zero = 0 |
| 51 self._coarse_scale = self._fine_scale = 0 | 52 self._coarse_scale = self._fine_scale = 0 |
| 52 self._last_seq = 0 | 53 self._last_seq = 0 |
| 53 self._voltage_multiplier = None | 54 self._voltage_multiplier = None |
| 54 | 55 |
| 55 if device: | 56 if device: |
| 56 self.ser = serial.Serial(device, timeout=1) | 57 self.ser = serial.Serial(device, timeout=1) |
| 57 return | 58 return |
| 58 | 59 |
| 59 while 1: # Try all /dev/ttyACM* until we find one we can use. | 60 while 1: |
| 60 for dev in os.listdir('/dev'): | 61 for (port, desc, _) in serial.tools.list_ports.comports(): |
| 61 if not dev.startswith('ttyACM'): | 62 if not desc.lower().startswith('mobile device power monitor'): |
| 62 continue | 63 continue |
| 63 tmpname = '/tmp/monsoon.%s.%s' % (os.uname()[0], dev) | 64 tmpname = '/tmp/monsoon.%s.%s' % (os.uname()[0], os.path.basename(port)) |
| 64 self._tempfile = open(tmpname, 'w') | 65 self._tempfile = open(tmpname, 'w') |
| 65 try: # Use a lockfile to ensure exclusive access. | 66 try: # Use a lockfile to ensure exclusive access. |
| 66 # Put the import in here to avoid doing it on unsupported platforms. | 67 # Put the import in here to avoid doing it on unsupported platforms. |
| 67 import fcntl | 68 import fcntl |
| 68 fcntl.lockf(self._tempfile, fcntl.LOCK_EX | fcntl.LOCK_NB) | 69 fcntl.lockf(self._tempfile, fcntl.LOCK_EX | fcntl.LOCK_NB) |
| 69 except IOError: | 70 except IOError: |
| 70 logging.error('device %s is in use', dev) | 71 logging.error('device %s is in use', port) |
| 71 continue | 72 continue |
| 72 | 73 |
| 73 try: # Try to open the device. | 74 try: # Try to open the device. |
| 74 self.ser = serial.Serial('/dev/%s' % dev, timeout=1) | 75 self.ser = serial.Serial(port, timeout=1) |
| 75 self.StopDataCollection() # Just in case. | 76 self.StopDataCollection() # Just in case. |
| 76 self._FlushInput() # Discard stale input. | 77 self._FlushInput() # Discard stale input. |
| 77 status = self.GetStatus() | 78 status = self.GetStatus() |
| 78 except IOError, e: | 79 except IOError, e: |
| 79 logging.error('error opening device %s: %s', dev, e) | 80 logging.error('error opening device %s: %s', port, e) |
| 80 continue | 81 continue |
| 81 | 82 |
| 82 if not status: | 83 if not status: |
| 83 logging.error('no response from device %s', dev) | 84 logging.error('no response from device %s', port) |
| 84 elif serialno and status['serialNumber'] != serialno: | 85 elif serialno and status['serialNumber'] != serialno: |
| 85 logging.error('device %s is #%d', dev, status['serialNumber']) | 86 logging.error('device %s is #%d', port, status['serialNumber']) |
| 86 else: | 87 else: |
| 87 if status['hardwareRevision'] == 1: | 88 if status['hardwareRevision'] == 1: |
| 88 self._voltage_multiplier = 62.5 / 10**6 | 89 self._voltage_multiplier = 62.5 / 10**6 |
| 89 else: | 90 else: |
| 90 self._voltage_multiplier = 125.0 / 10**6 | 91 self._voltage_multiplier = 125.0 / 10**6 |
| 91 return | 92 return |
| 92 | 93 |
| 93 self._tempfile = None | 94 self._tempfile = None |
| 94 if not wait: | 95 if not wait: |
| 95 raise IOError('No device found') | 96 raise IOError('No device found') |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 278 logging.error('exception from serial port') | 279 logging.error('exception from serial port') |
| 279 return None | 280 return None |
| 280 elif len(ready_r) > 0: | 281 elif len(ready_r) > 0: |
| 281 flushed += 1 | 282 flushed += 1 |
| 282 self.ser.read(1) # This may cause underlying buffering. | 283 self.ser.read(1) # This may cause underlying buffering. |
| 283 self.ser.flush() # Flush the underlying buffer too. | 284 self.ser.flush() # Flush the underlying buffer too. |
| 284 else: | 285 else: |
| 285 break | 286 break |
| 286 if flushed > 0: | 287 if flushed > 0: |
| 287 logging.debug('dropped >%d bytes', flushed) | 288 logging.debug('dropped >%d bytes', flushed) |
| OLD | NEW |