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