1 # Copyright 2014-2015 ARM Limited 2 # 3 # Licensed under the Apache License, Version 2.0 (the "License"); 4 # you may not use this file except in compliance with the License. 5 # You may obtain a copy of the License at 6 # 7 # http://www.apache.org/licenses/LICENSE-2.0 8 # 9 # Unless required by applicable law or agreed to in writing, software 10 # distributed under the License is distributed on an "AS IS" BASIS, 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 # See the License for the specific language governing permissions and 13 # limitations under the License. 14 # 15 import logging 16 from inspect import isclass 17 18 from devlib.utils.misc import walk_modules 19 from devlib.utils.types import identifier 20 21 22 __module_cache = {} 23 24 25 class Module(object): 26 27 name = None 28 kind = None 29 # This is the stage at which the module will be installed. Current valid 30 # stages are: 31 # 'early' -- installed when the Target is first created. This should be 32 # used for modules that do not rely on the main connection 33 # being established (usually because the commumnitcate with the 34 # target through some sorto of secondary connection, e.g. via 35 # serial). 36 # 'connected' -- installed when a connection to to the target has been 37 # established. This is the default. 38 stage = 'connected' 39 40 @staticmethod 41 def probe(target): 42 raise NotImplementedError() 43 44 @classmethod 45 def install(cls, target, **params): 46 if cls.kind is not None: 47 attr_name = identifier(cls.kind) 48 else: 49 attr_name = identifier(cls.name) 50 if hasattr(target, attr_name): 51 existing_module = getattr(target, attr_name) 52 existing_name = getattr(existing_module, 'name', str(existing_module)) 53 message = 'Attempting to install module "{}" which already exists (new: {}, existing: {})' 54 raise ValueError(message.format(attr_name, cls.name, existing_name)) 55 setattr(target, attr_name, cls(target, **params)) 56 57 def __init__(self, target): 58 self.target = target 59 self.logger = logging.getLogger(self.name) 60 61 62 class HardRestModule(Module): # pylint: disable=R0921 63 64 kind = 'hard_reset' 65 66 def __call__(self): 67 raise NotImplementedError() 68 69 70 class BootModule(Module): # pylint: disable=R0921 71 72 kind = 'boot' 73 74 def __call__(self): 75 raise NotImplementedError() 76 77 def update(self, **kwargs): 78 for name, value in kwargs.iteritems(): 79 if not hasattr(self, name): 80 raise ValueError('Unknown parameter "{}" for {}'.format(name, self.name)) 81 self.logger.debug('Updating "{}" to "{}"'.format(name, value)) 82 setattr(self, name, value) 83 84 85 class FlashModule(Module): 86 87 kind = 'flash' 88 89 def __call__(self, image_bundle=None, images=None, boot_config=None): 90 raise NotImplementedError() 91 92 93 def get_module(mod): 94 if not __module_cache: 95 __load_cache() 96 97 if isinstance(mod, basestring): 98 try: 99 return __module_cache[mod] 100 except KeyError: 101 raise ValueError('Module "{}" does not exist'.format(mod)) 102 elif issubclass(mod, Module): 103 return mod 104 else: 105 raise ValueError('Not a valid module: {}'.format(mod)) 106 107 108 def register_module(mod): 109 if not issubclass(mod, Module): 110 raise ValueError('A module must subclass devlib.Module') 111 if mod.name is None: 112 raise ValueError('A module must define a name') 113 if mod.name in __module_cache: 114 raise ValueError('Module {} already exists'.format(mod.name)) 115 __module_cache[mod.name] = mod 116 117 118 def __load_cache(): 119 for module in walk_modules('devlib.module'): 120 for obj in vars(module).itervalues(): 121 if isclass(obj) and issubclass(obj, Module) and obj.name: 122 register_module(obj) 123