1 #!/usr/bin/env python 2 # 3 # Copyright 2017 - The Android Open Source Project 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 from acts.controllers.relay_lib.errors import RelayConfigError 17 from acts.controllers.relay_lib.helpers import validate_key 18 from acts.controllers.relay_lib.rdl_relay_board import RdlRelayBoard 19 from acts.controllers.relay_lib.sain_smart_board import SainSmartBoard 20 from acts.controllers.relay_lib.sain_smart_8_channel_usb_relay_board import SainSmart8ChannelUsbRelayBoard 21 from acts.controllers.relay_lib.generic_relay_device import GenericRelayDevice 22 from acts.controllers.relay_lib.fugu_remote import FuguRemote 23 from acts.controllers.relay_lib.i6s_headset import I6sHeadset 24 from acts.controllers.relay_lib.logitech_headset import LogitechAudioReceiver 25 from acts.controllers.relay_lib.sony_xb2_speaker import SonyXB2Speaker 26 from acts.controllers.relay_lib.sony_xb20_speaker import SonyXB20Speaker 27 from acts.controllers.relay_lib.ak_xb10_speaker import AkXB10Speaker 28 from acts.controllers.relay_lib.dongles import SingleButtonDongle 29 from acts.controllers.relay_lib.dongles import ThreeButtonDongle 30 31 32 class RelayRig: 33 """A group of relay boards and their connected devices. 34 35 This class is also responsible for handling the creation of the relay switch 36 boards, as well as the devices and relays associated with them. 37 38 The boards dict can contain different types of relay boards. They share a 39 common interface through inheriting from RelayBoard. This layer can be 40 ignored by the user. 41 42 The relay devices are stored in a dict of (device_name: device). These 43 device references should be used by the user when they want to directly 44 interface with the relay switches. See RelayDevice or GeneralRelayDevice for 45 implementation. 46 47 """ 48 DUPLICATE_ID_ERR_MSG = 'The {} "{}" is not unique. Duplicated in:\n {}' 49 50 # A dict of lambdas that instantiate relay board upon invocation. 51 # The key is the class type name, the value is the lambda. 52 _board_constructors = { 53 'SainSmartBoard': 54 lambda x: SainSmartBoard(x), 55 'RdlRelayBoard': 56 lambda x: RdlRelayBoard(x), 57 'SainSmart8ChannelUsbRelayBoard': 58 lambda x: SainSmart8ChannelUsbRelayBoard(x), 59 } 60 61 # Similar to the dict above, except for devices. 62 _device_constructors = { 63 'GenericRelayDevice': lambda x, rig: GenericRelayDevice(x, rig), 64 'FuguRemote': lambda x, rig: FuguRemote(x, rig), 65 'I6sHeadset': lambda x, rig: I6sHeadset(x, rig), 66 "LogitechAudioReceiver" :lambda x, rig: LogitechAudioReceiver(x, rig), 67 'SonyXB2Speaker': lambda x, rig: SonyXB2Speaker(x, rig), 68 'SonyXB20Speaker': lambda x, rig: SonyXB20Speaker(x, rig), 69 'AkXB10Speaker': lambda x, rig: AkXB10Speaker(x, rig), 70 'SingleButtonDongle': lambda x, rig: SingleButtonDongle(x, rig), 71 'ThreeButtonDongle': lambda x, rig: ThreeButtonDongle(x, rig), 72 } 73 74 def __init__(self, config): 75 self.relays = dict() 76 self.boards = dict() 77 self.devices = dict() 78 79 validate_key('boards', config, list, 'relay config file') 80 81 for elem in config['boards']: 82 board = self.create_relay_board(elem) 83 if board.name in self.boards: 84 raise RelayConfigError( 85 self.DUPLICATE_ID_ERR_MSG.format('name', elem['name'], 86 elem)) 87 self.boards[board.name] = board 88 89 # Note: 'boards' is a necessary value, 'devices' is not. 90 if 'devices' in config: 91 for elem in config['devices']: 92 relay_device = self.create_relay_device(elem) 93 if relay_device.name in self.devices: 94 raise RelayConfigError( 95 self.DUPLICATE_ID_ERR_MSG.format( 96 'name', elem['name'], elem)) 97 self.devices[relay_device.name] = relay_device 98 else: 99 device_config = dict() 100 device_config['name'] = 'GenericRelayDevice' 101 device_config['relays'] = dict() 102 for relay_id in self.relays: 103 device_config['relays'][relay_id] = relay_id 104 self.devices['device'] = self.create_relay_device(device_config) 105 106 def create_relay_board(self, config): 107 """Builds a RelayBoard from the given config. 108 109 Args: 110 config: An object containing 'type', 'name', 'relays', and 111 (optionally) 'properties'. See the example json file. 112 113 Returns: 114 A RelayBoard with the given type found in the config. 115 116 Raises: 117 RelayConfigError if config['type'] doesn't exist or is not a string. 118 119 """ 120 validate_key('type', config, str, '"boards" element') 121 try: 122 ret = self._board_constructors[config['type']](config) 123 except LookupError: 124 raise RelayConfigError( 125 'RelayBoard with type {} not found. Has it been added ' 126 'to the _board_constructors dict?'.format(config['type'])) 127 for _, relay in ret.relays.items(): 128 self.relays[relay.relay_id] = relay 129 return ret 130 131 def create_relay_device(self, config): 132 """Builds a RelayDevice from the given config. 133 134 When given no 'type' key in the config, the function will default to 135 returning a GenericRelayDevice with the relays found in the 'relays' 136 array. 137 138 Args: 139 config: An object containing 'name', 'relays', and (optionally) 140 type. 141 142 Returns: 143 A RelayDevice with the given type found in the config. If no type is 144 found, it will default to GenericRelayDevice. 145 146 Raises: 147 RelayConfigError if the type given does not match any from the 148 _device_constructors dictionary. 149 150 """ 151 if 'type' in config: 152 if config['type'] not in RelayRig._device_constructors: 153 raise RelayConfigError( 154 'Device with type {} not found. Has it been added ' 155 'to the _device_constructors dict?'.format(config['type'])) 156 else: 157 device = self._device_constructors[config['type']](config, 158 self) 159 160 else: 161 device = GenericRelayDevice(config, self) 162 163 return device 164