blob: 38a2315959e3b2395d66ae1a8eec6529856e67c9 [file] [log] [blame]
Sergei Trofimov4e6afe92015-10-09 09:30:04 +01001# 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#
15import logging
16from inspect import isclass
17
18from devlib.utils.misc import walk_modules
19from devlib.utils.types import identifier
20
21
22__module_cache = {}
23
24
25class 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
Sergei Trofimov92fb54d2017-10-03 16:50:23 +010059 self.logger = logging.getLogger(self.name)
Sergei Trofimov4e6afe92015-10-09 09:30:04 +010060
61
62class HardRestModule(Module): # pylint: disable=R0921
63
64 kind = 'hard_reset'
65
66 def __call__(self):
67 raise NotImplementedError()
68
69
70class 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
85class FlashModule(Module):
86
87 kind = 'flash'
88
89 def __call__(self, image_bundle=None, images=None, boot_config=None):
90 raise NotImplementedError()
91
92
93def 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
108def 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
118def __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)