Subversion Repositories HomeAutomation

Rev

Details | Last modification | View Log | SVN | RSS feed

Rev Author Line No. Line
736 olof 1
###########################################################
2
#
3
# Daemon configuration
4
#
5
###########################################################
6
import logging as log
7
import pickle
8
import hashlib
9
import os
10
import imp
11
import re
12
from ConfigParser import ConfigParser
13
import filters
14
import statespaces
749 olof 15
from CanPktHandlerBase import CanPktHandlerBase
16
from CanPktHandler1 import CanPktHandler1
736 olof 17
 
750 olof 18
from NodeIfSerial import NodeIfSerial
19
from NodeIfTCP import NodeIfTCP
20
from NodeIfUDP import NodeIfUDP
21
from NodeIfTCPTLS import NodeIfTCPTLS
22
from NodeIfCanStim import NodeIfCanStim
23
 
736 olof 24
class DynamicModuleCfg:
25
    """Dynamic module manager"""
26
 
27
    modSubDir = None
28
    CHECKSUM_FILE = 'checksums'
29
    CHECKSUM_SECTION = 'SHA-1_CHECKSUMS'
30
 
31
    def __init__(self, modSubDir):
32
        self.modSubDir = modSubDir
33
        self.checkSumFile = modSubDir + '/' + self.CHECKSUM_FILE
738 olof 34
        if not os.path.exists(self.checkSumFile):
35
            self.__createCsumsFile()
736 olof 36
 
37
    def loadModule(self, className):
38
        pFileName = os.getcwd() + '/' + self.modSubDir + '/' + className + '.p'
39
        log.debug('Reading from ' + pFileName)
40
        fp = open(pFileName, 'r')
41
        p = pickle.Unpickler(fp)
42
        loadedMod = p.load()
43
        fp.close()
44
        if not self.__verifyCheckSum(className, pFileName):
45
            print 'Invalid checksum'
46
            return None
47
        else:
48
            return loadedMod
49
 
50
 
51
    def loadModules(self, config = None):
52
        subDirFiles = os.listdir(os.getcwd() + '/' + self.modSubDir)
53
        p = re.compile('.p$', re.IGNORECASE)
54
        modFiles = [elem for elem in subDirFiles if p.search(elem) is not None]
55
        modNames = []
56
        for mfName in modFiles:
57
            modNames.append(mfName.split('.')[0])
58
        log.debug('Found modules: ' + str(modNames))
59
        myMods = {}
60
        for mName in modNames:
61
            classObj = self.loadModule(mName)
62
            if classObj is not None:
63
                myMods[mName] = classObj
64
        return myMods
65
 
66
 
67
    def saveModule(self, className, classObj):
68
        pFileName = os.getcwd() + '/' + self.modSubDir + '/' + className + '.p'
69
        log.debug('Writing to ' + pFileName)
70
        fp = open(pFileName, 'w')
71
        p = pickle.Pickler(fp)
72
        p.dump(classObj)
73
        fp.close()
74
        self.__writeCheckSum(className, pFileName)
75
 
76
 
77
    def __doCheckSum(self, filename):
78
        f = open(filename, 'r')
79
        data = f.read()
80
        f.close()
81
        hasher = hashlib.sha1()
82
        hasher.update(data)
83
        digest = hasher.hexdigest()
84
        return digest
85
 
86
 
738 olof 87
    def __createCsumsFile(self):
88
         csumsfile = open(self.checkSumFile, 'w')
89
         csumsfile.write('[' + self.CHECKSUM_SECTION + ']\n')
90
         csumsfile.close()
91
 
92
 
736 olof 93
    def __writeCheckSum(self, entryname, filename):
94
        csumsfile = open(self.checkSumFile, 'r+')
95
        csumcfg = ConfigParser()
96
        csumcfg.readfp(csumsfile)
97
        digest = self.__doCheckSum(filename)
98
        csumcfg.set(self.CHECKSUM_SECTION, entryname, digest)
99
        csumsfile.seek(0)
100
        csumcfg.write(csumsfile)
101
 
102
 
103
    def __verifyCheckSum(self, entryname, filename):
104
        csumsfile = open(self.checkSumFile, 'r')
105
        csumcfg = ConfigParser()
106
        csumcfg.readfp(csumsfile)
107
        digest = csumcfg.get(self.CHECKSUM_SECTION, entryname)
108
        cur_digest = self.__doCheckSum(filename)
109
        log.debug('Old checksum ' + digest + '\nNew checksum: ' + cur_digest)
110
        if cur_digest == digest:
111
            return True
112
        return False
113
 
114
 
115
    def importModule(self, className, requiredAttributes):
116
        """Imports a given class from the module with the same name """
117
 
118
        codeFile = os.getcwd() + '/' + self.modSubDir + '/' + className + '.py'
119
        mod = imp.load_source(self.modSubDir + '.' + className, codeFile)
120
        newClass = eval('mod.' + className)()
121
 
122
        for ra in requiredAttributes:
123
            if not hasattr(newClass, ra):
124
                print className, ': missing required symbol \"' + ra + '\"'
125
                return None
126
 
127
        self.saveModule(className, newClass)
128
        return newClass
129
 
130
 
131
class FilterCfg:
132
    """Filter resource manager"""
133
 
134
    REQUIRED_ATTRIBUTES = ['ASSOCIATED_SPACES', 'DESCRIPTIVE_NAME',
135
                           'attach', 'detach', 'filter']
136
 
137
    dynamicModuleCfg = None
138
    FILTER_SUBDIR = 'filters'
139
    filterModules = {}
140
 
141
    def __init__(self):
142
        self.dynamicModuleCfg = DynamicModuleCfg(self.FILTER_SUBDIR)
143
 
144
    def loadFilter(self, name):
145
        newFilt = self.dynamicModuleCfg.loadModule(name)
146
        if newFilt is not None:
748 olof 147
            self.filterModules[name] = newFilt
736 olof 148
            return True
149
        else:
150
            return False
151
 
152
    def loadFilters(self, config = None):
153
        self.filterModules = self.dynamicModuleCfg.loadModules()
154
        for fM in self.filterModules:
155
            log.debug(fM)
156
 
157
    def __saveFilter(self, className, classObj):
158
        self.dynamicModuleCfg.saveModule(className, classObj)
159
 
160
    def saveFilters(self):
161
        for className in self.filterModules:
162
            self.__saveFilter(className, self.filterModules[className])
163
 
164
    def importFilter(self, className):
165
        """Imports a given filter definition """
166
        classObj = self.dynamicModuleCfg.importModule(className, self.REQUIRED_ATTRIBUTES)
167
        if classObj is not None:
168
            print 'Imported: ' + classObj.DESCRIPTIVE_NAME
169
            return True
170
        else:
171
            return False
172
 
173
 
174
class StateSpaceCfg:
175
    """State space resource manager"""
176
 
748 olof 177
    REQUIRED_ATTRIBUTES = ['DESCRIPTIVE_NAME', 'RELATED_SPACES'
736 olof 178
                           'load', 'reset', 'run', 'unload']
179
 
180
    dynamicModuleCfg = None
181
    FILTER_SUBDIR = 'statespaces'
182
    spaceModules = {}
183
 
184
    def __init__(self):
185
        self.dynamicModuleCfg = DynamicModuleCfg(self.FILTER_SUBDIR)
186
 
187
    def loadSpace(self, name):
188
        newSpace = self.dynamicModuleCfg.loadModule(name)
189
        if newSpace is not None:
748 olof 190
            self.spaceModules[name] = newFilt
736 olof 191
            return True
192
        else:
193
            return False
194
 
195
    def loadSpaces(self, config = None):
196
        self.spaceModules = self.dynamicModuleCfg.loadModules()
197
        for sM in self.spaceModules:
198
            log.debug(sM)
199
 
200
    def __saveSpace(self, className, classObj):
201
        self.dynamicModuleCfg.saveModule(className, classObj)
202
 
203
    def saveSpaces(self):
204
        for className in self.spaceModules:
205
            self.__saveSpace(className, self.spaceModules[className])
206
 
207
    def importSpace(self, name):
208
        """Imports a given state space definition file """
209
        classObj = self.dynamicModuleCfg.importModule(name, self.REQUIRED_ATTRIBUTES)
210
        if classObj is not None:
211
            print 'Imported: ' + classObj.DESCRIPTIVE_NAME
212
            return True
213
        else:
214
            return False
215
 
216
class DaemonConfig:
217
 
218
    stateSpaceCfg = None
219
    filterCfg = None
749 olof 220
    pktHandler = None
221
 
736 olof 222
    filterChain = []
749 olof 223
    nodeInterfaces = []
224
    nodeInterfaceMap = {}
736 olof 225
 
750 olof 226
    INTERFACE_TYPES = {'serial' : NodeIfSerial, 'tcp' : NodeIfTCP,
227
                       'udp' : NodeIfUDP, 'sim' : NodeIfCanStim,
228
                       'tcptls' : NodeIfTCPTLS}
229
 
736 olof 230
    def __init__ (self):
231
        self.filterCfg = FilterCfg()
232
        self.stateSpaceCfg = StateSpaceCfg()
750 olof 233
        self.pktHandler = CanPktHandler1(self)
736 olof 234
 
749 olof 235
    def load(self):
236
        self.stateSpaceCfg.loadSpaces()
750 olof 237
        self.filterCfg.loadFilters()
238
        self.__setupFilterBindings()
239
        self.__setupStateSpaceRelations()
240
        self.__setupFilterChain()
241
 
749 olof 242
    def save(self):
243
        self.stateSpaceCfg.saveSpaces()
244
        self.filterCfg.saveFilters()
245
 
750 olof 246
    def addInterface(self, type, cfg = None):
247
        """ addInterface
248
        type - a valid interface type name
249
        cfg - interface configuration
250
        returns: True on success, False otherwise """
251
 
252
        if not self.INTERFACE_TYPES.has_key(type):
253
            log.debug('addInterface called with invalid interface type')
254
            return False
255
 
256
        cfg = self.INTERFACE_TYPES[type].DEFAULT_CONFIG
257
        print cfg
258
        nodeIf = self.INTERFACE_TYPES[type](self.pktHandler, cfg)
259
        print nodeIf
260
        self.nodeInterfaces.append(nodeIf)
261
 
262
    def remInterface(self, name):
263
        pass
264
 
749 olof 265
    def __setupFilterChain(self):
736 olof 266
        self.filterChain = ['DefaultFilter']
267
 
749 olof 268
    def __setupFilterBindings(self):
736 olof 269
        for f in self.filterCfg.filterModules.values():
270
            assocSpaces = []
271
            for s in f.ASSOCIATED_SPACES:
272
                if self.stateSpaceCfg.spaceModules.has_key(s):
273
                    assocSpaces.append(self.stateSpaceCfg.spaceModules[s])
274
                else:
275
                    print 'WARNING: Reference to undefined state space: ' + s
276
            setattr(f, '__ASSOCIATED_SPACES__', assocSpaces)
748 olof 277
 
750 olof 278
    def __setupStateSpaceRelations(self):
748 olof 279
        for sm in self.stateSpaceCfg.spaceModules:
280
            relatedSpaceNames = self.stateSpaceCfg.spaceModules[sm].RELATED_SPACES
281
            relatedSpaces = {}
282
            for rsname in relatedSpaceNames:
283
                relatedSpaces[rsname] = self.stateSpaceCfg.spaceModules[rsname]
750 olof 284
            setattr(self.stateSpaceCfg.spaceModules[sm], '__RELATED_SPACES__', relatedSpaces)
285