source: remote_control/puzzlebox_brainstorms_server_thinkgear.py @ 53

Last change on this file since 53 was 53, checked in by sc, 11 years ago

client_thinkgear:

  • code cleanups
  • enhanced debugging
  • need to fix Deferred error on C terminated connections

client_server:

  • good progress towards basic signal generator
File size: 8.2 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#
4# Puzzlebox - Brainstorms - Server - ThinkGear Emulator
5#
6# Copyright Puzzlebox Productions, LLC (2010)
7#
8# This code is released under the GNU Pulic License (GPL) version 2
9# For more information please refer to http://www.gnu.org/copyleft/gpl.html
10#
11# Last Update: 2010.06.18
12#
13#####################################################################
14
15import os, signal, sys, time
16import simplejson as json
17
18from twisted.internet import reactor, protocol, defer, task
19from twisted.protocols import basic
20
21import puzzlebox_brainstorms_configuration as configuration
22#import puzzlebox_brainstorms_client
23#import puzzlebox_logger
24
25#####################################################################
26# Globals
27#####################################################################
28
29DEBUG = 1
30
31SERVER_INTERFACE = configuration.SERVER_INTERFACE
32SERVER_PORT = configuration.THINKGEAR_SERVER_PORT
33
34THINKGEAR_DELIMITER = '\r'
35
36MESSAGE_FREQUENCY_TIMER = 1 # 1 Hz
37BLINK_FREQUENCY_TIMER = 10 # 10 seconds
38
39DEFAULT_SIGNAL_LEVEL_MESSAGE = \
40        {"poorSignalLevel": 0}
41                # A quantifier of the quality of the brainwave signal.
42                # This is an integer value that is generally in the
43                # range of 0 to 200, with 0 indicating a
44                # good signal and 200 indicating an off-head state.
45
46DEFAULT_EEG_POWER_MESSAGE = \
47        {'eegPower': { \
48                'lowGamma': 0, \
49                'highGamma': 0, \
50                'highAlpha': 0, \
51                'delta': 0, \
52                'highBeta': 0, \
53                'lowAlpha': 0, \
54                'lowBeta': 0, \
55                'theta': 0, \
56                }, \
57         } # A container for the EEG powers. These may
58           # be either integer or floating-point values.
59
60DEFAULT_ESENSE_MESSAGE = \
61        {'eSense': { \
62                'meditation': 0, \
63                'attention': 0, \
64                }, \
65        } # A container for the eSense™ attributes.
66          # These are integer values between 0 and 100,
67          # where 0 is perceived as a lack of that attribute
68          # and 100 is an excess of that attribute.
69               
70DEFAULT_BLINK_MESSAGE = {"blinkStrength": 100}
71        # The strength of a detected blink. This is
72        # an integer in the range of 0-255.
73
74DEFAULT_RAWEEG_MESSAGE = {"rawEeg": 255}
75        # The raw data reading off the forehead sensor.
76        # This may be either an integer or a floating-point value.
77
78DEFAULT_PACKET = {}
79DEFAULT_PACKET.update(DEFAULT_EEG_POWER_MESSAGE)
80DEFAULT_PACKET.update(DEFAULT_SIGNAL_LEVEL_MESSAGE)
81DEFAULT_PACKET.update(DEFAULT_ESENSE_MESSAGE)
82
83DEFAULT_RESPONSE_MESSAGE = DEFAULT_SIGNAL_LEVEL_MESSAGE
84
85#####################################################################
86# Classes
87#####################################################################
88
89class puzzlebox_brainstorms_server_thinkgear(protocol.ServerFactory):
90       
91        def __init__(self, log, DEBUG=DEBUG):
92               
93                self.log = log
94                self.DEBUG = DEBUG
95               
96                self.protocol = puzzlebox_brainstorms_server_protocol
97       
98       
99        ##################################################################
100       
101        def process_data(self, data):
102               
103                d = defer.Deferred()
104               
105##              response = '%s command received' % data
106
107                response = DEFAULT_RESPONSE_MESSAGE
108               
109                if self.DEBUG:
110                        print "--> [ThinkGear Emulator] Received:",
111                        print data
112               
113               
114##              if DISCRETE_CONTROL_COMMANDS:
115##                     
116##                      self.execute_command(command)
117               
118               
119                if response:
120                        d.callback(response)
121               
122               
123                return d
124       
125       
126        ##################################################################
127       
128##      def execute_command(self, command):
129##             
130##              #command_line = 'python puzzlebox_brainstorms_remote_control.py --command=%s' % command
131##             
132##              #os.system(command_line)
133##             
134##              rc = remote_control.puzzlebox_brainstorms_rc( \
135##                      device=configuration.BLUETOOTH_DEVICE, \
136##                      command=command, \
137##                      DEBUG=DEBUG)
138##             
139##              if rc.connection != None:
140##                      rc.run(rc.command)
141##                      rc.stop()
142       
143       
144        ##################################################################
145       
146        def process_connection_lost(self, data):
147               
148                if not data:
149                       
150                        #self.log.debug("Connection lost with no data")
151                       
152                        if self.DEBUG:
153                                print "--> [ThinkGear Emulator] Connection lost with no data"
154               
155               
156                else:
157                       
158                        #self.log.debug("Connection lost")
159                       
160                        #if self.DEBUG:
161                                #print "--> [Server] Connection lost"
162                       
163                        pass
164
165
166        ##################################################################
167
168        def send_packet(self):
169
170##              print dir(self.protocol)
171##              print self.protocol.connected
172##              if self.protocol.transport != None:
173##                      data = json.dumps(DEFAULT_SIGNAL_LEVEL_MESSAGE)
174##                      self.transport.write(data)
175
176                pass
177
178
179        ##################################################################
180
181        def start(self):
182
183                self.looping_timer = task.LoopingCall(self.send_packet)
184                self.looping_timer.start(MESSAGE_FREQUENCY_TIMER)
185
186
187#####################################################################
188# Protocol
189#####################################################################
190
191class puzzlebox_brainstorms_server_protocol(basic.LineReceiver):
192
193        delimiter='\r'
194       
195        def __init__(self):
196               
197                self.DEBUG = DEBUG
198                self.data = None
199                self.data_chunk = ""
200
201       
202        ##################################################################
203       
204        def connectionMade(self):
205               
206##              data = json.dumps(self.factory.command)
207##              self.transport.write(data)
208##             
209##              self.factory.noReply = reactor.callLater(NO_REPLY_WAIT, self.noReply)
210
211
212                if self.DEBUG:
213                        print "connectionMade"
214
215
216                response = DEFAULT_RESPONSE_MESSAGE
217
218
219                if self.DEBUG:
220                        print "--> [ThinkGear Emulator] Sending:",
221                        print response
222                       
223                response = json.dumps(response)
224##              self.transport.write(response)
225                self.sendLine(response)
226
227        ##################################################################
228       
229        def noReply(self):
230               
231                try:
232                        self.factory.replyDefer.callback('NO_REPLY')
233                except:
234                        if self.DEBUG:
235                                print "noReply failed to call callback"
236                        #self.factory.log.error("noReply failed to call callback")
237               
238                self.transport.loseConnection()
239       
240       
241        ##################################################################
242
243        def lineReceived(self, line):
244
245                # Ignore blank lines
246                if not line:
247                        return
248               
249                self.data = json.loads(line)
250
251                if self.DEBUG:
252                        print "line received:",
253                        print self.data
254
255                d = self.factory.process_data("%s" % self.data)
256                d.addCallback(self.send_response)
257
258       
259        ##################################################################
260       
261        def dataReceived(self, data):
262
263##              if self.DEBUG:
264##                      print "data received:",
265##                      print data
266               
267                self.data_chunk += data
268               
269                try:
270                        self.data = json.loads(self.data_chunk)
271               
272                except Exception, e:
273##                      self.factory.log.error("Partial data received (or error:",
274##                                             e, ").")
275                        if DEBUG:
276                                print "Partial data received (or error:",
277                                print e
278                                print ")."
279               
280                else:
281                        self.data_chunk = ""
282                       
283                        d = self.factory.process_data("%s" % self.data)
284                        d.addCallback(self.send_response)
285       
286       
287        ##################################################################
288       
289        def send_response(self, response):
290
291                if self.DEBUG:
292                        print "--> [ThinkGear Emulator] Sending:",
293                        print response
294                       
295                response = json.dumps(response)
296##              self.transport.write(response)
297                self.sendLine(response)
298
299##              reactor.callLater(MESSAGE_FREQUENCY_TIMER, self.send_response, DEFAULT_RESPONSE_MESSAGE)
300                reactor.callLater(MESSAGE_FREQUENCY_TIMER, self.send_response, DEFAULT_PACKET)
301
302       
303       
304        ##################################################################
305       
306        def connectionLost(self, reason):
307               
308                self.factory.process_connection_lost(self.data)
309
310
311#####################################################################
312# Main
313#####################################################################
314
315if __name__ == '__main__':
316       
317        #log = puzzlebox_logger.puzzlebox_logger(logfile='master_control')
318        log = None
319       
320        # Collect default settings and command line parameters
321        server_interface = SERVER_INTERFACE
322        server_port = SERVER_PORT
323       
324        for each in sys.argv:
325               
326                if each.startswith("--interface="):
327                        server_interface = each[ len("--interface="): ]
328                if each.startswith("--port="):
329                        server_port = each[ len("--port="): ]
330       
331       
332        thinkgear_server = puzzlebox_brainstorms_server_thinkgear(log, DEBUG=DEBUG)
333       
334        if DEBUG:
335                print "--> [ThinkGear Emulator] Initializing server on %s:%i" % \
336                        (server_interface, server_port)
337       
338        reactor.listenTCP(interface=server_interface, \
339                          port=server_port, \
340                          factory=thinkgear_server)
341        reactor.callWhenRunning(reactor.callLater, 0, thinkgear_server.start)
342        reactor.run()
343
Note: See TracBrowser for help on using the repository browser.