blob: 4fec83ed631a656ef2077a643720bb03ca9183fc [file] [log] [blame]
Pau Espin Pedrol19c508c2018-03-08 20:54:56 +01001# osmo_gsm_tester: class defining a Power Supply object
2#
3# Copyright (C) 2018 by sysmocom - s.f.m.c. GmbH
4#
5# Author: Pau Espin Pedrol <pespin@sysmocom.de>
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19
Pau Espin Pedrole1a58bd2020-04-10 20:46:07 +020020from ..core import log
21from ..core.event_loop import MainLoop
Pau Espin Pedrol19c508c2018-03-08 20:54:56 +010022from .powersupply import PowerSupply
23
24class PowerSupplySispm(PowerSupply):
25 """PowerSupply implementation using pysispm.
26
27 The device object from sismpm is not cached into an attribute of the class
28 instance because it is actually a libusb object keeping the device assigned
29 to it until it destroyed, meaning it will block other users to use the whole
30 device until the object is released. Instead, we pick the object in the
31 smallest scope possible, and we re-try if we receive a "Resource Busy" error
32 because we know it will be available in short time.
33 """
34
35 def _retry_usberr(self, func, *args):
36 """Run function until it runs successfully, retry on spurious errors.
37
38 Sometimes when operating the usb device, libusb reports the following spurious exception:
39 [Errno 16] Resource busy -> This can appear if another instance is using the device.
40 [Errno 110] Operation timed out
41
42 Retrying after that it's usually enough.
43 """
44 while True:
45 try:
46 ret = func(*args)
47 return ret
48 except USBError as e:
49 if e.errno == 16 or e.errno==110:
50 self.log('skip usb error, retry', repr(e))
Pau Espin Pedrol664e3832020-06-10 19:30:33 +020051 MainLoop.sleep(0.1)
Pau Espin Pedrol19c508c2018-03-08 20:54:56 +010052 continue
53 raise e
54
55 def _get_device(self):
56 """Get the sispm device object.
57
58 It should be kept alive as short as possible as it blocks other users
59 from using the device until the object is released.
60 """
61 mydevid = self.conf.get('device')
62 devices = self._retry_usberr(sispm.connect)
63 for d in devices:
64 did = self._retry_usberr(sispm.getid, d)
65 self.dbg('detected device:', did)
66 if did == mydevid:
67 self.dbg('found matching device: %s' % did)
68 return d
69 return None
70
71
72########################
73# PUBLIC - INTERNAL API
74########################
75 def __init__(self, conf):
76 super().__init__(conf, 'sispm')
Pau Espin Pedrol32609152020-05-05 17:41:04 +020077
78 import sispm
79 from usb.core import USBError
80
Pau Espin Pedrol19c508c2018-03-08 20:54:56 +010081 mydevid = conf.get('device')
82 if mydevid is None:
83 raise log.Error('No "device" attribute provided in supply conf!')
84 self.set_name('sispm-'+mydevid)
85 myport = conf.get('port')
86 if myport is None:
87 raise log.Error('No "port" attribute provided in power_supply conf!')
88 if not int(myport):
89 raise log.Error('Wrong non numeric "port" attribute provided in power_supply conf!')
Pau Espin Pedrol7f4807a2018-05-28 12:21:35 +020090 self.set_name('sispm-'+mydevid+'-'+myport)
Pau Espin Pedrol19c508c2018-03-08 20:54:56 +010091 self.port = int(myport)
92 device = self._get_device()
93 if device is None:
94 raise log.Error('device with with id %s not found!' % mydevid)
95 dmin = self._retry_usberr(sispm.getminport, device)
96 dmax = self._retry_usberr(sispm.getmaxport, device)
97 if dmin > self.port or dmax < self.port:
98 raise log.Error('Out of range "port" attribute provided in power_supply conf!')
99
100 def is_powered(self):
101 """Get whether the device is powered on or off."""
102 return self._retry_usberr(sispm.getstatus, self._get_device(), self.port)
103
104 def power_set(self, onoff):
105 """Turn on (onoff=True) or off (onoff=False) the device."""
106 if onoff:
107 self.dbg('switchon')
108 self._retry_usberr(sispm.switchon, self._get_device(), self.port)
109 else:
110 self.dbg('switchoff')
111 self._retry_usberr(sispm.switchoff, self._get_device(), self.port)
112
113
114# vim: expandtab tabstop=4 shiftwidth=4