Subversion Repositories HomeAutomation

Rev

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

Rev Author Line No. Line
736 olof 1
#!/bin/env python
2
 
3
import os
4
import sys
5
import logging as log
6
import getopt
7
import atexit
738 olof 8
import time
736 olof 9
 
10
from CanPktHandlerBase import CanPktHandlerBase
11
from CanPktHandler1 import CanPktHandler1
12
 
13
from NodeIfBase import NodeIfBase
14
from NodeIfCanStim import NodeIfCanStim
15
from NodeIfSerial import NodeIfSerial
746 olof 16
from NodeIfTCP import NodeIfTCP
736 olof 17
 
18
from DaemonConfig import DaemonConfig
19
 
20
daemonApp = None
21
 
22
class CanDaemon():
23
 
740 olof 24
    cfg = None
736 olof 25
    nodeIf = None
738 olof 26
    ifNotifier = None
27
    terminated = False
741 olof 28
 
739 olof 29
    command_list = []
740 olof 30
    command_map = {}
741 olof 31
    CMDLIST_NAME = 0
32
    CMDLIST_HANDLER = 1
33
    CMDLIST_PARAMINFO = 2
34
    CMDLIST_HELP = 3
35
 
36
    logHelp = 'usage:\t log [options]\n\n' \
37
              '\t options:\n' \
38
              '\t level <num>, where: 0 < num < 3\n'
39
    stateHelp = 'usage: state [name/add/rem]'
40
    filterHelp = 'usage: filter [name/add/rem]'
41
    addifHelp = 'usage: addif [name] [options]'
42
    addbridgeHelp = 'usage: addbridge [interface names]'
43
    tcpdHelp = 'usage: tcpd [start/stop/configure] [options]'
44
    tlsdHelp = 'usage: tlsd [start/stop/configure] [options]'
45
    canctldHelp = 'usage: canctld [start/stop/configure] [options]'
46
    simHelp = 'usage: sim [record/play/add/rem/save/load] [options]'
740 olof 47
    help_command_map = {}
741 olof 48
 
49
    logOptions = {}
50
    ifOptions = {}
51
    bridgeOptions = {}
52
    tcpdOptions = {}
53
    tlsdOptions = {}
54
    canctldOptions = {}
55
    simOptions = {}
739 olof 56
 
741 olof 57
    logValidOptions = {'level' : ['range', 0, 3]}
58
    ifValidOptions = {'type' : ['alt', 'serial','udp']}
59
 
60
    ifSerialOptions = {'' : []}
61
    ifCanStimOptions = {'' : []}
62
    ifTelnetOptions = {'' : []}
63
    ifTcpTlsOptions = {'' : []}
64
    ifUDPOptions = {'' : []}
65
 
66
    bridgeValidOptions = {'' : ['']}
67
    tcpdValidOptions = {'' : []}
68
    tlsdValidOptions = {'' : []}
69
    canctldValidOptions = {'' : []}
70
    simValidOptions = {'' : []}
71
 
739 olof 72
    def __init__ (self):
740 olof 73
 
741 olof 74
        self.command_list = [['help', self.helpCmd, '', 'display help'],
75
                       ['log', self.logCmd, '<options>', 'log control: \"help log\"'],
76
                       ['exec', self.execCmd, '<filename>', 'run command listing\n'],
77
                       ['filter', self.filterCmd, '<cmd>', 'filter commands: \"help filter\"'],
78
                       ['state', self.stateCmd, '<cmd>', 'state commands: \"help state\"\n'],
79
                       ['addif', self.ifAddCmd, '<options>', 'add interface: \"help addif\"'],
80
                       ['remif', self.ifRemCmd, '<name>', 'remove interface'],
81
                       ['ifup', self.ifUpCmd, '<name>', 'bring up interface'],
82
                       ['ifdown', self.ifDownCmd, '<name>', 'bring down interface\n'],
83
                       ['addbrigde', self.addBridgeCmd, '<options>', 'add bridge: \"help addbridge\"'],
84
                       ['rembridge', self.remBridgeCmd, '<id>', 'remove bridge\n'],
85
                       ['tcpd', self.tcpdCmd, '<cmd>', 'tcpd server control: \"help tcpd\"'],
86
                       ['tlsd', self.tlsdCmd, '<cmd>', 'tlsd server control: \"help tlsd\"'],
87
                       ['canctld', self.canCtldCmd, '<cmd>', 'canctld server control: \"help canctld\"\n'],
88
                       ['status', self.statusCmd, '', 'show daemon status'],
89
                       ['stats', self.statsCmd, '', 'show statistics\n'],
90
                       ['nodelist', self.nodesCmd, '', 'list can nodes'],
91
                       ['filterlist', self.filterlistCmd, '', 'list active filters\n'],
92
                       ['sim', self.simCmd, '<cmd>', 'simulator commands: \"help sim\"']]
93
 
740 olof 94
        index = 0
95
        for cmd in self.command_list:
96
            self.command_map[cmd[0]] = index
97
            index += 1
98
 
741 olof 99
        self.help_command_map = {'log' : self.logHelp,
100
                                'filter' : self.filterHelp,
101
                                'state' : self.stateHelp,
102
                                'addif' : self.addifHelp,
103
                                'addbridge' : self.addbridgeHelp,
104
                                'tcpd' : self.tcpdHelp,
105
                                'tlsd' : self.tlsdHelp,
106
                                'canctld' : self.canctldHelp,
107
                                'sim' : self.simHelp}
740 olof 108
 
109
        self.cfg = DaemonConfig()
736 olof 110
 
738 olof 111
    class IfNotifier():
739 olof 112
        """ Used by if threads to send messages to the main program thread """
742 olof 113
 
114
        parent = None
738 olof 115
        UNDEFINED = 0
116
        TERMINATE = 1
742 olof 117
 
118
        def __init__(self, parent):
119
            self.parent = parent
738 olof 120
 
121
        def notify(self, msg):
122
            if msg == self.TERMINATE:
123
                print 'Main terminate notify'
124
            else:
125
                print 'UNDEFINED NOTIFY'
126
 
739 olof 127
 
128
    def __rightAdjust(self, refstr, str):
129
        spcstr = ''
741 olof 130
        endpos = 25-len(refstr)
739 olof 131
        for i in range(1,endpos):
132
            if i == endpos-5:
133
                spcstr += ':'
134
            else:
135
                spcstr += ' '
136
        return (spcstr+str)
137
 
138
    def helpCmd(self, *args):
741 olof 139
        try:
140
            args = args[0]
141
        except:
142
            args = []
740 olof 143
        if len(args) < 1:
144
            quitStr = 'quit, exit'
145
            print quitStr, self.__rightAdjust(quitStr, 'shutdown pyCanDaemon')
146
            for cmd in self.command_list:
741 olof 147
                cmdstr = cmd[self.CMDLIST_NAME] + ' ' + cmd[self.CMDLIST_PARAMINFO]
148
                print cmdstr, \
149
                      self.__rightAdjust(cmdstr, cmd[self.CMDLIST_HELP])
740 olof 150
        elif len(args) < 2:
151
            subCmd = args[0]
152
            if self.help_command_map.has_key(subCmd):
153
                print self.help_command_map[subCmd]
154
            else:
155
                print 'no help for ' + subCmd
156
        else:
157
            print 'usage: help [topic]'
158
 
739 olof 159
    def filterCmd(self, *args):
741 olof 160
        try:
161
            args = args[0]
162
        except:
163
            args = []
164
        log.debug('filterCmd ' + str(args))
165
        if len(args) < 2:
166
            print 'Invalid arguments\n' + self.filterHelp
167
            return
740 olof 168
        cmd = args[0]
169
        filterName = args[1]
170
        # FIXME: verify 
171
        if cmd == 'add':
172
            print 'Importing filter: ' + filterName
173
            self.cfg.filterCfg.importFilter(filterName)
174
        elif cmd == 'rem' or cmd == 'remove':
175
            print 'Deleting filter: ' + filterName
176
            # FIXME: actually delete
741 olof 177
            raise 'Not implemented'
736 olof 178
 
739 olof 179
    def stateCmd(self, *args):
741 olof 180
        try:
181
            args = args[0]
182
        except:
183
            args = []
184
        log.debug('stateCmd ' + str(args))
185
        if len(args) < 2:
186
            print 'Invalid arguments\n' + self.stateHelp
187
            return
740 olof 188
        cmd = args[0]
189
        spaceName = args[1]
741 olof 190
        # FIXME: verify 
740 olof 191
        if cmd == 'add':
192
            print 'Importing state space: ' + spaceName
193
            self.cfg.stateSpaceCfg.importSpace(spaceName)
194
        elif cmd == 'rem' or cmd == 'remove':
195
            print 'Deleting state space: ' + spaceName
196
            # FIXME: actually delete statespace
741 olof 197
            raise 'Not implemented'
736 olof 198
 
739 olof 199
    def ifAddCmd(self, *args):
741 olof 200
        raise 'not implemented'
736 olof 201
 
739 olof 202
    def ifRemCmd(self, *args):
741 olof 203
        raise 'not implemented'
740 olof 204
 
739 olof 205
    def ifUpCmd(self, *args):
741 olof 206
        raise 'not implemented'
740 olof 207
 
739 olof 208
    def ifDownCmd(self, *args):
741 olof 209
        raise 'not implemented'
736 olof 210
 
739 olof 211
    def addBridgeCmd(self, *args):
741 olof 212
        raise 'not implemented'
740 olof 213
 
739 olof 214
    def remBridgeCmd(self, *args):
741 olof 215
        raise 'not implemented'
739 olof 216
 
217
    def tcpdCmd(self, *args):
741 olof 218
        raise 'not implemented'
739 olof 219
 
220
    def tlsdCmd(self, *args):
741 olof 221
        raise 'not implemented'
739 olof 222
 
223
    def canCtldCmd(self, *args):
741 olof 224
        raise 'not implemented'
739 olof 225
 
226
    def statusCmd(self, *args):
741 olof 227
        raise 'not implemented'
739 olof 228
 
229
    def statsCmd(self, *args):
741 olof 230
        raise 'not implemented'
739 olof 231
 
232
    def nodesCmd(self, *args):
741 olof 233
        raise 'not implemented'
739 olof 234
 
235
    def filterlistCmd(self, *args):
741 olof 236
        raise 'not implemented'
739 olof 237
 
238
    def simCmd(self, *args):
741 olof 239
        raise 'not implemented'
739 olof 240
 
241
    def logCmd(self, *args):
741 olof 242
        raise 'not implemented'
740 olof 243
 
739 olof 244
    def execCmd(self, *args):
741 olof 245
        raise 'not implemented'
739 olof 246
 
741 olof 247
    def parseCommand(self, cmdstr):
248
        incmd = cmdstr.strip()
249
        cmd = incmd.split(' ')
250
        if len(cmd[0]) < 2:
251
            return
252
        cmd[0] = cmd[0].lower()
253
        if cmd[0] == 'quit' or cmd[0] == 'exit':
254
            self.terminated = True
255
        elif self.command_map.has_key(cmd[0]):
256
            self.command_list[self.command_map[cmd[0]]][self.CMDLIST_HANDLER](cmd[1:])
257
        else:
258
            print 'unknown command: ' + cmd[0]
259
 
736 olof 260
    def exitHelper(self):
737 olof 261
        if self.nodeIf is not None and self.nodeIf.running():
736 olof 262
            self.nodeIf.stop()
739 olof 263
 
264
    def exceptHelper(self, type, value, tb):
265
        import traceback
266
        traceback.print_exception(type, value, tb)
267
        print '\nException in main program, shutting down threads'
268
        self.terminated = True
269
        self.exitHelper()
270
 #       sys.exit(-1)
271
 
736 olof 272
    def run(self):
273
        try:
741 olof 274
            myPath = os.path.dirname(__file__)
275
            os.chdir(myPath)
736 olof 276
        except:
277
            return
278
 
737 olof 279
        print 'INIT: Start logging'
736 olof 280
        log.basicConfig(level=log.DEBUG)
281
 
741 olof 282
        """command parameters only dictate verbosity and use of config file"""
737 olof 283
        print 'INIT: Get config options from command line / config file'
736 olof 284
        try:
285
            opts, args = getopt.getopt(sys.argv[1:], "ho:v", ["help", "output="])
286
        except getopt.GetoptError:
287
            print 'Invalid usage'
288
            usage()
289
            sys.exit(2)
290
     #   output = None
291
     #   verbose = False
292
        for o, a in opts:
293
            if o == "-v":
294
                pass
295
     #           verbose = True
296
            if o in ("-h", "--help"):
297
                usage()
298
                sys.exit()
299
            if o in ("-o", "--output"):
300
                pass
301
    #            output = a
740 olof 302
 
741 olof 303
        """load config defaults, or last config if exists"""
304
        """run startup.cfg"""
305
 
306
#        print 'INIT: Loading filters and spaces'
740 olof 307
#       self.cfg.filterCfg.importFilter('DefaultFilter')
308
#       self.cfg.stateSpaceCfg.importSpace('DefaultStateSpace')
741 olof 309
#        self.cfg.stateSpaceCfg.loadSpaces()
310
#        self.cfg.filterCfg.loadFilters()
311
#        self.cfg.setupFilterBindings()
312
#        self.cfg.setupFilterChain()
740 olof 313
 
741 olof 314
#        print 'INIT: Starting selected can interface'
315
#        ''' nodeif thread launch '''
746 olof 316
        self.ifNotifier = self.IfNotifier(self)
317
        pktHandler = CanPktHandler1(self.cfg)
741 olof 318
#        
319
#        ifConfig = NodeIfCanStim.DEFAULT_CONFIG
320
#        self.nodeIf = NodeIfCanStim(ifConfig, pktHandler, self.ifNotifier)
321
# #       ifConfig = NodeIfSerial.DEFAULT_CONFIG
746 olof 322
        ifConfig = NodeIfTCP.DEFAULT_CONFIG
741 olof 323
#    
746 olof 324
        atexit.register(self.exitHelper)
325
        sys.excepthook = self.exceptHelper
326
        self.nodeIf = NodeIfTCP(pktHandler, self.ifNotifier ,None)
327
#       self.nodeIf = NodeIfSerial(pktHandler, ifConfig)
741 olof 328
#        
746 olof 329
        if not self.nodeIf.start():
330
            print 'FATAL: Failed to initialize node interface.'
331
            print 'This may indicate that the interface is unavailable, ' \
332
                  'or that you do not have permission to access it.'
333
            sys.exit(-1)
736 olof 334
 
335
        print 'Initialize/gather info on connected can nodes and load associated state'
336
        print 'Start selected TCP and UDP server(s)'
337
        # server threads launch
338
 
339
        print 'CanDaemon v1 ready'
340
        print 'Enter command or type \"help\" for a list of commands'
738 olof 341
        while not self.terminated:
741 olof 342
            input = raw_input('> ')
343
            self.parseCommand(input)
739 olof 344
 
736 olof 345
        print 'Shutdown'
741 olof 346
#        if self.nodeIf.running():
347
#            print 'Stopping If thread'
348
#            self.nodeIf.stop()
738 olof 349
 
741 olof 350
#        self.cfg.stateSpaceCfg.saveSpaces()
351
#        self.cfg.filterCfg.saveFilters()
738 olof 352
 
739 olof 353
        print 'Waiting 0.1..'
738 olof 354
        time.sleep(0.1) # wait for threads
739 olof 355
        print 'Terminating'
738 olof 356
        sys.exit(0) # will except if there are threads remaining
736 olof 357
 
358
#---------------------------------------------------------------------------
359
 
360
def main():
361
    daemonApp = CanDaemon()
737 olof 362
#    install_thread_excepthook()
736 olof 363
    daemonApp.run()
364
 
365
#---------------------------------------------------------------------------
366
 
367
if __name__ == '__main__':
368
    __name__ = 'Main'
369
    main()